|
| 1 | +(** Regression tests for the semantics of one-operand [mul] and [imul]. |
| 2 | +
|
| 3 | + The one-operand form of [imul] is a *signed* widening multiply |
| 4 | + (rdx:rax := signed(rax) * signed(src)), whereas [mul] is unsigned. The |
| 5 | + two agree on the low half of the product but not on the high half |
| 6 | + whenever an operand has its top bit set. The concrete semantics |
| 7 | + ([Semantics.DenoteNormalInstruction]) and the symbolic executor |
| 8 | + ([Symbolic.SymexNormalInstruction]) used to share a single unsigned |
| 9 | + branch for both mnemonics (scrutineer finding #2514); these tests pin |
| 10 | + down the hardware behaviour for both models, on the same inputs. |
| 11 | +
|
| 12 | + The expected values were obtained by executing the instructions on |
| 13 | + x86-64 hardware. *) |
| 14 | +From Coq Require Import ZArith. |
| 15 | +From Coq Require Import List. |
| 16 | +From Coq Require Import String. |
| 17 | +Require Import Crypto.Util.ErrorT. |
| 18 | +Require Import Crypto.Util.Tuple. |
| 19 | +Require Import Crypto.Assembly.Syntax. |
| 20 | +Require Import Crypto.Assembly.Symbolic. |
| 21 | +Require Import Crypto.Assembly.Equivalence. |
| 22 | +Require Import Crypto.Assembly.WithBedrock.Semantics. |
| 23 | +Require Import coqutil.Map.Interface. |
| 24 | +Import ListNotations. |
| 25 | +Local Open Scope Z_scope. |
| 26 | +Local Open Scope list_scope. |
| 27 | +Local Open Scope string_scope. |
| 28 | + |
| 29 | +(** ** Concrete semantics *) |
| 30 | + |
| 31 | +Definition initial_machine_state (rax_val rcx_val : Z) : machine_state |
| 32 | + := {| machine_reg_state := Semantics.set_reg (Semantics.set_reg (Tuple.repeat 0 _) rax rax_val) rcx rcx_val |
| 33 | + ; machine_flag_state := havoc_flags |
| 34 | + ; machine_mem_state := map.empty |}. |
| 35 | + |
| 36 | +Definition denote_one (instr : NormalInstruction) (rax_val rcx_val : Z) (out : REG) : option Z |
| 37 | + := option_map (fun st : machine_state => Semantics.get_reg st out) (DenoteNormalInstruction (initial_machine_state rax_val rcx_val) instr). |
| 38 | + |
| 39 | +Definition mul_rcx : NormalInstruction := {| Syntax.prefix := None ; Syntax.op := Syntax.mul ; Syntax.args := [reg rcx] |}. |
| 40 | +Definition imul_rcx : NormalInstruction := {| Syntax.prefix := None ; Syntax.op := Syntax.imul ; Syntax.args := [reg rcx] |}. |
| 41 | +Definition mul_cl : NormalInstruction := {| Syntax.prefix := None ; Syntax.op := Syntax.mul ; Syntax.args := [reg cl] |}. |
| 42 | +Definition imul_cl : NormalInstruction := {| Syntax.prefix := None ; Syntax.op := Syntax.imul ; Syntax.args := [reg cl] |}. |
| 43 | + |
| 44 | +(** rax = 0xffffffff00000001 (the top limb of the P-256 prime; bit 63 set), rcx = 3 *) |
| 45 | +Example denote_mul_rcx_hi : denote_one mul_rcx 0xffffffff00000001 3 rdx = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 46 | +Example denote_mul_rcx_lo : denote_one mul_rcx 0xffffffff00000001 3 rax = Some 0xfffffffd00000003. Proof. vm_compute; reflexivity. Qed. |
| 47 | +Example denote_imul_rcx_hi : denote_one imul_rcx 0xffffffff00000001 3 rdx = Some 0xffffffffffffffff. Proof. vm_compute; reflexivity. Qed. |
| 48 | +Example denote_imul_rcx_lo : denote_one imul_rcx 0xffffffff00000001 3 rax = Some 0xfffffffd00000003. Proof. vm_compute; reflexivity. Qed. |
| 49 | + |
| 50 | +(** both operands with bit 63 set: rax = -2, rcx = -2^63+1 as signed values *) |
| 51 | +Example denote_mul_rcx_hi' : denote_one mul_rcx 0xfffffffffffffffe 0x8000000000000001 rdx = Some 0x7fffffffffffffff. Proof. vm_compute; reflexivity. Qed. |
| 52 | +Example denote_imul_rcx_hi' : denote_one imul_rcx 0xfffffffffffffffe 0x8000000000000001 rdx = Some 0x0. Proof. vm_compute; reflexivity. Qed. |
| 53 | +Example denote_mul_rcx_lo' : denote_one mul_rcx 0xfffffffffffffffe 0x8000000000000001 rax = Some 0xfffffffffffffffe. Proof. vm_compute; reflexivity. Qed. |
| 54 | +Example denote_imul_rcx_lo' : denote_one imul_rcx 0xfffffffffffffffe 0x8000000000000001 rax = Some 0xfffffffffffffffe. Proof. vm_compute; reflexivity. Qed. |
| 55 | + |
| 56 | +(** no top bit set: signed and unsigned agree *) |
| 57 | +Example denote_mul_rcx_hi'' : denote_one mul_rcx 0x123456789 0x23456789a rdx = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 58 | +Example denote_imul_rcx_hi'' : denote_one imul_rcx 0x123456789 0x23456789a rdx = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 59 | + |
| 60 | +(** 8-bit form writes ah:al; al = 0xff (-1), cl = 3 *) |
| 61 | +Example denote_mul_cl_ah : denote_one mul_cl 0xff 3 ah = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 62 | +Example denote_mul_cl_al : denote_one mul_cl 0xff 3 al = Some 0xfd. Proof. vm_compute; reflexivity. Qed. |
| 63 | +Example denote_imul_cl_ah : denote_one imul_cl 0xff 3 ah = Some 0xff. Proof. vm_compute; reflexivity. Qed. |
| 64 | +Example denote_imul_cl_al : denote_one imul_cl 0xff 3 al = Some 0xfd. Proof. vm_compute; reflexivity. Qed. |
| 65 | +(** the untouched upper bytes of rax are preserved *) |
| 66 | +Example denote_imul_cl_rax : denote_one imul_cl 0x11223344556677ff 3 rax = Some 0x112233445566fffd. Proof. vm_compute; reflexivity. Qed. |
| 67 | + |
| 68 | +(** ** Symbolic executor *) |
| 69 | + |
| 70 | +Local Instance test_symbolic_options : symbolic_options_computed_opt |
| 71 | + := {| asm_rewriting_passes := default_rewriting_passes (rewriting_pipeline:=default_rewrite_pass_order) (rewriting_pass_filter:=fun _ => true) |
| 72 | + ; asm_debug_symex_asm_first_computed := false |
| 73 | + ; asm_node_reveal_depth_computed := default_node_reveal_depth |}. |
| 74 | + |
| 75 | +(** Symbolically execute [instr] from a state where every register holds a |
| 76 | + fresh symbol, then evaluate the requested output register with the |
| 77 | + symbols for [rax] and [rcx] instantiated to the given values (and every |
| 78 | + other register to [0]). *) |
| 79 | +Definition symex_one (instr : NormalInstruction) (rax_val rcx_val : Z) (out : REG) : option Z |
| 80 | + := let st := init_symbolic_state dag.empty in |
| 81 | + let ctx : symbol -> option Z |
| 82 | + := fun n => if (n =? reg_index rax)%N then Some rax_val |
| 83 | + else if (n =? reg_index rcx)%N then Some rcx_val |
| 84 | + else Some 0 in |
| 85 | + match (_ <- SymexNormalInstruction (descr:=Build_description "SemanticsTests" true) instr; |
| 86 | + GetReg (descr:=Build_description "SemanticsTests" true) out)%x86symex st with |
| 87 | + | Success (i, st) => interp_expr ctx (reveal st 100 i) |
| 88 | + | Error _ => None |
| 89 | + end. |
| 90 | + |
| 91 | +Example symex_mul_rcx_hi : symex_one mul_rcx 0xffffffff00000001 3 rdx = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 92 | +Example symex_mul_rcx_lo : symex_one mul_rcx 0xffffffff00000001 3 rax = Some 0xfffffffd00000003. Proof. vm_compute; reflexivity. Qed. |
| 93 | +Example symex_imul_rcx_hi : symex_one imul_rcx 0xffffffff00000001 3 rdx = Some 0xffffffffffffffff. Proof. vm_compute; reflexivity. Qed. |
| 94 | +Example symex_imul_rcx_lo : symex_one imul_rcx 0xffffffff00000001 3 rax = Some 0xfffffffd00000003. Proof. vm_compute; reflexivity. Qed. |
| 95 | + |
| 96 | +Example symex_mul_rcx_hi' : symex_one mul_rcx 0xfffffffffffffffe 0x8000000000000001 rdx = Some 0x7fffffffffffffff. Proof. vm_compute; reflexivity. Qed. |
| 97 | +Example symex_imul_rcx_hi' : symex_one imul_rcx 0xfffffffffffffffe 0x8000000000000001 rdx = Some 0x0. Proof. vm_compute; reflexivity. Qed. |
| 98 | +Example symex_mul_rcx_lo' : symex_one mul_rcx 0xfffffffffffffffe 0x8000000000000001 rax = Some 0xfffffffffffffffe. Proof. vm_compute; reflexivity. Qed. |
| 99 | +Example symex_imul_rcx_lo' : symex_one imul_rcx 0xfffffffffffffffe 0x8000000000000001 rax = Some 0xfffffffffffffffe. Proof. vm_compute; reflexivity. Qed. |
| 100 | + |
| 101 | +Example symex_mul_rcx_hi'' : symex_one mul_rcx 0x123456789 0x23456789a rdx = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 102 | +Example symex_imul_rcx_hi'' : symex_one imul_rcx 0x123456789 0x23456789a rdx = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 103 | + |
| 104 | +Example symex_mul_cl_ah : symex_one mul_cl 0xff 3 ah = Some 0x2. Proof. vm_compute; reflexivity. Qed. |
| 105 | +Example symex_mul_cl_al : symex_one mul_cl 0xff 3 al = Some 0xfd. Proof. vm_compute; reflexivity. Qed. |
| 106 | +Example symex_imul_cl_ah : symex_one imul_cl 0xff 3 ah = Some 0xff. Proof. vm_compute; reflexivity. Qed. |
| 107 | +Example symex_imul_cl_al : symex_one imul_cl 0xff 3 al = Some 0xfd. Proof. vm_compute; reflexivity. Qed. |
| 108 | +Example symex_imul_cl_rax : symex_one imul_cl 0x11223344556677ff 3 rax = Some 0x112233445566fffd. Proof. vm_compute; reflexivity. Qed. |
0 commit comments