X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=a34fdb66cf256a5fd6b6e269a474476c7199f031;hb=0c9f250d54ed59108fffe5ce2f7df7bc8448915c;hp=11015d887398aeeb0fa55b3d4d5843e075db1730;hpb=6aa49435994c33257b7588cac24671785d17fa6e;p=oota-llvm.git diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 11015d88739..a34fdb66cf2 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -9,6 +9,8 @@ #include "ARM.h" #include "ARMAddressingModes.h" +#include "ARMMCExpr.h" +#include "ARMBaseRegisterInfo.h" #include "ARMSubtarget.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" @@ -22,11 +24,12 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" using namespace llvm; -// The shift types for register controlled shifts in arm memory addressing +/// Shift types used for register controlled shifts in ARM memory addressing. enum ShiftType { Lsl, Lsr, @@ -50,10 +53,15 @@ class ARMAsmParser : public TargetAsmParser { bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } int TryParseRegister(); + bool TryParseMCRName(SmallVectorImpl&); bool TryParseRegisterWithWriteBack(SmallVectorImpl &); bool ParseRegisterList(SmallVectorImpl &); bool ParseMemory(SmallVectorImpl &); - bool ParseOperand(SmallVectorImpl &); + bool ParseOperand(SmallVectorImpl &, bool isMCR); + bool ParsePrefix(ARMMCExpr::VariantKind &RefKind); + const MCExpr *ApplyPrefixToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant); + bool ParseMemoryOffsetReg(bool &Negative, bool &OffsetRegShifted, @@ -134,7 +142,7 @@ class ARMOperand : public MCParsedAsmOperand { const MCExpr *Val; } Imm; - // This is for all forms of ARM address expressions + /// Combined record for all forms of ARM address expressions. struct { unsigned BaseRegNum; unsigned OffsetRegNum; // used when OffsetIsReg is true @@ -236,11 +244,16 @@ public: int64_t Value = CE->getValue(); return ((Value & 0x3) == 0 && Value <= 1020 && Value >= -1020); } - bool isMemModeThumb() const { + bool isMemModeRegThumb() const { + if (!isMemory() || (!Mem.OffsetIsReg && !Mem.Offset) || Mem.Writeback) + return false; + return !Mem.Offset || !isa(Mem.Offset); + } + bool isMemModeImmThumb() const { if (!isMemory() || (!Mem.OffsetIsReg && !Mem.Offset) || Mem.Writeback) return false; - if (!Mem.Offset) return true; + if (!Mem.Offset) return false; const MCConstantExpr *CE = dyn_cast(Mem.Offset); if (!CE) return false; @@ -324,19 +337,18 @@ public: } } - void addMemModeThumbOperands(MCInst &Inst, unsigned N) const { - assert(N == 3 && isMemModeThumb() && "Invalid number of operands!"); + void addMemModeRegThumbOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && isMemModeRegThumb() && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + } - if (Mem.Offset) { - const MCConstantExpr *CE = dyn_cast(Mem.Offset); - assert(CE && "Non-constant mode offset operand!"); - Inst.addOperand(MCOperand::CreateImm(CE->getValue())); - Inst.addOperand(MCOperand::CreateReg(0)); - } else { - Inst.addOperand(MCOperand::CreateImm(0)); - Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); - } + void addMemModeImmThumbOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && isMemModeImmThumb() && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + const MCConstantExpr *CE = dyn_cast(Mem.Offset); + assert(CE && "Non-constant mode offset operand!"); + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); } virtual void dump(raw_ostream &OS) const; @@ -432,7 +444,7 @@ public: void ARMOperand::dump(raw_ostream &OS) const { switch (Kind) { case CondCode: - OS << ARMCondCodeToString(getCondCode()); + OS << ""; break; case CCOut: OS << ""; @@ -484,9 +496,19 @@ int ARMAsmParser::TryParseRegister() { // FIXME: Validate register for the current architecture; we have to do // validation later, so maybe there is no need for this here. - unsigned RegNum = MatchRegisterName(Tok.getString()); - if (RegNum == 0) - return -1; + std::string upperCase = Tok.getString().str(); + std::string lowerCase = LowercaseString(upperCase); + unsigned RegNum = MatchRegisterName(lowerCase); + if (!RegNum) { + RegNum = StringSwitch(lowerCase) + .Case("r13", ARM::SP) + .Case("r14", ARM::LR) + .Case("r15", ARM::PC) + .Case("ip", ARM::R12) + .Default(0); + } + if (!RegNum) return -1; + Parser.Lex(); // Eat identifier token. return RegNum; } @@ -517,6 +539,67 @@ TryParseRegisterWithWriteBack(SmallVectorImpl &Operands) { return false; } +static int MatchMCRName(StringRef Name) { + // Use the same layout as the tablegen'erated register name matcher. Ugly, + // but efficient. + switch (Name.size()) { + default: break; + case 2: + if (Name[0] != 'p' && Name[0] != 'c') + return -1; + switch (Name[1]) { + default: return -1; + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + break; + case 3: + if ((Name[0] != 'p' && Name[0] != 'c') || Name[1] != '1') + return -1; + switch (Name[2]) { + default: return -1; + case '0': return 10; + case '1': return 11; + case '2': return 12; + case '3': return 13; + case '4': return 14; + case '5': return 15; + } + break; + } + + llvm_unreachable("Unhandled coprocessor operand string!"); + return -1; +} + +/// TryParseMCRName - Try to parse an MCR/MRC symbolic operand +/// name. The token must be an Identifier when called, and if it is a MCR +/// operand name, the token is eaten and the operand is added to the +/// operand list. +bool ARMAsmParser:: +TryParseMCRName(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + const AsmToken &Tok = Parser.getTok(); + assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); + + int Num = MatchMCRName(Tok.getString()); + if (Num == -1) + return true; + + Parser.Lex(); // Eat identifier token. + Operands.push_back(ARMOperand::CreateImm( + MCConstantExpr::Create(Num, getContext()), S, Parser.getTok().getLoc())); + return false; +} + /// Parse a register list, return it if successful else return null. The first /// token must be a '{' when called. bool ARMAsmParser:: @@ -574,15 +657,15 @@ ParseRegisterList(SmallVectorImpl &Operands) { SmallVectorImpl >::const_iterator RI = Registers.begin(), RE = Registers.end(); - DenseMap RegMap; - RegMap[RI->first] = true; - - unsigned HighRegNum = RI->first; + unsigned HighRegNum = getARMRegisterNumbering(RI->first); bool EmittedWarning = false; + DenseMap RegMap; + RegMap[HighRegNum] = true; + for (++RI; RI != RE; ++RI) { const std::pair &RegInfo = *RI; - unsigned Reg = RegInfo.first; + unsigned Reg = getARMRegisterNumbering(RegInfo.first); if (RegMap[Reg]) { Error(RegInfo.second, "register duplicated in register list"); @@ -824,16 +907,23 @@ bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount, /// Parse a arm instruction operand. For now this parses the operand regardless /// of the mnemonic. -bool ARMAsmParser::ParseOperand(SmallVectorImpl &Operands){ +bool ARMAsmParser::ParseOperand(SmallVectorImpl &Operands, + bool isMCR){ SMLoc S, E; switch (getLexer().getKind()) { default: Error(Parser.getTok().getLoc(), "unexpected token in operand"); return true; - case AsmToken::Identifier: { + case AsmToken::Identifier: if (!TryParseRegisterWithWriteBack(Operands)) return false; + if (isMCR && !TryParseMCRName(Operands)) + return false; + // Fall though for the Identifier case that is not a register or a + // special name. + case AsmToken::Integer: // things like 1f and 2b as a branch targets + case AsmToken::Dot: { // . as a branch target // This was not a register so parse other operands that start with an // identifier (like labels) as expressions and create them as immediates. const MCExpr *IdVal; @@ -859,27 +949,130 @@ bool ARMAsmParser::ParseOperand(SmallVectorImpl &Operands){ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(ARMOperand::CreateImm(ImmVal, S, E)); return false; + case AsmToken::Colon: { + // ":lower16:" and ":upper16:" expression prefixes + // FIXME: Check it's an expression prefix, + // e.g. (FOO - :lower16:BAR) isn't legal. + ARMMCExpr::VariantKind RefKind; + if (ParsePrefix(RefKind)) + return true; + + const MCExpr *SubExprVal; + if (getParser().ParseExpression(SubExprVal)) + return true; + + const MCExpr *ExprVal = ARMMCExpr::Create(RefKind, SubExprVal, + getContext()); + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(ARMOperand::CreateImm(ExprVal, S, E)); + return false; + } } } -/// Parse an arm instruction mnemonic followed by its operands. -bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, - SmallVectorImpl &Operands) { - // Create the leading tokens for the mnemonic, split by '.' characters. - size_t Start = 0, Next = Name.find('.'); - StringRef Head = Name.slice(Start, Next); +// ParsePrefix - Parse ARM 16-bit relocations expression prefix, i.e. +// :lower16: and :upper16:. +bool ARMAsmParser::ParsePrefix(ARMMCExpr::VariantKind &RefKind) { + RefKind = ARMMCExpr::VK_ARM_None; + + // :lower16: and :upper16: modifiers + assert(getLexer().is(AsmToken::Colon) && "expected a :"); + Parser.Lex(); // Eat ':' + + if (getLexer().isNot(AsmToken::Identifier)) { + Error(Parser.getTok().getLoc(), "expected prefix identifier in operand"); + return true; + } + + StringRef IDVal = Parser.getTok().getIdentifier(); + if (IDVal == "lower16") { + RefKind = ARMMCExpr::VK_ARM_LO16; + } else if (IDVal == "upper16") { + RefKind = ARMMCExpr::VK_ARM_HI16; + } else { + Error(Parser.getTok().getLoc(), "unexpected prefix in operand"); + return true; + } + Parser.Lex(); + + if (getLexer().isNot(AsmToken::Colon)) { + Error(Parser.getTok().getLoc(), "unexpected token after prefix"); + return true; + } + Parser.Lex(); // Eat the last ':' + return false; +} + +const MCExpr * +ARMAsmParser::ApplyPrefixToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant) { + // Recurse over the given expression, rebuilding it to apply the given variant + // to the leftmost symbol. + if (Variant == MCSymbolRefExpr::VK_None) + return E; + + switch (E->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle target expr yet"); + case MCExpr::Constant: + llvm_unreachable("Can't handle lower16/upper16 of constant yet"); + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr *SRE = cast(E); + + if (SRE->getKind() != MCSymbolRefExpr::VK_None) + return 0; + + return MCSymbolRefExpr::Create(&SRE->getSymbol(), Variant, getContext()); + } + + case MCExpr::Unary: + llvm_unreachable("Can't handle unary expressions yet"); - // Determine the predicate, if any. + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(E); + const MCExpr *LHS = ApplyPrefixToExpr(BE->getLHS(), Variant); + const MCExpr *RHS = BE->getRHS(); + if (!LHS) + return 0; + + return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext()); + } + } + + assert(0 && "Invalid expression kind!"); + return 0; +} + +/// \brief Given a mnemonic, split out possible predication code and carry +/// setting letters to form a canonical mnemonic and flags. +// +// FIXME: Would be nice to autogen this. +static StringRef SplitMnemonicAndCC(StringRef Mnemonic, + unsigned &PredicationCode, + bool &CarrySetting) { + PredicationCode = ARMCC::AL; + CarrySetting = false; + + // Ignore some mnemonics we know aren't predicated forms. // - // FIXME: We need a way to check whether a prefix supports predication, - // otherwise we will end up with an ambiguity for instructions that happen to - // end with a predicate name. - // FIXME: Likewise, some arithmetic instructions have an 's' prefix which - // indicates to update the condition codes. Those instructions have an - // additional immediate operand which encodes the prefix as reg0 or CPSR. - // Just checking for a suffix of 's' definitely creates ambiguities; e.g, - // the SMMLS instruction. - unsigned CC = StringSwitch(Head.substr(Head.size()-2)) + // FIXME: Would be nice to autogen this. + if (Mnemonic == "teq" || Mnemonic == "vceq" || + Mnemonic == "movs" || + Mnemonic == "svc" || + (Mnemonic == "mls" || Mnemonic == "smmls" || Mnemonic == "vcls" || + Mnemonic == "vmls" || Mnemonic == "vnmls") || + Mnemonic == "vacge" || Mnemonic == "vcge" || + Mnemonic == "vclt" || + Mnemonic == "vacgt" || Mnemonic == "vcgt" || + Mnemonic == "vcle" || + (Mnemonic == "smlal" || Mnemonic == "umaal" || Mnemonic == "umlal" || + Mnemonic == "vabal" || Mnemonic == "vmlal" || Mnemonic == "vpadal" || + Mnemonic == "vqdmlal")) + return Mnemonic; + + // First, split out any predication code. + unsigned CC = StringSwitch(Mnemonic.substr(Mnemonic.size()-2)) .Case("eq", ARMCC::EQ) .Case("ne", ARMCC::NE) .Case("hs", ARMCC::HS) @@ -896,20 +1089,105 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, .Case("le", ARMCC::LE) .Case("al", ARMCC::AL) .Default(~0U); + if (CC != ~0U) { + Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 2); + PredicationCode = CC; + } + + // Next, determine if we have a carry setting bit. We explicitly ignore all + // the instructions we know end in 's'. + if (Mnemonic.endswith("s") && + !(Mnemonic == "asrs" || Mnemonic == "cps" || Mnemonic == "mls" || + Mnemonic == "movs" || Mnemonic == "mrs" || Mnemonic == "smmls" || + Mnemonic == "vabs" || Mnemonic == "vcls" || Mnemonic == "vmls" || + Mnemonic == "vmrs" || Mnemonic == "vnmls" || Mnemonic == "vqabs" || + Mnemonic == "vrecps" || Mnemonic == "vrsqrts")) { + Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 1); + CarrySetting = true; + } + + return Mnemonic; +} + +/// \brief Given a canonical mnemonic, determine if the instruction ever allows +/// inclusion of carry set or predication code operands. +// +// FIXME: It would be nice to autogen this. +static void GetMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet, + bool &CanAcceptPredicationCode) { + if (Mnemonic == "and" || Mnemonic == "lsl" || Mnemonic == "lsr" || + Mnemonic == "rrx" || Mnemonic == "ror" || Mnemonic == "sub" || + Mnemonic == "smull" || Mnemonic == "add" || Mnemonic == "adc" || + Mnemonic == "mul" || Mnemonic == "bic" || Mnemonic == "asr" || + Mnemonic == "umlal" || Mnemonic == "orr" || Mnemonic == "mov" || + Mnemonic == "rsb" || Mnemonic == "rsc" || Mnemonic == "orn" || + Mnemonic == "sbc" || Mnemonic == "mla" || Mnemonic == "umull" || + Mnemonic == "eor" || Mnemonic == "smlal" || Mnemonic == "mvn") { + CanAcceptCarrySet = true; + } else { + CanAcceptCarrySet = false; + } - if (CC == ~0U || - (CC == ARMCC::LS && (Head == "vmls" || Head == "vnmls"))) { - CC = ARMCC::AL; + if (Mnemonic == "cbnz" || Mnemonic == "setend" || Mnemonic == "dmb" || + Mnemonic == "cps" || Mnemonic == "mcr2" || Mnemonic == "it" || + Mnemonic == "mcrr2" || Mnemonic == "cbz" || Mnemonic == "cdp2" || + Mnemonic == "trap" || Mnemonic == "mrc2" || Mnemonic == "mrrc2" || + Mnemonic == "dsb" || Mnemonic == "movs") { + CanAcceptPredicationCode = false; } else { - Head = Head.slice(0, Head.size() - 2); + CanAcceptPredicationCode = true; } +} + +/// Parse an arm instruction mnemonic followed by its operands. +bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, + SmallVectorImpl &Operands) { + // Create the leading tokens for the mnemonic, split by '.' characters. + size_t Start = 0, Next = Name.find('.'); + StringRef Head = Name.slice(Start, Next); + + // Split out the predication code and carry setting flag from the mnemonic. + unsigned PredicationCode; + bool CarrySetting; + Head = SplitMnemonicAndCC(Head, PredicationCode, CarrySetting); Operands.push_back(ARMOperand::CreateToken(Head, NameLoc)); - if (Head != "trap") - // FIXME: Should only add this operand for predicated instructions - Operands.push_back(ARMOperand::CreateCondCode(ARMCC::CondCodes(CC), - NameLoc)); + // Next, add the CCOut and ConditionCode operands, if needed. + // + // For mnemonics which can ever incorporate a carry setting bit or predication + // code, our matching model involves us always generating CCOut and + // ConditionCode operands to match the mnemonic "as written" and then we let + // the matcher deal with finding the right instruction or generating an + // appropriate error. + bool CanAcceptCarrySet, CanAcceptPredicationCode; + GetMnemonicAcceptInfo(Head, CanAcceptCarrySet, CanAcceptPredicationCode); + + // Add the carry setting operand, if necessary. + // + // FIXME: It would be awesome if we could somehow invent a location such that + // match errors on this operand would print a nice diagnostic about how the + // 's' character in the mnemonic resulted in a CCOut operand. + if (CanAcceptCarrySet) { + Operands.push_back(ARMOperand::CreateCCOut(CarrySetting ? ARM::CPSR : 0, + NameLoc)); + } else { + // This mnemonic can't ever accept a carry set, but the user wrote one (or + // misspelled another mnemonic). + + // FIXME: Issue a nice error. + } + + // Add the predication code operand, if necessary. + if (CanAcceptPredicationCode) { + Operands.push_back(ARMOperand::CreateCondCode( + ARMCC::CondCodes(PredicationCode), NameLoc)); + } else { + // This mnemonic can't ever accept a predication code, but the user wrote + // one (or misspelled another mnemonic). + + // FIXME: Issue a nice error. + } // Add the remaining tokens in the mnemonic. while (Next != StringRef::npos) { @@ -920,10 +1198,15 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Operands.push_back(ARMOperand::CreateToken(Head, NameLoc)); } + bool isMCR = (Head == "mcr" || Head == "mcr2" || + Head == "mcrr" || Head == "mcrr2" || + Head == "mrc" || Head == "mrc2" || + Head == "mrrc" || Head == "mrrc2"); + // Read the remaining operands. if (getLexer().isNot(AsmToken::EndOfStatement)) { // Read the first operand. - if (ParseOperand(Operands)) { + if (ParseOperand(Operands, isMCR)) { Parser.EatToEndOfStatement(); return true; } @@ -932,7 +1215,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Parser.Lex(); // Eat the comma. // Parse and remember the operand. - if (ParseOperand(Operands)) { + if (ParseOperand(Operands, isMCR)) { Parser.EatToEndOfStatement(); return true; } @@ -954,7 +1237,60 @@ MatchAndEmitInstruction(SMLoc IDLoc, MCStreamer &Out) { MCInst Inst; unsigned ErrorInfo; - switch (MatchInstructionImpl(Operands, Inst, ErrorInfo)) { + MatchResultTy MatchResult, MatchResult2; + MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo); + if (MatchResult != Match_Success) { + // If we get a Match_InvalidOperand it might be some arithmetic instruction + // that does not update the condition codes. So try adding a CCOut operand + // with a value of reg0. + if (MatchResult == Match_InvalidOperand) { + Operands.insert(Operands.begin() + 1, + ARMOperand::CreateCCOut(0, + ((ARMOperand*)Operands[0])->getStartLoc())); + MatchResult2 = MatchInstructionImpl(Operands, Inst, ErrorInfo); + if (MatchResult2 == Match_Success) + MatchResult = Match_Success; + else { + ARMOperand *CCOut = ((ARMOperand*)Operands[1]); + Operands.erase(Operands.begin() + 1); + delete CCOut; + } + } + // If we get a Match_MnemonicFail it might be some arithmetic instruction + // that updates the condition codes if it ends in 's'. So see if the + // mnemonic ends in 's' and if so try removing the 's' and adding a CCOut + // operand with a value of CPSR. + else if(MatchResult == Match_MnemonicFail) { + // Get the instruction mnemonic, which is the first token. + StringRef Mnemonic = ((ARMOperand*)Operands[0])->getToken(); + if (Mnemonic.substr(Mnemonic.size()-1) == "s") { + // removed the 's' from the mnemonic for matching. + StringRef MnemonicNoS = Mnemonic.slice(0, Mnemonic.size() - 1); + SMLoc NameLoc = ((ARMOperand*)Operands[0])->getStartLoc(); + ARMOperand *OldMnemonic = ((ARMOperand*)Operands[0]); + Operands.erase(Operands.begin()); + delete OldMnemonic; + Operands.insert(Operands.begin(), + ARMOperand::CreateToken(MnemonicNoS, NameLoc)); + Operands.insert(Operands.begin() + 1, + ARMOperand::CreateCCOut(ARM::CPSR, NameLoc)); + MatchResult2 = MatchInstructionImpl(Operands, Inst, ErrorInfo); + if (MatchResult2 == Match_Success) + MatchResult = Match_Success; + else { + ARMOperand *OldMnemonic = ((ARMOperand*)Operands[0]); + Operands.erase(Operands.begin()); + delete OldMnemonic; + Operands.insert(Operands.begin(), + ARMOperand::CreateToken(Mnemonic, NameLoc)); + ARMOperand *CCOut = ((ARMOperand*)Operands[1]); + Operands.erase(Operands.begin() + 1); + delete CCOut; + } + } + } + } + switch (MatchResult) { case Match_Success: Out.EmitInstruction(Inst); return false; @@ -1094,10 +1430,20 @@ bool ARMAsmParser::ParseDirectiveCode(SMLoc L) { return Error(Parser.getTok().getLoc(), "unexpected token in directive"); Parser.Lex(); - if (Val == 16) + // FIXME: We need to be able switch subtargets at this point so that + // MatchInstructionImpl() will work when it gets the AvailableFeatures which + // includes Feature_IsThumb or not to match the right instructions. This is + // blocked on the FIXME in llvm-mc.cpp when creating the TargetMachine. + if (Val == 16){ + assert(TM.getSubtarget().isThumb() && + "switching between arm/thumb not yet suppported via .code 16)"); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); - else + } + else{ + assert(!TM.getSubtarget().isThumb() && + "switching between thumb/arm not yet suppported via .code 32)"); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32); + } return false; }