diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index 895ad7322d9..fc12ddc1d26 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -225,6 +225,8 @@ namespace { const { return 0; } unsigned getBitfieldInvertedMaskOpValue(const MachineInstr &MI, unsigned Op) const { return 0; } + unsigned getMsbOpValue(const MachineInstr &MI, + unsigned Op) const { return 0; } uint32_t getLdStmModeOpValue(const MachineInstr &MI, unsigned OpIdx) const {return 0; } uint32_t getLdStSORegOpValue(const MachineInstr &MI, unsigned OpIdx) diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 9909dd0d021..15949c0698f 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -443,6 +443,18 @@ def bf_inv_mask_imm : Operand, let PrintMethod = "printBitfieldInvMaskImmOperand"; } +/// lsb_pos_imm - position of the lsb bit, used by BFI4p and t2BFI4p +def lsb_pos_imm : Operand, PatLeaf<(imm), [{ + return isInt<5>(N->getSExtValue()); +}]>; + +/// width_imm - number of bits to be copied, used by BFI4p and t2BFI4p +def width_imm : Operand, PatLeaf<(imm), [{ + return N->getSExtValue() > 0 && N->getSExtValue() <= 32; +}] > { + let EncoderMethod = "getMsbOpValue"; +} + // Define ARM specific addressing modes. @@ -2463,6 +2475,25 @@ def BFI : I<(outs GPR:$Rd), (ins GPR:$src, GPR:$Rn, bf_inv_mask_imm:$imm), let Inst{3-0} = Rn; } +// GNU as only supports this form of bfi (w/ 4 arguments) +let isAsmParserOnly = 1 in +def BFI4p : I<(outs GPR:$Rd), (ins GPR:$src, GPR:$Rn, + lsb_pos_imm:$lsb, width_imm:$width), + AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, + "bfi", "\t$Rd, $Rn, $lsb, $width", "$src = $Rd", + []>, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<4> Rn; + bits<5> lsb; + bits<5> width; + let Inst{27-21} = 0b0111110; + let Inst{6-4} = 0b001; // Rn: Inst{3-0} != 15 + let Inst{15-12} = Rd; + let Inst{11-7} = lsb; + let Inst{20-16} = width; // Custom encoder => lsb+width-1 + let Inst{3-0} = Rn; +} + def MVNr : AsI1<0b1111, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMVNr, "mvn", "\t$Rd, $Rm", [(set GPR:$Rd, (not GPR:$Rm))]>, UnaryDP { diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index fe143af934a..1bd853005e1 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -2152,20 +2152,39 @@ def t2UBFX: T2TwoRegBitFI< } // A8.6.18 BFI - Bitfield insert (Encoding T1) -let Constraints = "$src = $Rd" in -def t2BFI : T2TwoRegBitFI<(outs rGPR:$Rd), - (ins rGPR:$src, rGPR:$Rn, bf_inv_mask_imm:$imm), - IIC_iBITi, "bfi", "\t$Rd, $Rn, $imm", - [(set rGPR:$Rd, (ARMbfi rGPR:$src, rGPR:$Rn, - bf_inv_mask_imm:$imm))]> { - let Inst{31-27} = 0b11110; - let Inst{25} = 1; - let Inst{24-20} = 0b10110; - let Inst{15} = 0; +let Constraints = "$src = $Rd" in { + def t2BFI : T2TwoRegBitFI<(outs rGPR:$Rd), + (ins rGPR:$src, rGPR:$Rn, bf_inv_mask_imm:$imm), + IIC_iBITi, "bfi", "\t$Rd, $Rn, $imm", + [(set rGPR:$Rd, (ARMbfi rGPR:$src, rGPR:$Rn, + bf_inv_mask_imm:$imm))]> { + let Inst{31-27} = 0b11110; + let Inst{25} = 1; + let Inst{24-20} = 0b10110; + let Inst{15} = 0; - bits<10> imm; - let msb{4-0} = imm{9-5}; - let lsb{4-0} = imm{4-0}; + bits<10> imm; + let msb{4-0} = imm{9-5}; + let lsb{4-0} = imm{4-0}; + } + + // GNU as only supports this form of bfi (w/ 4 arguments) + let isAsmParserOnly = 1 in + def t2BFI4p : T2TwoRegBitFI<(outs rGPR:$Rd), + (ins rGPR:$src, rGPR:$Rn, lsb_pos_imm:$lsbit, + width_imm:$width), + IIC_iBITi, "bfi", "\t$Rd, $Rn, $lsbit, $width", + []> { + let Inst{31-27} = 0b11110; + let Inst{25} = 1; + let Inst{24-20} = 0b10110; + let Inst{15} = 0; + + bits<5> lsbit; + bits<5> width; + let msb{4-0} = width; // Custom encoder => lsb+width-1 + let lsb{4-0} = lsbit; + } } defm t2ORN : T2I_bin_irs<0b0011, "orn", diff --git a/lib/Target/ARM/ARMMCCodeEmitter.cpp b/lib/Target/ARM/ARMMCCodeEmitter.cpp index 3aa40dbae70..a309122160f 100644 --- a/lib/Target/ARM/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/ARMMCCodeEmitter.cpp @@ -262,6 +262,9 @@ public: unsigned getBitfieldInvertedMaskOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl &Fixups) const; + unsigned getMsbOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups) const; + unsigned getRegisterListOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl &Fixups) const; unsigned getAddrMode6AddressOpValue(const MCInst &MI, unsigned Op, @@ -1066,6 +1069,17 @@ getBitfieldInvertedMaskOpValue(const MCInst &MI, unsigned Op, return lsb | (msb << 5); } +unsigned ARMMCCodeEmitter:: +getMsbOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups) const { + // MSB - 5 bits. + uint32_t lsb = MI.getOperand(Op-1).getImm(); + uint32_t width = MI.getOperand(Op).getImm(); + uint32_t msb = lsb+width-1; + assert (width != 0 && msb < 32 && "Illegal bit width!"); + return msb; +} + unsigned ARMMCCodeEmitter:: getRegisterListOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl &Fixups) const { diff --git a/test/MC/ARM/arm_instructions.s b/test/MC/ARM/arm_instructions.s index 43cad2f6524..002e5eb2627 100644 --- a/test/MC/ARM/arm_instructions.s +++ b/test/MC/ARM/arm_instructions.s @@ -124,3 +124,6 @@ @ may depend on flags. @ CHECK-FIXME:: mlas r1, r2, r3, r4 @ encoding: [0x92,0x43,0x31,0xe0] @ mlas r1,r2,r3,r4 + +@ CHECK: bfi r0, r0, #5, #7 @ encoding: [0x90,0x02,0xcb,0xe7] + bfi r0, r0, #5, #7 diff --git a/test/MC/ARM/thumb2.s b/test/MC/ARM/thumb2.s index ae88d4806ec..ceaf0a424f9 100644 --- a/test/MC/ARM/thumb2.s +++ b/test/MC/ARM/thumb2.s @@ -162,3 +162,6 @@ ldrsb.w r0, [r0] @ CHECK: ldrsh.w r0, [r0] @ encoding: [0x00,0x00,0xb0,0xf9] ldrsh.w r0, [r0] +@ CHECK: bfi r0, r0, #5, #7 @ encoding: [0x60,0xf3,0x4b,0x10] + bfi r0, r0, #5, #7 + diff --git a/utils/TableGen/ARMDecoderEmitter.cpp b/utils/TableGen/ARMDecoderEmitter.cpp index 0c88a316580..21af62050d7 100644 --- a/utils/TableGen/ARMDecoderEmitter.cpp +++ b/utils/TableGen/ARMDecoderEmitter.cpp @@ -1560,6 +1560,10 @@ ARMDEBackend::populateInstruction(const CodeGenInstruction &CGI, // which is a better design and less fragile than the name matchings. if (Bits.allInComplete()) return false; + // Ignore "asm parser only" instructions. + if (Def.getValueAsBit("isAsmParserOnly")) + return false; + if (TN == TARGET_ARM) { // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6? if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") && diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index c4391437474..353dbd6340c 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -566,6 +566,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("i32imm"); IMM("i32imm_hilo16"); IMM("bf_inv_mask_imm"); + IMM("lsb_pos_imm"); + IMM("width_imm"); IMM("jtblock_operand"); IMM("nohash_imm"); IMM("p_imm");