diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index 5f18673a3c8..4a63eadba03 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -181,6 +181,8 @@ namespace { const { return 0; } unsigned getT2AddrModeImm8OpValue(const MachineInstr &MI, unsigned Op) const { return 0; } + unsigned getT2AddrModeImm8OffsetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } unsigned getT2AddrModeSORegOpValue(const MachineInstr &MI, unsigned Op) const { return 0; } unsigned getT2SORegOpValue(const MachineInstr &MI, unsigned Op) diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index fcbc3cbee51..d011a428fa0 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -1050,6 +1050,15 @@ class T2Iidxldst opcod, bit load, bit pre, // (P, W) = (1, 1) Pre-indexed or (0, 1) Post-indexed let Inst{10} = pre; // The P bit. let Inst{8} = 1; // The W bit. + + bits<9> addr; + let Inst{7-0} = addr{7-0}; + let Inst{9} = addr{8}; // Sign bit + + bits<4> Rt; + bits<4> Rn; + let Inst{15-12} = Rt{3-0}; + let Inst{19-16} = Rn{3-0}; } // Tv5Pat - Same as Pat<>, but requires V5T Thumb mode. diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index ce4115c2ce3..1f8e9fb20d6 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -143,6 +143,7 @@ def t2am_imm8_offset : Operand, ComplexPattern { let PrintMethod = "printT2AddrModeImm8OffsetOperand"; + string EncoderMethod = "getT2AddrModeImm8OffsetOpValue"; } // t2addrmode_imm8s4 := reg +/- (imm8 << 2) @@ -917,7 +918,7 @@ multiclass T2I_st opcod, string opc, let Inst{20} = 0; // !load bits<4> Rt; - let Inst{19-16} = Rt{3-0}; + let Inst{15-12} = Rt{3-0}; bits<16> addr; let Inst{19-16} = addr{15-12}; // Rn @@ -936,7 +937,7 @@ multiclass T2I_st opcod, string opc, let Inst{8} = 0; // The W bit. bits<4> Rt; - let Inst{19-16} = Rt{3-0}; + let Inst{15-12} = Rt{3-0}; bits<13> addr; let Inst{19-16} = addr{12-9}; // Rn @@ -1319,61 +1320,75 @@ def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)), // not via pattern. // Indexed loads + +class T2Iidxld opcod, bit pre, + dag oops, dag iops, + AddrMode am, IndexMode im, InstrItinClass itin, + string opc, string asm, string cstr, list pattern> + : T2Iidxldst; +class T2Iidxst opcod, bit pre, + dag oops, dag iops, + AddrMode am, IndexMode im, InstrItinClass itin, + string opc, string asm, string cstr, list pattern> + : T2Iidxldst; + let mayLoad = 1, neverHasSideEffects = 1 in { -def t2LDR_PRE : T2Iidxldst<0, 0b10, 1, 1, (outs GPR:$dst, GPR:$base_wb), +def t2LDR_PRE : T2Iidxld<0, 0b10, 1, (outs GPR:$Rt, GPR:$Rn), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_iu, - "ldr", "\t$dst, $addr!", "$addr.base = $base_wb", + "ldr", "\t$Rt, $addr!", "$addr.base = $Rn", []>; -def t2LDR_POST : T2Iidxldst<0, 0b10, 1, 0, (outs GPR:$dst, GPR:$base_wb), +def t2LDR_POST : T2Iidxld<0, 0b10, 0, (outs GPR:$Rt, GPR:$Rn), (ins GPR:$base, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_iu, - "ldr", "\t$dst, [$base], $offset", "$base = $base_wb", + "ldr", "\t$Rt, [$Rn], $offset", "$base = $Rn", []>; -def t2LDRB_PRE : T2Iidxldst<0, 0b00, 1, 1, (outs GPR:$dst, GPR:$base_wb), +def t2LDRB_PRE : T2Iidxld<0, 0b00, 1, (outs GPR:$Rt, GPR:$Rn), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, - "ldrb", "\t$dst, $addr!", "$addr.base = $base_wb", + "ldrb", "\t$Rt, $addr!", "$addr.base = $Rn", []>; -def t2LDRB_POST : T2Iidxldst<0, 0b00, 1, 0, (outs GPR:$dst, GPR:$base_wb), +def t2LDRB_POST : T2Iidxld<0, 0b00, 0, (outs GPR:$Rt, GPR:$Rn), (ins GPR:$base, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, - "ldrb", "\t$dst, [$base], $offset", "$base = $base_wb", + "ldrb", "\t$Rt, [$Rn], $offset", "$base = $Rn", []>; -def t2LDRH_PRE : T2Iidxldst<0, 0b01, 1, 1, (outs GPR:$dst, GPR:$base_wb), +def t2LDRH_PRE : T2Iidxld<0, 0b01, 1, (outs GPR:$Rt, GPR:$Rn), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, - "ldrh", "\t$dst, $addr!", "$addr.base = $base_wb", + "ldrh", "\t$Rt, $addr!", "$addr.base = $Rn", []>; -def t2LDRH_POST : T2Iidxldst<0, 0b01, 1, 0, (outs GPR:$dst, GPR:$base_wb), +def t2LDRH_POST : T2Iidxld<0, 0b01, 0, (outs GPR:$Rt, GPR:$Rn), (ins GPR:$base, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, - "ldrh", "\t$dst, [$base], $offset", "$base = $base_wb", + "ldrh", "\t$Rt, [$Rn], $offset", "$base = $Rn", []>; -def t2LDRSB_PRE : T2Iidxldst<1, 0b00, 1, 1, (outs GPR:$dst, GPR:$base_wb), +def t2LDRSB_PRE : T2Iidxld<1, 0b00, 1, (outs GPR:$Rt, GPR:$Rn), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, - "ldrsb", "\t$dst, $addr!", "$addr.base = $base_wb", + "ldrsb", "\t$Rt, $addr!", "$addr.base = $Rn", []>; -def t2LDRSB_POST : T2Iidxldst<1, 0b00, 1, 0, (outs GPR:$dst, GPR:$base_wb), +def t2LDRSB_POST : T2Iidxld<1, 0b00, 0, (outs GPR:$Rt, GPR:$Rn), (ins GPR:$base, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, - "ldrsb", "\t$dst, [$base], $offset", "$base = $base_wb", + "ldrsb", "\t$Rt, [$Rn], $offset", "$base = $Rn", []>; -def t2LDRSH_PRE : T2Iidxldst<1, 0b01, 1, 1, (outs GPR:$dst, GPR:$base_wb), +def t2LDRSH_PRE : T2Iidxld<1, 0b01, 1, (outs GPR:$Rt, GPR:$Rn), (ins t2addrmode_imm8:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, - "ldrsh", "\t$dst, $addr!", "$addr.base = $base_wb", + "ldrsh", "\t$Rt, $addr!", "$addr.base = $Rn", []>; -def t2LDRSH_POST : T2Iidxldst<1, 0b01, 1, 0, (outs GPR:$dst, GPR:$base_wb), +def t2LDRSH_POST : T2Iidxld<1, 0b01, 0, (outs GPR:$dst, GPR:$Rn), (ins GPR:$base, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, - "ldrsh", "\t$dst, [$base], $offset", "$base = $base_wb", + "ldrsh", "\t$dst, [$Rn], $offset", "$base = $Rn", []>; } // mayLoad = 1, neverHasSideEffects = 1 @@ -1415,47 +1430,47 @@ def t2STRDi8 : T2Ii8s4<1, 0, 0, (outs), IIC_iStore_d_r, "strd", "\t$src1, $addr", []>; // Indexed stores -def t2STR_PRE : T2Iidxldst<0, 0b10, 0, 1, (outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, t2am_imm8_offset:$offset), +def t2STR_PRE : T2Iidxst<0, 0b10, 1, (outs GPR:$base_wb), + (ins GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_iu, - "str", "\t$src, [$base, $offset]!", "$base = $base_wb", + "str", "\t$Rt, [$Rn, $addr]!", "$Rn = $base_wb", [(set GPR:$base_wb, - (pre_store GPR:$src, GPR:$base, t2am_imm8_offset:$offset))]>; + (pre_store GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr))]>; -def t2STR_POST : T2Iidxldst<0, 0b10, 0, 0, (outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, t2am_imm8_offset:$offset), +def t2STR_POST : T2Iidxst<0, 0b10, 0, (outs GPR:$base_wb), + (ins GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr), AddrModeT2_i8, IndexModePost, IIC_iStore_iu, - "str", "\t$src, [$base], $offset", "$base = $base_wb", + "str", "\t$Rt, [$Rn], $addr", "$Rn = $base_wb", [(set GPR:$base_wb, - (post_store GPR:$src, GPR:$base, t2am_imm8_offset:$offset))]>; + (post_store GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr))]>; -def t2STRH_PRE : T2Iidxldst<0, 0b01, 0, 1, (outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, t2am_imm8_offset:$offset), +def t2STRH_PRE : T2Iidxst<0, 0b01, 1, (outs GPR:$base_wb), + (ins GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_iu, - "strh", "\t$src, [$base, $offset]!", "$base = $base_wb", + "strh", "\t$Rt, [$Rn, $addr]!", "$Rn = $base_wb", [(set GPR:$base_wb, - (pre_truncsti16 GPR:$src, GPR:$base, t2am_imm8_offset:$offset))]>; + (pre_truncsti16 GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr))]>; -def t2STRH_POST : T2Iidxldst<0, 0b01, 0, 0, (outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, t2am_imm8_offset:$offset), +def t2STRH_POST : T2Iidxst<0, 0b01, 0, (outs GPR:$base_wb), + (ins GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr), AddrModeT2_i8, IndexModePost, IIC_iStore_bh_iu, - "strh", "\t$src, [$base], $offset", "$base = $base_wb", + "strh", "\t$Rt, [$Rn], $addr", "$Rn = $base_wb", [(set GPR:$base_wb, - (post_truncsti16 GPR:$src, GPR:$base, t2am_imm8_offset:$offset))]>; + (post_truncsti16 GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr))]>; -def t2STRB_PRE : T2Iidxldst<0, 0b00, 0, 1, (outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, t2am_imm8_offset:$offset), +def t2STRB_PRE : T2Iidxst<0, 0b00, 1, (outs GPR:$base_wb), + (ins GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_bh_iu, - "strb", "\t$src, [$base, $offset]!", "$base = $base_wb", + "strb", "\t$Rt, [$Rn, $addr]!", "$Rn = $base_wb", [(set GPR:$base_wb, - (pre_truncsti8 GPR:$src, GPR:$base, t2am_imm8_offset:$offset))]>; + (pre_truncsti8 GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr))]>; -def t2STRB_POST : T2Iidxldst<0, 0b00, 0, 0, (outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, t2am_imm8_offset:$offset), +def t2STRB_POST : T2Iidxst<0, 0b00, 0, (outs GPR:$base_wb), + (ins GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr), AddrModeT2_i8, IndexModePost, IIC_iStore_bh_iu, - "strb", "\t$src, [$base], $offset", "$base = $base_wb", + "strb", "\t$Rt, [$Rn], $addr", "$Rn = $base_wb", [(set GPR:$base_wb, - (post_truncsti8 GPR:$src, GPR:$base, t2am_imm8_offset:$offset))]>; + (post_truncsti8 GPR:$Rt, GPR:$Rn, t2am_imm8_offset:$addr))]>; // STRT, STRBT, STRHT all have offset mode (PUW=0b110) and are for disassembly // only. diff --git a/lib/Target/ARM/ARMMCCodeEmitter.cpp b/lib/Target/ARM/ARMMCCodeEmitter.cpp index 2e9d804894e..a9f8133af0e 100644 --- a/lib/Target/ARM/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/ARMMCCodeEmitter.cpp @@ -177,6 +177,8 @@ public: SmallVectorImpl &Fixups) const; unsigned getT2AddrModeImm8OpValue(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups) const; + unsigned getT2AddrModeImm8OffsetOpValue(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups) const; unsigned getT2AddrModeImm12OpValue(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups) const; @@ -671,8 +673,28 @@ getT2AddrModeImm8OpValue(const MCInst &MI, unsigned OpNum, // Even though the immediate is 8 bits long, we need 9 bits in order // to represent the (inverse of the) sign bit. Value <<= 9; - Value |= ((int32_t)MO2.getImm()) & 511; - Value ^= 256; // Invert the sign bit. + int32_t tmp = (int32_t)MO2.getImm(); + if (tmp < 0) + tmp = abs(tmp); + else + Value |= 256; // Set the ADD bit + Value |= tmp & 255; + return Value; +} + +unsigned ARMMCCodeEmitter:: +getT2AddrModeImm8OffsetOpValue(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups) const { + const MCOperand &MO1 = MI.getOperand(OpNum); + + // FIXME: Needs fixup support. + unsigned Value = 0; + int32_t tmp = (int32_t)MO1.getImm(); + if (tmp < 0) + tmp = abs(tmp); + else + Value |= 256; // Set the ADD bit + Value |= tmp & 255; return Value; } diff --git a/test/MC/ARM/thumb2.s b/test/MC/ARM/thumb2.s index 410011d1fd6..3d0c4ba1b37 100644 --- a/test/MC/ARM/thumb2.s +++ b/test/MC/ARM/thumb2.s @@ -115,3 +115,18 @@ @ CHECK: ldr.w r0, [r0, r1, lsl #2] @ encoding: [0x21,0x00,0x50,0xf8] ldr.w r0, [r0, r1, lsl #2] +@ CHECK: str r1, [r0, #16]! @ encoding: [0x10,0x1f,0x40,0xf8] + str r1, [r0, #16]! +@ CHECK: strh r1, [r0, #8]! @ encoding: [0x08,0x1f,0x20,0xf8] + strh r1, [r0, #8]! +@ CHECK: strh r2, [r0], #-4 @ encoding: [0x04,0x29,0x20,0xf8] + strh r2, [r0], #-4 +@ CHECK: str r2, [r0], #-4 @ encoding: [0x04,0x29,0x40,0xf8] + str r2, [r0], #-4 + +@ CHECK: ldr r2, [r0, #16]! @ encoding: [0x10,0x2f,0x50,0xf8] + ldr r2, [r0, #16]! +@ CHECK: ldr r2, [r0, #-64]! @ encoding: [0x40,0x2d,0x50,0xf8] + ldr r2, [r0, #-64]! +@ CHECK: ldrsb r2, [r0, #4]! @ encoding: [0x04,0x2f,0x10,0xf9] + ldrsb r2, [r0, #4]!