//===- MIParser.cpp - Machine instructions parser implementation ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the parsing of machine instructions. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/MIRParser/MIParser.h" #include "MILexer.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/AsmParser/Parser.h" #include "llvm/AsmParser/SlotMapping.h" #include "llvm/CodeGen/MIRFormatter.h" #include "llvm/CodeGen/MIRPrinter.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValueManager.h" #include "llvm/CodeGen/RegisterBank.h" #include "llvm/CodeGen/RegisterBankInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGenTypes/LowLevelType.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSlotTracker.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/MC/LaneBitmask.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/BranchProbability.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetMachine.h" #include #include #include #include #include #include #include using namespace llvm; void PerTargetMIParsingState::setTarget( const TargetSubtargetInfo &NewSubtarget) { // If the subtarget changed, over conservatively assume everything is invalid. if (&Subtarget == &NewSubtarget) return; Names2InstrOpCodes.clear(); Names2Regs.clear(); Names2RegMasks.clear(); Names2SubRegIndices.clear(); Names2TargetIndices.clear(); Names2DirectTargetFlags.clear(); Names2BitmaskTargetFlags.clear(); Names2MMOTargetFlags.clear(); initNames2RegClasses(); initNames2RegBanks(); } void PerTargetMIParsingState::initNames2Regs() { if (!Names2Regs.empty()) return; // The '%noreg' register is the register 0. Names2Regs.insert(std::make_pair("noreg", 0)); const auto *TRI = Subtarget.getRegisterInfo(); assert(TRI && "Expected target register info"); for (unsigned I = 0, E = TRI->getNumRegs(); I < E; ++I) { bool WasInserted = Names2Regs.insert(std::make_pair(StringRef(TRI->getName(I)).lower(), I)) .second; (void)WasInserted; assert(WasInserted && "Expected registers to be unique case-insensitively"); } } bool PerTargetMIParsingState::getRegisterByName(StringRef RegName, Register &Reg) { initNames2Regs(); auto RegInfo = Names2Regs.find(RegName); if (RegInfo == Names2Regs.end()) return true; Reg = RegInfo->getValue(); return false; } void PerTargetMIParsingState::initNames2InstrOpCodes() { if (!Names2InstrOpCodes.empty()) return; const auto *TII = Subtarget.getInstrInfo(); assert(TII && "Expected target instruction info"); for (unsigned I = 0, E = TII->getNumOpcodes(); I < E; ++I) Names2InstrOpCodes.insert(std::make_pair(StringRef(TII->getName(I)), I)); } bool PerTargetMIParsingState::parseInstrName(StringRef InstrName, unsigned &OpCode) { initNames2InstrOpCodes(); auto InstrInfo = Names2InstrOpCodes.find(InstrName); if (InstrInfo == Names2InstrOpCodes.end()) return true; OpCode = InstrInfo->getValue(); return false; } void PerTargetMIParsingState::initNames2RegMasks() { if (!Names2RegMasks.empty()) return; const auto *TRI = Subtarget.getRegisterInfo(); assert(TRI && "Expected target register info"); ArrayRef RegMasks = TRI->getRegMasks(); ArrayRef RegMaskNames = TRI->getRegMaskNames(); assert(RegMasks.size() == RegMaskNames.size()); for (size_t I = 0, E = RegMasks.size(); I < E; ++I) Names2RegMasks.insert( std::make_pair(StringRef(RegMaskNames[I]).lower(), RegMasks[I])); } const uint32_t *PerTargetMIParsingState::getRegMask(StringRef Identifier) { initNames2RegMasks(); auto RegMaskInfo = Names2RegMasks.find(Identifier); if (RegMaskInfo == Names2RegMasks.end()) return nullptr; return RegMaskInfo->getValue(); } void PerTargetMIParsingState::initNames2SubRegIndices() { if (!Names2SubRegIndices.empty()) return; const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); for (unsigned I = 1, E = TRI->getNumSubRegIndices(); I < E; ++I) Names2SubRegIndices.insert( std::make_pair(TRI->getSubRegIndexName(I), I)); } unsigned PerTargetMIParsingState::getSubRegIndex(StringRef Name) { initNames2SubRegIndices(); auto SubRegInfo = Names2SubRegIndices.find(Name); if (SubRegInfo == Names2SubRegIndices.end()) return 0; return SubRegInfo->getValue(); } void PerTargetMIParsingState::initNames2TargetIndices() { if (!Names2TargetIndices.empty()) return; const auto *TII = Subtarget.getInstrInfo(); assert(TII && "Expected target instruction info"); auto Indices = TII->getSerializableTargetIndices(); for (const auto &I : Indices) Names2TargetIndices.insert(std::make_pair(StringRef(I.second), I.first)); } bool PerTargetMIParsingState::getTargetIndex(StringRef Name, int &Index) { initNames2TargetIndices(); auto IndexInfo = Names2TargetIndices.find(Name); if (IndexInfo == Names2TargetIndices.end()) return true; Index = IndexInfo->second; return false; } void PerTargetMIParsingState::initNames2DirectTargetFlags() { if (!Names2DirectTargetFlags.empty()) return; const auto *TII = Subtarget.getInstrInfo(); assert(TII && "Expected target instruction info"); auto Flags = TII->getSerializableDirectMachineOperandTargetFlags(); for (const auto &I : Flags) Names2DirectTargetFlags.insert( std::make_pair(StringRef(I.second), I.first)); } bool PerTargetMIParsingState::getDirectTargetFlag(StringRef Name, unsigned &Flag) { initNames2DirectTargetFlags(); auto FlagInfo = Names2DirectTargetFlags.find(Name); if (FlagInfo == Names2DirectTargetFlags.end()) return true; Flag = FlagInfo->second; return false; } void PerTargetMIParsingState::initNames2BitmaskTargetFlags() { if (!Names2BitmaskTargetFlags.empty()) return; const auto *TII = Subtarget.getInstrInfo(); assert(TII && "Expected target instruction info"); auto Flags = TII->getSerializableBitmaskMachineOperandTargetFlags(); for (const auto &I : Flags) Names2BitmaskTargetFlags.insert( std::make_pair(StringRef(I.second), I.first)); } bool PerTargetMIParsingState::getBitmaskTargetFlag(StringRef Name, unsigned &Flag) { initNames2BitmaskTargetFlags(); auto FlagInfo = Names2BitmaskTargetFlags.find(Name); if (FlagInfo == Names2BitmaskTargetFlags.end()) return true; Flag = FlagInfo->second; return false; } void PerTargetMIParsingState::initNames2MMOTargetFlags() { if (!Names2MMOTargetFlags.empty()) return; const auto *TII = Subtarget.getInstrInfo(); assert(TII && "Expected target instruction info"); auto Flags = TII->getSerializableMachineMemOperandTargetFlags(); for (const auto &I : Flags) Names2MMOTargetFlags.insert(std::make_pair(StringRef(I.second), I.first)); } bool PerTargetMIParsingState::getMMOTargetFlag(StringRef Name, MachineMemOperand::Flags &Flag) { initNames2MMOTargetFlags(); auto FlagInfo = Names2MMOTargetFlags.find(Name); if (FlagInfo == Names2MMOTargetFlags.end()) return true; Flag = FlagInfo->second; return false; } void PerTargetMIParsingState::initNames2RegClasses() { if (!Names2RegClasses.empty()) return; const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); for (unsigned I = 0, E = TRI->getNumRegClasses(); I < E; ++I) { const auto *RC = TRI->getRegClass(I); Names2RegClasses.insert( std::make_pair(StringRef(TRI->getRegClassName(RC)).lower(), RC)); } } void PerTargetMIParsingState::initNames2RegBanks() { if (!Names2RegBanks.empty()) return; const RegisterBankInfo *RBI = Subtarget.getRegBankInfo(); // If the target does not support GlobalISel, we may not have a // register bank info. if (!RBI) return; for (unsigned I = 0, E = RBI->getNumRegBanks(); I < E; ++I) { const auto &RegBank = RBI->getRegBank(I); Names2RegBanks.insert( std::make_pair(StringRef(RegBank.getName()).lower(), &RegBank)); } } const TargetRegisterClass * PerTargetMIParsingState::getRegClass(StringRef Name) { auto RegClassInfo = Names2RegClasses.find(Name); if (RegClassInfo == Names2RegClasses.end()) return nullptr; return RegClassInfo->getValue(); } const RegisterBank *PerTargetMIParsingState::getRegBank(StringRef Name) { auto RegBankInfo = Names2RegBanks.find(Name); if (RegBankInfo == Names2RegBanks.end()) return nullptr; return RegBankInfo->getValue(); } PerFunctionMIParsingState::PerFunctionMIParsingState(MachineFunction &MF, SourceMgr &SM, const SlotMapping &IRSlots, PerTargetMIParsingState &T) : MF(MF), SM(&SM), IRSlots(IRSlots), Target(T) { } VRegInfo &PerFunctionMIParsingState::getVRegInfo(Register Num) { auto I = VRegInfos.insert(std::make_pair(Num, nullptr)); if (I.second) { MachineRegisterInfo &MRI = MF.getRegInfo(); VRegInfo *Info = new (Allocator) VRegInfo; Info->VReg = MRI.createIncompleteVirtualRegister(); I.first->second = Info; } return *I.first->second; } VRegInfo &PerFunctionMIParsingState::getVRegInfoNamed(StringRef RegName) { assert(RegName != "" && "Expected named reg."); auto I = VRegInfosNamed.insert(std::make_pair(RegName.str(), nullptr)); if (I.second) { VRegInfo *Info = new (Allocator) VRegInfo; Info->VReg = MF.getRegInfo().createIncompleteVirtualRegister(RegName); I.first->second = Info; } return *I.first->second; } static void mapValueToSlot(const Value *V, ModuleSlotTracker &MST, DenseMap &Slots2Values) { int Slot = MST.getLocalSlot(V); if (Slot == -1) return; Slots2Values.insert(std::make_pair(unsigned(Slot), V)); } /// Creates the mapping from slot numbers to function's unnamed IR values. static void initSlots2Values(const Function &F, DenseMap &Slots2Values) { ModuleSlotTracker MST(F.getParent(), /*ShouldInitializeAllMetadata=*/false); MST.incorporateFunction(F); for (const auto &Arg : F.args()) mapValueToSlot(&Arg, MST, Slots2Values); for (const auto &BB : F) { mapValueToSlot(&BB, MST, Slots2Values); for (const auto &I : BB) mapValueToSlot(&I, MST, Slots2Values); } } const Value* PerFunctionMIParsingState::getIRValue(unsigned Slot) { if (Slots2Values.empty()) initSlots2Values(MF.getFunction(), Slots2Values); return Slots2Values.lookup(Slot); } namespace { /// A wrapper struct around the 'MachineOperand' struct that includes a source /// range and other attributes. struct ParsedMachineOperand { MachineOperand Operand; StringRef::iterator Begin; StringRef::iterator End; std::optional TiedDefIdx; ParsedMachineOperand(const MachineOperand &Operand, StringRef::iterator Begin, StringRef::iterator End, std::optional &TiedDefIdx) : Operand(Operand), Begin(Begin), End(End), TiedDefIdx(TiedDefIdx) { if (TiedDefIdx) assert(Operand.isReg() && Operand.isUse() && "Only used register operands can be tied"); } }; class MIParser { MachineFunction &MF; SMDiagnostic &Error; StringRef Source, CurrentSource; SMRange SourceRange; MIToken Token; PerFunctionMIParsingState &PFS; /// Maps from slot numbers to function's unnamed basic blocks. DenseMap Slots2BasicBlocks; public: MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error, StringRef Source); MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error, StringRef Source, SMRange SourceRange); /// \p SkipChar gives the number of characters to skip before looking /// for the next token. void lex(unsigned SkipChar = 0); /// Report an error at the current location with the given message. /// /// This function always return true. bool error(const Twine &Msg); /// Report an error at the given location with the given message. /// /// This function always return true. bool error(StringRef::iterator Loc, const Twine &Msg); bool parseBasicBlockDefinitions(DenseMap &MBBSlots); bool parseBasicBlocks(); bool parse(MachineInstr *&MI); bool parseStandaloneMBB(MachineBasicBlock *&MBB); bool parseStandaloneNamedRegister(Register &Reg); bool parseStandaloneVirtualRegister(VRegInfo *&Info); bool parseStandaloneRegister(Register &Reg); bool parseStandaloneStackObject(int &FI); bool parseStandaloneMDNode(MDNode *&Node); bool parseMachineMetadata(); bool parseMDTuple(MDNode *&MD, bool IsDistinct); bool parseMDNodeVector(SmallVectorImpl &Elts); bool parseMetadata(Metadata *&MD); bool parseBasicBlockDefinition(DenseMap &MBBSlots); bool parseBasicBlock(MachineBasicBlock &MBB, MachineBasicBlock *&AddFalthroughFrom); bool parseBasicBlockLiveins(MachineBasicBlock &MBB); bool parseBasicBlockSuccessors(MachineBasicBlock &MBB); bool parseNamedRegister(Register &Reg); bool parseVirtualRegister(VRegInfo *&Info); bool parseNamedVirtualRegister(VRegInfo *&Info); bool parseRegister(Register &Reg, VRegInfo *&VRegInfo); bool parseRegisterFlag(unsigned &Flags); bool parseRegisterClassOrBank(VRegInfo &RegInfo); bool parseSubRegisterIndex(unsigned &SubReg); bool parseRegisterTiedDefIndex(unsigned &TiedDefIdx); bool parseRegisterOperand(MachineOperand &Dest, std::optional &TiedDefIdx, bool IsDef = false); bool parseImmediateOperand(MachineOperand &Dest); bool parseIRConstant(StringRef::iterator Loc, StringRef StringValue, const Constant *&C); bool parseIRConstant(StringRef::iterator Loc, const Constant *&C); bool parseLowLevelType(StringRef::iterator Loc, LLT &Ty); bool parseTypedImmediateOperand(MachineOperand &Dest); bool parseFPImmediateOperand(MachineOperand &Dest); bool parseMBBReference(MachineBasicBlock *&MBB); bool parseMBBOperand(MachineOperand &Dest); bool parseStackFrameIndex(int &FI); bool parseStackObjectOperand(MachineOperand &Dest); bool parseFixedStackFrameIndex(int &FI); bool parseFixedStackObjectOperand(MachineOperand &Dest); bool parseGlobalValue(GlobalValue *&GV); bool parseGlobalAddressOperand(MachineOperand &Dest); bool parseConstantPoolIndexOperand(MachineOperand &Dest); bool parseSubRegisterIndexOperand(MachineOperand &Dest); bool parseJumpTableIndexOperand(MachineOperand &Dest); bool parseExternalSymbolOperand(MachineOperand &Dest); bool parseMCSymbolOperand(MachineOperand &Dest); [[nodiscard]] bool parseMDNode(MDNode *&Node); bool parseDIExpression(MDNode *&Expr); bool parseDILocation(MDNode *&Expr); bool parseMetadataOperand(MachineOperand &Dest); bool parseCFIOffset(int &Offset); bool parseCFIRegister(Register &Reg); bool parseCFIAddressSpace(unsigned &AddressSpace); bool parseCFIEscapeValues(std::string& Values); bool parseCFIOperand(MachineOperand &Dest); bool parseIRBlock(BasicBlock *&BB, const Function &F); bool parseBlockAddressOperand(MachineOperand &Dest); bool parseIntrinsicOperand(MachineOperand &Dest); bool parsePredicateOperand(MachineOperand &Dest); bool parseShuffleMaskOperand(MachineOperand &Dest); bool parseTargetIndexOperand(MachineOperand &Dest); bool parseDbgInstrRefOperand(MachineOperand &Dest); bool parseCustomRegisterMaskOperand(MachineOperand &Dest); bool parseLiveoutRegisterMaskOperand(MachineOperand &Dest); bool parseMachineOperand(const unsigned OpCode, const unsigned OpIdx, MachineOperand &Dest, std::optional &TiedDefIdx); bool parseMachineOperandAndTargetFlags(const unsigned OpCode, const unsigned OpIdx, MachineOperand &Dest, std::optional &TiedDefIdx); bool parseOffset(int64_t &Offset); bool parseIRBlockAddressTaken(BasicBlock *&BB); bool parseAlignment(uint64_t &Alignment); bool parseAddrspace(unsigned &Addrspace); bool parseSectionID(std::optional &SID); bool parseBBID(std::optional &BBID); bool parseCallFrameSize(unsigned &CallFrameSize); bool parseOperandsOffset(MachineOperand &Op); bool parseIRValue(const Value *&V); bool parseMemoryOperandFlag(MachineMemOperand::Flags &Flags); bool parseMemoryPseudoSourceValue(const PseudoSourceValue *&PSV); bool parseMachinePointerInfo(MachinePointerInfo &Dest); bool parseOptionalScope(LLVMContext &Context, SyncScope::ID &SSID); bool parseOptionalAtomicOrdering(AtomicOrdering &Order); bool parseMachineMemoryOperand(MachineMemOperand *&Dest); bool parsePreOrPostInstrSymbol(MCSymbol *&Symbol); bool parseHeapAllocMarker(MDNode *&Node); bool parsePCSections(MDNode *&Node); bool parseTargetImmMnemonic(const unsigned OpCode, const unsigned OpIdx, MachineOperand &Dest, const MIRFormatter &MF); private: /// Convert the integer literal in the current token into an unsigned integer. /// /// Return true if an error occurred. bool getUnsigned(unsigned &Result); /// Convert the integer literal in the current token into an uint64. /// /// Return true if an error occurred. bool getUint64(uint64_t &Result); /// Convert the hexadecimal literal in the current token into an unsigned /// APInt with a minimum bitwidth required to represent the value. /// /// Return true if the literal does not represent an integer value. bool getHexUint(APInt &Result); /// If the current token is of the given kind, consume it and return false. /// Otherwise report an error and return true. bool expectAndConsume(MIToken::TokenKind TokenKind); /// If the current token is of the given kind, consume it and return true. /// Otherwise return false. bool consumeIfPresent(MIToken::TokenKind TokenKind); bool parseInstruction(unsigned &OpCode, unsigned &Flags); bool assignRegisterTies(MachineInstr &MI, ArrayRef Operands); bool verifyImplicitOperands(ArrayRef Operands, const MCInstrDesc &MCID); const BasicBlock *getIRBlock(unsigned Slot); const BasicBlock *getIRBlock(unsigned Slot, const Function &F); /// Get or create an MCSymbol for a given name. MCSymbol *getOrCreateMCSymbol(StringRef Name); /// parseStringConstant /// ::= StringConstant bool parseStringConstant(std::string &Result); /// Map the location in the MI string to the corresponding location specified /// in `SourceRange`. SMLoc mapSMLoc(StringRef::iterator Loc); }; } // end anonymous namespace MIParser::MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error, StringRef Source) : MF(PFS.MF), Error(Error), Source(Source), CurrentSource(Source), PFS(PFS) {} MIParser::MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error, StringRef Source, SMRange SourceRange) : MF(PFS.MF), Error(Error), Source(Source), CurrentSource(Source), SourceRange(SourceRange), PFS(PFS) {} void MIParser::lex(unsigned SkipChar) { CurrentSource = lexMIToken( CurrentSource.slice(SkipChar, StringRef::npos), Token, [this](StringRef::iterator Loc, const Twine &Msg) { error(Loc, Msg); }); } bool MIParser::error(const Twine &Msg) { return error(Token.location(), Msg); } bool MIParser::error(StringRef::iterator Loc, const Twine &Msg) { const SourceMgr &SM = *PFS.SM; assert(Loc >= Source.data() && Loc <= (Source.data() + Source.size())); const MemoryBuffer &Buffer = *SM.getMemoryBuffer(SM.getMainFileID()); if (Loc >= Buffer.getBufferStart() && Loc <= Buffer.getBufferEnd()) { // Create an ordinary diagnostic when the source manager's buffer is the // source string. Error = SM.GetMessage(SMLoc::getFromPointer(Loc), SourceMgr::DK_Error, Msg); return true; } // Create a diagnostic for a YAML string literal. Error = SMDiagnostic(SM, SMLoc(), Buffer.getBufferIdentifier(), 1, Loc - Source.data(), SourceMgr::DK_Error, Msg.str(), Source, std::nullopt, std::nullopt); return true; } SMLoc MIParser::mapSMLoc(StringRef::iterator Loc) { assert(SourceRange.isValid() && "Invalid source range"); assert(Loc >= Source.data() && Loc <= (Source.data() + Source.size())); return SMLoc::getFromPointer(SourceRange.Start.getPointer() + (Loc - Source.data())); } typedef function_ref ErrorCallbackType; static const char *toString(MIToken::TokenKind TokenKind) { switch (TokenKind) { case MIToken::comma: return "','"; case MIToken::equal: return "'='"; case MIToken::colon: return "':'"; case MIToken::lparen: return "'('"; case MIToken::rparen: return "')'"; default: return ""; } } bool MIParser::expectAndConsume(MIToken::TokenKind TokenKind) { if (Token.isNot(TokenKind)) return error(Twine("expected ") + toString(TokenKind)); lex(); return false; } bool MIParser::consumeIfPresent(MIToken::TokenKind TokenKind) { if (Token.isNot(TokenKind)) return false; lex(); return true; } // Parse Machine Basic Block Section ID. bool MIParser::parseSectionID(std::optional &SID) { assert(Token.is(MIToken::kw_bbsections)); lex(); if (Token.is(MIToken::IntegerLiteral)) { unsigned Value = 0; if (getUnsigned(Value)) return error("Unknown Section ID"); SID = MBBSectionID{Value}; } else { const StringRef &S = Token.stringValue(); if (S == "Exception") SID = MBBSectionID::ExceptionSectionID; else if (S == "Cold") SID = MBBSectionID::ColdSectionID; else return error("Unknown Section ID"); } lex(); return false; } // Parse Machine Basic Block ID. bool MIParser::parseBBID(std::optional &BBID) { assert(Token.is(MIToken::kw_bb_id)); lex(); unsigned BaseID = 0; unsigned CloneID = 0; if (getUnsigned(BaseID)) return error("Unknown BB ID"); lex(); if (Token.is(MIToken::IntegerLiteral)) { if (getUnsigned(CloneID)) return error("Unknown Clone ID"); lex(); } BBID = {BaseID, CloneID}; return false; } // Parse basic block call frame size. bool MIParser::parseCallFrameSize(unsigned &CallFrameSize) { assert(Token.is(MIToken::kw_call_frame_size)); lex(); unsigned Value = 0; if (getUnsigned(Value)) return error("Unknown call frame size"); CallFrameSize = Value; lex(); return false; } bool MIParser::parseBasicBlockDefinition( DenseMap &MBBSlots) { assert(Token.is(MIToken::MachineBasicBlockLabel)); unsigned ID = 0; if (getUnsigned(ID)) return true; auto Loc = Token.location(); auto Name = Token.stringValue(); lex(); bool MachineBlockAddressTaken = false; BasicBlock *AddressTakenIRBlock = nullptr; bool IsLandingPad = false; bool IsInlineAsmBrIndirectTarget = false; bool IsEHFuncletEntry = false; std::optional SectionID; uint64_t Alignment = 0; std::optional BBID; unsigned CallFrameSize = 0; BasicBlock *BB = nullptr; if (consumeIfPresent(MIToken::lparen)) { do { // TODO: Report an error when multiple same attributes are specified. switch (Token.kind()) { case MIToken::kw_machine_block_address_taken: MachineBlockAddressTaken = true; lex(); break; case MIToken::kw_ir_block_address_taken: if (parseIRBlockAddressTaken(AddressTakenIRBlock)) return true; break; case MIToken::kw_landing_pad: IsLandingPad = true; lex(); break; case MIToken::kw_inlineasm_br_indirect_target: IsInlineAsmBrIndirectTarget = true; lex(); break; case MIToken::kw_ehfunclet_entry: IsEHFuncletEntry = true; lex(); break; case MIToken::kw_align: if (parseAlignment(Alignment)) return true; break; case MIToken::IRBlock: case MIToken::NamedIRBlock: // TODO: Report an error when both name and ir block are specified. if (parseIRBlock(BB, MF.getFunction())) return true; lex(); break; case MIToken::kw_bbsections: if (parseSectionID(SectionID)) return true; break; case MIToken::kw_bb_id: if (parseBBID(BBID)) return true; break; case MIToken::kw_call_frame_size: if (parseCallFrameSize(CallFrameSize)) return true; break; default: break; } } while (consumeIfPresent(MIToken::comma)); if (expectAndConsume(MIToken::rparen)) return true; } if (expectAndConsume(MIToken::colon)) return true; if (!Name.empty()) { BB = dyn_cast_or_null( MF.getFunction().getValueSymbolTable()->lookup(Name)); if (!BB) return error(Loc, Twine("basic block '") + Name + "' is not defined in the function '" + MF.getName() + "'"); } auto *MBB = MF.CreateMachineBasicBlock(BB); MF.insert(MF.end(), MBB); bool WasInserted = MBBSlots.insert(std::make_pair(ID, MBB)).second; if (!WasInserted) return error(Loc, Twine("redefinition of machine basic block with id #") + Twine(ID)); if (Alignment) MBB->setAlignment(Align(Alignment)); if (MachineBlockAddressTaken) MBB->setMachineBlockAddressTaken(); if (AddressTakenIRBlock) MBB->setAddressTakenIRBlock(AddressTakenIRBlock); MBB->setIsEHPad(IsLandingPad); MBB->setIsInlineAsmBrIndirectTarget(IsInlineAsmBrIndirectTarget); MBB->setIsEHFuncletEntry(IsEHFuncletEntry); if (SectionID) { MBB->setSectionID(*SectionID); MF.setBBSectionsType(BasicBlockSection::List); } if (BBID.has_value()) { // BBSectionsType is set to `List` if any basic blocks has `SectionID`. // Here, we set it to `Labels` if it hasn't been set above. if (!MF.hasBBSections()) MF.setBBSectionsType(BasicBlockSection::Labels); MBB->setBBID(BBID.value()); } MBB->setCallFrameSize(CallFrameSize); return false; } bool MIParser::parseBasicBlockDefinitions( DenseMap &MBBSlots) { lex(); // Skip until the first machine basic block. while (Token.is(MIToken::Newline)) lex(); if (Token.isErrorOrEOF()) return Token.isError(); if (Token.isNot(MIToken::MachineBasicBlockLabel)) return error("expected a basic block definition before instructions"); unsigned BraceDepth = 0; do { if (parseBasicBlockDefinition(MBBSlots)) return true; bool IsAfterNewline = false; // Skip until the next machine basic block. while (true) { if ((Token.is(MIToken::MachineBasicBlockLabel) && IsAfterNewline) || Token.isErrorOrEOF()) break; else if (Token.is(MIToken::MachineBasicBlockLabel)) return error("basic block definition should be located at the start of " "the line"); else if (consumeIfPresent(MIToken::Newline)) { IsAfterNewline = true; continue; } IsAfterNewline = false; if (Token.is(MIToken::lbrace)) ++BraceDepth; if (Token.is(MIToken::rbrace)) { if (!BraceDepth) return error("extraneous closing brace ('}')"); --BraceDepth; } lex(); } // Verify that we closed all of the '{' at the end of a file or a block. if (!Token.isError() && BraceDepth) return error("expected '}'"); // FIXME: Report a note that shows '{'. } while (!Token.isErrorOrEOF()); return Token.isError(); } bool MIParser::parseBasicBlockLiveins(MachineBasicBlock &MBB) { assert(Token.is(MIToken::kw_liveins)); lex(); if (expectAndConsume(MIToken::colon)) return true; if (Token.isNewlineOrEOF()) // Allow an empty list of liveins. return false; do { if (Token.isNot(MIToken::NamedRegister)) return error("expected a named register"); Register Reg; if (parseNamedRegister(Reg)) return true; lex(); LaneBitmask Mask = LaneBitmask::getAll(); if (consumeIfPresent(MIToken::colon)) { // Parse lane mask. if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::HexLiteral)) return error("expected a lane mask"); static_assert(sizeof(LaneBitmask::Type) == sizeof(uint64_t), "Use correct get-function for lane mask"); LaneBitmask::Type V; if (getUint64(V)) return error("invalid lane mask value"); Mask = LaneBitmask(V); lex(); } MBB.addLiveIn(Reg, Mask); } while (consumeIfPresent(MIToken::comma)); return false; } bool MIParser::parseBasicBlockSuccessors(MachineBasicBlock &MBB) { assert(Token.is(MIToken::kw_successors)); lex(); if (expectAndConsume(MIToken::colon)) return true; if (Token.isNewlineOrEOF()) // Allow an empty list of successors. return false; do { if (Token.isNot(MIToken::MachineBasicBlock)) return error("expected a machine basic block reference"); MachineBasicBlock *SuccMBB = nullptr; if (parseMBBReference(SuccMBB)) return true; lex(); unsigned Weight = 0; if (consumeIfPresent(MIToken::lparen)) { if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::HexLiteral)) return error("expected an integer literal after '('"); if (getUnsigned(Weight)) return true; lex(); if (expectAndConsume(MIToken::rparen)) return true; } MBB.addSuccessor(SuccMBB, BranchProbability::getRaw(Weight)); } while (consumeIfPresent(MIToken::comma)); MBB.normalizeSuccProbs(); return false; } bool MIParser::parseBasicBlock(MachineBasicBlock &MBB, MachineBasicBlock *&AddFalthroughFrom) { // Skip the definition. assert(Token.is(MIToken::MachineBasicBlockLabel)); lex(); if (consumeIfPresent(MIToken::lparen)) { while (Token.isNot(MIToken::rparen) && !Token.isErrorOrEOF()) lex(); consumeIfPresent(MIToken::rparen); } consumeIfPresent(MIToken::colon); // Parse the liveins and successors. // N.B: Multiple lists of successors and liveins are allowed and they're // merged into one. // Example: // liveins: $edi // liveins: $esi // // is equivalent to // liveins: $edi, $esi bool ExplicitSuccessors = false; while (true) { if (Token.is(MIToken::kw_successors)) { if (parseBasicBlockSuccessors(MBB)) return true; ExplicitSuccessors = true; } else if (Token.is(MIToken::kw_liveins)) { if (parseBasicBlockLiveins(MBB)) return true; } else if (consumeIfPresent(MIToken::Newline)) { continue; } else break; if (!Token.isNewlineOrEOF()) return error("expected line break at the end of a list"); lex(); } // Parse the instructions. bool IsInBundle = false; MachineInstr *PrevMI = nullptr; while (!Token.is(MIToken::MachineBasicBlockLabel) && !Token.is(MIToken::Eof)) { if (consumeIfPresent(MIToken::Newline)) continue; if (consumeIfPresent(MIToken::rbrace)) { // The first parsing pass should verify that all closing '}' have an // opening '{'. assert(IsInBundle); IsInBundle = false; continue; } MachineInstr *MI = nullptr; if (parse(MI)) return true; MBB.insert(MBB.end(), MI); if (IsInBundle) { PrevMI->setFlag(MachineInstr::BundledSucc); MI->setFlag(MachineInstr::BundledPred); } PrevMI = MI; if (Token.is(MIToken::lbrace)) { if (IsInBundle) return error("nested instruction bundles are not allowed"); lex(); // This instruction is the start of the bundle. MI->setFlag(MachineInstr::BundledSucc); IsInBundle = true; if (!Token.is(MIToken::Newline)) // The next instruction can be on the same line. continue; } assert(Token.isNewlineOrEOF() && "MI is not fully parsed"); lex(); } // Construct successor list by searching for basic block machine operands. if (!ExplicitSuccessors) { SmallVector Successors; bool IsFallthrough; guessSuccessors(MBB, Successors, IsFallthrough); for (MachineBasicBlock *Succ : Successors) MBB.addSuccessor(Succ); if (IsFallthrough) { AddFalthroughFrom = &MBB; } else { MBB.normalizeSuccProbs(); } } return false; } bool MIParser::parseBasicBlocks() { lex(); // Skip until the first machine basic block. while (Token.is(MIToken::Newline)) lex(); if (Token.isErrorOrEOF()) return Token.isError(); // The first parsing pass should have verified that this token is a MBB label // in the 'parseBasicBlockDefinitions' method. assert(Token.is(MIToken::MachineBasicBlockLabel)); MachineBasicBlock *AddFalthroughFrom = nullptr; do { MachineBasicBlock *MBB = nullptr; if (parseMBBReference(MBB)) return true; if (AddFalthroughFrom) { if (!AddFalthroughFrom->isSuccessor(MBB)) AddFalthroughFrom->addSuccessor(MBB); AddFalthroughFrom->normalizeSuccProbs(); AddFalthroughFrom = nullptr; } if (parseBasicBlock(*MBB, AddFalthroughFrom)) return true; // The method 'parseBasicBlock' should parse the whole block until the next // block or the end of file. assert(Token.is(MIToken::MachineBasicBlockLabel) || Token.is(MIToken::Eof)); } while (Token.isNot(MIToken::Eof)); return false; } bool MIParser::parse(MachineInstr *&MI) { // Parse any register operands before '=' MachineOperand MO = MachineOperand::CreateImm(0); SmallVector Operands; while (Token.isRegister() || Token.isRegisterFlag()) { auto Loc = Token.location(); std::optional TiedDefIdx; if (parseRegisterOperand(MO, TiedDefIdx, /*IsDef=*/true)) return true; Operands.push_back( ParsedMachineOperand(MO, Loc, Token.location(), TiedDefIdx)); if (Token.isNot(MIToken::comma)) break; lex(); } if (!Operands.empty() && expectAndConsume(MIToken::equal)) return true; unsigned OpCode, Flags = 0; if (Token.isError() || parseInstruction(OpCode, Flags)) return true; // Parse the remaining machine operands. while (!Token.isNewlineOrEOF() && Token.isNot(MIToken::kw_pre_instr_symbol) && Token.isNot(MIToken::kw_post_instr_symbol) && Token.isNot(MIToken::kw_heap_alloc_marker) && Token.isNot(MIToken::kw_pcsections) && Token.isNot(MIToken::kw_cfi_type) && Token.isNot(MIToken::kw_debug_location) && Token.isNot(MIToken::kw_debug_instr_number) && Token.isNot(MIToken::coloncolon) && Token.isNot(MIToken::lbrace)) { auto Loc = Token.location(); std::optional TiedDefIdx; if (parseMachineOperandAndTargetFlags(OpCode, Operands.size(), MO, TiedDefIdx)) return true; Operands.push_back( ParsedMachineOperand(MO, Loc, Token.location(), TiedDefIdx)); if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) || Token.is(MIToken::lbrace)) break; if (Token.isNot(MIToken::comma)) return error("expected ',' before the next machine operand"); lex(); } MCSymbol *PreInstrSymbol = nullptr; if (Token.is(MIToken::kw_pre_instr_symbol)) if (parsePreOrPostInstrSymbol(PreInstrSymbol)) return true; MCSymbol *PostInstrSymbol = nullptr; if (Token.is(MIToken::kw_post_instr_symbol)) if (parsePreOrPostInstrSymbol(PostInstrSymbol)) return true; MDNode *HeapAllocMarker = nullptr; if (Token.is(MIToken::kw_heap_alloc_marker)) if (parseHeapAllocMarker(HeapAllocMarker)) return true; MDNode *PCSections = nullptr; if (Token.is(MIToken::kw_pcsections)) if (parsePCSections(PCSections)) return true; unsigned CFIType = 0; if (Token.is(MIToken::kw_cfi_type)) { lex(); if (Token.isNot(MIToken::IntegerLiteral)) return error("expected an integer literal after 'cfi-type'"); // getUnsigned is sufficient for 32-bit integers. if (getUnsigned(CFIType)) return true; lex(); // Lex past trailing comma if present. if (Token.is(MIToken::comma)) lex(); } unsigned InstrNum = 0; if (Token.is(MIToken::kw_debug_instr_number)) { lex(); if (Token.isNot(MIToken::IntegerLiteral)) return error("expected an integer literal after 'debug-instr-number'"); if (getUnsigned(InstrNum)) return true; lex(); // Lex past trailing comma if present. if (Token.is(MIToken::comma)) lex(); } DebugLoc DebugLocation; if (Token.is(MIToken::kw_debug_location)) { lex(); MDNode *Node = nullptr; if (Token.is(MIToken::exclaim)) { if (parseMDNode(Node)) return true; } else if (Token.is(MIToken::md_dilocation)) { if (parseDILocation(Node)) return true; } else return error("expected a metadata node after 'debug-location'"); if (!isa(Node)) return error("referenced metadata is not a DILocation"); DebugLocation = DebugLoc(Node); } // Parse the machine memory operands. SmallVector MemOperands; if (Token.is(MIToken::coloncolon)) { lex(); while (!Token.isNewlineOrEOF()) { MachineMemOperand *MemOp = nullptr; if (parseMachineMemoryOperand(MemOp)) return true; MemOperands.push_back(MemOp); if (Token.isNewlineOrEOF()) break; if (Token.isNot(MIToken::comma)) return error("expected ',' before the next machine memory operand"); lex(); } } const auto &MCID = MF.getSubtarget().getInstrInfo()->get(OpCode); if (!MCID.isVariadic()) { // FIXME: Move the implicit operand verification to the machine verifier. if (verifyImplicitOperands(Operands, MCID)) return true; } MI = MF.CreateMachineInstr(MCID, DebugLocation, /*NoImplicit=*/true); MI->setFlags(Flags); // Don't check the operands make sense, let the verifier catch any // improprieties. for (const auto &Operand : Operands) MI->addOperand(MF, Operand.Operand); if (assignRegisterTies(*MI, Operands)) return true; if (PreInstrSymbol) MI->setPreInstrSymbol(MF, PreInstrSymbol); if (PostInstrSymbol) MI->setPostInstrSymbol(MF, PostInstrSymbol); if (HeapAllocMarker) MI->setHeapAllocMarker(MF, HeapAllocMarker); if (PCSections) MI->setPCSections(MF, PCSections); if (CFIType) MI->setCFIType(MF, CFIType); if (!MemOperands.empty()) MI->setMemRefs(MF, MemOperands); if (InstrNum) MI->setDebugInstrNum(InstrNum); return false; } bool MIParser::parseStandaloneMBB(MachineBasicBlock *&MBB) { lex(); if (Token.isNot(MIToken::MachineBasicBlock)) return error("expected a machine basic block reference"); if (parseMBBReference(MBB)) return true; lex(); if (Token.isNot(MIToken::Eof)) return error( "expected end of string after the machine basic block reference"); return false; } bool MIParser::parseStandaloneNamedRegister(Register &Reg) { lex(); if (Token.isNot(MIToken::NamedRegister)) return error("expected a named register"); if (parseNamedRegister(Reg)) return true; lex(); if (Token.isNot(MIToken::Eof)) return error("expected end of string after the register reference"); return false; } bool MIParser::parseStandaloneVirtualRegister(VRegInfo *&Info) { lex(); if (Token.isNot(MIToken::VirtualRegister)) return error("expected a virtual register"); if (parseVirtualRegister(Info)) return true; lex(); if (Token.isNot(MIToken::Eof)) return error("expected end of string after the register reference"); return false; } bool MIParser::parseStandaloneRegister(Register &Reg) { lex(); if (Token.isNot(MIToken::NamedRegister) && Token.isNot(MIToken::VirtualRegister)) return error("expected either a named or virtual register"); VRegInfo *Info; if (parseRegister(Reg, Info)) return true; lex(); if (Token.isNot(MIToken::Eof)) return error("expected end of string after the register reference"); return false; } bool MIParser::parseStandaloneStackObject(int &FI) { lex(); if (Token.isNot(MIToken::StackObject)) return error("expected a stack object"); if (parseStackFrameIndex(FI)) return true; if (Token.isNot(MIToken::Eof)) return error("expected end of string after the stack object reference"); return false; } bool MIParser::parseStandaloneMDNode(MDNode *&Node) { lex(); if (Token.is(MIToken::exclaim)) { if (parseMDNode(Node)) return true; } else if (Token.is(MIToken::md_diexpr)) { if (parseDIExpression(Node)) return true; } else if (Token.is(MIToken::md_dilocation)) { if (parseDILocation(Node)) return true; } else return error("expected a metadata node"); if (Token.isNot(MIToken::Eof)) return error("expected end of string after the metadata node"); return false; } bool MIParser::parseMachineMetadata() { lex(); if (Token.isNot(MIToken::exclaim)) return error("expected a metadata node"); lex(); if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected metadata id after '!'"); unsigned ID = 0; if (getUnsigned(ID)) return true; lex(); if (expectAndConsume(MIToken::equal)) return true; bool IsDistinct = Token.is(MIToken::kw_distinct); if (IsDistinct) lex(); if (Token.isNot(MIToken::exclaim)) return error("expected a metadata node"); lex(); MDNode *MD; if (parseMDTuple(MD, IsDistinct)) return true; auto FI = PFS.MachineForwardRefMDNodes.find(ID); if (FI != PFS.MachineForwardRefMDNodes.end()) { FI->second.first->replaceAllUsesWith(MD); PFS.MachineForwardRefMDNodes.erase(FI); assert(PFS.MachineMetadataNodes[ID] == MD && "Tracking VH didn't work"); } else { if (PFS.MachineMetadataNodes.count(ID)) return error("Metadata id is already used"); PFS.MachineMetadataNodes[ID].reset(MD); } return false; } bool MIParser::parseMDTuple(MDNode *&MD, bool IsDistinct) { SmallVector Elts; if (parseMDNodeVector(Elts)) return true; MD = (IsDistinct ? MDTuple::getDistinct : MDTuple::get)(MF.getFunction().getContext(), Elts); return false; } bool MIParser::parseMDNodeVector(SmallVectorImpl &Elts) { if (Token.isNot(MIToken::lbrace)) return error("expected '{' here"); lex(); if (Token.is(MIToken::rbrace)) { lex(); return false; } do { Metadata *MD; if (parseMetadata(MD)) return true; Elts.push_back(MD); if (Token.isNot(MIToken::comma)) break; lex(); } while (true); if (Token.isNot(MIToken::rbrace)) return error("expected end of metadata node"); lex(); return false; } // ::= !42 // ::= !"string" bool MIParser::parseMetadata(Metadata *&MD) { if (Token.isNot(MIToken::exclaim)) return error("expected '!' here"); lex(); if (Token.is(MIToken::StringConstant)) { std::string Str; if (parseStringConstant(Str)) return true; MD = MDString::get(MF.getFunction().getContext(), Str); return false; } if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected metadata id after '!'"); SMLoc Loc = mapSMLoc(Token.location()); unsigned ID = 0; if (getUnsigned(ID)) return true; lex(); auto NodeInfo = PFS.IRSlots.MetadataNodes.find(ID); if (NodeInfo != PFS.IRSlots.MetadataNodes.end()) { MD = NodeInfo->second.get(); return false; } // Check machine metadata. NodeInfo = PFS.MachineMetadataNodes.find(ID); if (NodeInfo != PFS.MachineMetadataNodes.end()) { MD = NodeInfo->second.get(); return false; } // Forward reference. auto &FwdRef = PFS.MachineForwardRefMDNodes[ID]; FwdRef = std::make_pair( MDTuple::getTemporary(MF.getFunction().getContext(), std::nullopt), Loc); PFS.MachineMetadataNodes[ID].reset(FwdRef.first.get()); MD = FwdRef.first.get(); return false; } static const char *printImplicitRegisterFlag(const MachineOperand &MO) { assert(MO.isImplicit()); return MO.isDef() ? "implicit-def" : "implicit"; } static std::string getRegisterName(const TargetRegisterInfo *TRI, Register Reg) { assert(Reg.isPhysical() && "expected phys reg"); return StringRef(TRI->getName(Reg)).lower(); } /// Return true if the parsed machine operands contain a given machine operand. static bool isImplicitOperandIn(const MachineOperand &ImplicitOperand, ArrayRef Operands) { for (const auto &I : Operands) { if (ImplicitOperand.isIdenticalTo(I.Operand)) return true; } return false; } bool MIParser::verifyImplicitOperands(ArrayRef Operands, const MCInstrDesc &MCID) { if (MCID.isCall()) // We can't verify call instructions as they can contain arbitrary implicit // register and register mask operands. return false; // Gather all the expected implicit operands. SmallVector ImplicitOperands; for (MCPhysReg ImpDef : MCID.implicit_defs()) ImplicitOperands.push_back(MachineOperand::CreateReg(ImpDef, true, true)); for (MCPhysReg ImpUse : MCID.implicit_uses()) ImplicitOperands.push_back(MachineOperand::CreateReg(ImpUse, false, true)); const auto *TRI = MF.getSubtarget().getRegisterInfo(); assert(TRI && "Expected target register info"); for (const auto &I : ImplicitOperands) { if (isImplicitOperandIn(I, Operands)) continue; return error(Operands.empty() ? Token.location() : Operands.back().End, Twine("missing implicit register operand '") + printImplicitRegisterFlag(I) + " $" + getRegisterName(TRI, I.getReg()) + "'"); } return false; } bool MIParser::parseInstruction(unsigned &OpCode, unsigned &Flags) { // Allow frame and fast math flags for OPCODE // clang-format off while (Token.is(MIToken::kw_frame_setup) || Token.is(MIToken::kw_frame_destroy) || Token.is(MIToken::kw_nnan) || Token.is(MIToken::kw_ninf) || Token.is(MIToken::kw_nsz) || Token.is(MIToken::kw_arcp) || Token.is(MIToken::kw_contract) || Token.is(MIToken::kw_afn) || Token.is(MIToken::kw_reassoc) || Token.is(MIToken::kw_nuw) || Token.is(MIToken::kw_nsw) || Token.is(MIToken::kw_exact) || Token.is(MIToken::kw_nofpexcept) || Token.is(MIToken::kw_noconvergent) || Token.is(MIToken::kw_unpredictable) || Token.is(MIToken::kw_nneg) || Token.is(MIToken::kw_disjoint)) { // clang-format on // Mine frame and fast math flags if (Token.is(MIToken::kw_frame_setup)) Flags |= MachineInstr::FrameSetup; if (Token.is(MIToken::kw_frame_destroy)) Flags |= MachineInstr::FrameDestroy; if (Token.is(MIToken::kw_nnan)) Flags |= MachineInstr::FmNoNans; if (Token.is(MIToken::kw_ninf)) Flags |= MachineInstr::FmNoInfs; if (Token.is(MIToken::kw_nsz)) Flags |= MachineInstr::FmNsz; if (Token.is(MIToken::kw_arcp)) Flags |= MachineInstr::FmArcp; if (Token.is(MIToken::kw_contract)) Flags |= MachineInstr::FmContract; if (Token.is(MIToken::kw_afn)) Flags |= MachineInstr::FmAfn; if (Token.is(MIToken::kw_reassoc)) Flags |= MachineInstr::FmReassoc; if (Token.is(MIToken::kw_nuw)) Flags |= MachineInstr::NoUWrap; if (Token.is(MIToken::kw_nsw)) Flags |= MachineInstr::NoSWrap; if (Token.is(MIToken::kw_exact)) Flags |= MachineInstr::IsExact; if (Token.is(MIToken::kw_nofpexcept)) Flags |= MachineInstr::NoFPExcept; if (Token.is(MIToken::kw_unpredictable)) Flags |= MachineInstr::Unpredictable; if (Token.is(MIToken::kw_noconvergent)) Flags |= MachineInstr::NoConvergent; if (Token.is(MIToken::kw_nneg)) Flags |= MachineInstr::NonNeg; if (Token.is(MIToken::kw_disjoint)) Flags |= MachineInstr::Disjoint; lex(); } if (Token.isNot(MIToken::Identifier)) return error("expected a machine instruction"); StringRef InstrName = Token.stringValue(); if (PFS.Target.parseInstrName(InstrName, OpCode)) return error(Twine("unknown machine instruction name '") + InstrName + "'"); lex(); return false; } bool MIParser::parseNamedRegister(Register &Reg) { assert(Token.is(MIToken::NamedRegister) && "Needs NamedRegister token"); StringRef Name = Token.stringValue(); if (PFS.Target.getRegisterByName(Name, Reg)) return error(Twine("unknown register name '") + Name + "'"); return false; } bool MIParser::parseNamedVirtualRegister(VRegInfo *&Info) { assert(Token.is(MIToken::NamedVirtualRegister) && "Expected NamedVReg token"); StringRef Name = Token.stringValue(); // TODO: Check that the VReg name is not the same as a physical register name. // If it is, then print a warning (when warnings are implemented). Info = &PFS.getVRegInfoNamed(Name); return false; } bool MIParser::parseVirtualRegister(VRegInfo *&Info) { if (Token.is(MIToken::NamedVirtualRegister)) return parseNamedVirtualRegister(Info); assert(Token.is(MIToken::VirtualRegister) && "Needs VirtualRegister token"); unsigned ID; if (getUnsigned(ID)) return true; Info = &PFS.getVRegInfo(ID); return false; } bool MIParser::parseRegister(Register &Reg, VRegInfo *&Info) { switch (Token.kind()) { case MIToken::underscore: Reg = 0; return false; case MIToken::NamedRegister: return parseNamedRegister(Reg); case MIToken::NamedVirtualRegister: case MIToken::VirtualRegister: if (parseVirtualRegister(Info)) return true; Reg = Info->VReg; return false; // TODO: Parse other register kinds. default: llvm_unreachable("The current token should be a register"); } } bool MIParser::parseRegisterClassOrBank(VRegInfo &RegInfo) { if (Token.isNot(MIToken::Identifier) && Token.isNot(MIToken::underscore)) return error("expected '_', register class, or register bank name"); StringRef::iterator Loc = Token.location(); StringRef Name = Token.stringValue(); // Was it a register class? const TargetRegisterClass *RC = PFS.Target.getRegClass(Name); if (RC) { lex(); switch (RegInfo.Kind) { case VRegInfo::UNKNOWN: case VRegInfo::NORMAL: RegInfo.Kind = VRegInfo::NORMAL; if (RegInfo.Explicit && RegInfo.D.RC != RC) { const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); return error(Loc, Twine("conflicting register classes, previously: ") + Twine(TRI.getRegClassName(RegInfo.D.RC))); } RegInfo.D.RC = RC; RegInfo.Explicit = true; return false; case VRegInfo::GENERIC: case VRegInfo::REGBANK: return error(Loc, "register class specification on generic register"); } llvm_unreachable("Unexpected register kind"); } // Should be a register bank or a generic register. const RegisterBank *RegBank = nullptr; if (Name != "_") { RegBank = PFS.Target.getRegBank(Name); if (!RegBank) return error(Loc, "expected '_', register class, or register bank name"); } lex(); switch (RegInfo.Kind) { case VRegInfo::UNKNOWN: case VRegInfo::GENERIC: case VRegInfo::REGBANK: RegInfo.Kind = RegBank ? VRegInfo::REGBANK : VRegInfo::GENERIC; if (RegInfo.Explicit && RegInfo.D.RegBank != RegBank) return error(Loc, "conflicting generic register banks"); RegInfo.D.RegBank = RegBank; RegInfo.Explicit = true; return false; case VRegInfo::NORMAL: return error(Loc, "register bank specification on normal register"); } llvm_unreachable("Unexpected register kind"); } bool MIParser::parseRegisterFlag(unsigned &Flags) { const unsigned OldFlags = Flags; switch (Token.kind()) { case MIToken::kw_implicit: Flags |= RegState::Implicit; break; case MIToken::kw_implicit_define: Flags |= RegState::ImplicitDefine; break; case MIToken::kw_def: Flags |= RegState::Define; break; case MIToken::kw_dead: Flags |= RegState::Dead; break; case MIToken::kw_killed: Flags |= RegState::Kill; break; case MIToken::kw_undef: Flags |= RegState::Undef; break; case MIToken::kw_internal: Flags |= RegState::InternalRead; break; case MIToken::kw_early_clobber: Flags |= RegState::EarlyClobber; break; case MIToken::kw_debug_use: Flags |= RegState::Debug; break; case MIToken::kw_renamable: Flags |= RegState::Renamable; break; default: llvm_unreachable("The current token should be a register flag"); } if (OldFlags == Flags) // We know that the same flag is specified more than once when the flags // weren't modified. return error("duplicate '" + Token.stringValue() + "' register flag"); lex(); return false; } bool MIParser::parseSubRegisterIndex(unsigned &SubReg) { assert(Token.is(MIToken::dot)); lex(); if (Token.isNot(MIToken::Identifier)) return error("expected a subregister index after '.'"); auto Name = Token.stringValue(); SubReg = PFS.Target.getSubRegIndex(Name); if (!SubReg) return error(Twine("use of unknown subregister index '") + Name + "'"); lex(); return false; } bool MIParser::parseRegisterTiedDefIndex(unsigned &TiedDefIdx) { if (!consumeIfPresent(MIToken::kw_tied_def)) return true; if (Token.isNot(MIToken::IntegerLiteral)) return error("expected an integer literal after 'tied-def'"); if (getUnsigned(TiedDefIdx)) return true; lex(); if (expectAndConsume(MIToken::rparen)) return true; return false; } bool MIParser::assignRegisterTies(MachineInstr &MI, ArrayRef Operands) { SmallVector, 4> TiedRegisterPairs; for (unsigned I = 0, E = Operands.size(); I != E; ++I) { if (!Operands[I].TiedDefIdx) continue; // The parser ensures that this operand is a register use, so we just have // to check the tied-def operand. unsigned DefIdx = *Operands[I].TiedDefIdx; if (DefIdx >= E) return error(Operands[I].Begin, Twine("use of invalid tied-def operand index '" + Twine(DefIdx) + "'; instruction has only ") + Twine(E) + " operands"); const auto &DefOperand = Operands[DefIdx].Operand; if (!DefOperand.isReg() || !DefOperand.isDef()) // FIXME: add note with the def operand. return error(Operands[I].Begin, Twine("use of invalid tied-def operand index '") + Twine(DefIdx) + "'; the operand #" + Twine(DefIdx) + " isn't a defined register"); // Check that the tied-def operand wasn't tied elsewhere. for (const auto &TiedPair : TiedRegisterPairs) { if (TiedPair.first == DefIdx) return error(Operands[I].Begin, Twine("the tied-def operand #") + Twine(DefIdx) + " is already tied with another register operand"); } TiedRegisterPairs.push_back(std::make_pair(DefIdx, I)); } // FIXME: Verify that for non INLINEASM instructions, the def and use tied // indices must be less than tied max. for (const auto &TiedPair : TiedRegisterPairs) MI.tieOperands(TiedPair.first, TiedPair.second); return false; } bool MIParser::parseRegisterOperand(MachineOperand &Dest, std::optional &TiedDefIdx, bool IsDef) { unsigned Flags = IsDef ? RegState::Define : 0; while (Token.isRegisterFlag()) { if (parseRegisterFlag(Flags)) return true; } if (!Token.isRegister()) return error("expected a register after register flags"); Register Reg; VRegInfo *RegInfo; if (parseRegister(Reg, RegInfo)) return true; lex(); unsigned SubReg = 0; if (Token.is(MIToken::dot)) { if (parseSubRegisterIndex(SubReg)) return true; if (!Reg.isVirtual()) return error("subregister index expects a virtual register"); } if (Token.is(MIToken::colon)) { if (!Reg.isVirtual()) return error("register class specification expects a virtual register"); lex(); if (parseRegisterClassOrBank(*RegInfo)) return true; } MachineRegisterInfo &MRI = MF.getRegInfo(); if ((Flags & RegState::Define) == 0) { if (consumeIfPresent(MIToken::lparen)) { unsigned Idx; if (!parseRegisterTiedDefIndex(Idx)) TiedDefIdx = Idx; else { // Try a redundant low-level type. LLT Ty; if (parseLowLevelType(Token.location(), Ty)) return error("expected tied-def or low-level type after '('"); if (expectAndConsume(MIToken::rparen)) return true; if (MRI.getType(Reg).isValid() && MRI.getType(Reg) != Ty) return error("inconsistent type for generic virtual register"); MRI.setRegClassOrRegBank(Reg, static_cast(nullptr)); MRI.setType(Reg, Ty); } } } else if (consumeIfPresent(MIToken::lparen)) { // Virtual registers may have a tpe with GlobalISel. if (!Reg.isVirtual()) return error("unexpected type on physical register"); LLT Ty; if (parseLowLevelType(Token.location(), Ty)) return true; if (expectAndConsume(MIToken::rparen)) return true; if (MRI.getType(Reg).isValid() && MRI.getType(Reg) != Ty) return error("inconsistent type for generic virtual register"); MRI.setRegClassOrRegBank(Reg, static_cast(nullptr)); MRI.setType(Reg, Ty); } else if (Reg.isVirtual()) { // Generic virtual registers must have a type. // If we end up here this means the type hasn't been specified and // this is bad! if (RegInfo->Kind == VRegInfo::GENERIC || RegInfo->Kind == VRegInfo::REGBANK) return error("generic virtual registers must have a type"); } if (Flags & RegState::Define) { if (Flags & RegState::Kill) return error("cannot have a killed def operand"); } else { if (Flags & RegState::Dead) return error("cannot have a dead use operand"); } Dest = MachineOperand::CreateReg( Reg, Flags & RegState::Define, Flags & RegState::Implicit, Flags & RegState::Kill, Flags & RegState::Dead, Flags & RegState::Undef, Flags & RegState::EarlyClobber, SubReg, Flags & RegState::Debug, Flags & RegState::InternalRead, Flags & RegState::Renamable); return false; } bool MIParser::parseImmediateOperand(MachineOperand &Dest) { assert(Token.is(MIToken::IntegerLiteral)); const APSInt &Int = Token.integerValue(); if (auto SImm = Int.trySExtValue(); Int.isSigned() && SImm.has_value()) Dest = MachineOperand::CreateImm(*SImm); else if (auto UImm = Int.tryZExtValue(); !Int.isSigned() && UImm.has_value()) Dest = MachineOperand::CreateImm(*UImm); else return error("integer literal is too large to be an immediate operand"); lex(); return false; } bool MIParser::parseTargetImmMnemonic(const unsigned OpCode, const unsigned OpIdx, MachineOperand &Dest, const MIRFormatter &MF) { assert(Token.is(MIToken::dot)); auto Loc = Token.location(); // record start position size_t Len = 1; // for "." lex(); // Handle the case that mnemonic starts with number. if (Token.is(MIToken::IntegerLiteral)) { Len += Token.range().size(); lex(); } StringRef Src; if (Token.is(MIToken::comma)) Src = StringRef(Loc, Len); else { assert(Token.is(MIToken::Identifier)); Src = StringRef(Loc, Len + Token.stringValue().size()); } int64_t Val; if (MF.parseImmMnemonic(OpCode, OpIdx, Src, Val, [this](StringRef::iterator Loc, const Twine &Msg) -> bool { return error(Loc, Msg); })) return true; Dest = MachineOperand::CreateImm(Val); if (!Token.is(MIToken::comma)) lex(); return false; } static bool parseIRConstant(StringRef::iterator Loc, StringRef StringValue, PerFunctionMIParsingState &PFS, const Constant *&C, ErrorCallbackType ErrCB) { auto Source = StringValue.str(); // The source has to be null terminated. SMDiagnostic Err; C = parseConstantValue(Source, Err, *PFS.MF.getFunction().getParent(), &PFS.IRSlots); if (!C) return ErrCB(Loc + Err.getColumnNo(), Err.getMessage()); return false; } bool MIParser::parseIRConstant(StringRef::iterator Loc, StringRef StringValue, const Constant *&C) { return ::parseIRConstant( Loc, StringValue, PFS, C, [this](StringRef::iterator Loc, const Twine &Msg) -> bool { return error(Loc, Msg); }); } bool MIParser::parseIRConstant(StringRef::iterator Loc, const Constant *&C) { if (parseIRConstant(Loc, StringRef(Loc, Token.range().end() - Loc), C)) return true; lex(); return false; } // See LLT implementation for bit size limits. static bool verifyScalarSize(uint64_t Size) { return Size != 0 && isUInt<16>(Size); } static bool verifyVectorElementCount(uint64_t NumElts) { return NumElts != 0 && isUInt<16>(NumElts); } static bool verifyAddrSpace(uint64_t AddrSpace) { return isUInt<24>(AddrSpace); } bool MIParser::parseLowLevelType(StringRef::iterator Loc, LLT &Ty) { if (Token.range().front() == 's' || Token.range().front() == 'p') { StringRef SizeStr = Token.range().drop_front(); if (SizeStr.size() == 0 || !llvm::all_of(SizeStr, isdigit)) return error("expected integers after 's'/'p' type character"); } if (Token.range().front() == 's') { auto ScalarSize = APSInt(Token.range().drop_front()).getZExtValue(); if (ScalarSize) { if (!verifyScalarSize(ScalarSize)) return error("invalid size for scalar type"); Ty = LLT::scalar(ScalarSize); } else { Ty = LLT::token(); } lex(); return false; } else if (Token.range().front() == 'p') { const DataLayout &DL = MF.getDataLayout(); uint64_t AS = APSInt(Token.range().drop_front()).getZExtValue(); if (!verifyAddrSpace(AS)) return error("invalid address space number"); Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS)); lex(); return false; } // Now we're looking for a vector. if (Token.isNot(MIToken::less)) return error(Loc, "expected sN, pA, , , , " "or for GlobalISel type"); lex(); bool HasVScale = Token.is(MIToken::Identifier) && Token.stringValue() == "vscale"; if (HasVScale) { lex(); if (Token.isNot(MIToken::Identifier) || Token.stringValue() != "x") return error("expected or "); lex(); } auto GetError = [this, &HasVScale, Loc]() { if (HasVScale) return error( Loc, "expected or for vector type"); return error(Loc, "expected or for vector type"); }; if (Token.isNot(MIToken::IntegerLiteral)) return GetError(); uint64_t NumElements = Token.integerValue().getZExtValue(); if (!verifyVectorElementCount(NumElements)) return error("invalid number of vector elements"); lex(); if (Token.isNot(MIToken::Identifier) || Token.stringValue() != "x") return GetError(); lex(); if (Token.range().front() != 's' && Token.range().front() != 'p') return GetError(); StringRef SizeStr = Token.range().drop_front(); if (SizeStr.size() == 0 || !llvm::all_of(SizeStr, isdigit)) return error("expected integers after 's'/'p' type character"); if (Token.range().front() == 's') { auto ScalarSize = APSInt(Token.range().drop_front()).getZExtValue(); if (!verifyScalarSize(ScalarSize)) return error("invalid size for scalar element in vector"); Ty = LLT::scalar(ScalarSize); } else if (Token.range().front() == 'p') { const DataLayout &DL = MF.getDataLayout(); uint64_t AS = APSInt(Token.range().drop_front()).getZExtValue(); if (!verifyAddrSpace(AS)) return error("invalid address space number"); Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS)); } else return GetError(); lex(); if (Token.isNot(MIToken::greater)) return GetError(); lex(); Ty = LLT::vector(ElementCount::get(NumElements, HasVScale), Ty); return false; } bool MIParser::parseTypedImmediateOperand(MachineOperand &Dest) { assert(Token.is(MIToken::Identifier)); StringRef TypeStr = Token.range(); if (TypeStr.front() != 'i' && TypeStr.front() != 's' && TypeStr.front() != 'p') return error( "a typed immediate operand should start with one of 'i', 's', or 'p'"); StringRef SizeStr = Token.range().drop_front(); if (SizeStr.size() == 0 || !llvm::all_of(SizeStr, isdigit)) return error("expected integers after 'i'/'s'/'p' type character"); auto Loc = Token.location(); lex(); if (Token.isNot(MIToken::IntegerLiteral)) { if (Token.isNot(MIToken::Identifier) || !(Token.range() == "true" || Token.range() == "false")) return error("expected an integer literal"); } const Constant *C = nullptr; if (parseIRConstant(Loc, C)) return true; Dest = MachineOperand::CreateCImm(cast(C)); return false; } bool MIParser::parseFPImmediateOperand(MachineOperand &Dest) { auto Loc = Token.location(); lex(); if (Token.isNot(MIToken::FloatingPointLiteral) && Token.isNot(MIToken::HexLiteral)) return error("expected a floating point literal"); const Constant *C = nullptr; if (parseIRConstant(Loc, C)) return true; Dest = MachineOperand::CreateFPImm(cast(C)); return false; } static bool getHexUint(const MIToken &Token, APInt &Result) { assert(Token.is(MIToken::HexLiteral)); StringRef S = Token.range(); assert(S[0] == '0' && tolower(S[1]) == 'x'); // This could be a floating point literal with a special prefix. if (!isxdigit(S[2])) return true; StringRef V = S.substr(2); APInt A(V.size()*4, V, 16); // If A is 0, then A.getActiveBits() is 0. This isn't a valid bitwidth. Make // sure it isn't the case before constructing result. unsigned NumBits = (A == 0) ? 32 : A.getActiveBits(); Result = APInt(NumBits, ArrayRef(A.getRawData(), A.getNumWords())); return false; } static bool getUnsigned(const MIToken &Token, unsigned &Result, ErrorCallbackType ErrCB) { if (Token.hasIntegerValue()) { const uint64_t Limit = uint64_t(std::numeric_limits::max()) + 1; uint64_t Val64 = Token.integerValue().getLimitedValue(Limit); if (Val64 == Limit) return ErrCB(Token.location(), "expected 32-bit integer (too large)"); Result = Val64; return false; } if (Token.is(MIToken::HexLiteral)) { APInt A; if (getHexUint(Token, A)) return true; if (A.getBitWidth() > 32) return ErrCB(Token.location(), "expected 32-bit integer (too large)"); Result = A.getZExtValue(); return false; } return true; } bool MIParser::getUnsigned(unsigned &Result) { return ::getUnsigned( Token, Result, [this](StringRef::iterator Loc, const Twine &Msg) -> bool { return error(Loc, Msg); }); } bool MIParser::parseMBBReference(MachineBasicBlock *&MBB) { assert(Token.is(MIToken::MachineBasicBlock) || Token.is(MIToken::MachineBasicBlockLabel)); unsigned Number; if (getUnsigned(Number)) return true; auto MBBInfo = PFS.MBBSlots.find(Number); if (MBBInfo == PFS.MBBSlots.end()) return error(Twine("use of undefined machine basic block #") + Twine(Number)); MBB = MBBInfo->second; // TODO: Only parse the name if it's a MachineBasicBlockLabel. Deprecate once // we drop the from the bb.. format. if (!Token.stringValue().empty() && Token.stringValue() != MBB->getName()) return error(Twine("the name of machine basic block #") + Twine(Number) + " isn't '" + Token.stringValue() + "'"); return false; } bool MIParser::parseMBBOperand(MachineOperand &Dest) { MachineBasicBlock *MBB; if (parseMBBReference(MBB)) return true; Dest = MachineOperand::CreateMBB(MBB); lex(); return false; } bool MIParser::parseStackFrameIndex(int &FI) { assert(Token.is(MIToken::StackObject)); unsigned ID; if (getUnsigned(ID)) return true; auto ObjectInfo = PFS.StackObjectSlots.find(ID); if (ObjectInfo == PFS.StackObjectSlots.end()) return error(Twine("use of undefined stack object '%stack.") + Twine(ID) + "'"); StringRef Name; if (const auto *Alloca = MF.getFrameInfo().getObjectAllocation(ObjectInfo->second)) Name = Alloca->getName(); if (!Token.stringValue().empty() && Token.stringValue() != Name) return error(Twine("the name of the stack object '%stack.") + Twine(ID) + "' isn't '" + Token.stringValue() + "'"); lex(); FI = ObjectInfo->second; return false; } bool MIParser::parseStackObjectOperand(MachineOperand &Dest) { int FI; if (parseStackFrameIndex(FI)) return true; Dest = MachineOperand::CreateFI(FI); return false; } bool MIParser::parseFixedStackFrameIndex(int &FI) { assert(Token.is(MIToken::FixedStackObject)); unsigned ID; if (getUnsigned(ID)) return true; auto ObjectInfo = PFS.FixedStackObjectSlots.find(ID); if (ObjectInfo == PFS.FixedStackObjectSlots.end()) return error(Twine("use of undefined fixed stack object '%fixed-stack.") + Twine(ID) + "'"); lex(); FI = ObjectInfo->second; return false; } bool MIParser::parseFixedStackObjectOperand(MachineOperand &Dest) { int FI; if (parseFixedStackFrameIndex(FI)) return true; Dest = MachineOperand::CreateFI(FI); return false; } static bool parseGlobalValue(const MIToken &Token, PerFunctionMIParsingState &PFS, GlobalValue *&GV, ErrorCallbackType ErrCB) { switch (Token.kind()) { case MIToken::NamedGlobalValue: { const Module *M = PFS.MF.getFunction().getParent(); GV = M->getNamedValue(Token.stringValue()); if (!GV) return ErrCB(Token.location(), Twine("use of undefined global value '") + Token.range() + "'"); break; } case MIToken::GlobalValue: { unsigned GVIdx; if (getUnsigned(Token, GVIdx, ErrCB)) return true; GV = PFS.IRSlots.GlobalValues.get(GVIdx); if (!GV) return ErrCB(Token.location(), Twine("use of undefined global value '@") + Twine(GVIdx) + "'"); break; } default: llvm_unreachable("The current token should be a global value"); } return false; } bool MIParser::parseGlobalValue(GlobalValue *&GV) { return ::parseGlobalValue( Token, PFS, GV, [this](StringRef::iterator Loc, const Twine &Msg) -> bool { return error(Loc, Msg); }); } bool MIParser::parseGlobalAddressOperand(MachineOperand &Dest) { GlobalValue *GV = nullptr; if (parseGlobalValue(GV)) return true; lex(); Dest = MachineOperand::CreateGA(GV, /*Offset=*/0); if (parseOperandsOffset(Dest)) return true; return false; } bool MIParser::parseConstantPoolIndexOperand(MachineOperand &Dest) { assert(Token.is(MIToken::ConstantPoolItem)); unsigned ID; if (getUnsigned(ID)) return true; auto ConstantInfo = PFS.ConstantPoolSlots.find(ID); if (ConstantInfo == PFS.ConstantPoolSlots.end()) return error("use of undefined constant '%const." + Twine(ID) + "'"); lex(); Dest = MachineOperand::CreateCPI(ID, /*Offset=*/0); if (parseOperandsOffset(Dest)) return true; return false; } bool MIParser::parseJumpTableIndexOperand(MachineOperand &Dest) { assert(Token.is(MIToken::JumpTableIndex)); unsigned ID; if (getUnsigned(ID)) return true; auto JumpTableEntryInfo = PFS.JumpTableSlots.find(ID); if (JumpTableEntryInfo == PFS.JumpTableSlots.end()) return error("use of undefined jump table '%jump-table." + Twine(ID) + "'"); lex(); Dest = MachineOperand::CreateJTI(JumpTableEntryInfo->second); return false; } bool MIParser::parseExternalSymbolOperand(MachineOperand &Dest) { assert(Token.is(MIToken::ExternalSymbol)); const char *Symbol = MF.createExternalSymbolName(Token.stringValue()); lex(); Dest = MachineOperand::CreateES(Symbol); if (parseOperandsOffset(Dest)) return true; return false; } bool MIParser::parseMCSymbolOperand(MachineOperand &Dest) { assert(Token.is(MIToken::MCSymbol)); MCSymbol *Symbol = getOrCreateMCSymbol(Token.stringValue()); lex(); Dest = MachineOperand::CreateMCSymbol(Symbol); if (parseOperandsOffset(Dest)) return true; return false; } bool MIParser::parseSubRegisterIndexOperand(MachineOperand &Dest) { assert(Token.is(MIToken::SubRegisterIndex)); StringRef Name = Token.stringValue(); unsigned SubRegIndex = PFS.Target.getSubRegIndex(Token.stringValue()); if (SubRegIndex == 0) return error(Twine("unknown subregister index '") + Name + "'"); lex(); Dest = MachineOperand::CreateImm(SubRegIndex); return false; } bool MIParser::parseMDNode(MDNode *&Node) { assert(Token.is(MIToken::exclaim)); auto Loc = Token.location(); lex(); if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected metadata id after '!'"); unsigned ID; if (getUnsigned(ID)) return true; auto NodeInfo = PFS.IRSlots.MetadataNodes.find(ID); if (NodeInfo == PFS.IRSlots.MetadataNodes.end()) { NodeInfo = PFS.MachineMetadataNodes.find(ID); if (NodeInfo == PFS.MachineMetadataNodes.end()) return error(Loc, "use of undefined metadata '!" + Twine(ID) + "'"); } lex(); Node = NodeInfo->second.get(); return false; } bool MIParser::parseDIExpression(MDNode *&Expr) { unsigned Read; Expr = llvm::parseDIExpressionBodyAtBeginning( CurrentSource, Read, Error, *PFS.MF.getFunction().getParent(), &PFS.IRSlots); CurrentSource = CurrentSource.slice(Read, StringRef::npos); lex(); if (!Expr) return error(Error.getMessage()); return false; } bool MIParser::parseDILocation(MDNode *&Loc) { assert(Token.is(MIToken::md_dilocation)); lex(); bool HaveLine = false; unsigned Line = 0; unsigned Column = 0; MDNode *Scope = nullptr; MDNode *InlinedAt = nullptr; bool ImplicitCode = false; if (expectAndConsume(MIToken::lparen)) return true; if (Token.isNot(MIToken::rparen)) { do { if (Token.is(MIToken::Identifier)) { if (Token.stringValue() == "line") { lex(); if (expectAndConsume(MIToken::colon)) return true; if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected unsigned integer"); Line = Token.integerValue().getZExtValue(); HaveLine = true; lex(); continue; } if (Token.stringValue() == "column") { lex(); if (expectAndConsume(MIToken::colon)) return true; if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected unsigned integer"); Column = Token.integerValue().getZExtValue(); lex(); continue; } if (Token.stringValue() == "scope") { lex(); if (expectAndConsume(MIToken::colon)) return true; if (parseMDNode(Scope)) return error("expected metadata node"); if (!isa(Scope)) return error("expected DIScope node"); continue; } if (Token.stringValue() == "inlinedAt") { lex(); if (expectAndConsume(MIToken::colon)) return true; if (Token.is(MIToken::exclaim)) { if (parseMDNode(InlinedAt)) return true; } else if (Token.is(MIToken::md_dilocation)) { if (parseDILocation(InlinedAt)) return true; } else return error("expected metadata node"); if (!isa(InlinedAt)) return error("expected DILocation node"); continue; } if (Token.stringValue() == "isImplicitCode") { lex(); if (expectAndConsume(MIToken::colon)) return true; if (!Token.is(MIToken::Identifier)) return error("expected true/false"); // As far as I can see, we don't have any existing need for parsing // true/false in MIR yet. Do it ad-hoc until there's something else // that needs it. if (Token.stringValue() == "true") ImplicitCode = true; else if (Token.stringValue() == "false") ImplicitCode = false; else return error("expected true/false"); lex(); continue; } } return error(Twine("invalid DILocation argument '") + Token.stringValue() + "'"); } while (consumeIfPresent(MIToken::comma)); } if (expectAndConsume(MIToken::rparen)) return true; if (!HaveLine) return error("DILocation requires line number"); if (!Scope) return error("DILocation requires a scope"); Loc = DILocation::get(MF.getFunction().getContext(), Line, Column, Scope, InlinedAt, ImplicitCode); return false; } bool MIParser::parseMetadataOperand(MachineOperand &Dest) { MDNode *Node = nullptr; if (Token.is(MIToken::exclaim)) { if (parseMDNode(Node)) return true; } else if (Token.is(MIToken::md_diexpr)) { if (parseDIExpression(Node)) return true; } Dest = MachineOperand::CreateMetadata(Node); return false; } bool MIParser::parseCFIOffset(int &Offset) { if (Token.isNot(MIToken::IntegerLiteral)) return error("expected a cfi offset"); if (Token.integerValue().getSignificantBits() > 32) return error("expected a 32 bit integer (the cfi offset is too large)"); Offset = (int)Token.integerValue().getExtValue(); lex(); return false; } bool MIParser::parseCFIRegister(Register &Reg) { if (Token.isNot(MIToken::NamedRegister)) return error("expected a cfi register"); Register LLVMReg; if (parseNamedRegister(LLVMReg)) return true; const auto *TRI = MF.getSubtarget().getRegisterInfo(); assert(TRI && "Expected target register info"); int DwarfReg = TRI->getDwarfRegNum(LLVMReg, true); if (DwarfReg < 0) return error("invalid DWARF register"); Reg = (unsigned)DwarfReg; lex(); return false; } bool MIParser::parseCFIAddressSpace(unsigned &AddressSpace) { if (Token.isNot(MIToken::IntegerLiteral)) return error("expected a cfi address space literal"); if (Token.integerValue().isSigned()) return error("expected an unsigned integer (cfi address space)"); AddressSpace = Token.integerValue().getZExtValue(); lex(); return false; } bool MIParser::parseCFIEscapeValues(std::string &Values) { do { if (Token.isNot(MIToken::HexLiteral)) return error("expected a hexadecimal literal"); unsigned Value; if (getUnsigned(Value)) return true; if (Value > UINT8_MAX) return error("expected a 8-bit integer (too large)"); Values.push_back(static_cast(Value)); lex(); } while (consumeIfPresent(MIToken::comma)); return false; } bool MIParser::parseCFIOperand(MachineOperand &Dest) { auto Kind = Token.kind(); lex(); int Offset; Register Reg; unsigned AddressSpace; unsigned CFIIndex; switch (Kind) { case MIToken::kw_cfi_same_value: if (parseCFIRegister(Reg)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createSameValue(nullptr, Reg)); break; case MIToken::kw_cfi_offset: if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) || parseCFIOffset(Offset)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(nullptr, Reg, Offset)); break; case MIToken::kw_cfi_rel_offset: if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) || parseCFIOffset(Offset)) return true; CFIIndex = MF.addFrameInst( MCCFIInstruction::createRelOffset(nullptr, Reg, Offset)); break; case MIToken::kw_cfi_def_cfa_register: if (parseCFIRegister(Reg)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, Reg)); break; case MIToken::kw_cfi_def_cfa_offset: if (parseCFIOffset(Offset)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, Offset)); break; case MIToken::kw_cfi_adjust_cfa_offset: if (parseCFIOffset(Offset)) return true; CFIIndex = MF.addFrameInst( MCCFIInstruction::createAdjustCfaOffset(nullptr, Offset)); break; case MIToken::kw_cfi_def_cfa: if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) || parseCFIOffset(Offset)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(nullptr, Reg, Offset)); break; case MIToken::kw_cfi_llvm_def_aspace_cfa: if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) || parseCFIOffset(Offset) || expectAndConsume(MIToken::comma) || parseCFIAddressSpace(AddressSpace)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMDefAspaceCfa( nullptr, Reg, Offset, AddressSpace, SMLoc())); break; case MIToken::kw_cfi_remember_state: CFIIndex = MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr)); break; case MIToken::kw_cfi_restore: if (parseCFIRegister(Reg)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg)); break; case MIToken::kw_cfi_restore_state: CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr)); break; case MIToken::kw_cfi_undefined: if (parseCFIRegister(Reg)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createUndefined(nullptr, Reg)); break; case MIToken::kw_cfi_register: { Register Reg2; if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) || parseCFIRegister(Reg2)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createRegister(nullptr, Reg, Reg2)); break; } case MIToken::kw_cfi_window_save: CFIIndex = MF.addFrameInst(MCCFIInstruction::createWindowSave(nullptr)); break; case MIToken::kw_cfi_aarch64_negate_ra_sign_state: CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr)); break; case MIToken::kw_cfi_escape: { std::string Values; if (parseCFIEscapeValues(Values)) return true; CFIIndex = MF.addFrameInst(MCCFIInstruction::createEscape(nullptr, Values)); break; } default: // TODO: Parse the other CFI operands. llvm_unreachable("The current token should be a cfi operand"); } Dest = MachineOperand::CreateCFIIndex(CFIIndex); return false; } bool MIParser::parseIRBlock(BasicBlock *&BB, const Function &F) { switch (Token.kind()) { case MIToken::NamedIRBlock: { BB = dyn_cast_or_null( F.getValueSymbolTable()->lookup(Token.stringValue())); if (!BB) return error(Twine("use of undefined IR block '") + Token.range() + "'"); break; } case MIToken::IRBlock: { unsigned SlotNumber = 0; if (getUnsigned(SlotNumber)) return true; BB = const_cast(getIRBlock(SlotNumber, F)); if (!BB) return error(Twine("use of undefined IR block '%ir-block.") + Twine(SlotNumber) + "'"); break; } default: llvm_unreachable("The current token should be an IR block reference"); } return false; } bool MIParser::parseBlockAddressOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_blockaddress)); lex(); if (expectAndConsume(MIToken::lparen)) return true; if (Token.isNot(MIToken::GlobalValue) && Token.isNot(MIToken::NamedGlobalValue)) return error("expected a global value"); GlobalValue *GV = nullptr; if (parseGlobalValue(GV)) return true; auto *F = dyn_cast(GV); if (!F) return error("expected an IR function reference"); lex(); if (expectAndConsume(MIToken::comma)) return true; BasicBlock *BB = nullptr; if (Token.isNot(MIToken::IRBlock) && Token.isNot(MIToken::NamedIRBlock)) return error("expected an IR block reference"); if (parseIRBlock(BB, *F)) return true; lex(); if (expectAndConsume(MIToken::rparen)) return true; Dest = MachineOperand::CreateBA(BlockAddress::get(F, BB), /*Offset=*/0); if (parseOperandsOffset(Dest)) return true; return false; } bool MIParser::parseIntrinsicOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_intrinsic)); lex(); if (expectAndConsume(MIToken::lparen)) return error("expected syntax intrinsic(@llvm.whatever)"); if (Token.isNot(MIToken::NamedGlobalValue)) return error("expected syntax intrinsic(@llvm.whatever)"); std::string Name = std::string(Token.stringValue()); lex(); if (expectAndConsume(MIToken::rparen)) return error("expected ')' to terminate intrinsic name"); // Find out what intrinsic we're dealing with, first try the global namespace // and then the target's private intrinsics if that fails. const TargetIntrinsicInfo *TII = MF.getTarget().getIntrinsicInfo(); Intrinsic::ID ID = Function::lookupIntrinsicID(Name); if (ID == Intrinsic::not_intrinsic && TII) ID = static_cast(TII->lookupName(Name)); if (ID == Intrinsic::not_intrinsic) return error("unknown intrinsic name"); Dest = MachineOperand::CreateIntrinsicID(ID); return false; } bool MIParser::parsePredicateOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_intpred) || Token.is(MIToken::kw_floatpred)); bool IsFloat = Token.is(MIToken::kw_floatpred); lex(); if (expectAndConsume(MIToken::lparen)) return error("expected syntax intpred(whatever) or floatpred(whatever"); if (Token.isNot(MIToken::Identifier)) return error("whatever"); CmpInst::Predicate Pred; if (IsFloat) { Pred = StringSwitch(Token.stringValue()) .Case("false", CmpInst::FCMP_FALSE) .Case("oeq", CmpInst::FCMP_OEQ) .Case("ogt", CmpInst::FCMP_OGT) .Case("oge", CmpInst::FCMP_OGE) .Case("olt", CmpInst::FCMP_OLT) .Case("ole", CmpInst::FCMP_OLE) .Case("one", CmpInst::FCMP_ONE) .Case("ord", CmpInst::FCMP_ORD) .Case("uno", CmpInst::FCMP_UNO) .Case("ueq", CmpInst::FCMP_UEQ) .Case("ugt", CmpInst::FCMP_UGT) .Case("uge", CmpInst::FCMP_UGE) .Case("ult", CmpInst::FCMP_ULT) .Case("ule", CmpInst::FCMP_ULE) .Case("une", CmpInst::FCMP_UNE) .Case("true", CmpInst::FCMP_TRUE) .Default(CmpInst::BAD_FCMP_PREDICATE); if (!CmpInst::isFPPredicate(Pred)) return error("invalid floating-point predicate"); } else { Pred = StringSwitch(Token.stringValue()) .Case("eq", CmpInst::ICMP_EQ) .Case("ne", CmpInst::ICMP_NE) .Case("sgt", CmpInst::ICMP_SGT) .Case("sge", CmpInst::ICMP_SGE) .Case("slt", CmpInst::ICMP_SLT) .Case("sle", CmpInst::ICMP_SLE) .Case("ugt", CmpInst::ICMP_UGT) .Case("uge", CmpInst::ICMP_UGE) .Case("ult", CmpInst::ICMP_ULT) .Case("ule", CmpInst::ICMP_ULE) .Default(CmpInst::BAD_ICMP_PREDICATE); if (!CmpInst::isIntPredicate(Pred)) return error("invalid integer predicate"); } lex(); Dest = MachineOperand::CreatePredicate(Pred); if (expectAndConsume(MIToken::rparen)) return error("predicate should be terminated by ')'."); return false; } bool MIParser::parseShuffleMaskOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_shufflemask)); lex(); if (expectAndConsume(MIToken::lparen)) return error("expected syntax shufflemask(, ...)"); SmallVector ShufMask; do { if (Token.is(MIToken::kw_undef)) { ShufMask.push_back(-1); } else if (Token.is(MIToken::IntegerLiteral)) { const APSInt &Int = Token.integerValue(); ShufMask.push_back(Int.getExtValue()); } else return error("expected integer constant"); lex(); } while (consumeIfPresent(MIToken::comma)); if (expectAndConsume(MIToken::rparen)) return error("shufflemask should be terminated by ')'."); ArrayRef MaskAlloc = MF.allocateShuffleMask(ShufMask); Dest = MachineOperand::CreateShuffleMask(MaskAlloc); return false; } bool MIParser::parseDbgInstrRefOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_dbg_instr_ref)); lex(); if (expectAndConsume(MIToken::lparen)) return error("expected syntax dbg-instr-ref(, )"); if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isNegative()) return error("expected unsigned integer for instruction index"); uint64_t InstrIdx = Token.integerValue().getZExtValue(); assert(InstrIdx <= std::numeric_limits::max() && "Instruction reference's instruction index is too large"); lex(); if (expectAndConsume(MIToken::comma)) return error("expected syntax dbg-instr-ref(, )"); if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isNegative()) return error("expected unsigned integer for operand index"); uint64_t OpIdx = Token.integerValue().getZExtValue(); assert(OpIdx <= std::numeric_limits::max() && "Instruction reference's operand index is too large"); lex(); if (expectAndConsume(MIToken::rparen)) return error("expected syntax dbg-instr-ref(, )"); Dest = MachineOperand::CreateDbgInstrRef(InstrIdx, OpIdx); return false; } bool MIParser::parseTargetIndexOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_target_index)); lex(); if (expectAndConsume(MIToken::lparen)) return true; if (Token.isNot(MIToken::Identifier)) return error("expected the name of the target index"); int Index = 0; if (PFS.Target.getTargetIndex(Token.stringValue(), Index)) return error("use of undefined target index '" + Token.stringValue() + "'"); lex(); if (expectAndConsume(MIToken::rparen)) return true; Dest = MachineOperand::CreateTargetIndex(unsigned(Index), /*Offset=*/0); if (parseOperandsOffset(Dest)) return true; return false; } bool MIParser::parseCustomRegisterMaskOperand(MachineOperand &Dest) { assert(Token.stringValue() == "CustomRegMask" && "Expected a custom RegMask"); lex(); if (expectAndConsume(MIToken::lparen)) return true; uint32_t *Mask = MF.allocateRegMask(); do { if (Token.isNot(MIToken::rparen)) { if (Token.isNot(MIToken::NamedRegister)) return error("expected a named register"); Register Reg; if (parseNamedRegister(Reg)) return true; lex(); Mask[Reg / 32] |= 1U << (Reg % 32); } // TODO: Report an error if the same register is used more than once. } while (consumeIfPresent(MIToken::comma)); if (expectAndConsume(MIToken::rparen)) return true; Dest = MachineOperand::CreateRegMask(Mask); return false; } bool MIParser::parseLiveoutRegisterMaskOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_liveout)); uint32_t *Mask = MF.allocateRegMask(); lex(); if (expectAndConsume(MIToken::lparen)) return true; while (true) { if (Token.isNot(MIToken::NamedRegister)) return error("expected a named register"); Register Reg; if (parseNamedRegister(Reg)) return true; lex(); Mask[Reg / 32] |= 1U << (Reg % 32); // TODO: Report an error if the same register is used more than once. if (Token.isNot(MIToken::comma)) break; lex(); } if (expectAndConsume(MIToken::rparen)) return true; Dest = MachineOperand::CreateRegLiveOut(Mask); return false; } bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx, MachineOperand &Dest, std::optional &TiedDefIdx) { switch (Token.kind()) { case MIToken::kw_implicit: case MIToken::kw_implicit_define: case MIToken::kw_def: case MIToken::kw_dead: case MIToken::kw_killed: case MIToken::kw_undef: case MIToken::kw_internal: case MIToken::kw_early_clobber: case MIToken::kw_debug_use: case MIToken::kw_renamable: case MIToken::underscore: case MIToken::NamedRegister: case MIToken::VirtualRegister: case MIToken::NamedVirtualRegister: return parseRegisterOperand(Dest, TiedDefIdx); case MIToken::IntegerLiteral: return parseImmediateOperand(Dest); case MIToken::kw_half: case MIToken::kw_bfloat: case MIToken::kw_float: case MIToken::kw_double: case MIToken::kw_x86_fp80: case MIToken::kw_fp128: case MIToken::kw_ppc_fp128: return parseFPImmediateOperand(Dest); case MIToken::MachineBasicBlock: return parseMBBOperand(Dest); case MIToken::StackObject: return parseStackObjectOperand(Dest); case MIToken::FixedStackObject: return parseFixedStackObjectOperand(Dest); case MIToken::GlobalValue: case MIToken::NamedGlobalValue: return parseGlobalAddressOperand(Dest); case MIToken::ConstantPoolItem: return parseConstantPoolIndexOperand(Dest); case MIToken::JumpTableIndex: return parseJumpTableIndexOperand(Dest); case MIToken::ExternalSymbol: return parseExternalSymbolOperand(Dest); case MIToken::MCSymbol: return parseMCSymbolOperand(Dest); case MIToken::SubRegisterIndex: return parseSubRegisterIndexOperand(Dest); case MIToken::md_diexpr: case MIToken::exclaim: return parseMetadataOperand(Dest); case MIToken::kw_cfi_same_value: case MIToken::kw_cfi_offset: case MIToken::kw_cfi_rel_offset: case MIToken::kw_cfi_def_cfa_register: case MIToken::kw_cfi_def_cfa_offset: case MIToken::kw_cfi_adjust_cfa_offset: case MIToken::kw_cfi_escape: case MIToken::kw_cfi_def_cfa: case MIToken::kw_cfi_llvm_def_aspace_cfa: case MIToken::kw_cfi_register: case MIToken::kw_cfi_remember_state: case MIToken::kw_cfi_restore: case MIToken::kw_cfi_restore_state: case MIToken::kw_cfi_undefined: case MIToken::kw_cfi_window_save: case MIToken::kw_cfi_aarch64_negate_ra_sign_state: return parseCFIOperand(Dest); case MIToken::kw_blockaddress: return parseBlockAddressOperand(Dest); case MIToken::kw_intrinsic: return parseIntrinsicOperand(Dest); case MIToken::kw_target_index: return parseTargetIndexOperand(Dest); case MIToken::kw_liveout: return parseLiveoutRegisterMaskOperand(Dest); case MIToken::kw_floatpred: case MIToken::kw_intpred: return parsePredicateOperand(Dest); case MIToken::kw_shufflemask: return parseShuffleMaskOperand(Dest); case MIToken::kw_dbg_instr_ref: return parseDbgInstrRefOperand(Dest); case MIToken::Error: return true; case MIToken::Identifier: if (const auto *RegMask = PFS.Target.getRegMask(Token.stringValue())) { Dest = MachineOperand::CreateRegMask(RegMask); lex(); break; } else if (Token.stringValue() == "CustomRegMask") { return parseCustomRegisterMaskOperand(Dest); } else return parseTypedImmediateOperand(Dest); case MIToken::dot: { const auto *TII = MF.getSubtarget().getInstrInfo(); if (const auto *Formatter = TII->getMIRFormatter()) { return parseTargetImmMnemonic(OpCode, OpIdx, Dest, *Formatter); } [[fallthrough]]; } default: // FIXME: Parse the MCSymbol machine operand. return error("expected a machine operand"); } return false; } bool MIParser::parseMachineOperandAndTargetFlags( const unsigned OpCode, const unsigned OpIdx, MachineOperand &Dest, std::optional &TiedDefIdx) { unsigned TF = 0; bool HasTargetFlags = false; if (Token.is(MIToken::kw_target_flags)) { HasTargetFlags = true; lex(); if (expectAndConsume(MIToken::lparen)) return true; if (Token.isNot(MIToken::Identifier)) return error("expected the name of the target flag"); if (PFS.Target.getDirectTargetFlag(Token.stringValue(), TF)) { if (PFS.Target.getBitmaskTargetFlag(Token.stringValue(), TF)) return error("use of undefined target flag '" + Token.stringValue() + "'"); } lex(); while (Token.is(MIToken::comma)) { lex(); if (Token.isNot(MIToken::Identifier)) return error("expected the name of the target flag"); unsigned BitFlag = 0; if (PFS.Target.getBitmaskTargetFlag(Token.stringValue(), BitFlag)) return error("use of undefined target flag '" + Token.stringValue() + "'"); // TODO: Report an error when using a duplicate bit target flag. TF |= BitFlag; lex(); } if (expectAndConsume(MIToken::rparen)) return true; } auto Loc = Token.location(); if (parseMachineOperand(OpCode, OpIdx, Dest, TiedDefIdx)) return true; if (!HasTargetFlags) return false; if (Dest.isReg()) return error(Loc, "register operands can't have target flags"); Dest.setTargetFlags(TF); return false; } bool MIParser::parseOffset(int64_t &Offset) { if (Token.isNot(MIToken::plus) && Token.isNot(MIToken::minus)) return false; StringRef Sign = Token.range(); bool IsNegative = Token.is(MIToken::minus); lex(); if (Token.isNot(MIToken::IntegerLiteral)) return error("expected an integer literal after '" + Sign + "'"); if (Token.integerValue().getSignificantBits() > 64) return error("expected 64-bit integer (too large)"); Offset = Token.integerValue().getExtValue(); if (IsNegative) Offset = -Offset; lex(); return false; } bool MIParser::parseIRBlockAddressTaken(BasicBlock *&BB) { assert(Token.is(MIToken::kw_ir_block_address_taken)); lex(); if (Token.isNot(MIToken::IRBlock) && Token.isNot(MIToken::NamedIRBlock)) return error("expected basic block after 'ir_block_address_taken'"); if (parseIRBlock(BB, MF.getFunction())) return true; lex(); return false; } bool MIParser::parseAlignment(uint64_t &Alignment) { assert(Token.is(MIToken::kw_align) || Token.is(MIToken::kw_basealign)); lex(); if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected an integer literal after 'align'"); if (getUint64(Alignment)) return true; lex(); if (!isPowerOf2_64(Alignment)) return error("expected a power-of-2 literal after 'align'"); return false; } bool MIParser::parseAddrspace(unsigned &Addrspace) { assert(Token.is(MIToken::kw_addrspace)); lex(); if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned()) return error("expected an integer literal after 'addrspace'"); if (getUnsigned(Addrspace)) return true; lex(); return false; } bool MIParser::parseOperandsOffset(MachineOperand &Op) { int64_t Offset = 0; if (parseOffset(Offset)) return true; Op.setOffset(Offset); return false; } static bool parseIRValue(const MIToken &Token, PerFunctionMIParsingState &PFS, const Value *&V, ErrorCallbackType ErrCB) { switch (Token.kind()) { case MIToken::NamedIRValue: { V = PFS.MF.getFunction().getValueSymbolTable()->lookup(Token.stringValue()); break; } case MIToken::IRValue: { unsigned SlotNumber = 0; if (getUnsigned(Token, SlotNumber, ErrCB)) return true; V = PFS.getIRValue(SlotNumber); break; } case MIToken::NamedGlobalValue: case MIToken::GlobalValue: { GlobalValue *GV = nullptr; if (parseGlobalValue(Token, PFS, GV, ErrCB)) return true; V = GV; break; } case MIToken::QuotedIRValue: { const Constant *C = nullptr; if (parseIRConstant(Token.location(), Token.stringValue(), PFS, C, ErrCB)) return true; V = C; break; } case MIToken::kw_unknown_address: V = nullptr; return false; default: llvm_unreachable("The current token should be an IR block reference"); } if (!V) return ErrCB(Token.location(), Twine("use of undefined IR value '") + Token.range() + "'"); return false; } bool MIParser::parseIRValue(const Value *&V) { return ::parseIRValue( Token, PFS, V, [this](StringRef::iterator Loc, const Twine &Msg) -> bool { return error(Loc, Msg); }); } bool MIParser::getUint64(uint64_t &Result) { if (Token.hasIntegerValue()) { if (Token.integerValue().getActiveBits() > 64) return error("expected 64-bit integer (too large)"); Result = Token.integerValue().getZExtValue(); return false; } if (Token.is(MIToken::HexLiteral)) { APInt A; if (getHexUint(A)) return true; if (A.getBitWidth() > 64) return error("expected 64-bit integer (too large)"); Result = A.getZExtValue(); return false; } return true; } bool MIParser::getHexUint(APInt &Result) { return ::getHexUint(Token, Result); } bool MIParser::parseMemoryOperandFlag(MachineMemOperand::Flags &Flags) { const auto OldFlags = Flags; switch (Token.kind()) { case MIToken::kw_volatile: Flags |= MachineMemOperand::MOVolatile; break; case MIToken::kw_non_temporal: Flags |= MachineMemOperand::MONonTemporal; break; case MIToken::kw_dereferenceable: Flags |= MachineMemOperand::MODereferenceable; break; case MIToken::kw_invariant: Flags |= MachineMemOperand::MOInvariant; break; case MIToken::StringConstant: { MachineMemOperand::Flags TF; if (PFS.Target.getMMOTargetFlag(Token.stringValue(), TF)) return error("use of undefined target MMO flag '" + Token.stringValue() + "'"); Flags |= TF; break; } default: llvm_unreachable("The current token should be a memory operand flag"); } if (OldFlags == Flags) // We know that the same flag is specified more than once when the flags // weren't modified. return error("duplicate '" + Token.stringValue() + "' memory operand flag"); lex(); return false; } bool MIParser::parseMemoryPseudoSourceValue(const PseudoSourceValue *&PSV) { switch (Token.kind()) { case MIToken::kw_stack: PSV = MF.getPSVManager().getStack(); break; case MIToken::kw_got: PSV = MF.getPSVManager().getGOT(); break; case MIToken::kw_jump_table: PSV = MF.getPSVManager().getJumpTable(); break; case MIToken::kw_constant_pool: PSV = MF.getPSVManager().getConstantPool(); break; case MIToken::FixedStackObject: { int FI; if (parseFixedStackFrameIndex(FI)) return true; PSV = MF.getPSVManager().getFixedStack(FI); // The token was already consumed, so use return here instead of break. return false; } case MIToken::StackObject: { int FI; if (parseStackFrameIndex(FI)) return true; PSV = MF.getPSVManager().getFixedStack(FI); // The token was already consumed, so use return here instead of break. return false; } case MIToken::kw_call_entry: lex(); switch (Token.kind()) { case MIToken::GlobalValue: case MIToken::NamedGlobalValue: { GlobalValue *GV = nullptr; if (parseGlobalValue(GV)) return true; PSV = MF.getPSVManager().getGlobalValueCallEntry(GV); break; } case MIToken::ExternalSymbol: PSV = MF.getPSVManager().getExternalSymbolCallEntry( MF.createExternalSymbolName(Token.stringValue())); break; default: return error( "expected a global value or an external symbol after 'call-entry'"); } break; case MIToken::kw_custom: { lex(); const auto *TII = MF.getSubtarget().getInstrInfo(); if (const auto *Formatter = TII->getMIRFormatter()) { if (Formatter->parseCustomPseudoSourceValue( Token.stringValue(), MF, PFS, PSV, [this](StringRef::iterator Loc, const Twine &Msg) -> bool { return error(Loc, Msg); })) return true; } else return error("unable to parse target custom pseudo source value"); break; } default: llvm_unreachable("The current token should be pseudo source value"); } lex(); return false; } bool MIParser::parseMachinePointerInfo(MachinePointerInfo &Dest) { if (Token.is(MIToken::kw_constant_pool) || Token.is(MIToken::kw_stack) || Token.is(MIToken::kw_got) || Token.is(MIToken::kw_jump_table) || Token.is(MIToken::FixedStackObject) || Token.is(MIToken::StackObject) || Token.is(MIToken::kw_call_entry) || Token.is(MIToken::kw_custom)) { const PseudoSourceValue *PSV = nullptr; if (parseMemoryPseudoSourceValue(PSV)) return true; int64_t Offset = 0; if (parseOffset(Offset)) return true; Dest = MachinePointerInfo(PSV, Offset); return false; } if (Token.isNot(MIToken::NamedIRValue) && Token.isNot(MIToken::IRValue) && Token.isNot(MIToken::GlobalValue) && Token.isNot(MIToken::NamedGlobalValue) && Token.isNot(MIToken::QuotedIRValue) && Token.isNot(MIToken::kw_unknown_address)) return error("expected an IR value reference"); const Value *V = nullptr; if (parseIRValue(V)) return true; if (V && !V->getType()->isPointerTy()) return error("expected a pointer IR value"); lex(); int64_t Offset = 0; if (parseOffset(Offset)) return true; Dest = MachinePointerInfo(V, Offset); return false; } bool MIParser::parseOptionalScope(LLVMContext &Context, SyncScope::ID &SSID) { SSID = SyncScope::System; if (Token.is(MIToken::Identifier) && Token.stringValue() == "syncscope") { lex(); if (expectAndConsume(MIToken::lparen)) return error("expected '(' in syncscope"); std::string SSN; if (parseStringConstant(SSN)) return true; SSID = Context.getOrInsertSyncScopeID(SSN); if (expectAndConsume(MIToken::rparen)) return error("expected ')' in syncscope"); } return false; } bool MIParser::parseOptionalAtomicOrdering(AtomicOrdering &Order) { Order = AtomicOrdering::NotAtomic; if (Token.isNot(MIToken::Identifier)) return false; Order = StringSwitch(Token.stringValue()) .Case("unordered", AtomicOrdering::Unordered) .Case("monotonic", AtomicOrdering::Monotonic) .Case("acquire", AtomicOrdering::Acquire) .Case("release", AtomicOrdering::Release) .Case("acq_rel", AtomicOrdering::AcquireRelease) .Case("seq_cst", AtomicOrdering::SequentiallyConsistent) .Default(AtomicOrdering::NotAtomic); if (Order != AtomicOrdering::NotAtomic) { lex(); return false; } return error("expected an atomic scope, ordering or a size specification"); } bool MIParser::parseMachineMemoryOperand(MachineMemOperand *&Dest) { if (expectAndConsume(MIToken::lparen)) return true; MachineMemOperand::Flags Flags = MachineMemOperand::MONone; while (Token.isMemoryOperandFlag()) { if (parseMemoryOperandFlag(Flags)) return true; } if (Token.isNot(MIToken::Identifier) || (Token.stringValue() != "load" && Token.stringValue() != "store")) return error("expected 'load' or 'store' memory operation"); if (Token.stringValue() == "load") Flags |= MachineMemOperand::MOLoad; else Flags |= MachineMemOperand::MOStore; lex(); // Optional 'store' for operands that both load and store. if (Token.is(MIToken::Identifier) && Token.stringValue() == "store") { Flags |= MachineMemOperand::MOStore; lex(); } // Optional synchronization scope. SyncScope::ID SSID; if (parseOptionalScope(MF.getFunction().getContext(), SSID)) return true; // Up to two atomic orderings (cmpxchg provides guarantees on failure). AtomicOrdering Order, FailureOrder; if (parseOptionalAtomicOrdering(Order)) return true; if (parseOptionalAtomicOrdering(FailureOrder)) return true; LLT MemoryType; if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::kw_unknown_size) && Token.isNot(MIToken::lparen)) return error("expected memory LLT, the size integer literal or 'unknown-size' after " "memory operation"); uint64_t Size = MemoryLocation::UnknownSize; if (Token.is(MIToken::IntegerLiteral)) { if (getUint64(Size)) return true; // Convert from bytes to bits for storage. MemoryType = LLT::scalar(8 * Size); lex(); } else if (Token.is(MIToken::kw_unknown_size)) { Size = MemoryLocation::UnknownSize; lex(); } else { if (expectAndConsume(MIToken::lparen)) return true; if (parseLowLevelType(Token.location(), MemoryType)) return true; if (expectAndConsume(MIToken::rparen)) return true; Size = MemoryType.getSizeInBytes(); } MachinePointerInfo Ptr = MachinePointerInfo(); if (Token.is(MIToken::Identifier)) { const char *Word = ((Flags & MachineMemOperand::MOLoad) && (Flags & MachineMemOperand::MOStore)) ? "on" : Flags & MachineMemOperand::MOLoad ? "from" : "into"; if (Token.stringValue() != Word) return error(Twine("expected '") + Word + "'"); lex(); if (parseMachinePointerInfo(Ptr)) return true; } uint64_t BaseAlignment = (Size != MemoryLocation::UnknownSize ? PowerOf2Ceil(Size) : 1); AAMDNodes AAInfo; MDNode *Range = nullptr; while (consumeIfPresent(MIToken::comma)) { switch (Token.kind()) { case MIToken::kw_align: { // align is printed if it is different than size. uint64_t Alignment; if (parseAlignment(Alignment)) return true; if (Ptr.Offset & (Alignment - 1)) { // MachineMemOperand::getAlign never returns a value greater than the // alignment of offset, so this just guards against hand-written MIR // that specifies a large "align" value when it should probably use // "basealign" instead. return error("specified alignment is more aligned than offset"); } BaseAlignment = Alignment; break; } case MIToken::kw_basealign: // basealign is printed if it is different than align. if (parseAlignment(BaseAlignment)) return true; break; case MIToken::kw_addrspace: if (parseAddrspace(Ptr.AddrSpace)) return true; break; case MIToken::md_tbaa: lex(); if (parseMDNode(AAInfo.TBAA)) return true; break; case MIToken::md_alias_scope: lex(); if (parseMDNode(AAInfo.Scope)) return true; break; case MIToken::md_noalias: lex(); if (parseMDNode(AAInfo.NoAlias)) return true; break; case MIToken::md_range: lex(); if (parseMDNode(Range)) return true; break; // TODO: Report an error on duplicate metadata nodes. default: return error("expected 'align' or '!tbaa' or '!alias.scope' or " "'!noalias' or '!range'"); } } if (expectAndConsume(MIToken::rparen)) return true; Dest = MF.getMachineMemOperand(Ptr, Flags, MemoryType, Align(BaseAlignment), AAInfo, Range, SSID, Order, FailureOrder); return false; } bool MIParser::parsePreOrPostInstrSymbol(MCSymbol *&Symbol) { assert((Token.is(MIToken::kw_pre_instr_symbol) || Token.is(MIToken::kw_post_instr_symbol)) && "Invalid token for a pre- post-instruction symbol!"); lex(); if (Token.isNot(MIToken::MCSymbol)) return error("expected a symbol after 'pre-instr-symbol'"); Symbol = getOrCreateMCSymbol(Token.stringValue()); lex(); if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) || Token.is(MIToken::lbrace)) return false; if (Token.isNot(MIToken::comma)) return error("expected ',' before the next machine operand"); lex(); return false; } bool MIParser::parseHeapAllocMarker(MDNode *&Node) { assert(Token.is(MIToken::kw_heap_alloc_marker) && "Invalid token for a heap alloc marker!"); lex(); if (parseMDNode(Node)) return true; if (!Node) return error("expected a MDNode after 'heap-alloc-marker'"); if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) || Token.is(MIToken::lbrace)) return false; if (Token.isNot(MIToken::comma)) return error("expected ',' before the next machine operand"); lex(); return false; } bool MIParser::parsePCSections(MDNode *&Node) { assert(Token.is(MIToken::kw_pcsections) && "Invalid token for a PC sections!"); lex(); if (parseMDNode(Node)) return true; if (!Node) return error("expected a MDNode after 'pcsections'"); if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) || Token.is(MIToken::lbrace)) return false; if (Token.isNot(MIToken::comma)) return error("expected ',' before the next machine operand"); lex(); return false; } static void initSlots2BasicBlocks( const Function &F, DenseMap &Slots2BasicBlocks) { ModuleSlotTracker MST(F.getParent(), /*ShouldInitializeAllMetadata=*/false); MST.incorporateFunction(F); for (const auto &BB : F) { if (BB.hasName()) continue; int Slot = MST.getLocalSlot(&BB); if (Slot == -1) continue; Slots2BasicBlocks.insert(std::make_pair(unsigned(Slot), &BB)); } } static const BasicBlock *getIRBlockFromSlot( unsigned Slot, const DenseMap &Slots2BasicBlocks) { return Slots2BasicBlocks.lookup(Slot); } const BasicBlock *MIParser::getIRBlock(unsigned Slot) { if (Slots2BasicBlocks.empty()) initSlots2BasicBlocks(MF.getFunction(), Slots2BasicBlocks); return getIRBlockFromSlot(Slot, Slots2BasicBlocks); } const BasicBlock *MIParser::getIRBlock(unsigned Slot, const Function &F) { if (&F == &MF.getFunction()) return getIRBlock(Slot); DenseMap CustomSlots2BasicBlocks; initSlots2BasicBlocks(F, CustomSlots2BasicBlocks); return getIRBlockFromSlot(Slot, CustomSlots2BasicBlocks); } MCSymbol *MIParser::getOrCreateMCSymbol(StringRef Name) { // FIXME: Currently we can't recognize temporary or local symbols and call all // of the appropriate forms to create them. However, this handles basic cases // well as most of the special aspects are recognized by a prefix on their // name, and the input names should already be unique. For test cases, keeping // the symbol name out of the symbol table isn't terribly important. return MF.getContext().getOrCreateSymbol(Name); } bool MIParser::parseStringConstant(std::string &Result) { if (Token.isNot(MIToken::StringConstant)) return error("expected string constant"); Result = std::string(Token.stringValue()); lex(); return false; } bool llvm::parseMachineBasicBlockDefinitions(PerFunctionMIParsingState &PFS, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseBasicBlockDefinitions(PFS.MBBSlots); } bool llvm::parseMachineInstructions(PerFunctionMIParsingState &PFS, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseBasicBlocks(); } bool llvm::parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneMBB(MBB); } bool llvm::parseRegisterReference(PerFunctionMIParsingState &PFS, Register &Reg, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneRegister(Reg); } bool llvm::parseNamedRegisterReference(PerFunctionMIParsingState &PFS, Register &Reg, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneNamedRegister(Reg); } bool llvm::parseVirtualRegisterReference(PerFunctionMIParsingState &PFS, VRegInfo *&Info, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneVirtualRegister(Info); } bool llvm::parseStackObjectReference(PerFunctionMIParsingState &PFS, int &FI, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneStackObject(FI); } bool llvm::parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneMDNode(Node); } bool llvm::parseMachineMetadata(PerFunctionMIParsingState &PFS, StringRef Src, SMRange SrcRange, SMDiagnostic &Error) { return MIParser(PFS, Error, Src, SrcRange).parseMachineMetadata(); } bool MIRFormatter::parseIRValue(StringRef Src, MachineFunction &MF, PerFunctionMIParsingState &PFS, const Value *&V, ErrorCallbackType ErrorCallback) { MIToken Token; Src = lexMIToken(Src, Token, [&](StringRef::iterator Loc, const Twine &Msg) { ErrorCallback(Loc, Msg); }); V = nullptr; return ::parseIRValue(Token, PFS, V, ErrorCallback); }