diff --git a/cranelift/filetests/isa/intel/binary32.cton b/cranelift/filetests/isa/intel/binary32.cton index 4509507005..5cac489f77 100644 --- a/cranelift/filetests/isa/intel/binary32.cton +++ b/cranelift/filetests/isa/intel/binary32.cton @@ -92,5 +92,110 @@ ebb0: ; asm: xorl $1000000, %esi [-,%rsi] v47 = bxor_imm v2, 1000000 ; bin: 81 f6 000f4240 + ; Load/Store instructions. + + ; Register indirect addressing with no displacement. + + ; asm: movl %ecx, (%esi) + store v1, v2 ; bin: 89 0e + ; asm: movl %esi, (%ecx) + store v2, v1 ; bin: 89 31 + ; asm: movw %cx, (%esi) + istore16 v1, v2 ; bin: 66 89 0e + ; asm: movw %si, (%ecx) + istore16 v2, v1 ; bin: 66 89 31 + ; asm: movb %cl, (%esi) + istore8 v1, v2 ; bin: 88 0e + ; Can't store %sil in 32-bit mode (needs REX prefix). + + ; asm: movl (%ecx), %edi + [-,%rdi] v100 = load.i32 v1 ; bin: 8b 39 + ; asm: movl (%esi), %edx + [-,%rdx] v101 = load.i32 v2 ; bin: 8b 16 + ; asm: movzwl (%ecx), %edi + [-,%rdi] v102 = uload16.i32 v1 ; bin: 0f b7 39 + ; asm: movzwl (%esi), %edx + [-,%rdx] v103 = uload16.i32 v2 ; bin: 0f b7 16 + ; asm: movswl (%ecx), %edi + [-,%rdi] v104 = sload16.i32 v1 ; bin: 0f bf 39 + ; asm: movswl (%esi), %edx + [-,%rdx] v105 = sload16.i32 v2 ; bin: 0f bf 16 + ; asm: movzbl (%ecx), %edi + [-,%rdi] v106 = uload8.i32 v1 ; bin: 0f b6 39 + ; asm: movzbl (%esi), %edx + [-,%rdx] v107 = uload8.i32 v2 ; bin: 0f b6 16 + ; asm: movsbl (%ecx), %edi + [-,%rdi] v108 = sload8.i32 v1 ; bin: 0f be 39 + ; asm: movsbl (%esi), %edx + [-,%rdx] v109 = sload8.i32 v2 ; bin: 0f be 16 + + ; Register-indirect with 8-bit signed displacement. + + ; asm: movl %ecx, 100(%esi) + store v1, v2+100 ; bin: 89 4e 64 + ; asm: movl %esi, -100(%ecx) + store v2, v1-100 ; bin: 89 71 9c + ; asm: movw %cx, 100(%esi) + istore16 v1, v2+100 ; bin: 66 89 4e 64 + ; asm: movw %si, -100(%ecx) + istore16 v2, v1-100 ; bin: 66 89 71 9c + ; asm: movb %cl, 100(%esi) + istore8 v1, v2+100 ; bin: 88 4e 64 + + ; asm: movl 50(%ecx), %edi + [-,%rdi] v110 = load.i32 v1+50 ; bin: 8b 79 32 + ; asm: movl -50(%esi), %edx + [-,%rdx] v111 = load.i32 v2-50 ; bin: 8b 56 ce + ; asm: movzwl 50(%ecx), %edi + [-,%rdi] v112 = uload16.i32 v1+50 ; bin: 0f b7 79 32 + ; asm: movzwl -50(%esi), %edx + [-,%rdx] v113 = uload16.i32 v2-50 ; bin: 0f b7 56 ce + ; asm: movswl 50(%ecx), %edi + [-,%rdi] v114 = sload16.i32 v1+50 ; bin: 0f bf 79 32 + ; asm: movswl -50(%esi), %edx + [-,%rdx] v115 = sload16.i32 v2-50 ; bin: 0f bf 56 ce + ; asm: movzbl 50(%ecx), %edi + [-,%rdi] v116 = uload8.i32 v1+50 ; bin: 0f b6 79 32 + ; asm: movzbl -50(%esi), %edx + [-,%rdx] v117 = uload8.i32 v2-50 ; bin: 0f b6 56 ce + ; asm: movsbl 50(%ecx), %edi + [-,%rdi] v118 = sload8.i32 v1+50 ; bin: 0f be 79 32 + ; asm: movsbl -50(%esi), %edx + [-,%rdx] v119 = sload8.i32 v2-50 ; bin: 0f be 56 ce + + ; Register-indirect with 32-bit signed displacement. + + ; asm: movl %ecx, 10000(%esi) + store v1, v2+10000 ; bin: 89 8e 00002710 + ; asm: movl %esi, -10000(%ecx) + store v2, v1-10000 ; bin: 89 b1 ffffd8f0 + ; asm: movw %cx, 10000(%esi) + istore16 v1, v2+10000 ; bin: 66 89 8e 00002710 + ; asm: movw %si, -10000(%ecx) + istore16 v2, v1-10000 ; bin: 66 89 b1 ffffd8f0 + ; asm: movb %cl, 10000(%esi) + istore8 v1, v2+10000 ; bin: 88 8e 00002710 + + ; asm: movl 50000(%ecx), %edi + [-,%rdi] v120 = load.i32 v1+50000 ; bin: 8b b9 0000c350 + ; asm: movl -50000(%esi), %edx + [-,%rdx] v121 = load.i32 v2-50000 ; bin: 8b 96 ffff3cb0 + ; asm: movzwl 50000(%ecx), %edi + [-,%rdi] v122 = uload16.i32 v1+50000 ; bin: 0f b7 b9 0000c350 + ; asm: movzwl -50000(%esi), %edx + [-,%rdx] v123 = uload16.i32 v2-50000 ; bin: 0f b7 96 ffff3cb0 + ; asm: movswl 50000(%ecx), %edi + [-,%rdi] v124 = sload16.i32 v1+50000 ; bin: 0f bf b9 0000c350 + ; asm: movswl -50000(%esi), %edx + [-,%rdx] v125 = sload16.i32 v2-50000 ; bin: 0f bf 96 ffff3cb0 + ; asm: movzbl 50000(%ecx), %edi + [-,%rdi] v126 = uload8.i32 v1+50000 ; bin: 0f b6 b9 0000c350 + ; asm: movzbl -50000(%esi), %edx + [-,%rdx] v127 = uload8.i32 v2-50000 ; bin: 0f b6 96 ffff3cb0 + ; asm: movsbl 50000(%ecx), %edi + [-,%rdi] v128 = sload8.i32 v1+50000 ; bin: 0f be b9 0000c350 + ; asm: movsbl -50000(%esi), %edx + [-,%rdx] v129 = sload8.i32 v2-50000 ; bin: 0f be 96 ffff3cb0 + return } diff --git a/lib/cretonne/meta/isa/intel/encodings.py b/lib/cretonne/meta/isa/intel/encodings.py index 967da0d857..8d6d466aa7 100644 --- a/lib/cretonne/meta/isa/intel/encodings.py +++ b/lib/cretonne/meta/isa/intel/encodings.py @@ -4,15 +4,15 @@ Intel Encodings. from __future__ import absolute_import from base import instructions as base from .defs import I32 -from .recipes import Op1rr, Op1rc, Op1rib, Op1rid -from .recipes import OP +from . import recipes as rcp +from .recipes import OP, OP0F, MP66 -I32.enc(base.iadd.i32, Op1rr, OP(0x01)) -I32.enc(base.isub.i32, Op1rr, OP(0x29)) +I32.enc(base.iadd.i32, rcp.Op1rr, OP(0x01)) +I32.enc(base.isub.i32, rcp.Op1rr, OP(0x29)) -I32.enc(base.band.i32, Op1rr, OP(0x21)) -I32.enc(base.bor.i32, Op1rr, OP(0x09)) -I32.enc(base.bxor.i32, Op1rr, OP(0x31)) +I32.enc(base.band.i32, rcp.Op1rr, OP(0x21)) +I32.enc(base.bor.i32, rcp.Op1rr, OP(0x09)) +I32.enc(base.bxor.i32, rcp.Op1rr, OP(0x31)) # Immediate instructions with sign-extended 8-bit and 32-bit immediate. for inst, r in [ @@ -20,12 +20,45 @@ for inst, r in [ (base.band_imm.i32, 4), (base.bor_imm.i32, 1), (base.bxor_imm.i32, 6)]: - I32.enc(inst, Op1rib, OP(0x83, rrr=r)) - I32.enc(inst, Op1rid, OP(0x81, rrr=r)) + I32.enc(inst, rcp.Op1rib, OP(0x83, rrr=r)) + I32.enc(inst, rcp.Op1rid, OP(0x81, rrr=r)) # 32-bit shifts and rotates. # Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit # and 16-bit shifts would need explicit masking. -I32.enc(base.ishl.i32.i32, Op1rc, OP(0xd3, rrr=4)) -I32.enc(base.ushr.i32.i32, Op1rc, OP(0xd3, rrr=5)) -I32.enc(base.sshr.i32.i32, Op1rc, OP(0xd3, rrr=7)) +I32.enc(base.ishl.i32.i32, rcp.Op1rc, OP(0xd3, rrr=4)) +I32.enc(base.ushr.i32.i32, rcp.Op1rc, OP(0xd3, rrr=5)) +I32.enc(base.sshr.i32.i32, rcp.Op1rc, OP(0xd3, rrr=7)) + +# Loads and stores. +I32.enc(base.store.i32.i32, rcp.Op1st, OP(0x89)) +I32.enc(base.store.i32.i32, rcp.Op1stDisp8, OP(0x89)) +I32.enc(base.store.i32.i32, rcp.Op1stDisp32, OP(0x89)) + +I32.enc(base.istore16.i32.i32, rcp.Mp1st, MP66(0x89)) +I32.enc(base.istore16.i32.i32, rcp.Mp1stDisp8, MP66(0x89)) +I32.enc(base.istore16.i32.i32, rcp.Mp1stDisp32, MP66(0x89)) + +I32.enc(base.istore8.i32.i32, rcp.Op1st_abcd, OP(0x88)) +I32.enc(base.istore8.i32.i32, rcp.Op1stDisp8_abcd, OP(0x88)) +I32.enc(base.istore8.i32.i32, rcp.Op1stDisp32_abcd, OP(0x88)) + +I32.enc(base.load.i32.i32, rcp.Op1ld, OP(0x8b)) +I32.enc(base.load.i32.i32, rcp.Op1ldDisp8, OP(0x8b)) +I32.enc(base.load.i32.i32, rcp.Op1ldDisp32, OP(0x8b)) + +I32.enc(base.uload16.i32.i32, rcp.Op2ld, OP0F(0xb7)) +I32.enc(base.uload16.i32.i32, rcp.Op2ldDisp8, OP0F(0xb7)) +I32.enc(base.uload16.i32.i32, rcp.Op2ldDisp32, OP0F(0xb7)) + +I32.enc(base.sload16.i32.i32, rcp.Op2ld, OP0F(0xbf)) +I32.enc(base.sload16.i32.i32, rcp.Op2ldDisp8, OP0F(0xbf)) +I32.enc(base.sload16.i32.i32, rcp.Op2ldDisp32, OP0F(0xbf)) + +I32.enc(base.uload8.i32.i32, rcp.Op2ld, OP0F(0xb6)) +I32.enc(base.uload8.i32.i32, rcp.Op2ldDisp8, OP0F(0xb6)) +I32.enc(base.uload8.i32.i32, rcp.Op2ldDisp32, OP0F(0xb6)) + +I32.enc(base.sload8.i32.i32, rcp.Op2ld, OP0F(0xbe)) +I32.enc(base.sload8.i32.i32, rcp.Op2ldDisp8, OP0F(0xbe)) +I32.enc(base.sload8.i32.i32, rcp.Op2ldDisp32, OP0F(0xbe)) diff --git a/lib/cretonne/meta/isa/intel/recipes.py b/lib/cretonne/meta/isa/intel/recipes.py index d4891fba27..6c72fe4690 100644 --- a/lib/cretonne/meta/isa/intel/recipes.py +++ b/lib/cretonne/meta/isa/intel/recipes.py @@ -3,9 +3,9 @@ Intel Encoding recipes. """ from __future__ import absolute_import from cdsl.isa import EncRecipe -from cdsl.predicates import IsSignedInt -from base.formats import Binary, BinaryImm -from .registers import GPR +from cdsl.predicates import IsSignedInt, IsEqual +from base.formats import Binary, BinaryImm, Store, Load +from .registers import GPR, ABCD # Opcode representation. # @@ -15,21 +15,21 @@ from .registers import GPR # name prefix: # # Op1* OP(op) -# 0F Op2* OP(op) +# 0F Op2* OP0F(op) # 0F 38 Op3* OP38(op) # 0F 3A Op3* OP3A(op) # 66 Mp1* MP66(op) -# 66 0F Mp2* MP66(op) -# 66 0F 38 Mp3* MP6638(op) -# 66 0F 3A Mp3* MP663A(op) +# 66 0F Mp2* MP660F(op) +# 66 0F 38 Mp3* MP660F38(op) +# 66 0F 3A Mp3* MP660F3A(op) # F2 Mp1* MPF2(op) -# F2 0F Mp2* MPF2(op) -# F2 0F 38 Mp3* MPF238(op) -# F2 0F 3A Mp3* MPF23A(op) +# F2 0F Mp2* MPF20F(op) +# F2 0F 38 Mp3* MPF20F38(op) +# F2 0F 3A Mp3* MPF20F3A(op) # F3 Mp1* MPF3(op) -# F3 0F Mp2* MPF3(op) -# F3 0F 38 Mp3* MPF338(op) -# F3 0F 3A Mp3* MPF33A(op) +# F3 0F Mp2* MP0FF3(op) +# F3 0F 38 Mp3* MPF30F38(op) +# F3 0F 3A Mp3* MPF30F3A(op) # # VEX/XOP and EVEX prefixes are not yet supported. # @@ -63,6 +63,16 @@ def OP(op, pp=0, mm=0, rrr=0, w=0): return op | (pp << 8) | (mm << 10) | (rrr << 12) | (w << 15) +def OP0F(op, rrr=0, w=0): + # type: (int, int, int) -> int + return OP(op, pp=0, mm=1, rrr=rrr, w=w) + + +def MP66(op, rrr=0, w=0): + # type: (int, int, int) -> int + return OP(op, pp=1, mm=0, rrr=rrr, w=w) + + # XX /r Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0) @@ -78,3 +88,78 @@ Op1rib = EncRecipe( Op1rid = EncRecipe( 'Op1rid', BinaryImm, size=6, ins=GPR, outs=0, instp=IsSignedInt(BinaryImm.imm, 32)) + +# +# Store recipes. +# + +# XX /r register-indirect store with no offset. +Op1st = EncRecipe( + 'Op1st', Store, size=2, ins=(GPR, GPR), outs=(), + instp=IsEqual(Store.offset, 0)) + +# XX /r register-indirect store with no offset. +# Only ABCD allowed for stored value. This is for byte stores. +Op1st_abcd = EncRecipe( + 'Op1st_abcd', Store, size=2, ins=(ABCD, GPR), outs=(), + instp=IsEqual(Store.offset, 0)) + +# XX /r register-indirect store with 8-bit offset. +Op1stDisp8 = EncRecipe( + 'Op1stDisp8', Store, size=3, ins=(GPR, GPR), outs=(), + instp=IsSignedInt(Store.offset, 8)) +Op1stDisp8_abcd = EncRecipe( + 'Op1stDisp8_abcd', Store, size=3, ins=(ABCD, GPR), outs=(), + instp=IsSignedInt(Store.offset, 8)) + +# XX /r register-indirect store with 32-bit offset. +Op1stDisp32 = EncRecipe('Op1stDisp32', Store, size=6, ins=(GPR, GPR), outs=()) +Op1stDisp32_abcd = EncRecipe( + 'Op1stDisp32_abcd', Store, size=6, ins=(ABCD, GPR), outs=()) + +# PP WW /r register-indirect store with no offset. +Mp1st = EncRecipe( + 'Mp1st', Store, size=3, ins=(GPR, GPR), outs=(), + instp=IsEqual(Store.offset, 0)) + +# PP XX /r register-indirect store with 8-bit offset. +Mp1stDisp8 = EncRecipe( + 'Mp1stDisp8', Store, size=4, ins=(GPR, GPR), outs=(), + instp=IsSignedInt(Store.offset, 8)) + +# PP XX /r register-indirect store with 32-bit offset. +Mp1stDisp32 = EncRecipe('Mp1stDisp32', Store, size=7, ins=(GPR, GPR), outs=()) + +# +# Load recipes +# + +# XX /r load with no offset. +Op1ld = EncRecipe( + 'Op1ld', Load, size=2, ins=(GPR), outs=(GPR), + instp=IsEqual(Load.offset, 0)) + +# XX /r load with 8-bit offset. +Op1ldDisp8 = EncRecipe( + 'Op1ldDisp8', Load, size=3, ins=(GPR), outs=(GPR), + instp=IsSignedInt(Load.offset, 8)) + +# XX /r load with 32-bit offset. +Op1ldDisp32 = EncRecipe( + 'Op1ldDisp32', Load, size=6, ins=(GPR), outs=(GPR), + instp=IsSignedInt(Load.offset, 32)) + +# 0F XX /r load with no offset. +Op2ld = EncRecipe( + 'Op2ld', Load, size=3, ins=(GPR), outs=(GPR), + instp=IsEqual(Load.offset, 0)) + +# XX /r load with 8-bit offset. +Op2ldDisp8 = EncRecipe( + 'Op2ldDisp8', Load, size=4, ins=(GPR), outs=(GPR), + instp=IsSignedInt(Load.offset, 8)) + +# XX /r load with 32-bit offset. +Op2ldDisp32 = EncRecipe( + 'Op2ldDisp32', Load, size=7, ins=(GPR), outs=(GPR), + instp=IsSignedInt(Load.offset, 32)) diff --git a/lib/cretonne/src/isa/intel/binemit.rs b/lib/cretonne/src/isa/intel/binemit.rs index 75f8241e9c..834a9848c3 100644 --- a/lib/cretonne/src/isa/intel/binemit.rs +++ b/lib/cretonne/src/isa/intel/binemit.rs @@ -8,11 +8,30 @@ include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs")); pub static RELOC_NAMES: [&'static str; 1] = ["Call"]; +// Emit single-byte opcode. fn put_op1(bits: u16, sink: &mut CS) { debug_assert!(bits & 0x0f00 == 0, "Invalid encoding bits for Op1*"); sink.put1(bits as u8); } +// Emit two-byte opcode: 0F XX +fn put_op2(bits: u16, sink: &mut CS) { + debug_assert!(bits & 0x0f00 == 0x0400, "Invalid encoding bits for Op2*"); + sink.put1(0x0f); + sink.put1(bits as u8); +} + +// Mandatory prefix bytes for Mp* opcodes. +const PREFIX: [u8; 3] = [0x66, 0xf3, 0xf2]; + +// Emit single-byte opcode with mandatory prefix. +fn put_mp1(bits: u16, sink: &mut CS) { + debug_assert!(bits & 0x0c00 == 0, "Invalid encoding bits for Mp1*"); + let pp = (bits >> 8) & 3; + sink.put1(PREFIX[(pp - 1) as usize]); + sink.put1(bits as u8); +} + /// Emit a ModR/M byte for reg-reg operands. fn modrm_rr(rm: RegUnit, reg: RegUnit, sink: &mut CS) { let reg = reg as u8 & 7; @@ -33,6 +52,42 @@ fn modrm_r_bits(rm: RegUnit, bits: u16, sink: &mut CS) { sink.put1(b); } +/// Emit a mode 00 ModR/M byte. This is a register-indirect addressing mode with no offset. +/// Registers %rsp and %rbp are invalid for `rm`, %rsp indicates a SIB byte, and %rbp indicates an +/// absolute immediate 32-bit address. +fn modrm_rm(rm: RegUnit, reg: RegUnit, sink: &mut CS) { + let reg = reg as u8 & 7; + let rm = rm as u8 & 7; + let mut b = 0b00000000; + b |= reg << 3; + b |= rm; + sink.put1(b); +} + +/// Emit a mode 01 ModR/M byte. This is a register-indirect addressing mode with 8-bit +/// displacement. +/// Register %rsp is invalid for `rm`. It indicates the presence of a SIB byte. +fn modrm_disp8(rm: RegUnit, reg: RegUnit, sink: &mut CS) { + let reg = reg as u8 & 7; + let rm = rm as u8 & 7; + let mut b = 0b01000000; + b |= reg << 3; + b |= rm; + sink.put1(b); +} + +/// Emit a mode 10 ModR/M byte. This is a register-indirect addressing mode with 32-bit +/// displacement. +/// Register %rsp is invalid for `rm`. It indicates the presence of a SIB byte. +fn modrm_disp32(rm: RegUnit, reg: RegUnit, sink: &mut CS) { + let reg = reg as u8 & 7; + let rm = rm as u8 & 7; + let mut b = 0b10000000; + b |= reg << 3; + b |= rm; + sink.put1(b); +} + fn recipe_op1rr(func: &Function, inst: Inst, sink: &mut CS) { if let InstructionData::Binary { args, .. } = func.dfg[inst] { put_op1(func.encodings[inst].bits(), sink); @@ -77,3 +132,168 @@ fn recipe_op1rid(func: &Function, inst: Inst, sink: &mut panic!("Expected BinaryImm format: {:?}", func.dfg[inst]); } } + +// Store recipes. + +fn recipe_op1st(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Store { args, .. } = func.dfg[inst] { + put_op1(func.encodings[inst].bits(), sink); + modrm_rm(func.locations[args[1]].unwrap_reg(), + func.locations[args[0]].unwrap_reg(), + sink); + } else { + panic!("Expected Store format: {:?}", func.dfg[inst]); + } +} + +// This is just a tighter register class constraint. +fn recipe_op1st_abcd(func: &Function, inst: Inst, sink: &mut CS) { + recipe_op1st(func, inst, sink) +} + +fn recipe_mp1st(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Store { args, .. } = func.dfg[inst] { + put_mp1(func.encodings[inst].bits(), sink); + modrm_rm(func.locations[args[1]].unwrap_reg(), + func.locations[args[0]].unwrap_reg(), + sink); + } else { + panic!("Expected Store format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op1stdisp8(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Store { args, offset, .. } = func.dfg[inst] { + put_op1(func.encodings[inst].bits(), sink); + modrm_disp8(func.locations[args[1]].unwrap_reg(), + func.locations[args[0]].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put1(offset as u8); + } else { + panic!("Expected Store format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op1stdisp8_abcd(func: &Function, inst: Inst, sink: &mut CS) { + recipe_op1stdisp8(func, inst, sink) +} + +fn recipe_mp1stdisp8(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Store { args, offset, .. } = func.dfg[inst] { + put_mp1(func.encodings[inst].bits(), sink); + modrm_disp8(func.locations[args[1]].unwrap_reg(), + func.locations[args[0]].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put1(offset as u8); + } else { + panic!("Expected Store format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op1stdisp32(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Store { args, offset, .. } = func.dfg[inst] { + put_op1(func.encodings[inst].bits(), sink); + modrm_disp32(func.locations[args[1]].unwrap_reg(), + func.locations[args[0]].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put4(offset as u32); + } else { + panic!("Expected Store format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op1stdisp32_abcd(func: &Function, inst: Inst, sink: &mut CS) { + recipe_op1stdisp32(func, inst, sink) +} + +fn recipe_mp1stdisp32(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Store { args, offset, .. } = func.dfg[inst] { + put_mp1(func.encodings[inst].bits(), sink); + modrm_disp32(func.locations[args[1]].unwrap_reg(), + func.locations[args[0]].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put4(offset as u32); + } else { + panic!("Expected Store format: {:?}", func.dfg[inst]); + } +} + +// Load recipes + +fn recipe_op1ld(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Load { arg, .. } = func.dfg[inst] { + put_op1(func.encodings[inst].bits(), sink); + modrm_rm(func.locations[arg].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + } else { + panic!("Expected Load format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op1lddisp8(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] { + put_op1(func.encodings[inst].bits(), sink); + modrm_disp8(func.locations[arg].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put1(offset as u8); + } else { + panic!("Expected Load format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op1lddisp32(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] { + put_op1(func.encodings[inst].bits(), sink); + modrm_disp32(func.locations[arg].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put4(offset as u32); + } else { + panic!("Expected Load format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op2ld(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Load { arg, .. } = func.dfg[inst] { + put_op2(func.encodings[inst].bits(), sink); + modrm_rm(func.locations[arg].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + } else { + panic!("Expected Load format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op2lddisp8(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] { + put_op2(func.encodings[inst].bits(), sink); + modrm_disp8(func.locations[arg].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put1(offset as u8); + } else { + panic!("Expected Load format: {:?}", func.dfg[inst]); + } +} + +fn recipe_op2lddisp32(func: &Function, inst: Inst, sink: &mut CS) { + if let InstructionData::Load { arg, offset, .. } = func.dfg[inst] { + put_op2(func.encodings[inst].bits(), sink); + modrm_disp32(func.locations[arg].unwrap_reg(), + func.locations[func.dfg.first_result(inst)].unwrap_reg(), + sink); + let offset: i32 = offset.into(); + sink.put4(offset as u32); + } else { + panic!("Expected Load format: {:?}", func.dfg[inst]); + } +} diff --git a/lib/cretonne/src/predicates.rs b/lib/cretonne/src/predicates.rs index 770857d100..6ce3e0a799 100644 --- a/lib/cretonne/src/predicates.rs +++ b/lib/cretonne/src/predicates.rs @@ -11,8 +11,8 @@ /// Check that `x` is the same as `y`. #[allow(dead_code)] -pub fn is_equal(x: T, y: T) -> bool { - x == y +pub fn is_equal + Copy>(x: T, y: O) -> bool { + x == y.into() } /// Check that `x` can be represented as a `wd`-bit signed integer with `sc` low zero bits.