From 89df996ab20609676ecc8823f58414d598b09b46 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Fri, 26 Aug 2011 21:43:41 +0000 Subject: [PATCH] Thumb2 assembler parsing and encoding of IT instruction. This handles only the handling of the IT instruction itself, not the processing and validation of the instructions in the IT block. That's next, and will include encoding tests for IT itself. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@138665 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrThumb2.td | 7 ++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 141 ++++++++++++++++++++-- 2 files changed, 136 insertions(+), 12 deletions(-) diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 07f79815980..3c193ac80fb 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -12,14 +12,21 @@ //===----------------------------------------------------------------------===// // IT block predicate field +def it_pred_asmoperand : AsmOperandClass { + let Name = "ITCondCode"; + let ParserMethod = "parseITCondCode"; +} def it_pred : Operand { let PrintMethod = "printMandatoryPredicateOperand"; + let ParserMatchClass = it_pred_asmoperand; let DecoderMethod = "DecodeITCond"; } // IT block condition mask +def it_mask_asmoperand : AsmOperandClass { let Name = "ITMask"; } def it_mask : Operand { let PrintMethod = "printThumbITMask"; + let ParserMatchClass = it_mask_asmoperand; let DecoderMethod = "DecodeITMask"; } diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index a1054250c4c..33ebaa0b2fb 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -22,6 +22,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" @@ -69,7 +70,8 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectiveSyntax(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, - bool &CarrySetting, unsigned &ProcessorIMod); + bool &CarrySetting, unsigned &ProcessorIMod, + StringRef &ITMask); void getMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet, bool &CanAcceptPredicationCode); @@ -99,6 +101,7 @@ class ARMAsmParser : public MCTargetAsmParser { /// } + OperandMatchResultTy parseITCondCode(SmallVectorImpl&); OperandMatchResultTy parseCoprocNumOperand( SmallVectorImpl&); OperandMatchResultTy parseCoprocRegOperand( @@ -196,6 +199,7 @@ class ARMOperand : public MCParsedAsmOperand { enum KindTy { CondCode, CCOut, + ITCondMask, CoprocNum, CoprocReg, Immediate, @@ -224,14 +228,18 @@ class ARMOperand : public MCParsedAsmOperand { ARMCC::CondCodes Val; } CC; - struct { - ARM_MB::MemBOpt Val; - } MBOpt; - struct { unsigned Val; } Cop; + struct { + unsigned Mask:4; + } ITMask; + + struct { + ARM_MB::MemBOpt Val; + } MBOpt; + struct { ARM_PROC::IFlags Val; } IFlags; @@ -306,6 +314,9 @@ public: case CondCode: CC = o.CC; break; + case ITCondMask: + ITMask = o.ITMask; + break; case Token: Tok = o.Tok; break; @@ -413,6 +424,8 @@ public: bool isCoprocReg() const { return Kind == CoprocReg; } bool isCondCode() const { return Kind == CondCode; } bool isCCOut() const { return Kind == CCOut; } + bool isITMask() const { return Kind == ITCondMask; } + bool isITCondCode() const { return Kind == CondCode; } bool isImm() const { return Kind == Immediate; } bool isImm0_1020s4() const { if (Kind != Immediate) @@ -732,6 +745,16 @@ public: Inst.addOperand(MCOperand::CreateImm(getCoproc())); } + void addITMaskOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(ITMask.Mask)); + } + + void addITCondCodeOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode()))); + } + void addCoprocRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateImm(getCoproc())); @@ -1116,6 +1139,14 @@ public: virtual void print(raw_ostream &OS) const; + static ARMOperand *CreateITMask(unsigned Mask, SMLoc S) { + ARMOperand *Op = new ARMOperand(ITCondMask); + Op->ITMask.Mask = Mask; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) { ARMOperand *Op = new ARMOperand(CondCode); Op->CC.Val = CC; @@ -1319,6 +1350,14 @@ void ARMOperand::print(raw_ostream &OS) const { case CCOut: OS << ""; break; + case ITCondMask: { + static char MaskStr[][6] = { "()", "(t)", "(e)", "(tt)", "(et)", "(te)", + "(ee)", "(ttt)", "(ett)", "(tet)", "(eet)", "(tte)", "(ete)", + "(tee)", "(eee)" }; + assert((ITMask.Mask & 0xf) == ITMask.Mask); + OS << ""; + break; + } case CoprocNum: OS << ""; break; @@ -1607,6 +1646,41 @@ static int MatchCoprocessorOperandName(StringRef Name, char CoprocOp) { return -1; } +/// parseITCondCode - Try to parse a condition code for an IT instruction. +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseITCondCode(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + const AsmToken &Tok = Parser.getTok(); + if (!Tok.is(AsmToken::Identifier)) + return MatchOperand_NoMatch; + unsigned CC = StringSwitch(Tok.getString()) + .Case("eq", ARMCC::EQ) + .Case("ne", ARMCC::NE) + .Case("hs", ARMCC::HS) + .Case("cs", ARMCC::HS) + .Case("lo", ARMCC::LO) + .Case("cc", ARMCC::LO) + .Case("mi", ARMCC::MI) + .Case("pl", ARMCC::PL) + .Case("vs", ARMCC::VS) + .Case("vc", ARMCC::VC) + .Case("hi", ARMCC::HI) + .Case("ls", ARMCC::LS) + .Case("ge", ARMCC::GE) + .Case("lt", ARMCC::LT) + .Case("gt", ARMCC::GT) + .Case("le", ARMCC::LE) + .Case("al", ARMCC::AL) + .Default(~0U); + if (CC == ~0U) + return MatchOperand_NoMatch; + Parser.Lex(); // Eat the token. + + Operands.push_back(ARMOperand::CreateCondCode(ARMCC::CondCodes(CC), S)); + + return MatchOperand_Success; +} + /// parseCoprocNumOperand - Try to parse an coprocessor number operand. The /// token must be an Identifier when called, and if it is a coprocessor /// number, the token is eaten and the operand is added to the operand list. @@ -2782,10 +2856,12 @@ ARMAsmParser::applyPrefixToExpr(const MCExpr *E, /// setting letters to form a canonical mnemonic and flags. // // FIXME: Would be nice to autogen this. +// FIXME: This is a bit of a maze of special cases. StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, - unsigned &ProcessorIMod) { + unsigned &ProcessorIMod, + StringRef &ITMask) { PredicationCode = ARMCC::AL; CarrySetting = false; ProcessorIMod = 0; @@ -2862,6 +2938,12 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, } } + // The "it" instruction has the condition mask on the end of the mnemonic. + if (Mnemonic.startswith("it")) { + ITMask = Mnemonic.slice(2, Mnemonic.size()); + Mnemonic = Mnemonic.slice(0, 2); + } + return Mnemonic; } @@ -2968,8 +3050,9 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, unsigned PredicationCode; unsigned ProcessorIMod; bool CarrySetting; + StringRef ITMask; Mnemonic = splitMnemonic(Mnemonic, PredicationCode, CarrySetting, - ProcessorIMod); + ProcessorIMod, ITMask); // In Thumb1, only the branch (B) instruction can be predicated. if (isThumbOne() && PredicationCode != ARMCC::AL && Mnemonic != "b") { @@ -2979,6 +3062,26 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Operands.push_back(ARMOperand::CreateToken(Mnemonic, NameLoc)); + // Handle the IT instruction ITMask. Convert it to a bitmask. This + // is the mask as it will be for the IT encoding if the conditional + // encoding has a '1' as it's bit0 (i.e. 't' ==> '1'). In the case + // where the conditional bit0 is zero, the instruction post-processing + // will adjust the mask accordingly. + if (Mnemonic == "it") { + unsigned Mask = 8; + for (unsigned i = ITMask.size(); i != 0; --i) { + char pos = ITMask[i - 1]; + if (pos != 't' && pos != 'e') { + Parser.EatToEndOfStatement(); + return Error(NameLoc, "illegal IT instruction mask '" + ITMask + "'"); + } + Mask >>= 1; + if (ITMask[i - 1] == 't') + Mask |= 8; + } + Operands.push_back(ARMOperand::CreateITMask(Mask, NameLoc)); + } + // FIXME: This is all a pretty gross hack. We should automatically handle // optional operands like this via tblgen. @@ -3027,11 +3130,6 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Operands.push_back(ARMOperand::CreateImm( MCConstantExpr::Create(ProcessorIMod, getContext()), NameLoc, NameLoc)); - } else { - // This mnemonic can't ever accept a imod, but the user wrote - // one (or misspelled another mnemonic). - - // FIXME: Issue a nice error. } // Add the remaining tokens in the mnemonic. @@ -3289,6 +3387,25 @@ processInstruction(MCInst &Inst, if (Inst.getOperand(1).getImm() == ARMCC::AL) Inst.setOpcode(ARM::tB); break; + case ARM::t2IT: { + // The mask bits for all but the first condition are represented as + // the low bit of the condition code value implies 't'. We currently + // always have 1 implies 't', so XOR toggle the bits if the low bit + // of the condition code is zero. The encoding also expects the low + // bit of the condition to be encoded as bit 4 of the mask operand, + // so mask that in if needed + MCOperand &MO = Inst.getOperand(1); + unsigned Mask = MO.getImm(); + if ((Inst.getOperand(0).getImm() & 1) == 0) { + unsigned TZ = CountTrailingZeros_32(Mask); + assert(Mask && TZ <= 3 && "illegal IT mask value!"); + for (unsigned i = 3; i != TZ; --i) + Mask ^= 1 << i; + } else + Mask |= 0x10; + MO.setImm(Mask); + break; + } } } -- 2.34.1