diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 819b8987d44..dc19f4657c5 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -3131,10 +3131,10 @@ def BFC : I<(outs GPR:$Rd), (ins GPR:$src, bf_inv_mask_imm:$imm), } // A8.6.18 BFI - Bitfield insert (Encoding A1) -def BFI : I<(outs GPR:$Rd), (ins GPR:$src, GPR:$Rn, bf_inv_mask_imm:$imm), +def BFI : I<(outs GPRnopc:$Rd), (ins GPRnopc:$src, GPR:$Rn, bf_inv_mask_imm:$imm), AddrMode1, 4, IndexModeNone, DPFrm, IIC_iUNAsi, "bfi", "\t$Rd, $Rn, $imm", "$src = $Rd", - [(set GPR:$Rd, (ARMbfi GPR:$src, GPR:$Rn, + [(set GPRnopc:$Rd, (ARMbfi GPRnopc:$src, GPR:$Rn, bf_inv_mask_imm:$imm))]>, Requires<[IsARM, HasV6T2]> { bits<4> Rd; @@ -3150,7 +3150,7 @@ def BFI : I<(outs GPR:$Rd), (ins GPR:$src, GPR:$Rn, bf_inv_mask_imm:$imm), // 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, +def BFI4p : I<(outs GPRnopc:$Rd), (ins GPRnopc:$src, GPR:$Rn, lsb_pos_imm:$lsb, width_imm:$width), AddrMode1, 4, IndexModeNone, DPFrm, IIC_iUNAsi, "bfi", "\t$Rd, $Rn, $lsb, $width", "$src = $Rd", diff --git a/lib/Target/ARM/ARMRegisterInfo.td b/lib/Target/ARM/ARMRegisterInfo.td index 98357d48f31..cf3d66873b4 100644 --- a/lib/Target/ARM/ARMRegisterInfo.td +++ b/lib/Target/ARM/ARMRegisterInfo.td @@ -215,6 +215,16 @@ def GPR : RegisterClass<"ARM", [i32], 32, (add (sequence "R%u", 0, 12), }]; } +// GPRs without the PC. Some ARM instructions do not allow the PC in +// certain operand slots, particularly as the destination. Primarily +// useful for disassembly. +def GPRnopc : RegisterClass<"ARM", [i32], 32, (sub GPR, PC)> { + let AltOrders = [(add LR, GPRnopc), (trunc GPRnopc, 8)]; + let AltOrderSelect = [{ + return 1 + MF.getTarget().getSubtarget().isThumb1Only(); + }]; +} + // restricted GPR register class. Many Thumb2 instructions allow the full // register range for operands, but have undefined behaviours when PC // or SP (R13 or R15) are used. The ARM ISA refers to these operands diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 307ce885369..d7b88560d71 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -28,6 +28,8 @@ // Definitions are further down. static bool DecodeGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); +static bool DecodeGPRnopcRegisterClass(llvm::MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder); static bool DecodetGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); static bool DecodetcGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo, @@ -471,6 +473,12 @@ static bool DecodeGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo, return true; } +static bool DecodeGPRnopcRegisterClass(llvm::MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) { + if (RegNo == 15) return false; + return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder); +} + static bool DecodetGPRRegisterClass(llvm::MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { if (RegNo > 7) diff --git a/test/MC/Disassembler/ARM/invalid-BFI-arm.txt b/test/MC/Disassembler/ARM/invalid-BFI-arm.txt index e108d3872f7..a0d5944a053 100644 --- a/test/MC/Disassembler/ARM/invalid-BFI-arm.txt +++ b/test/MC/Disassembler/ARM/invalid-BFI-arm.txt @@ -1,5 +1,4 @@ # RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding} -# XFAIL: * # Opcode=60 Name=BFI Format=ARM_FORMAT_DPFRM(4) # 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index 59a765d5ba0..37fb6adf50a 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -555,6 +555,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, const std::string &name) { REG("GPR"); REG("rGPR"); + REG("GPRnopc"); REG("tcGPR"); REG("cc_out"); REG("s_cc_out");