Index: lib/Target/ARM/ARMInstrInfo.td =================================================================== --- lib/Target/ARM/ARMInstrInfo.td +++ lib/Target/ARM/ARMInstrInfo.td @@ -2414,6 +2414,23 @@ let Inst{3-0} = addr{3-0}; // imm3_0/Rm let DecoderMethod = "DecodeAddrMode3Instruction"; } + + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def LDRD_PRE_PAIR : AI3ldstidx<0b1101, 0, 1, (outs GPRPair:$Rt, GPR:$Rn_wb), + (ins addrmode3_pre:$addr), + IndexModePre, LdMiscFrm, IIC_iLoad_d_ru, + "ldrd", "\t$Rt, $addr!", + "$addr.base = $Rn_wb", []> { + bits<14> addr; + let Inst{23} = addr{8}; // U bit + let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm + let Inst{19-16} = addr{12-9}; // Rn + let Inst{11-8} = addr{7-4}; // imm7_4/zero + let Inst{3-0} = addr{3-0}; // imm3_0/Rm + let DecoderMethod = "DecodeAddrMode3Instruction"; + } + def LDRD_POST: AI3ldstidx<0b1101, 0, 0, (outs GPR:$Rt, GPR:$Rt2, GPR:$Rn_wb), (ins addr_offset_none:$addr, am3offset:$offset), IndexModePost, LdMiscFrm, IIC_iLoad_d_ru, @@ -2428,6 +2445,24 @@ let Inst{3-0} = offset{3-0}; // imm3_0/Rm let DecoderMethod = "DecodeAddrMode3Instruction"; } + + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def LDRD_POST_PAIR: AI3ldstidx<0b1101, 0, 0, (outs GPRPair:$Rt, GPR:$Rn_wb), + (ins addr_offset_none:$addr, + am3offset:$offset), + IndexModePost, LdMiscFrm, IIC_iLoad_d_ru, + "ldrd", "\t$Rt, $addr, $offset", + "$addr.base = $Rn_wb", []> { + bits<10> offset; + bits<4> addr; + let Inst{23} = offset{8}; // U bit + let Inst{22} = offset{9}; // 1 == imm8, 0 == Rm + let Inst{19-16} = addr; + let Inst{11-8} = offset{7-4}; // imm7_4/zero + let Inst{3-0} = offset{3-0}; // imm3_0/Rm + let DecoderMethod = "DecodeAddrMode3Instruction"; + } } // hasExtraDefRegAllocReq = 1 } // mayLoad = 1, neverHasSideEffects = 1 @@ -2735,6 +2770,23 @@ let DecoderMethod = "DecodeAddrMode3Instruction"; } + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def STRD_PRE_PAIR : AI3ldstidx<0b1111, 0, 1, + (outs GPR:$Rn_wb), + (ins GPRPair:$Rt, addrmode3_pre:$addr), + IndexModePre, StMiscFrm, IIC_iStore_d_ru, + "strd", "\t$Rt, $addr!", + "$addr.base = $Rn_wb", []> { + bits<14> addr; + let Inst{23} = addr{8}; // U bit + let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm + let Inst{19-16} = addr{12-9}; // Rn + let Inst{11-8} = addr{7-4}; // imm7_4/zero + let Inst{3-0} = addr{3-0}; // imm3_0/Rm + let DecoderMethod = "DecodeAddrMode3Instruction"; + } + def STRD_POST: AI3ldstidx<0b1111, 0, 0, (outs GPR:$Rn_wb), (ins GPR:$Rt, GPR:$Rt2, addr_offset_none:$addr, am3offset:$offset), @@ -2750,6 +2802,25 @@ let Inst{3-0} = offset{3-0}; // imm3_0/Rm let DecoderMethod = "DecodeAddrMode3Instruction"; } + + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def STRD_POST_PAIR: AI3ldstidx<0b1111, 0, 0, + (outs GPR:$Rn_wb), + (ins GPRPair:$Rt, addr_offset_none:$addr, + am3offset:$offset), + IndexModePost, StMiscFrm, IIC_iStore_d_ru, + "strd", "\t$Rt, $addr, $offset", + "$addr.base = $Rn_wb", []> { + bits<10> offset; + bits<4> addr; + let Inst{23} = offset{8}; // U bit + let Inst{22} = offset{9}; // 1 == imm8, 0 == Rm + let Inst{19-16} = addr; + let Inst{11-8} = offset{7-4}; // imm7_4/zero + let Inst{3-0} = offset{3-0}; // imm3_0/Rm + let DecoderMethod = "DecodeAddrMode3Instruction"; + } } // mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 // STRT, STRBT, and STRHT Index: lib/Target/ARM/ARMInstrThumb2.td =================================================================== --- lib/Target/ARM/ARMInstrThumb2.td +++ lib/Target/ARM/ARMInstrThumb2.td @@ -285,6 +285,8 @@ let MIOperandInfo = (ops GPR:$Rn, rGPR:$Rm); } +def t2GPRPairOp : RegisterOperand; + //===----------------------------------------------------------------------===// // Multiclass helpers... // @@ -1277,6 +1279,12 @@ def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs rGPR:$Rt, rGPR:$Rt2), (ins t2addrmode_imm8s4:$addr), IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", "", []>; + + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def rLDRDi8_PAIR : T2Ii8s4<1, 0, 1, (outs t2GPRPairOp:$Rt), + (ins t2addrmode_imm8s4:$addr), + IIC_iLoad_d_i, "ldrd", "\t$Rt, $addr", "", []>; } // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 // zextload i1 -> zextload i8 @@ -1443,10 +1451,16 @@ rGPR, BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>; // Store doubleword -let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in +let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in { def t2STRDi8 : T2Ii8s4<1, 0, 0, (outs), (ins GPR:$Rt, GPR:$Rt2, t2addrmode_imm8s4:$addr), IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", "", []>; + let isAsmParserOnly = 1 in + def t2STRDi8_PAIR : T2Ii8s4<1, 0, 0, (outs), + (ins t2GPRPairOp:$Rt, + t2addrmode_imm8s4:$addr), + IIC_iStore_d_r, "strd", "\t$Rt, $addr", "", []>; +} // let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 // Indexed stores @@ -1559,11 +1573,30 @@ let DecoderMethod = "DecodeT2LDRDPreInstruction"; } + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def t2LDRD_PRE_PAIR : T2Ii8s4<1, 1, 1, (outs t2GPRPairOp:$Rt, GPR:$wb), + (ins t2addrmode_imm8s4_pre:$addr), + IIC_iLoad_d_ru, "ldrd", "\t$Rt, $addr!", + "$addr.base = $wb", []> { + let DecoderMethod = "DecodeT2LDRDPreInstruction"; + } + def t2LDRD_POST : T2Ii8s4post<0, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), (ins addr_offset_none:$addr, t2am_imm8s4_offset:$imm), IIC_iLoad_d_ru, "ldrd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>; + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def t2LDRD_POST_PAIR : T2Ii8s4post<0, 1, 1, + (outs t2GPRPairOp:$Rt, GPR:$wb), + (ins addr_offset_none:$addr, + t2am_imm8s4_offset:$imm), + IIC_iLoad_d_ru, "ldrd", + "\t$Rt, $addr$imm", + "$addr.base = $wb", []>; + def t2STRD_PRE : T2Ii8s4<1, 1, 0, (outs GPR:$wb), (ins rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4_pre:$addr), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr!", @@ -1571,12 +1604,33 @@ let DecoderMethod = "DecodeT2STRDPreInstruction"; } + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def t2STRD_PRE_PAIR : T2Ii8s4<1, 1, 0, (outs GPR:$wb), + (ins t2GPRPairOp:$Rt, + t2addrmode_imm8s4_pre:$addr), + IIC_iStore_d_ru, "strd", + "\t$Rt, $addr!", "$addr.base = $wb", []> { + let DecoderMethod = "DecodeT2STRDPreInstruction"; + } + def t2STRD_POST : T2Ii8s4post<0, 1, 0, (outs GPR:$wb), (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr, t2am_imm8s4_offset:$imm), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>; + // GNU Assembler extension (compatibility) + let isAsmParserOnly = 1 in + def t2STRD_POST_PAIR : T2Ii8s4post<0, 1, 0, + (outs GPR:$wb), + (ins t2GPRPairOp:$Rt, + addr_offset_none:$addr, + t2am_imm8s4_offset:$imm), + IIC_iStore_d_ru, "strd", + "\t$Rt, $addr$imm", + "$addr.base = $wb", []>; + class T2Istrrel bit54, dag oops, dag iops, string opc, string asm, list pattern> : Thumb2I(Operands[2]); - assert(Op->isReg() && "expected register argument"); + if ((Mnemonic == "ldrd" || Mnemonic == "strd")) { + ARMOperand *Op2 = static_cast(Operands[2]); + ARMOperand *Op3 = static_cast(Operands[3]); + if (Op3->isMem()) { + assert(Op2->isReg() && "expected register argument"); - unsigned SuperReg = MRI->getMatchingSuperReg( - Op->getReg(), ARM::gsub_0, &MRI->getRegClass(ARM::GPRPairRegClassID)); + unsigned SuperReg = MRI->getMatchingSuperReg( + Op2->getReg(), ARM::gsub_0, &MRI->getRegClass(ARM::GPRPairRegClassID)); - assert(SuperReg && "expected register pair"); + assert(SuperReg && "expected register pair"); - unsigned PairedReg = MRI->getSubReg(SuperReg, ARM::gsub_1); + if (isThumb() && Op2->getReg() == ARM::R12) + Error(Op2->getStartLoc(), "r12:SP pair is not allowed in Thumb mode"); - Operands.insert(Operands.begin() + 3, - ARMOperand::CreateReg(PairedReg, Op->getStartLoc(), - Op->getEndLoc())); + unsigned PairedReg = MRI->getSubReg(SuperReg, ARM::gsub_1); + + Operands.insert(Operands.begin() + 3, + ARMOperand::CreateReg(PairedReg, + Op2->getStartLoc(), + Op2->getEndLoc())); + } } // FIXME: As said above, this is all a pretty gross hack. This instruction Index: test/MC/ARM/ldrd-strd-gnu-arm-bad-imm.s =================================================================== --- /dev/null +++ test/MC/ARM/ldrd-strd-gnu-arm-bad-imm.s @@ -0,0 +1,9 @@ +// RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s +.text +// CHECK: error: instruction requires: thumb2 +// CHECK: ldrd r0, [r0, #512] + ldrd r0, [r0, #512] + +// CHECK: error: instruction requires: thumb2 +// CHECK: strd r0, [r0, #512] + strd r0, [r0, #512] \ No newline at end of file Index: test/MC/ARM/ldrd-strd-gnu-arm.s =================================================================== --- /dev/null +++ test/MC/ARM/ldrd-strd-gnu-arm.s @@ -0,0 +1,20 @@ +// PR18921 +// RUN: llvm-mc -triple=armv7-linux-gnueabi -show-encoding < %s | FileCheck %s +.text + +// CHECK-NOT: .code 16 + + +// CHECK: ldrd r0, r1, [r10, #32]! @ encoding: [0xd0,0x02,0xea,0xe1] +// CHECK: ldrd r0, r1, [r10], #32 @ encoding: [0xd0,0x02,0xca,0xe0] +// CHECK: ldrd r0, r1, [r10, #32] @ encoding: [0xd0,0x02,0xca,0xe1] + ldrd r0, [r10, #32]! + ldrd r0, [r10], #32 + ldrd r0, [r10, #32] + +// CHECK: strd r0, r1, [r10, #32]! @ encoding: [0xf0,0x02,0xea,0xe1] +// CHECK: strd r0, r1, [r10], #32 @ encoding: [0xf0,0x02,0xca,0xe0] +// CHECK: strd r0, r1, [r10, #32] @ encoding: [0xf0,0x02,0xca,0xe1] + strd r0, [r10, #32]! + strd r0, [r10], #32 + strd r0, [r10, #32] Index: test/MC/ARM/ldrd-strd-gnu-thumb-bad-regs.s =================================================================== --- /dev/null +++ test/MC/ARM/ldrd-strd-gnu-thumb-bad-regs.s @@ -0,0 +1,10 @@ +// RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s +.text +.thumb +// CHECK: error: r12:SP pair is not allowed in Thumb mode +// CHECK: ldrd r12, [r0, #512] + ldrd r12, [r0, #512] + +// CHECK: error: r12:SP pair is not allowed in Thumb mode +// CHECK: strd r12, [r0, #512] + strd r12, [r0, #512] \ No newline at end of file Index: test/MC/ARM/ldrd-strd-gnu-thumb.s =================================================================== --- /dev/null +++ test/MC/ARM/ldrd-strd-gnu-thumb.s @@ -0,0 +1,20 @@ +// PR18921 +// RUN: llvm-mc -triple=armv7-linux-gnueabi -show-encoding < %s | FileCheck %s +.text +.thumb + +// CHECK: .code 16 + +// CHECK: ldrd r0, r1, [r10, #512]! @ encoding: [0xfa,0xe9,0x80,0x01] +// CHECK: ldrd r0, r1, [r10], #512 @ encoding: [0xfa,0xe8,0x80,0x01] +// CHECK: ldrd r0, r1, [r10, #512] @ encoding: [0xda,0xe9,0x80,0x01] + ldrd r0, [r10, #512]! + ldrd r0, [r10], #512 + ldrd r0, [r10, #512] + +// CHECK: strd r0, r1, [r10, #512]! @ encoding: [0xea,0xe9,0x80,0x01] +// CHECK: strd r0, r1, [r10], #512 @ encoding: [0xea,0xe8,0x80,0x01] +// CHECK: strd r0, r1, [r10, #512] @ encoding: [0xca,0xe9,0x80,0x01] + strd r0, [r10, #512]! + strd r0, [r10], #512 + strd r0, [r10, #512]