From 194bd8982936c819a4b14335a4d08f28af8f3d42 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Tue, 16 Aug 2011 22:20:01 +0000 Subject: [PATCH] Thumb parsing diagnostics for low-reg requirements on ADD and MOV. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137779 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMBaseRegisterInfo.h | 13 ----------- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 27 +++++++++++++++++++++-- lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h | 13 +++++++++++ test/MC/ARM/thumb-diagnostics.s | 10 +++++++++ 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index e2d597f3cc0..f76075a42d7 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -33,19 +33,6 @@ namespace ARMRI { }; } -/// isARMLowRegister - Returns true if the register is low register r0-r7. -/// -static inline bool isARMLowRegister(unsigned Reg) { - using namespace ARM; - switch (Reg) { - case R0: case R1: case R2: case R3: - case R4: case R5: case R6: case R7: - return true; - default: - return false; - } -} - /// isARMArea1Register - Returns true if the register is a low register (r0-r7) /// or a stack/pc register that we should push/pop. static inline bool isARMArea1Register(unsigned Reg, bool isDarwin) { diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index dcd2a873f20..3db8a7d4d1e 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -81,6 +81,9 @@ class ARMAsmParser : public MCTargetAsmParser { bool isThumbTwo() const { return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2); } + bool hasV6Ops() const { + return STI.getFeatureBits() & ARM::HasV6Ops; + } void SwitchMode() { unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); setAvailableFeatures(FB); @@ -152,7 +155,9 @@ class ARMAsmParser : public MCTargetAsmParser { public: enum ARMMatchResultTy { - Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY + Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresV6, + Match_RequiresThumb2 }; ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser) @@ -2714,6 +2719,8 @@ getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet, Mnemonic == "rsb" || Mnemonic == "rsc" || Mnemonic == "orn" || Mnemonic == "sbc" || Mnemonic == "mla" || Mnemonic == "umull" || Mnemonic == "eor" || Mnemonic == "smlal" || + // FIXME: We need a better way. This really confused Thumb2 + // parsing for 'mov'. (Mnemonic == "mov" && !isThumbOne())) { CanAcceptCarrySet = true; } else { @@ -3022,7 +3029,8 @@ static MCInstrDesc &getInstDesc(unsigned Opcode) { unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) { // 16-bit thumb arithmetic instructions either require or preclude the 'S' // suffix depending on whether they're in an IT block or not. - MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + unsigned Opc = Inst.getOpcode(); + MCInstrDesc &MCID = getInstDesc(Opc); if (MCID.TSFlags & ARMII::ThumbArithFlagSetting) { assert(MCID.hasOptionalDef() && "optionally flag setting instruction missing optional def operand"); @@ -3044,6 +3052,17 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) { if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR) return Match_RequiresITBlock; } + // Some high-register supporting Thumb1 encodings only allow both registers + // to be from r0-r7 when in Thumb2. + else if (Opc == ARM::tADDhirr && isThumbOne() && + isARMLowRegister(Inst.getOperand(1).getReg()) && + isARMLowRegister(Inst.getOperand(2).getReg())) + return Match_RequiresThumb2; + // Others only require ARMv6 or later. + else if (Opc == ARM::tMOVr && isThumbOne() && + isARMLowRegister(Inst.getOperand(0).getReg()) && + isARMLowRegister(Inst.getOperand(1).getReg())) + return Match_RequiresV6; return Match_Success; } @@ -3090,6 +3109,10 @@ MatchAndEmitInstruction(SMLoc IDLoc, return Error(IDLoc, "unable to convert operands to instruction"); case Match_RequiresITBlock: return Error(IDLoc, "instruction only valid inside IT block"); + case Match_RequiresV6: + return Error(IDLoc, "instruction variant requires ARMv6 or later"); + case Match_RequiresThumb2: + return Error(IDLoc, "instruction variant requires Thumb2"); } llvm_unreachable("Implement any new match types added!"); diff --git a/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h index 0a8fb6a03b6..ec4b6ffcfe8 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h +++ b/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h @@ -188,6 +188,19 @@ inline static unsigned getARMRegisterNumbering(unsigned Reg) { } } +/// isARMLowRegister - Returns true if the register is a low register (r0-r7). +/// +static inline bool isARMLowRegister(unsigned Reg) { + using namespace ARM; + switch (Reg) { + case R0: case R1: case R2: case R3: + case R4: case R5: case R6: case R7: + return true; + default: + return false; + } +} + /// ARMII - This namespace holds all of the target specific flags that /// instruction info tracks. /// diff --git a/test/MC/ARM/thumb-diagnostics.s b/test/MC/ARM/thumb-diagnostics.s index c8528c58564..a08a94689b2 100644 --- a/test/MC/ARM/thumb-diagnostics.s +++ b/test/MC/ARM/thumb-diagnostics.s @@ -8,3 +8,13 @@ @ CHECK-ERRORS: error: invalid instruction @ CHECK-ERRORS: add r1, r2, r3 @ CHECK-ERRORS: ^ + +@ Instructions which require v6+ for both registers to be low regs. + add r2, r3 + mov r2, r3 +@ CHECK-ERRORS: error: instruction variant requires Thumb2 +@ CHECK-ERRORS: add r2, r3 +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: instruction variant requires ARMv6 or later +@ CHECK-ERRORS: mov r2, r3 +@ CHECK-ERRORS: ^ -- 2.34.1