diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td index ba378ed5fed8..fecc6bfdef84 100644 --- a/llvm/lib/Target/ARM/ARMInstrFormats.td +++ b/llvm/lib/Target/ARM/ARMInstrFormats.td @@ -236,6 +236,10 @@ class InstTemplate<AddrMode am, int sz, IndexMode im, Domain D = d; bit isUnaryDataProc = 0; bit canXformTo16Bit = 0; + // The instruction is a 16-bit flag setting Thumb instruction. Used + // by the parser to determine whether to require the 'S' suffix on the + // mnemonic (when not in an IT block) or preclude it (when in an IT block). + bit thumbArithFlagSetting = 0; // If this is a pseudo instruction, mark it isCodeGenOnly. let isCodeGenOnly = !eq(!cast<string>(f), "Pseudo"); @@ -247,6 +251,7 @@ class InstTemplate<AddrMode am, int sz, IndexMode im, let TSFlags{13} = isUnaryDataProc; let TSFlags{14} = canXformTo16Bit; let TSFlags{17-15} = D.Value; + let TSFlags{18} = thumbArithFlagSetting; let Constraints = cstr; let Itinerary = itin; @@ -895,6 +900,7 @@ class Thumb1sI<dag oops, dag iops, AddrMode am, int sz, let InOperandList = !con(iops, (ins pred:$p)); let AsmString = !strconcat(opc, "${s}${p}", asm); let Pattern = pattern; + let thumbArithFlagSetting = 1; list<Predicate> Predicates = [IsThumb, IsThumb1Only]; } diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 1f298b3759c1..afc1e251c0d7 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -78,6 +78,9 @@ class ARMAsmParser : public MCTargetAsmParser { bool isThumbOne() const { return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2) == 0; } + bool isThumbTwo() const { + return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2); + } void SwitchMode() { unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); setAvailableFeatures(FB); @@ -146,6 +149,10 @@ class ARMAsmParser : public MCTargetAsmParser { const SmallVectorImpl<MCParsedAsmOperand*> &Ops); public: + enum ARMMatchResultTy { + Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY + }; + ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser) : MCTargetAsmParser(), STI(_STI), Parser(_Parser) { MCAsmParserExtension::Initialize(_Parser); @@ -160,6 +167,8 @@ public: SmallVectorImpl<MCParsedAsmOperand*> &Operands); bool ParseDirective(AsmToken DirectiveID); + unsigned checkTargetMatchPredicate(MCInst &Inst); + bool MatchAndEmitInstruction(SMLoc IDLoc, SmallVectorImpl<MCParsedAsmOperand*> &Operands, MCStreamer &Out); @@ -2975,6 +2984,44 @@ processInstruction(MCInst &Inst, } } +// FIXME: We would really prefer to have MCInstrInfo (the wrapper around +// the ARMInsts array) instead. Getting that here requires awkward +// API changes, though. Better way? +namespace llvm { +extern MCInstrDesc ARMInsts[]; +} +static MCInstrDesc &getInstDesc(unsigned Opcode) { + return ARMInsts[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()); + if (MCID.TSFlags & ARMII::ThumbArithFlagSetting) { + assert(MCID.hasOptionalDef() && + "optionally flag setting instruction missing optional def operand"); + assert(MCID.NumOperands == Inst.getNumOperands() && + "operand count mismatch!"); + // Find the optional-def operand (cc_out). + unsigned OpNo; + for (OpNo = 0; + !MCID.OpInfo[OpNo].isOptionalDef() && OpNo < MCID.NumOperands; + ++OpNo) + ; + // If we're parsing Thumb1, reject it completely. + if (isThumbOne() && Inst.getOperand(OpNo).getReg() != ARM::CPSR) + return Match_MnemonicFail; + // If we're parsing Thumb2, which form is legal depends on whether we're + // in an IT block. + // FIXME: We don't yet do IT blocks, so just always consider it to be + // that we aren't in one until we do. + if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR) + return Match_RequiresITBlock; + } + return Match_Success; +} + bool ARMAsmParser:: MatchAndEmitInstruction(SMLoc IDLoc, SmallVectorImpl<MCParsedAsmOperand*> &Operands, @@ -3013,9 +3060,11 @@ MatchAndEmitInstruction(SMLoc IDLoc, return Error(ErrorLoc, "invalid operand for instruction"); } case Match_MnemonicFail: - return Error(IDLoc, "unrecognized instruction mnemonic"); + return Error(IDLoc, "invalid instruction"); case Match_ConversionFail: return Error(IDLoc, "unable to convert operands to instruction"); + case Match_RequiresITBlock: + return Error(IDLoc, "instruction only valid inside IT block"); } llvm_unreachable("Implement any new match types added!"); diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h index 5fede1588b4f..0a8fb6a03b6c 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h @@ -384,6 +384,12 @@ namespace ARMII { // a 16-bit Thumb instruction if certain conditions are met. Xform16Bit = 1 << 14, + // ThumbArithFlagSetting - The instruction is a 16-bit flag setting Thumb + // instruction. Used by the parser to determine whether to require the 'S' + // suffix on the mnemonic (when not in an IT block) or preclude it (when + // in an IT block). + ThumbArithFlagSetting = 1 << 18, + //===------------------------------------------------------------------===// // Code domain. DomainShift = 15, diff --git a/llvm/test/MC/ARM/mode-switch.s b/llvm/test/MC/ARM/mode-switch.s index 4cc986a3e173..54e23f1b5c74 100644 --- a/llvm/test/MC/ARM/mode-switch.s +++ b/llvm/test/MC/ARM/mode-switch.s @@ -4,14 +4,14 @@ .code 16 -@ CHECK: add.w r0, r0, r1 @ encoding: [0x00,0xeb,0x01,0x00] +@ CHECK: add.w r0, r0, r1 @ encoding: [0x00,0xeb,0x01,0x00] add.w r0, r0, r1 .code 32 -@ CHECK: add r0, r0, r1 @ encoding: [0x01,0x00,0x80,0xe0] +@ CHECK: add r0, r0, r1 @ encoding: [0x01,0x00,0x80,0xe0] add r0, r0, r1 .code 16 -@ CHECK: add r0, r0, r1 @ encoding: [0x40,0x18] - - add r0, r0, r1 +@ CHECK: adds r0, r0, r1 @ encoding: [0x40,0x18] + + adds r0, r0, r1 diff --git a/llvm/test/MC/ARM/nop-thumb-padding.s b/llvm/test/MC/ARM/nop-thumb-padding.s index c7ef1fd59b5f..1e173f1a42d9 100644 --- a/llvm/test/MC/ARM/nop-thumb-padding.s +++ b/llvm/test/MC/ARM/nop-thumb-padding.s @@ -5,8 +5,8 @@ .thumb_func x .code 16 x: - add r0, r1, r2 + adds r0, r1, r2 .align 4 - add r0, r1, r2 + adds r0, r1, r2 @ CHECK: ('_section_data', '8818c046 c046c046 c046c046 c046c046 8818') diff --git a/llvm/test/MC/ARM/nop-thumb2-padding.s b/llvm/test/MC/ARM/nop-thumb2-padding.s index e1570c987fdf..a8aa3a1168ef 100644 --- a/llvm/test/MC/ARM/nop-thumb2-padding.s +++ b/llvm/test/MC/ARM/nop-thumb2-padding.s @@ -5,8 +5,8 @@ .thumb_func x .code 16 x: - add r0, r1, r2 + adds r0, r1, r2 .align 4 - add r0, r1, r2 + adds r0, r1, r2 @ CHECK: ('_section_data', '881800bf 00bf00bf 00bf00bf 00bf00bf 8818')