Repository: awslabs/s2n-bignum
Pull request #189: Enable testing of instructions with memory operands in x86_64 simulator
Author: login: pennyannn
Created: 2025-02-05T23:18:28Z | Merged: 2025-03-06T20:51:14Z

*Description of changes:*
This is a PR following what is done in https://github.com/awslabs/s2n-bignum/pull/186 for enabling testing of instructions with memory operands in x86_64 simulator.

Specifically, cosimulation tests with memory operands are added for the following instructions:
```
ADD, ADC, OR, SBB, SUB, XOR, MOV, CMOVA, CMOVB, MUL, PUSH and POP
```
They are tested for two addressing modes: `base + scale * index + displacement` and `base + displacement`. The tested operand size is 64 and displacement is `disp8`. One additional test is added when `base` register is `rsp`. They are represented as the following calls in the code:
```
cosimulate_mem_full_harness([opcode]); (* base + scale * index + displacement *)
cosimulate_mem_base_disp_harness([opcode]); (* base + displacement *)
cosimulate_mem_rsp_harness([opcode]); (* rsp_base + scale * index + displacement *)
```
To simplify the problem, the register usage is mostly fixed, however the parameters (`base`, `scale`, `index`, and `displacement`) are randomized. For `PUSH` and `POP`, the register usage is also randomized. 
These instructions and their respective addressing modes are chosen because they appear in existing s2n-bignum assembly. 
The `cosimulate_xxx_harness` functions are added in file x86-mem-insns.ml for convenience of adding tests for future x86 instruction modeling. 

Unlike in Arm, many of the instructions can take memory operands in x86. Therefore I set the cosimulation fraction to be 50% for both non memory-accessing instruction and memory-accessing instruction. The number of tests run in a 40min run is reduced from 2000 to 200, meaning it is now 10 times slower. Reducing the percentage to 10% and around 800 instructions are tested. Some analysis for why this slowdown:
1. The tactics used for the simulation proof is slightly more complex than the ARM version. Specifically, we repeated the use of `READ_MEMORY_MERGE_CONV` and `ASM_REWRITE_TAC[]` as in 
```
(if memop then CONV_TAC(ONCE_DEPTH_CONV READ_MEMORY_MERGE_CONV)
   else ALL_TAC) THEN
  ASM_REWRITE_TAC[] THEN extra_simp_tac THEN
  (if memop then CONV_TAC(ONCE_DEPTH_CONV READ_MEMORY_MERGE_CONV)
   else ALL_TAC) THEN
  ASM_REWRITE_TAC[] THEN extra_simp_tac
```
2. While running conversion over these tests, terms like `val (word xxx))` appear in expressions causing proofs to fail. To fix this problem, John (@jargh) proposes adding a tactic `EPTH_CONV WORD_NUM_RED_CONV THENC` in `x86_conv`. This change has an impact on all tests
3. Auxiliary instructions are slightly more. For example `cosimulate_mem_full_harness` function takes five instructions to simulate one

One minor thing, I often find myself having to test if an instruction could be decoded by s2n-bignum, so I wrote this function that currently resides in simulator.ml:
```
(* A function that decodes a list of bytes into an x86 instruction.
 Could be used for figuring out if an instruction exist in s2n-bignum. *)
let decode_inst ibytes =
  let ibyteterm =
     mk_flist(map (curry mk_comb `word:num->byte` o mk_small_numeral) ibytes) in
  let execth = X86_MK_EXEC_RULE(REFL ibyteterm) in
  let decoded = mk_flist
     (map (rand o rand o snd o strip_forall o concl o Option.get)
       (filter Option.is_some (Array.to_list (snd execth)))) in
  let _ = print_term decoded in
  decoded
```
I find it really helpful in times, but I'm not sure where to put it. Let me know if it should be moved to somewhere else.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.



Diff:
diff --git a/arm/proofs/simulator.ml b/arm/proofs/simulator.ml
index 625530442..1ac31e855 100755
--- a/arm/proofs/simulator.ml
+++ b/arm/proofs/simulator.ml
@@ -130,6 +130,10 @@ let template =
 
 let num_two_to_64 = Num.num_of_string "18446744073709551616";;
 
+(* This makes MESON quiet. *)
+verbose := false;;
+
+
 let READ_MEMORY_MERGE_CONV =
   let baseconv =
     GEN_REWRITE_CONV I [READ_MEMORY_BYTESIZED_SPLIT] THENC
@@ -169,8 +173,25 @@ let tac_before memop =
    `read SP s = stackpointer /\ P (read SP s) s <=>
     read SP s = stackpointer /\ P stackpointer s`] THEN
   ENSURES_INIT_TAC "s0" THEN
-  (if memop then MAP_EVERY MEMORY_SPLIT_TAC (1--4) else ALL_TAC)
-and tac_main memop = (if memop then ARM_VSTEPS_TAC else ARM_STEPS_TAC)
+  (if memop then
+    MAP_EVERY MEMORY_SPLIT_TAC (1--4) THEN
+	  (* Remove non-"memory :> bytes8" reads because they are not necessary :) *)
+    let non_byte_read_list = [
+      `read (memory :> bytes16 x) s = y`;
+      `read (memory :> bytes32 x) s = y`;
+      `read (memory :> bytes64 x) s = y`;
+      `read (memory :> bytes128 x) s = y`
+    ] in
+    DISCARD_MATCHING_ASSUMPTIONS non_byte_read_list
+  else ALL_TAC)
+and tac_main (memopidx: int option) mc states =
+  begin match memopidx with
+  | Some idx ->
+    let states1, states2 = chop_list idx states in
+    (if states1 <> [] then ARM_STEPS_TAC mc states1 else ALL_TAC) THEN
+    (if states2 <> [] then ARM_VSTEPS_TAC mc states2 else ALL_TAC)
+  | None -> ARM_STEPS_TAC mc states
+  end
 and tac_after memop =
   (if memop then MAP_EVERY MEMORY_SPLIT_TAC (0--4) else ALL_TAC) THEN
   ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN
@@ -186,7 +207,7 @@ and tac_after memop =
  *** it can be modified in between.
  ***)
 
-let cosimulate_instructions memop icodes =
+let cosimulate_instructions (memopidx: int option) icodes =
   let icodestring =
     end_itlist (fun s t -> s^","^t) (map string_of_num_hex icodes) in
   let _ =
@@ -257,9 +278,9 @@ let cosimulate_instructions memop icodes =
     can prove
      (goal,
       PURE_REWRITE_TAC [fst execth] THEN
-      (tac_before memop THEN
-       tac_main memop execth (1--length icodes) THEN
-       tac_after memop)) in
+      (tac_before (memopidx <> None) THEN
+       tac_main memopidx execth (1--length icodes) THEN
+       tac_after (memopidx <> None))) in
     (decoded,result)
   else
     let decoded = mk_flist(map mk_numeral icodes) in
@@ -269,7 +290,7 @@ let cosimulate_instructions memop icodes =
 
 let run_random_regsimulation () =
   let icode:num = random_instruction iclasses in
-  cosimulate_instructions false [icode];;
+  cosimulate_instructions None [icode];;
 
 (* ------------------------------------------------------------------------- *)
 (* Setting up safe self-contained tests for load-store instructions.         *)
@@ -343,31 +364,40 @@ let memclasses = [cosimulate_ldst_12; cosimulate_ld1r];;
 
 let run_random_memopsimulation() =
   let icodes = el (Random.int (length memclasses)) memclasses () in
-  cosimulate_instructions true icodes;;
+  let _ = assert (length icodes >= 2) in
+  let memop_index = length icodes - 2 in
+  cosimulate_instructions (Some memop_index) icodes;;
 
 (* ------------------------------------------------------------------------- *)
 (* Keep running tests till a failure happens then return it.                 *)
 (* ------------------------------------------------------------------------- *)
 
 let run_random_simulation() =
-  if Random.int 100 < 90 then run_random_regsimulation()
-  else run_random_memopsimulation();;
+  if Random.int 100 < 90 then
+    let decoded, result = run_random_regsimulation() in
+    decoded,result,true
+  else
+    let decoded, result = run_random_memopsimulation() in
+    decoded,result,false;;
 
 let time_limit_sec = 1800.0;;
-let tested_instances = ref 0;;
+let tested_reg_instances = ref 0;;
+let tested_mem_instances = ref 0;;
 
 let rec run_random_simulations start_t =
-  let decoded,result = run_random_simulation() in
+  let decoded,result,isreg = run_random_simulation() in
   if result then begin
-    tested_instances := !tested_instances + 1;
+    tested_reg_instances := !tested_reg_instances + (if isreg then 1 else 0);
+    tested_mem_instances := !tested_mem_instances + (if isreg then 0 else 1);
     let fey = if is_numeral (lhand decoded)
               then " (fails correctly) instruction codes " else " " in
     let _ = Format.print_string("OK:" ^ fey ^ string_of_term decoded);
             Format.print_newline() in
     let now_t = Sys.time() in
     if now_t -. start_t > time_limit_sec then
-      let _ = Printf.printf "Finished (time limit: %fs, tested instances: %d)\n"
-          time_limit_sec !tested_instances in
+      let _ = Printf.printf "Finished (time limit: %fs, tested reg instances: %d, tested mem instances: %d, total: %d)\n"
+          time_limit_sec !tested_reg_instances !tested_mem_instances
+          (!tested_reg_instances + !tested_mem_instances) in
       None
     else run_random_simulations start_t
   end
diff --git a/x86/proofs/simulator.c b/x86/proofs/simulator.c
index caf491a92..e9d414205 100755
--- a/x86/proofs/simulator.c
+++ b/x86/proofs/simulator.c
@@ -4,7 +4,7 @@
 
 #define DEBUG 0
 
-// regs[0..79]:  integer registers, YMMs and flags
+// regs[0..111]:  integer registers, YMMs, flags and small buffer in stack
 //
 //      RAX = regfile[0]
 //      RCX = regfile[1]
@@ -30,56 +30,66 @@
 //      ...
 //      YMM15.d[2] = regfile[78]
 //      YMM15.d[3] = regfile[79]
+//      [SP,...,SP+255] = regfile[80...111]
 
-static uint64_t regs[80];
+#define STATESIZE 112
+static uint64_t regs[STATESIZE];
 
 extern uint64_t harness(uint64_t *regfile);
 
 void print_regs()
 { uint64_t i;
-  printf("   RAX = 0x%016lx\n",regs[0]);
-  printf("   RCX = 0x%016lx\n",regs[1]);
-  printf("   RDX = 0x%016lx\n",regs[2]);
-  printf("   RBX = 0x%016lx\n",regs[3]);
-  printf("   RBP = 0x%016lx\n",regs[5]);
-  printf("   RSI = 0x%016lx\n",regs[6]);
-  printf("   RDI = 0x%016lx\n",regs[7]);
-  printf("    R8 = 0x%016lx\n",regs[8]);
-  printf("    R9 = 0x%016lx\n",regs[9]);
-  printf("   R10 = 0x%016lx\n",regs[10]);
-  printf("   R11 = 0x%016lx\n",regs[11]);
-  printf("   R12 = 0x%016lx\n",regs[12]);
-  printf("   R13 = 0x%016lx\n",regs[13]);
-  printf("   R14 = 0x%016lx\n",regs[14]);
-  printf("   R15 = 0x%016lx\n",regs[15]);
+  printf("   RAX = 0x%016"PRIx64"\n",regs[0]);
+  printf("   RCX = 0x%016"PRIx64"\n",regs[1]);
+  printf("   RDX = 0x%016"PRIx64"\n",regs[2]);
+  printf("   RBX = 0x%016"PRIx64"\n",regs[3]);
+  printf("   RBP = 0x%016"PRIx64"\n",regs[5]);
+  printf("   RSI = 0x%016"PRIx64"\n",regs[6]);
+  printf("   RDI = 0x%016"PRIx64"\n",regs[7]);
+  printf("    R8 = 0x%016"PRIx64"\n",regs[8]);
+  printf("    R9 = 0x%016"PRIx64"\n",regs[9]);
+  printf("   R10 = 0x%016"PRIx64"\n",regs[10]);
+  printf("   R11 = 0x%016"PRIx64"\n",regs[11]);
+  printf("   R12 = 0x%016"PRIx64"\n",regs[12]);
+  printf("   R13 = 0x%016"PRIx64"\n",regs[13]);
+  printf("   R14 = 0x%016"PRIx64"\n",regs[14]);
+  printf("   R15 = 0x%016"PRIx64"\n",regs[15]);
   printf("    OF = %d\n",(regs[4] & (1<<11)) != 0);
   printf("    SF = %d\n",(regs[4] & (1<<7)) != 0);
   printf("    ZF = %d\n",(regs[4] & (1<<6)) != 0);
   printf("    AF = %d\n",(regs[4] & (1<<4)) != 0);
   printf("    PF = %d\n",(regs[4] & (1<<2)) != 0);
   printf("    CF = %d\n",(regs[4] & (1<<0)) != 0);
-  printf("  YMM0 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[19],regs[18],regs[17],regs[16]);
-  printf("  YMM1 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[23],regs[22],regs[21],regs[20]);
-  printf("  YMM2 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[27],regs[26],regs[25],regs[24]);
-  printf("  YMM3 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[31],regs[30],regs[29],regs[28]);
-  printf("  YMM4 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[35],regs[34],regs[33],regs[32]);
-  printf("  YMM5 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[39],regs[38],regs[37],regs[36]);
-  printf("  YMM6 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[43],regs[42],regs[41],regs[40]);
-  printf("  YMM7 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[47],regs[46],regs[45],regs[44]);
-  printf("  YMM8 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[51],regs[50],regs[49],regs[48]);
-  printf("  YMM9 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[55],regs[54],regs[53],regs[52]);
-  printf(" YMM10 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[59],regs[58],regs[57],regs[56]);
-  printf(" YMM11 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[63],regs[62],regs[61],regs[60]);
-  printf(" YMM12 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[67],regs[66],regs[65],regs[64]);
-  printf(" YMM13 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[71],regs[70],regs[69],regs[68]);
-  printf(" YMM14 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[75],regs[74],regs[73],regs[72]);
-  printf(" YMM15 = 0x%016lx:%016lx:%016lx:%016lx\n",regs[79],regs[78],regs[77],regs[76]);
+  printf("  YMM0 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[19],regs[18],regs[17],regs[16]);
+  printf("  YMM1 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[23],regs[22],regs[21],regs[20]);
+  printf("  YMM2 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[27],regs[26],regs[25],regs[24]);
+  printf("  YMM3 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[31],regs[30],regs[29],regs[28]);
+  printf("  YMM4 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[35],regs[34],regs[33],regs[32]);
+  printf("  YMM5 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[39],regs[38],regs[37],regs[36]);
+  printf("  YMM6 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[43],regs[42],regs[41],regs[40]);
+  printf("  YMM7 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[47],regs[46],regs[45],regs[44]);
+  printf("  YMM8 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[51],regs[50],regs[49],regs[48]);
+  printf("  YMM9 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[55],regs[54],regs[53],regs[52]);
+  printf(" YMM10 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[59],regs[58],regs[57],regs[56]);
+  printf(" YMM11 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[63],regs[62],regs[61],regs[60]);
+  printf(" YMM12 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[67],regs[66],regs[65],regs[64]);
+  printf(" YMM13 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[71],regs[70],regs[69],regs[68]);
+  printf(" YMM14 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[75],regs[74],regs[73],regs[72]);
+  printf(" YMM15 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[79],regs[78],regs[77],regs[76]);
+  printf(" SP0 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[80],regs[81],regs[82],regs[83]);
+  printf(" SP1 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[84],regs[85],regs[86],regs[87]);
+  printf(" SP2 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[88],regs[89],regs[90],regs[91]);
+  printf(" SP3 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[92],regs[93],regs[94],regs[95]);
+  printf(" SP4 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[96],regs[97],regs[98],regs[99]);
+  printf(" SP5 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[100],regs[101],regs[102],regs[103]);
+  printf(" SP6 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[104],regs[105],regs[106],regs[107]);
+  printf(" SP7 = 0x%016"PRIx64":%016"PRIx64":%016"PRIx64":%016"PRIx64"\n",regs[108],regs[109],regs[110],regs[111]);
 }
 
 int main(int argc, char *argv[])
 { uint64_t retval, i;
 
-  for (i = 1; i < argc && i <= 80; ++i)
+  for (i = 1; i < argc && i <= STATESIZE; ++i)
     regs[i-1] = strtoul(argv[i],NULL,0);
 
   if (DEBUG)
@@ -90,11 +100,11 @@ int main(int argc, char *argv[])
   retval = harness(regs);
 
   if (DEBUG)
-   { printf("Called it and got %lu\n",retval);
+   { printf("Called it and got %"PRIu64"\n",retval);
      print_regs();
    }
   else
-   { for (i = 0; i < 80; ++i) printf("%lu ",regs[i]);
+   { for (i = 0; i < STATESIZE; ++i) printf("%"PRIu64" ",regs[i]);
      printf("\n");
    }
 
diff --git a/x86/proofs/simulator.ml b/x86/proofs/simulator.ml
index 9853aab01..3879790bd 100755
--- a/x86/proofs/simulator.ml
+++ b/x86/proofs/simulator.ml
@@ -81,7 +81,40 @@ let regfile = new_definition
     val(word_subword (read YMM15 s) (0,64):int64);
     val(word_subword (read YMM15 s) (64,64):int64);
     val(word_subword (read YMM15 s) (128,64):int64);
-    val(word_subword (read YMM15 s) (192,64):int64)]`;;
+    val(word_subword (read YMM15 s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(read RSP s)) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(read RSP s)) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(read RSP s)) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(read RSP s)) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 32))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 32))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 32))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 32))) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 64))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 64))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 64))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 64))) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 96))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 96))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 96))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 96))) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 128))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 128))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 128))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 128))) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 160))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 160))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 160))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 160))) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 192))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 192))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 192))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 192))) s) (192,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 224))) s) (0,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 224))) s) (64,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 224))) s) (128,64):int64);
+    val(word_subword (read (memory :> bytes256(word_add (read RSP s) (word 224))) s) (192,64):int64)
+    ]`;;
 
 let FLAGENCODING_11 = prove
  (`bitval b0 + 4 * bitval b1 + 16 * bitval b2 +
@@ -146,7 +179,8 @@ let random_regstate () =
   let d = Random.int 65 in
   map (fun _ -> randomnd 64 d) (0--3) @
   [num(Random.int 256 land 0b11010101)] @
-  map (fun _ -> randomnd 64 d) (5--79);;
+  map (fun _ -> randomnd 64 d) (5--79) @
+  map (fun _ -> randomnd 64 d) (80--111);;
 
 (* ------------------------------------------------------------------------- *)
 (* Generate random instance of instruction class itself.                     *)
@@ -230,15 +264,19 @@ let iclasses = iclasses @
 (* ------------------------------------------------------------------------- *)
 
 let template =
- `ensures x86
+ `nonoverlapping (word pc,LENGTH ibytes) (stackpointer,256)
+  ==> ensures x86
      (\s. bytes_loaded s (word pc) ibytes /\
           read RIP s = word pc /\
+          read RSP s = stackpointer /\
           regfile s = input_state)
-     (\s. regfile s = output_state)
-     (MAYCHANGE [RIP; RAX; RCX; RDX; RBX; RBP; RSI; RDI;
+     (\s. read RSP s = stackpointer /\
+          regfile s = output_state)
+     (MAYCHANGE [RIP; RSP; RAX; RCX; RDX; RBX; RBP; RSI; RDI;
                  R8; R9; R10; R11; R12; R13; R14; R15] ,,
       MAYCHANGE [ZMM0; ZMM1; ZMM2; ZMM3; ZMM4; ZMM5; ZMM6; ZMM7;
                  ZMM8; ZMM9; ZMM10; ZMM11; ZMM12; ZMM13; ZMM14; ZMM15] ,,
+      MAYCHANGE [memory :> bytes(stackpointer,256)] ,,
       MAYCHANGE SOME_FLAGS)`;;
 
 let num_two_to_64 = Num.num_of_string "18446744073709551616";;
@@ -261,11 +299,123 @@ let only_undefinedness =
     | _ -> is_undef tm in
   forall is_nundef o conjuncts;;
 
-let run_random_simulation () =
-  let ibytes:int list = random_instruction iclasses in
-  let icode = itlist (fun h t -> num h +/ num 256 */ t) ibytes num_0 in
-  let _ = Format.print_string
-   ("random inst: decode "^string_of_num icode ^ "\n") in
+(* This makes MESON quiet. *)
+verbose := false;;
+
+
+let READ_MEMORY_MERGE_CONV =
+  let baseconv =
+    GEN_REWRITE_CONV I [READ_MEMORY_BYTESIZED_SPLIT] THENC
+    LAND_CONV(LAND_CONV(RAND_CONV(RAND_CONV
+     (TRY_CONV(GEN_REWRITE_CONV I [GSYM WORD_ADD_ASSOC] THENC
+               RAND_CONV WORD_ADD_CONV))))) in
+  let rec conv tm =
+    (baseconv THENC BINOP_CONV(TRY_CONV conv)) tm in
+  conv;;
+
+let MEMORY_SPLIT_TAC k =
+  let tac =
+    STRIP_ASSUME_TAC o
+    CONV_RULE (BINOP_CONV(BINOP2_CONV
+       (ONCE_DEPTH_CONV NORMALIZE_RELATIVE_ADDRESS_CONV) WORD_REDUCE_CONV)) o
+    GEN_REWRITE_RULE I [el k (CONJUNCTS READ_MEMORY_BYTESIZED_UNSPLIT)] in
+  EVERY_ASSUM (fun th -> try tac th with Failure _ -> ALL_TAC);;
+
+(*** Before and after tactics for goals that either do or don't involve
+ *** memory operations (memop = they do). Non-memory ones are simpler and
+ *** quicker; the memory ones do some more elaborate fiddling with format
+ *** of memory assumptions to maximize their usability.
+ ***)
+
+let extra_simp_tac =
+  REWRITE_TAC[WORD_RULE `word_sub x (word_add x y):N word = word_neg y`;
+              WORD_RULE `word_sub y (word_add x y):N word = word_neg x`;
+              WORD_RULE `word_sub (word_add x y) x:N word = y`;
+              WORD_RULE `word_sub (word_add x y) y:N word = x`] THEN
+  CONV_TAC(DEPTH_CONV WORD_NUM_RED_CONV) THEN REWRITE_TAC[];;
+
+let tac_before memop =
+  REWRITE_TAC[NONOVERLAPPING_CLAUSES] THEN STRIP_TAC THEN
+  REWRITE_TAC[regfile; CONS_11; FLAGENCODING_11; VAL_WORD_GALOIS] THEN
+  REWRITE_TAC[DIMINDEX_64; DIMINDEX_128] THEN CONV_TAC NUM_REDUCE_CONV THEN
+  REWRITE_TAC[YMMENCODING_REGROUP] THEN CONV_TAC(DEPTH_CONV WORD_JOIN_CONV) THEN
+  REWRITE_TAC[SOME_FLAGS] THEN ONCE_REWRITE_TAC[MESON[]
+   `read RSP s = stackpointer /\ P (read RSP s) s <=>
+    read RSP s = stackpointer /\ P stackpointer s`] THEN
+  ENSURES_INIT_TAC "s0" THEN
+  (if memop then MAP_EVERY MEMORY_SPLIT_TAC (0--4) THEN
+    (* Remove non-"memory :> bytes8" reads because they are not necessary :) *)
+    let non_byte_read_list = [
+      `read (memory :> bytes16 x) s = y`;
+      `read (memory :> bytes32 x) s = y`;
+      `read (memory :> bytes64 x) s = y`;
+      `read (memory :> bytes128 x) s = y`;
+      `read (memory :> bytes256 x) s = y`
+    ] in
+    DISCARD_MATCHING_ASSUMPTIONS non_byte_read_list
+  else ALL_TAC)
+and tac_main (memopidx: int option) mc states =
+  begin match memopidx with
+  | Some idx ->
+    let states1, states2 = chop_list idx states in
+    (if states1 <> [] then X86_STEPS_TAC mc states1 else ALL_TAC) THEN
+    (if states2 <> [] then X86_VSTEPS_TAC mc states2 else ALL_TAC)
+  | None -> X86_STEPS_TAC mc states
+  end
+and tac_after memop =
+  (* MEMORY_SPLIT_TAC will split out the memory write to the stack.
+   Assumptions for flags that involves memory reads of more than one byte
+   (for example, ADD for byte64) will not be splitted out into bytes by
+   MEMORY_SPLIT_TAC. Instead, the flag expression is only treated until
+   it gets into the goal. After it gets into the goal, the first
+   READ_MEMORY_MERGE_CONV will split the memory read in the goal that
+   represents the flag changes. After that we simplify/rewrite the goal.
+   Given that the MEMORY_SPLIT_TAC splits out the memory write to the stack,
+   the rewrites pick that up and turn the memory read in the flag expression
+   into its RHS, which again isn't in byte form (but rather byte64 for the ADD
+   example). To further assist, we will perform the READ_MEMORY_MERGE_CONV
+   and rewrite/simplification again for spliting out the memory read and
+   simplify the goal. *)
+  (if memop then MAP_EVERY MEMORY_SPLIT_TAC (0--4) else ALL_TAC) THEN
+  ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN
+  (if memop then CONV_TAC(ONCE_DEPTH_CONV READ_MEMORY_MERGE_CONV)
+   else ALL_TAC) THEN
+  ASM_REWRITE_TAC[] THEN extra_simp_tac THEN
+  (if memop then CONV_TAC(ONCE_DEPTH_CONV READ_MEMORY_MERGE_CONV)
+   else ALL_TAC) THEN
+  ASM_REWRITE_TAC[] THEN extra_simp_tac THEN
+  ALL_TAC;;
+
+(* A function that decodes a list of bytes into an x86 instruction.
+ Could be used for figuring out if an instruction exist in s2n-bignum. *)
+let decode_inst ibytes =
+  let ibyteterm =
+     mk_flist(map (curry mk_comb `word:num->byte` o mk_small_numeral) ibytes) in
+  let execth = X86_MK_EXEC_RULE(REFL ibyteterm) in
+  let decoded = mk_flist
+     (map (rand o rand o snd o strip_forall o concl o Option.get)
+       (filter Option.is_some (Array.to_list (snd execth)))) in
+  let _ = print_term decoded in
+  decoded
+
+(*** Cosimulate a list of x86_64 instruction codes against hardware.
+ *** To pass, the formal simulation has to agree with the hardware,
+ *** only modify the 256-byte buffer [RSP,..,RSP+255] and also
+ *** leave the final RSP value the same as the initial value, though
+ *** it can be modified in between.
+ ***)
+
+let cosimulate_instructions (memopidx: int option) ibytes_list =
+  let ibyte_to_icode_fn =
+    fun ibyte -> (itlist (fun h t -> num h +/ num 256 */ t) (List.rev ibyte) num_0) in
+  let icodes = map ibyte_to_icode_fn ibytes_list in
+  let icodestring =
+    end_itlist (fun s t -> s^","^t) (map string_of_num_hex icodes) in
+  let _ =
+    (Format.print_string("Cosimulating "^icodestring);
+     Format.print_newline()) in
+
+  let ibytes = itlist (fun a b -> a @ b) ibytes_list [] in
 
   let ibyteterm =
     mk_flist(map (curry mk_comb `word:num->byte` o mk_small_numeral) ibytes) in
@@ -282,7 +432,6 @@ let run_random_simulation () =
     " >" ^ outfile in
 
   let _ = Sys.command command in
-
   (*** This branch determines whether the actual simulation worked ***)
   (*** In each branch we try to confirm that we likewise do or don't ***)
 
@@ -305,19 +454,16 @@ let run_random_simulation () =
     let execth = X86_MK_EXEC_RULE(REFL ibyteterm) in
 
     let inst_th = Option.get (snd execth).(0) in
-    let decoded =
-      rand(rand(snd(strip_forall(concl(inst_th))))) in
+    let decoded = mk_flist
+      (map (rand o rand o snd o strip_forall o concl o Option.get)
+        (filter Option.is_some (Array.to_list (snd execth)))) in
 
     let result =
       match
-       (REWRITE_TAC[regfile; CONS_11; FLAGENCODING_11; VAL_WORD_GALOIS] THEN
-        REWRITE_TAC[DIMINDEX_64; DIMINDEX_128] THEN
-        CONV_TAC NUM_REDUCE_CONV THEN
-        REWRITE_TAC[YMMENCODING_REGROUP] THEN
-        CONV_TAC(DEPTH_CONV WORD_JOIN_CONV) THEN
-        REWRITE_TAC[SOME_FLAGS] THEN
-        X86_SIM_TAC execth [1] THEN
-        CONV_TAC(DEPTH_CONV WORD_NUM_RED_CONV))
+       (PURE_REWRITE_TAC [fst execth] THEN
+        (tac_before (memopidx <> None) THEN
+         tac_main memopidx execth (1--length icodes) THEN
+         tac_after (memopidx <> None)))
        ([],goal)
       with
         _,[_,endres],_ ->
@@ -332,28 +478,264 @@ let run_random_simulation () =
      | _,[],_ -> true in
     (decoded,result)
   else
-    let decoded = mk_numeral icode in
+    let decoded = mk_flist(map mk_numeral icodes) in
     decoded,not(can X86_MK_EXEC_RULE(REFL ibyteterm));;
 
+(*** Pick random instances from register-to-register iclasses and run ***)
+
+let run_random_regsimulation () =
+  let ibytes:int list = random_instruction iclasses in
+  cosimulate_instructions None [ibytes];;
+
+(* ------------------------------------------------------------------------- *)
+(* Setting up safe self-contained tests for memory accessing instructions.   *)
+(* ------------------------------------------------------------------------- *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+  (* disp8 is sign-extended *)
+  let stack_start = Random.int 128 in
+  let rest = 248 - stack_start in
+  let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+  [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+   [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+   [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+   [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+  ];;
+
+(* Mode: base (rsp) + scale*index + displacement
+   Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+  let [rest, scale, index] = rand_scale_index 248 in
+  (* disp8 is a sign-extended *)
+  let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+  (* fix use of rcx and rsp *)
+  let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+  [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+   [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+  ];;
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+  (* disp8 is sign-extended *)
+  let stack_start = Random.int 128 in
+  let rest = 248 - stack_start in
+  let base = if rest = 0 then 0 else Random.int (min rest 8) in
+  let rest = rest - base in
+  let base = stack_start + base in
+  let [rest, scale, index] = rand_scale_index rest in
+  (* disp8 is sign-extended *)
+  let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+  let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+  [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+   [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+   [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+   [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+   [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+  ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+  *)
+let cosimulate_mul_base_disp_harness() =
+  (* disp8 is sign-extended *)
+  let stack_start = Random.int 128 in
+  let rest = 248 - stack_start in
+  let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+  [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+   [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+   [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+   [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+  ];;
+
+(* Mode: base (rsp) + scale*index + displacement
+   Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+  let reg = Random.int 6 in
+  let pop_inst = 0x58 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [pop_inst]; (* pop REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+  ];;
+
+let mem_iclasses = [
+  (* ADD r/m64, r64 *)
+  cosimulate_mem_full_harness([0x01]);
+  cosimulate_mem_base_disp_harness([0x01]);
+  cosimulate_mem_rsp_harness([0x01]);
+  (* ADD r64, r/m64 *)
+  cosimulate_mem_full_harness([0x03]);
+  cosimulate_mem_base_disp_harness([0x03]);
+  cosimulate_mem_rsp_harness([0x03]);
+  (* ADC r/m64, r64 *)
+  cosimulate_mem_full_harness([0x11]);
+  cosimulate_mem_base_disp_harness([0x11]);
+  cosimulate_mem_rsp_harness([0x11]);
+  (* ADC r64, r/m64 *)
+  cosimulate_mem_full_harness([0x13]);
+  cosimulate_mem_base_disp_harness([0x13]);
+  cosimulate_mem_rsp_harness([0x013]);
+  (* OR r/m64, r64 *)
+  cosimulate_mem_full_harness([0x09]);
+  cosimulate_mem_base_disp_harness([0x09]);
+  cosimulate_mem_rsp_harness([0x09]);
+  (* OR r64, r/m64 *)
+  cosimulate_mem_full_harness([0x0B]);
+  cosimulate_mem_base_disp_harness([0x0B]);
+  cosimulate_mem_rsp_harness([0x0B]);
+  (* SBB r/m64, r64 *)
+  cosimulate_mem_full_harness([0x19]);
+  cosimulate_mem_base_disp_harness([0x19]);
+  cosimulate_mem_rsp_harness([0x19]);
+  (* SBB r64, r/m64 *)
+  cosimulate_mem_full_harness([0x1B]);
+  cosimulate_mem_base_disp_harness([0x1B]);
+  cosimulate_mem_rsp_harness([0x1B]);
+  (* SUB r/m64, r64 *)
+  cosimulate_mem_full_harness([0x29]);
+  cosimulate_mem_base_disp_harness([0x29]);
+  cosimulate_mem_rsp_harness([0x29]);
+  (* SUB r64, r/m64 *)
+  cosimulate_mem_full_harness([0x2B]);
+  cosimulate_mem_base_disp_harness([0x2B]);
+  cosimulate_mem_rsp_harness([0x2B]);
+  (* XOR r/m64, r64 *)
+  cosimulate_mem_full_harness([0x31]);
+  cosimulate_mem_base_disp_harness([0x31]);
+  cosimulate_mem_rsp_harness([0x31]);
+  (* XOR r64, r/m64 *)
+  cosimulate_mem_full_harness([0x33]);
+  cosimulate_mem_base_disp_harness([0x33]);
+  cosimulate_mem_rsp_harness([0x33]);
+  (* MOV r/m64, r64 *)
+  cosimulate_mem_full_harness([0x89]);
+  cosimulate_mem_base_disp_harness([0x89]);
+  cosimulate_mem_rsp_harness([0x89]);
+  (* MOV r64, r/m64 *)
+  cosimulate_mem_full_harness([0x8B]);
+  cosimulate_mem_base_disp_harness([0x8B]);
+  cosimulate_mem_rsp_harness([0x8B]);
+  (* CMOVA r64, r/m64 *)
+  cosimulate_mem_full_harness([0x0F; 0x47]);
+  cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+  cosimulate_mem_rsp_harness([0x0F; 0x47]);
+  (* CMOVB r64, r/m64 *)
+  cosimulate_mem_full_harness([0x0F; 0x42]);
+  cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+  cosimulate_mem_rsp_harness([0x0F; 0x42]);
+  (* MUL r/m64 *)
+  cosimulate_mul_full_harness();
+  cosimulate_mul_base_disp_harness();
+  cosimulate_mul_rsp_harness();
+  (* PUSH r64 *)
+  cosimulate_push_harness();
+  (* POP r64 *)
+  cosimulate_pop_harness();
+  ];;
+
+let run_random_memopsimulation() =
+  let icodes = el (Random.int (length mem_iclasses)) mem_iclasses in
+  let _ = assert (length icodes >= 2) in
+  let memop_index = length icodes - 2 in
+  cosimulate_instructions (Some memop_index) icodes;;
+
 (* ------------------------------------------------------------------------- *)
 (* Keep running tests till a failure happens then return it.                 *)
 (* ------------------------------------------------------------------------- *)
 
+let run_random_simulation() =
+  if Random.int 100 < 90 then
+    let decoded, result = run_random_regsimulation() in
+    decoded,result,true
+  else
+    let decoded, result = run_random_memopsimulation() in
+    decoded,result,false;;
+
 let time_limit_sec = 1800.0;;
-let tested_instances = ref 0;;
+let tested_reg_instances = ref 0;;
+let tested_mem_instances = ref 0;;
 
 let rec run_random_simulations start_t =
-  let decoded,result = run_random_simulation() in
+  let decoded,result,isreg = run_random_simulation() in
   if result then begin
-    tested_instances := !tested_instances + 1;
+    tested_reg_instances := !tested_reg_instances + (if isreg then 1 else 0);
+    tested_mem_instances := !tested_mem_instances + (if isreg then 0 else 1);
     let fey = if is_numeral decoded
               then " (fails correctly) instruction code " else " " in
     let _ = Format.print_string("OK:" ^ fey ^ string_of_term decoded);
             Format.print_newline() in
     let now_t = Sys.time() in
     if now_t -. start_t > time_limit_sec then
-      let _ = Printf.printf "Finished (time limit: %fs, tested instances: %d)\n"
-          time_limit_sec !tested_instances in
+      let _ = Printf.printf "Finished (time limit: %fs, tested reg instances: %d, tested mem instances: %d, total: %d)\n"
+          time_limit_sec !tested_reg_instances !tested_mem_instances
+          (!tested_reg_instances + !tested_mem_instances) in
       None
     else run_random_simulations start_t
   end
diff --git a/x86/proofs/template.S b/x86/proofs/template.S
index 3daebba06..8d2d9c21a 100755
--- a/x86/proofs/template.S
+++ b/x86/proofs/template.S
@@ -3,7 +3,8 @@
 //
 //         uint64_t harness(uint64_t *regfile);
 //
-// Copies state from "regfile" into registers and flags as follows:
+// Copies state from "regfile" into registers, flags and a small buffer
+// starting at the stack pointer as follows:
 //
 //      RAX = regfile[0]
 //      RCX = regfile[1]
@@ -30,6 +31,10 @@
 //      YMM15.d[2] = regfile[78]
 //      YMM15.d[3] = regfile[79]
 //
+//      [SP+0,...,SP+7] = regfile[80]
+//      ...
+//      [SP+248,...,SP+255] = regfile[111]
+//
 // executes the instruction at "modinst", then copies the new state
 // back into the same array, also returning new value RAX directly.
 //
@@ -39,10 +44,11 @@
 // -------------------------------------------------------------------------
 
         .intel_syntax noprefix
-        .globl  harness
+        .globl  harness, _harness
         .text
 
 harness:
+_harness:
 
 // Save non-modifiable input registers and input arguments on the stack
 
@@ -57,6 +63,26 @@ harness:
 
         push    rdi
 
+// Create little 256-byte buffer and copy in the contents
+// We can use ymm0 because it hasn't been set yet
+        sub rsp, 256
+        vmovdqu ymm0, [rdi+640+0*32]
+        vmovdqu [rsp], ymm0
+        vmovdqu ymm0, [rdi+640+1*32]
+        vmovdqu [rsp+1*32], ymm0
+        vmovdqu ymm0, [rdi+640+2*32]
+        vmovdqu [rsp+2*32], ymm0
+        vmovdqu ymm0, [rdi+640+3*32]
+        vmovdqu [rsp+3*32], ymm0
+        vmovdqu ymm0, [rdi+640+4*32]
+        vmovdqu [rsp+4*32], ymm0
+        vmovdqu ymm0, [rdi+640+5*32]
+        vmovdqu [rsp+5*32], ymm0
+        vmovdqu ymm0, [rdi+640+6*32]
+        vmovdqu [rsp+6*32], ymm0
+        vmovdqu ymm0, [rdi+640+7*32]
+        vmovdqu [rsp+7*32], ymm0
+
 // Load new register contents from rdi (last overwrites the input pointer)
 
         pushfq
@@ -112,7 +138,7 @@ modinst:
 // Copy new state back to the buffer
 
         push    rdi
-        mov     rdi, [rsp+8]
+        mov     rdi, [rsp+256+8]
         mov     [rdi+0*8], rax
 
         pushfq
@@ -153,6 +179,26 @@ modinst:
         pop     rcx
         mov     [rdi+7*8],  rcx
 
+// Copy back contents of the buffer and deallocate stack
+// We can use ymm0 because its value has already been saved to regfile
+        vmovdqu ymm0, [rsp]
+        vmovdqu [rdi+640+0*32], ymm0
+        vmovdqu ymm0, [rsp+1*32]
+        vmovdqu [rdi+640+1*32], ymm0
+        vmovdqu ymm0, [rsp+2*32]
+        vmovdqu [rdi+640+2*32], ymm0
+        vmovdqu ymm0, [rsp+3*32]
+        vmovdqu [rdi+640+3*32], ymm0
+        vmovdqu ymm0, [rsp+4*32]
+        vmovdqu [rdi+640+4*32], ymm0
+        vmovdqu ymm0, [rsp+5*32]
+        vmovdqu [rdi+640+5*32], ymm0
+        vmovdqu ymm0, [rsp+6*32]
+        vmovdqu [rdi+640+6*32], ymm0
+        vmovdqu ymm0, [rsp+7*32]
+        vmovdqu [rdi+640+7*32], ymm0
+        add rsp, 256
+
 // Dummy pop to match push of rdi
 
         pop     rdi
diff --git a/x86/proofs/x86.ml b/x86/proofs/x86.ml
index 864223133..97892ab70 100644
--- a/x86/proofs/x86.ml
+++ b/x86/proofs/x86.ml
@@ -2555,6 +2555,7 @@ let X86_CONV (decode_ths:thm option array) ths tm =
    GEN_REWRITE_CONV (SUB_COMPONENTS_CONV o TOP_DEPTH_CONV) ths THENC
    GEN_REWRITE_CONV TOP_DEPTH_CONV [WORD_VAL] THENC
    ONCE_DEPTH_CONV WORD_PC_PLUS_CONV THENC
+   DEPTH_CONV WORD_NUM_RED_CONV THENC
    ONCE_DEPTH_CONV NORMALIZE_RELATIVE_ADDRESS_CONV
  ) tm;;
 


Reviews:
user: login: aqjune-aws
body: Hi Yann, thanks for working on this. It was really wonderful to see that this is working on my x86 machine too.
I have a question about two possible solutions for speed improvement:

1. Can we use `{ARM,X86}_VSTEPS_TAC` for instructions only for & after the main memory instruction? This will significantly reduce the size of assumption (hence faster simulation).
2. Would removing assumptions of larger-than-a-byte memory reads `memory :> bytes16 (..)` , `memory :> bytes32 (..)`, ... and only keep `memory :> bytes8 (..)` at the end of
    `tac_before` work? We can achieve this using `DISCARD_ASSUMPTIONS_TAC (fun th -> let t = concl th in ... (* we can use 'term_match' to find a subterm 'memory :> bytes16 x' from t *))`.
    This will also reduce the size of assumptions. In theory the simulator will still work because we are splitting memory reads in `tac_after` as well, but.. who knows :/

If you are busy, maybe I can try writing a patch by myself and add a commit this to PR if you don't mind.
I conjecture these could also have been applied when the ARM version of memory instruction simulation was being added.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T20:29:08Z
user: login: aqjune-aws
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T21:35:34Z
user: login: pennyannn
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T22:49:06Z
user: login: aqjune-aws
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T22:57:28Z
user: login: pennyannn
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T00:01:46Z
user: login: pennyannn
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T00:07:04Z
user: login: pennyannn
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T00:07:37Z
user: login: aqjune-aws
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-06T05:59:32Z
user: login: pennyannn
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-06T17:17:28Z

Review comments:
diff_hunk: @@ -0,0 +1,209 @@
+(*
path: x86/proofs/x86-mem-insns.ml
user: login: aqjune-aws
body: Do you want to update x86/Makefile to add x86-mem-insts.ml as dependency of the 'proofs/simulator.native' target? This will help rebuild 'proofs/simulator.native' when necessary. (In fact, I realized that 'x86-insns.ml' was also missing from its dependency..... :( )

And this is my personal opinion, but the file name of x86-mem-insts.ml doesn't give much intuitions about how the source file is supposed to be used. What about sim-mem-insts.ml that includes 'sim' to hint that this is for simulator? 
Or embed its contents in x86/proofs/simulator.ml instead & remove x86-mem-insts.ml (Makefile update isn't necessary in this case)?
created_at: 2025-03-05T20:23:36Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0
+ *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+   Mode: base + displacement *)
+let cosimulate_mul_base_disp_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+   let reg = Random.int 6 in
+   let pop_inst = 0x58 + reg in
+   [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+    [pop_inst]; (* pop REG *)
+    [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+   ];;
+
+let mem_iclasses = [
+   (* ADD r/m64, r64 *)
+   cosimulate_mem_full_harness([0x01]);
+   cosimulate_mem_base_disp_harness([0x01]);
+   cosimulate_mem_rsp_harness([0x01]);
+   (* ADD r64, r/m64 *)
+   cosimulate_mem_full_harness([0x03]);
+   cosimulate_mem_base_disp_harness([0x03]);
+   cosimulate_mem_rsp_harness([0x03]);
+   (* ADC r/m64, r64 *)
+   cosimulate_mem_full_harness([0x11]);
+   cosimulate_mem_base_disp_harness([0x11]);
+   cosimulate_mem_rsp_harness([0x11]);
+   (* ADC r64, r/m64 *)
+   cosimulate_mem_full_harness([0x13]);
+   cosimulate_mem_base_disp_harness([0x13]);
+   cosimulate_mem_rsp_harness([0x013]);
+   (* OR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x09]);
+   cosimulate_mem_base_disp_harness([0x09]);
+   cosimulate_mem_rsp_harness([0x09]);
+   (* OR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0B]);
+   cosimulate_mem_base_disp_harness([0x0B]);
+   cosimulate_mem_rsp_harness([0x0B]);
+   (* SBB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x19]);
+   cosimulate_mem_base_disp_harness([0x19]);
+   cosimulate_mem_rsp_harness([0x19]);
+   (* SBB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x1B]);
+   cosimulate_mem_base_disp_harness([0x1B]);
+   cosimulate_mem_rsp_harness([0x1B]);
+   (* SUB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x29]);
+   cosimulate_mem_base_disp_harness([0x29]);
+   cosimulate_mem_rsp_harness([0x29]);
+   (* SUB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x2B]);
+   cosimulate_mem_base_disp_harness([0x2B]);
+   cosimulate_mem_rsp_harness([0x2B]);
+   (* XOR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x31]);
+   cosimulate_mem_base_disp_harness([0x31]);
+   cosimulate_mem_rsp_harness([0x31]);
+   (* XOR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x33]);
+   cosimulate_mem_base_disp_harness([0x33]);
+   cosimulate_mem_rsp_harness([0x33]);
+   (* MOV r/m64, r64 *)
+   cosimulate_mem_full_harness([0x89]);
+   cosimulate_mem_base_disp_harness([0x89]);
+   cosimulate_mem_rsp_harness([0x89]);
+   (* MOV r64, r/m64 *)
+   cosimulate_mem_full_harness([0x8B]);
+   cosimulate_mem_base_disp_harness([0x8B]);
+   cosimulate_mem_rsp_harness([0x8B]);
+   (* CMOVA r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x47]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+   cosimulate_mem_rsp_harness([0x0F; 0x47]);
+   (* CMOVB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x42]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+   cosimulate_mem_rsp_harness([0x0F; 0x42]);
+   (* MUL r/m64 *)
+   cosimulate_mul_full_harness();
+   cosimulate_mul_base_disp_harness();
+   cosimulate_mul_rsp_harness();
+   (* PUSH r64 *)
+   cosimulate_push_harness();
+   (* POP r64 *)
+   cosimulate_pop_harness();
+  ];;
path: x86/proofs/x86-mem-insns.ml
user: login: aqjune-aws
body: For non-memory x86 instructions, `list-x86-insns.sh` that collects all such instructions at 'iclasses' list of x86-insns.ml and uses the list to pick which instruction to cosimulate.
Even if random testing will inevitably miss some cases, this still helps us give a kind of claim stating that "if we run the test for a sufficiently long time, we will test all instructions that appeared in bignum functions".

Do you think it is possible to achieve the same thing for x86 memory instructions as well? This is just my curiosity... :)
It is true that we are not doing this for Arm's loads and stores, but this must be expanded in the future as well I believe.
created_at: 2025-03-05T20:26:25Z
author_association: COLLABORATOR
diff_hunk: @@ -332,13 +458,29 @@ let run_random_simulation () =
      | _,[],_ -> true in
     (decoded,result)
   else
-    let decoded = mk_numeral icode in
+    let decoded = mk_flist(map mk_numeral icodes) in
     decoded,not(can X86_MK_EXEC_RULE(REFL ibyteterm));;
 
+(*** Pick random instances from register-to-register iclasses and run ***)
+
+let run_random_regsimulation () =
+  let ibytes:int list = random_instruction iclasses in
+  cosimulate_instructions false [ibytes];;
+
+loadt "x86/proofs/x86-mem-insns.ml";;
+
+let run_random_memopsimulation() =
+  let icodes = el (Random.int (length mem_iclasses)) mem_iclasses in
+  cosimulate_instructions true icodes;;
+
 (* ------------------------------------------------------------------------- *)
 (* Keep running tests till a failure happens then return it.                 *)
 (* ------------------------------------------------------------------------- *)
 
+let run_random_simulation() =
+  if Random.int 100 < 90 then run_random_regsimulation()
+  else run_random_memopsimulation();;
path: x86/proofs/simulator.ml
user: login: aqjune-aws
body: Q: what do you think about counting the number of memory vs. non-memory instructions that are simulated & eventually print at line 497? This can be pretty helpful when we are looking at Codebuild log, to see any changes in cosimulation speed. This did not exist in Arm cosimulator though, but I thought this could be useful (for both).
created_at: 2025-03-05T20:29:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0
+ *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+   Mode: base + displacement *)
+let cosimulate_mul_base_disp_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+   let reg = Random.int 6 in
+   let pop_inst = 0x58 + reg in
+   [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+    [pop_inst]; (* pop REG *)
+    [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+   ];;
+
+let mem_iclasses = [
+   (* ADD r/m64, r64 *)
+   cosimulate_mem_full_harness([0x01]);
+   cosimulate_mem_base_disp_harness([0x01]);
+   cosimulate_mem_rsp_harness([0x01]);
+   (* ADD r64, r/m64 *)
+   cosimulate_mem_full_harness([0x03]);
+   cosimulate_mem_base_disp_harness([0x03]);
+   cosimulate_mem_rsp_harness([0x03]);
+   (* ADC r/m64, r64 *)
+   cosimulate_mem_full_harness([0x11]);
+   cosimulate_mem_base_disp_harness([0x11]);
+   cosimulate_mem_rsp_harness([0x11]);
+   (* ADC r64, r/m64 *)
+   cosimulate_mem_full_harness([0x13]);
+   cosimulate_mem_base_disp_harness([0x13]);
+   cosimulate_mem_rsp_harness([0x013]);
+   (* OR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x09]);
+   cosimulate_mem_base_disp_harness([0x09]);
+   cosimulate_mem_rsp_harness([0x09]);
+   (* OR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0B]);
+   cosimulate_mem_base_disp_harness([0x0B]);
+   cosimulate_mem_rsp_harness([0x0B]);
+   (* SBB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x19]);
+   cosimulate_mem_base_disp_harness([0x19]);
+   cosimulate_mem_rsp_harness([0x19]);
+   (* SBB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x1B]);
+   cosimulate_mem_base_disp_harness([0x1B]);
+   cosimulate_mem_rsp_harness([0x1B]);
+   (* SUB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x29]);
+   cosimulate_mem_base_disp_harness([0x29]);
+   cosimulate_mem_rsp_harness([0x29]);
+   (* SUB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x2B]);
+   cosimulate_mem_base_disp_harness([0x2B]);
+   cosimulate_mem_rsp_harness([0x2B]);
+   (* XOR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x31]);
+   cosimulate_mem_base_disp_harness([0x31]);
+   cosimulate_mem_rsp_harness([0x31]);
+   (* XOR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x33]);
+   cosimulate_mem_base_disp_harness([0x33]);
+   cosimulate_mem_rsp_harness([0x33]);
+   (* MOV r/m64, r64 *)
+   cosimulate_mem_full_harness([0x89]);
+   cosimulate_mem_base_disp_harness([0x89]);
+   cosimulate_mem_rsp_harness([0x89]);
+   (* MOV r64, r/m64 *)
+   cosimulate_mem_full_harness([0x8B]);
+   cosimulate_mem_base_disp_harness([0x8B]);
+   cosimulate_mem_rsp_harness([0x8B]);
+   (* CMOVA r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x47]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+   cosimulate_mem_rsp_harness([0x0F; 0x47]);
+   (* CMOVB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x42]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+   cosimulate_mem_rsp_harness([0x0F; 0x42]);
+   (* MUL r/m64 *)
+   cosimulate_mul_full_harness();
+   cosimulate_mul_base_disp_harness();
+   cosimulate_mul_rsp_harness();
+   (* PUSH r64 *)
+   cosimulate_push_harness();
+   (* POP r64 *)
+   cosimulate_pop_harness();
+  ];;
path: x86/proofs/x86-mem-insns.ml
user: login: aqjune-aws
body: To clarify, I don't think this PR needs to address this challenge; it can be a future work of somebody. Maybe what we will need in the close future is to open an github issue that records this fact.
created_at: 2025-03-05T21:35:34Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0
+ *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+   Mode: base + displacement *)
+let cosimulate_mul_base_disp_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+   let reg = Random.int 6 in
+   let pop_inst = 0x58 + reg in
+   [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+    [pop_inst]; (* pop REG *)
+    [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+   ];;
+
+let mem_iclasses = [
+   (* ADD r/m64, r64 *)
+   cosimulate_mem_full_harness([0x01]);
+   cosimulate_mem_base_disp_harness([0x01]);
+   cosimulate_mem_rsp_harness([0x01]);
+   (* ADD r64, r/m64 *)
+   cosimulate_mem_full_harness([0x03]);
+   cosimulate_mem_base_disp_harness([0x03]);
+   cosimulate_mem_rsp_harness([0x03]);
+   (* ADC r/m64, r64 *)
+   cosimulate_mem_full_harness([0x11]);
+   cosimulate_mem_base_disp_harness([0x11]);
+   cosimulate_mem_rsp_harness([0x11]);
+   (* ADC r64, r/m64 *)
+   cosimulate_mem_full_harness([0x13]);
+   cosimulate_mem_base_disp_harness([0x13]);
+   cosimulate_mem_rsp_harness([0x013]);
+   (* OR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x09]);
+   cosimulate_mem_base_disp_harness([0x09]);
+   cosimulate_mem_rsp_harness([0x09]);
+   (* OR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0B]);
+   cosimulate_mem_base_disp_harness([0x0B]);
+   cosimulate_mem_rsp_harness([0x0B]);
+   (* SBB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x19]);
+   cosimulate_mem_base_disp_harness([0x19]);
+   cosimulate_mem_rsp_harness([0x19]);
+   (* SBB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x1B]);
+   cosimulate_mem_base_disp_harness([0x1B]);
+   cosimulate_mem_rsp_harness([0x1B]);
+   (* SUB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x29]);
+   cosimulate_mem_base_disp_harness([0x29]);
+   cosimulate_mem_rsp_harness([0x29]);
+   (* SUB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x2B]);
+   cosimulate_mem_base_disp_harness([0x2B]);
+   cosimulate_mem_rsp_harness([0x2B]);
+   (* XOR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x31]);
+   cosimulate_mem_base_disp_harness([0x31]);
+   cosimulate_mem_rsp_harness([0x31]);
+   (* XOR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x33]);
+   cosimulate_mem_base_disp_harness([0x33]);
+   cosimulate_mem_rsp_harness([0x33]);
+   (* MOV r/m64, r64 *)
+   cosimulate_mem_full_harness([0x89]);
+   cosimulate_mem_base_disp_harness([0x89]);
+   cosimulate_mem_rsp_harness([0x89]);
+   (* MOV r64, r/m64 *)
+   cosimulate_mem_full_harness([0x8B]);
+   cosimulate_mem_base_disp_harness([0x8B]);
+   cosimulate_mem_rsp_harness([0x8B]);
+   (* CMOVA r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x47]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+   cosimulate_mem_rsp_harness([0x0F; 0x47]);
+   (* CMOVB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x42]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+   cosimulate_mem_rsp_harness([0x0F; 0x42]);
+   (* MUL r/m64 *)
+   cosimulate_mul_full_harness();
+   cosimulate_mul_base_disp_harness();
+   cosimulate_mul_rsp_harness();
+   (* PUSH r64 *)
+   cosimulate_push_harness();
+   (* POP r64 *)
+   cosimulate_pop_harness();
+  ];;
path: x86/proofs/x86-mem-insns.ml
user: login: pennyannn
body: That is definitely one of the problems I faced when working on this PR. There seems to be two flavors of cosimulation testing in s2n-bignum: one is like what is done in Arm cosimulation where one randomly generate instructions according to some templates; another way is like what is done for non-memory instructions in x86, where all non-memory accessing instructions are scanned from all assembly files and that list is randomly picked from. 

I have tried scanning the existing x86 assembly files for memory-accessing instructions and after some thought, decided to do the template way. The reason is that for memory accessing instructions, we only allow certain addressing parameter combinations so that it would fit into the 256 byte buffer we allocated on the stack. Not all instructions scanned from the assembly satisfy this constraint (for example, sometimes they go beyond 256 bytes). In addition, one has to be able to automatically generate those auxiliary instructions for the scanned instructions, which could be nontrivial. 

In terms of what we can claim about what is tested, I think the second approach has a stronger argument in that the instructions tested are automatically collected, whereas the first approach depends on the instruction programmer to manually add a test harness for all added instruction. If one assumes that each newly introduced instruction gets a test manually added, then the first approach has the same coverage as the second.
created_at: 2025-03-05T22:49:06Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0
+ *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+   Mode: base + displacement *)
+let cosimulate_mul_base_disp_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+   let reg = Random.int 6 in
+   let pop_inst = 0x58 + reg in
+   [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+    [pop_inst]; (* pop REG *)
+    [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+   ];;
+
+let mem_iclasses = [
+   (* ADD r/m64, r64 *)
+   cosimulate_mem_full_harness([0x01]);
+   cosimulate_mem_base_disp_harness([0x01]);
+   cosimulate_mem_rsp_harness([0x01]);
+   (* ADD r64, r/m64 *)
+   cosimulate_mem_full_harness([0x03]);
+   cosimulate_mem_base_disp_harness([0x03]);
+   cosimulate_mem_rsp_harness([0x03]);
+   (* ADC r/m64, r64 *)
+   cosimulate_mem_full_harness([0x11]);
+   cosimulate_mem_base_disp_harness([0x11]);
+   cosimulate_mem_rsp_harness([0x11]);
+   (* ADC r64, r/m64 *)
+   cosimulate_mem_full_harness([0x13]);
+   cosimulate_mem_base_disp_harness([0x13]);
+   cosimulate_mem_rsp_harness([0x013]);
+   (* OR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x09]);
+   cosimulate_mem_base_disp_harness([0x09]);
+   cosimulate_mem_rsp_harness([0x09]);
+   (* OR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0B]);
+   cosimulate_mem_base_disp_harness([0x0B]);
+   cosimulate_mem_rsp_harness([0x0B]);
+   (* SBB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x19]);
+   cosimulate_mem_base_disp_harness([0x19]);
+   cosimulate_mem_rsp_harness([0x19]);
+   (* SBB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x1B]);
+   cosimulate_mem_base_disp_harness([0x1B]);
+   cosimulate_mem_rsp_harness([0x1B]);
+   (* SUB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x29]);
+   cosimulate_mem_base_disp_harness([0x29]);
+   cosimulate_mem_rsp_harness([0x29]);
+   (* SUB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x2B]);
+   cosimulate_mem_base_disp_harness([0x2B]);
+   cosimulate_mem_rsp_harness([0x2B]);
+   (* XOR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x31]);
+   cosimulate_mem_base_disp_harness([0x31]);
+   cosimulate_mem_rsp_harness([0x31]);
+   (* XOR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x33]);
+   cosimulate_mem_base_disp_harness([0x33]);
+   cosimulate_mem_rsp_harness([0x33]);
+   (* MOV r/m64, r64 *)
+   cosimulate_mem_full_harness([0x89]);
+   cosimulate_mem_base_disp_harness([0x89]);
+   cosimulate_mem_rsp_harness([0x89]);
+   (* MOV r64, r/m64 *)
+   cosimulate_mem_full_harness([0x8B]);
+   cosimulate_mem_base_disp_harness([0x8B]);
+   cosimulate_mem_rsp_harness([0x8B]);
+   (* CMOVA r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x47]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+   cosimulate_mem_rsp_harness([0x0F; 0x47]);
+   (* CMOVB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x42]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+   cosimulate_mem_rsp_harness([0x0F; 0x42]);
+   (* MUL r/m64 *)
+   cosimulate_mul_full_harness();
+   cosimulate_mul_base_disp_harness();
+   cosimulate_mul_rsp_harness();
+   (* PUSH r64 *)
+   cosimulate_push_harness();
+   (* POP r64 *)
+   cosimulate_pop_harness();
+  ];;
path: x86/proofs/x86-mem-insns.ml
user: login: aqjune-aws
body: The Arm cosimulator also checks whether instructions in the binaries also belong to at least one of the instruction patterns too. :) `check_insns ()` of `arm/proofs/simulator_iclasses.ml` does that. Since the instruction bitpatterns listed in the first approach are slightly more general than what instructions are actually used, the second approach cannot see the instructions that will appear in the future, but well that might be okay as long as everything works fine...

Anyway, what is important I think is that we need to record this at somewhere. I will open a github issue that mentions this.
created_at: 2025-03-05T22:57:28Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0
+ *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+   Mode: base + displacement *)
+let cosimulate_mul_base_disp_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+   let reg = Random.int 6 in
+   let pop_inst = 0x58 + reg in
+   [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+    [pop_inst]; (* pop REG *)
+    [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+   ];;
+
+let mem_iclasses = [
+   (* ADD r/m64, r64 *)
+   cosimulate_mem_full_harness([0x01]);
+   cosimulate_mem_base_disp_harness([0x01]);
+   cosimulate_mem_rsp_harness([0x01]);
+   (* ADD r64, r/m64 *)
+   cosimulate_mem_full_harness([0x03]);
+   cosimulate_mem_base_disp_harness([0x03]);
+   cosimulate_mem_rsp_harness([0x03]);
+   (* ADC r/m64, r64 *)
+   cosimulate_mem_full_harness([0x11]);
+   cosimulate_mem_base_disp_harness([0x11]);
+   cosimulate_mem_rsp_harness([0x11]);
+   (* ADC r64, r/m64 *)
+   cosimulate_mem_full_harness([0x13]);
+   cosimulate_mem_base_disp_harness([0x13]);
+   cosimulate_mem_rsp_harness([0x013]);
+   (* OR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x09]);
+   cosimulate_mem_base_disp_harness([0x09]);
+   cosimulate_mem_rsp_harness([0x09]);
+   (* OR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0B]);
+   cosimulate_mem_base_disp_harness([0x0B]);
+   cosimulate_mem_rsp_harness([0x0B]);
+   (* SBB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x19]);
+   cosimulate_mem_base_disp_harness([0x19]);
+   cosimulate_mem_rsp_harness([0x19]);
+   (* SBB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x1B]);
+   cosimulate_mem_base_disp_harness([0x1B]);
+   cosimulate_mem_rsp_harness([0x1B]);
+   (* SUB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x29]);
+   cosimulate_mem_base_disp_harness([0x29]);
+   cosimulate_mem_rsp_harness([0x29]);
+   (* SUB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x2B]);
+   cosimulate_mem_base_disp_harness([0x2B]);
+   cosimulate_mem_rsp_harness([0x2B]);
+   (* XOR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x31]);
+   cosimulate_mem_base_disp_harness([0x31]);
+   cosimulate_mem_rsp_harness([0x31]);
+   (* XOR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x33]);
+   cosimulate_mem_base_disp_harness([0x33]);
+   cosimulate_mem_rsp_harness([0x33]);
+   (* MOV r/m64, r64 *)
+   cosimulate_mem_full_harness([0x89]);
+   cosimulate_mem_base_disp_harness([0x89]);
+   cosimulate_mem_rsp_harness([0x89]);
+   (* MOV r64, r/m64 *)
+   cosimulate_mem_full_harness([0x8B]);
+   cosimulate_mem_base_disp_harness([0x8B]);
+   cosimulate_mem_rsp_harness([0x8B]);
+   (* CMOVA r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x47]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+   cosimulate_mem_rsp_harness([0x0F; 0x47]);
+   (* CMOVB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x42]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+   cosimulate_mem_rsp_harness([0x0F; 0x42]);
+   (* MUL r/m64 *)
+   cosimulate_mul_full_harness();
+   cosimulate_mul_base_disp_harness();
+   cosimulate_mul_rsp_harness();
+   (* PUSH r64 *)
+   cosimulate_push_harness();
+   (* POP r64 *)
+   cosimulate_pop_harness();
+  ];;
path: x86/proofs/x86-mem-insns.ml
user: login: pennyannn
body: I see. That makes sense. Then we do need to implement a similar `check_insns` for the memory instructions as well. :)
created_at: 2025-03-06T00:01:46Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
path: x86/proofs/x86-mem-insns.ml
user: login: pennyannn
body: Got it. I moved the code in x86-mem-insts.ml to simulator.ml
created_at: 2025-03-06T00:07:04Z
author_association: COLLABORATOR
diff_hunk: @@ -332,13 +458,29 @@ let run_random_simulation () =
      | _,[],_ -> true in
     (decoded,result)
   else
-    let decoded = mk_numeral icode in
+    let decoded = mk_flist(map mk_numeral icodes) in
     decoded,not(can X86_MK_EXEC_RULE(REFL ibyteterm));;
 
+(*** Pick random instances from register-to-register iclasses and run ***)
+
+let run_random_regsimulation () =
+  let ibytes:int list = random_instruction iclasses in
+  cosimulate_instructions false [ibytes];;
+
+loadt "x86/proofs/x86-mem-insns.ml";;
+
+let run_random_memopsimulation() =
+  let icodes = el (Random.int (length mem_iclasses)) mem_iclasses in
+  cosimulate_instructions true icodes;;
+
 (* ------------------------------------------------------------------------- *)
 (* Keep running tests till a failure happens then return it.                 *)
 (* ------------------------------------------------------------------------- *)
 
+let run_random_simulation() =
+  if Random.int 100 < 90 then run_random_regsimulation()
+  else run_random_memopsimulation();;
path: x86/proofs/simulator.ml
user: login: pennyannn
body: Added. Check new commit.
created_at: 2025-03-06T00:07:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,209 @@
+(*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0
+ *)
+
+(* Auxiliary instructions are for making sure operand registers don't depend
+   on RSP. This is because RSP in the theorem statement is an arbitrary value
+   represented by `stackpointer`. However in actual machine run, it is a
+   concrete value. If certain register's value depends on RSP value then the
+   machine run and the instruction modeling result won't match. *)
+
+let rand_scale_index(rest) =
+  let index = if rest = 0 then 0 else Random.int (min rest 8) in
+  let log2_int = fun x -> int_of_float (Float.log2 (float_of_int x)) in
+  let scale =
+    if index = 0 then Random.int 4
+    else
+      let scale_range = log2_int (rest/index) in
+        if scale_range = 0 then 0 else Random.int (min scale_range 4) in
+  let rest = rest - index * int_of_float (2.0 ** (float_of_int scale)) in
+  [rest, scale, index]
+
+(* Mode: base + scale*index + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_full_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rbx and rcx *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rbx + scale*rcx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Mode: base + displacement
+   Fixed: use of registers, operand size = 64, displacement size = 8
+   Randomized: addressing mode parameters
+   *)
+let cosimulate_mem_base_disp_harness(opcode) =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xda]; (* MOV rdx, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48] @ opcode @ [0x43; disp];  (* INST [rbx + displacement], rax *)
+    [0x48; 0x89; 0xd3]; (* MOV rbx, rdx *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mem_rsp_harness(opcode) =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48] @ opcode @ [0x44; sib; disp];  (* INST [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_full_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let base = if rest = 0 then 0 else Random.int (min rest 8) in
+   let rest = rest - base in
+   let base = stack_start + base in
+   let [rest, scale, index] = rand_scale_index rest in
+   (* disp8 is sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   let sib = scale * int_of_float (2.0**6.0) + 0b001011 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; base]; (* LEA rbx, [rsp+base] *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rbx + scale*rcx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters
+   Mode: base + displacement *)
+let cosimulate_mul_base_disp_harness() =
+   (* disp8 is sign-extended *)
+   let stack_start = Random.int 128 in
+   let rest = 248 - stack_start in
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   [[0x48; 0x89; 0xd8]; (* MOV r8, rbx *)
+    [0x48; 0x8d; 0x5c; 0x24; stack_start]; (* LEA rbx, [rsp+stack_start] *)
+    [0x48; 0xf7; 0x63; disp];  (* MUL [rbx + displacement] *)
+    [0x4c; 0x89; 0xc3]; (* MOV rbx, r8 *)
+   ];;
+
+(* Fixed: use of registers, operand size = 64
+   Randomized: addressing mode parameters *)
+let cosimulate_mul_rsp_harness() =
+   let [rest, scale, index] = rand_scale_index 248 in
+   (* disp8 is a sign-extended *)
+   let disp = if rest = 0 then 0 else Random.int (min 128 rest) in
+   (* fix use of rcx and rsp *)
+   let sib = scale * int_of_float (2.0**6.0) + 0b001100 in
+   [[0x48; 0xc7; 0xc1; index; 0x00; 0x00; 0x00]; (* MOV rcx, index *)
+    [0x48; 0xf7; 0x64; sib; disp];  (* MUL [rsp + scale*rcx + displacement], rax *)
+   ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_push_harness() =
+  let reg = Random.int 6 in
+  let push_inst = 0x50 + reg in
+  [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+   [push_inst]; (* push REG *)
+   [0x48; 0x8d; 0x64; 0x24; 0xf8] (* lea rsp, [rsp - 8] *)
+  ];;
+
+(* Fixed: operand size = 64 *)
+let cosimulate_pop_harness() =
+   let reg = Random.int 6 in
+   let pop_inst = 0x58 + reg in
+   [[0x48; 0x8d; 0x64; 0x24; 0x10]; (* lea rsp, [rsp + 16] *)
+    [pop_inst]; (* pop REG *)
+    [0x48; 0x8d; 0x64; 0x24; 0xE8] (* lea rsp, [rsp - 24] *)
+   ];;
+
+let mem_iclasses = [
+   (* ADD r/m64, r64 *)
+   cosimulate_mem_full_harness([0x01]);
+   cosimulate_mem_base_disp_harness([0x01]);
+   cosimulate_mem_rsp_harness([0x01]);
+   (* ADD r64, r/m64 *)
+   cosimulate_mem_full_harness([0x03]);
+   cosimulate_mem_base_disp_harness([0x03]);
+   cosimulate_mem_rsp_harness([0x03]);
+   (* ADC r/m64, r64 *)
+   cosimulate_mem_full_harness([0x11]);
+   cosimulate_mem_base_disp_harness([0x11]);
+   cosimulate_mem_rsp_harness([0x11]);
+   (* ADC r64, r/m64 *)
+   cosimulate_mem_full_harness([0x13]);
+   cosimulate_mem_base_disp_harness([0x13]);
+   cosimulate_mem_rsp_harness([0x013]);
+   (* OR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x09]);
+   cosimulate_mem_base_disp_harness([0x09]);
+   cosimulate_mem_rsp_harness([0x09]);
+   (* OR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0B]);
+   cosimulate_mem_base_disp_harness([0x0B]);
+   cosimulate_mem_rsp_harness([0x0B]);
+   (* SBB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x19]);
+   cosimulate_mem_base_disp_harness([0x19]);
+   cosimulate_mem_rsp_harness([0x19]);
+   (* SBB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x1B]);
+   cosimulate_mem_base_disp_harness([0x1B]);
+   cosimulate_mem_rsp_harness([0x1B]);
+   (* SUB r/m64, r64 *)
+   cosimulate_mem_full_harness([0x29]);
+   cosimulate_mem_base_disp_harness([0x29]);
+   cosimulate_mem_rsp_harness([0x29]);
+   (* SUB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x2B]);
+   cosimulate_mem_base_disp_harness([0x2B]);
+   cosimulate_mem_rsp_harness([0x2B]);
+   (* XOR r/m64, r64 *)
+   cosimulate_mem_full_harness([0x31]);
+   cosimulate_mem_base_disp_harness([0x31]);
+   cosimulate_mem_rsp_harness([0x31]);
+   (* XOR r64, r/m64 *)
+   cosimulate_mem_full_harness([0x33]);
+   cosimulate_mem_base_disp_harness([0x33]);
+   cosimulate_mem_rsp_harness([0x33]);
+   (* MOV r/m64, r64 *)
+   cosimulate_mem_full_harness([0x89]);
+   cosimulate_mem_base_disp_harness([0x89]);
+   cosimulate_mem_rsp_harness([0x89]);
+   (* MOV r64, r/m64 *)
+   cosimulate_mem_full_harness([0x8B]);
+   cosimulate_mem_base_disp_harness([0x8B]);
+   cosimulate_mem_rsp_harness([0x8B]);
+   (* CMOVA r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x47]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x47]);
+   cosimulate_mem_rsp_harness([0x0F; 0x47]);
+   (* CMOVB r64, r/m64 *)
+   cosimulate_mem_full_harness([0x0F; 0x42]);
+   cosimulate_mem_base_disp_harness([0x0F; 0x42]);
+   cosimulate_mem_rsp_harness([0x0F; 0x42]);
+   (* MUL r/m64 *)
+   cosimulate_mul_full_harness();
+   cosimulate_mul_base_disp_harness();
+   cosimulate_mul_rsp_harness();
+   (* PUSH r64 *)
+   cosimulate_push_harness();
+   (* POP r64 *)
+   cosimulate_pop_harness();
+  ];;
path: x86/proofs/x86-mem-insns.ml
user: login: pennyannn
body: Issue created at https://github.com/awslabs/s2n-bignum/issues/199
created_at: 2025-03-06T17:17:28Z
author_association: COLLABORATOR

PR comments:
user: login: aqjune-aws
created_at: 2025-02-28T02:57:27Z
body: Hi Yan, in the x86-sematests log the proof states are being printed when `~undefined` remains in the conclusion. Do you want to remove this logging? This is useful when wants to briefly look at the Codebuild output and see the checkd instructions trace.
author_association: COLLABORATOR
user: login: pennyannn
created_at: 2025-03-03T23:28:32Z
body: > Hi Yan, in the x86-sematests log the proof states are being printed when `~undefined` remains in the conclusion. Do you want to remove this logging? This is useful when wants to briefly look at the Codebuild output and see the checkd instructions trace.

Thanks, June. The log is removed.
author_association: COLLABORATOR
user: login: aqjune-aws
created_at: 2025-03-05T22:42:32Z
body: I just pushed two commits that implement my optimizations to x86 simulator. :) According to the Codebuild log, the number of simulated instruction has increased a bit (around 700 to 950?). Hope this can be even faster. Maybe we can even install a cache for `ORTHOGONAL_COMPONENTS_CONV` in common/components.ml , IDK. I will push another commit that implements the same optimization on the Arm simulator, finger crossed...
author_association: COLLABORATOR
user: login: jargh
created_at: 2025-03-06T20:50:29Z
body: Many thanks for this, Yan, which really closes one of the outstanding gaps in our soundness story! And thanks June for all the help with refining and perfecting this PR.

I agree that we need in the fairly near future to make absolutely sure we are running memory operand cosimulation on a fully representative sample of instructions, something that applies equally to aarch64. So it's good to see it logged as an issue.

Anyway, I'm now very happy with this update and will squash and merge it.
author_association: CONTRIBUTOR