diff --git a/filetests/isa/intel/binary32.cton b/filetests/isa/intel/binary32.cton index bd3ff06289..0eb136b5d6 100644 --- a/filetests/isa/intel/binary32.cton +++ b/filetests/isa/intel/binary32.cton @@ -105,6 +105,13 @@ ebb0: ; asm: xorl $1000000, %esi [-,%rsi] v47 = bxor_imm v2, 1000000 ; bin: 81 f6 000f4240 + ; More arithmetic. + + ; asm: imull %esi, %ecx + [-,%rcx] v50 = imul v1, v2 ; bin: 0f af ce + ; asm: imull %ecx, %esi + [-,%rsi] v51 = imul v2, v1 ; bin: 0f af f1 + ; Register copies. ; asm: movl %esi, %ecx diff --git a/filetests/isa/intel/binary64.cton b/filetests/isa/intel/binary64.cton index ecb4b8a40d..5e3507d473 100644 --- a/filetests/isa/intel/binary64.cton +++ b/filetests/isa/intel/binary64.cton @@ -145,6 +145,15 @@ ebb0: ; asm: movq %rcx, %r10 [-,%r10] v112 = copy v1 ; bin: 49 89 ca + ; More arithmetic. + + ; asm: imulq %rsi, %rcx + [-,%rcx] v120 = imul v1, v2 ; bin: 48 0f af ce + ; asm: imulq %r10, %rsi + [-,%rsi] v121 = imul v2, v3 ; bin: 49 0f af f2 + ; asm: imulq %rcx, %r10 + [-,%r10] v122 = imul v3, v1 ; bin: 4c 0f af d1 + ; Bit-counting instructions. ; asm: popcntq %rsi, %rcx @@ -313,6 +322,15 @@ ebb0: ; asm: movl %ecx, %r10d [-,%r10] v112 = copy v1 ; bin: 41 89 ca + ; More arithmetic. + + ; asm: imull %esi, %ecx + [-,%rcx] v120 = imul v1, v2 ; bin: 40 0f af ce + ; asm: imull %r10d, %esi + [-,%rsi] v121 = imul v2, v3 ; bin: 41 0f af f2 + ; asm: imull %ecx, %r10d + [-,%r10] v122 = imul v3, v1 ; bin: 44 0f af d1 + ; Bit-counting instructions. ; asm: popcntl %esi, %ecx diff --git a/filetests/wasm/i32-arith.cton b/filetests/wasm/i32-arith.cton index bddec1b52b..b345847eb9 100644 --- a/filetests/wasm/i32-arith.cton +++ b/filetests/wasm/i32-arith.cton @@ -49,7 +49,12 @@ ebb0(v0: i32, v1: i32): return v2 } -; function %i32_mul(i32, i32) -> i32 +function %i32_mul(i32, i32) -> i32 { +ebb0(v0: i32, v1: i32): + v2 = imul v0, v1 + return v2 +} + ; function %i32_div(i32, i32) -> i32 ; function %i32_rem_s(i32, i32) -> i32 ; function %i32_rem_u(i32, i32) -> i32 diff --git a/lib/cretonne/meta/isa/intel/encodings.py b/lib/cretonne/meta/isa/intel/encodings.py index c2c361ea86..f6f003bb1e 100644 --- a/lib/cretonne/meta/isa/intel/encodings.py +++ b/lib/cretonne/meta/isa/intel/encodings.py @@ -23,6 +23,11 @@ for inst, opc in [ # default. Otherwise reg-alloc would never use r8 and up. I64.enc(inst.i32, *r.rr(opc)) +I32.enc(base.imul.i32, *r.rrx(0x0f, 0xaf)) +I64.enc(base.imul.i64, *r.rrx.rex(0x0f, 0xaf, w=1)) +I64.enc(base.imul.i32, *r.rrx.rex(0x0f, 0xaf)) +I64.enc(base.imul.i32, *r.rrx(0x0f, 0xaf)) + I32.enc(base.copy.i32, *r.umr(0x89)) I64.enc(base.copy.i64, *r.umr.rex(0x89, w=1)) I64.enc(base.copy.i32, *r.umr.rex(0x89)) diff --git a/lib/cretonne/meta/isa/intel/recipes.py b/lib/cretonne/meta/isa/intel/recipes.py index b7e6aa5575..e521b205b1 100644 --- a/lib/cretonne/meta/isa/intel/recipes.py +++ b/lib/cretonne/meta/isa/intel/recipes.py @@ -197,6 +197,14 @@ rr = TailRecipe( modrm_rr(in_reg0, in_reg1, sink); ''') +# XX /r with operands swapped. (RM form). +rrx = TailRecipe( + 'rrx', Binary, size=1, ins=(GPR, GPR), outs=0, + emit=''' + PUT_OP(bits, rex2(in_reg1, in_reg0), sink); + modrm_rr(in_reg1, in_reg0, sink); + ''') + # XX /r, but for a unary operator with separate input/output register, like # copies. MR form. umr = TailRecipe( diff --git a/lib/cretonne/src/isa/intel/binemit.rs b/lib/cretonne/src/isa/intel/binemit.rs index 56f0c2f7f0..d3c9716680 100644 --- a/lib/cretonne/src/isa/intel/binemit.rs +++ b/lib/cretonne/src/isa/intel/binemit.rs @@ -76,6 +76,14 @@ fn put_op2(bits: u16, rex: u8, sink: &mut CS) { sink.put1(bits as u8); } +// Emit two-byte opcode: 0F XX with REX prefix. +fn put_rexop2(bits: u16, rex: u8, sink: &mut CS) { + debug_assert_eq!(bits & 0x0f00, 0x0400, "Invalid encoding bits for RexOp2*"); + rex_prefix(bits, rex, sink); + sink.put1(0x0f); + sink.put1(bits as u8); +} + // Emit single-byte opcode with mandatory prefix. fn put_mp1(bits: u16, rex: u8, sink: &mut CS) { debug_assert_eq!(bits & 0x8c00, 0, "Invalid encoding bits for Mp1*");