| //===- 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/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/InlineAsm.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/TargetMachine.h" | |
| #include <cassert> | |
| #include <cctype> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <limits> | |
| #include <string> | |
| #include <utility> | |
| 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; | |
| } | |
| bool PerTargetMIParsingState::getVRegFlagValue(StringRef FlagName, | |
| uint8_t &FlagValue) const { | |
| const auto *TRI = Subtarget.getRegisterInfo(); | |
| std::optional<uint8_t> FV = TRI->getVRegFlagValue(FlagName); | |
| if (!FV) | |
| return true; | |
| FlagValue = *FV; | |
| 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<const uint32_t *> RegMasks = TRI->getRegMasks(); | |
| ArrayRef<const char *> 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.try_emplace(Num); | |
| 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.try_emplace(RegName.str()); | |
| 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<unsigned, const Value *> &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<unsigned, const Value *> &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<unsigned> TiedDefIdx; | |
| ParsedMachineOperand(const MachineOperand &Operand, StringRef::iterator Begin, | |
| StringRef::iterator End, | |
| std::optional<unsigned> &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<unsigned, const BasicBlock *> 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<unsigned, MachineBasicBlock *> &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<Metadata *> &Elts); | |
| bool parseMetadata(Metadata *&MD); | |
| bool | |
| parseBasicBlockDefinition(DenseMap<unsigned, MachineBasicBlock *> &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(RegState &Flags); | |
| bool parseRegisterClassOrBank(VRegInfo &RegInfo); | |
| bool parseSubRegisterIndex(unsigned &SubReg); | |
| bool parseRegisterTiedDefIndex(unsigned &TiedDefIdx); | |
| bool parseRegisterOperand(MachineOperand &Dest, | |
| std::optional<unsigned> &TiedDefIdx, | |
| bool IsDef = false); | |
| bool parseImmediateOperand(MachineOperand &Dest); | |
| bool parseSymbolicInlineAsmOperand(unsigned OpIdx, 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(unsigned &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 parseLaneMaskOperand(MachineOperand &Dest); | |
| bool parseLiveoutRegisterMaskOperand(MachineOperand &Dest); | |
| bool parseMachineOperand(const unsigned OpCode, const unsigned OpIdx, | |
| MachineOperand &Dest, | |
| std::optional<unsigned> &TiedDefIdx); | |
| bool parseMachineOperandAndTargetFlags(const unsigned OpCode, | |
| const unsigned OpIdx, | |
| MachineOperand &Dest, | |
| std::optional<unsigned> &TiedDefIdx); | |
| bool parseOffset(int64_t &Offset); | |
| bool parseIRBlockAddressTaken(BasicBlock *&BB); | |
| bool parseAlignment(uint64_t &Alignment); | |
| bool parseAddrspace(unsigned &Addrspace); | |
| bool parseSectionID(std::optional<MBBSectionID> &SID); | |
| bool parseBBID(std::optional<UniqueBBID> &BBID); | |
| bool parseCallFrameSize(unsigned &CallFrameSize); | |
| bool parsePrefetchTarget(CallsiteID &Target); | |
| 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 parseMMRA(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<ParsedMachineOperand> Operands); | |
| bool verifyImplicitOperands(ArrayRef<ParsedMachineOperand> 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.substr(SkipChar), 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, {}, {}); | |
| 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<bool(StringRef::iterator Loc, const Twine &)> | |
| 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 "<unknown token>"; | |
| } | |
| } | |
| 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<MBBSectionID> &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<UniqueBBID> &BBID) { | |
| if (Token.isNot(MIToken::kw_bb_id)) | |
| return error("expected 'bb_id'"); | |
| lex(); | |
| unsigned BaseID = 0; | |
| unsigned CloneID = 0; | |
| if (Token.is(MIToken::FloatingPointLiteral)) { | |
| StringRef S = Token.range(); | |
| auto Parts = S.split('.'); | |
| if (Parts.first.getAsInteger(10, BaseID) || | |
| Parts.second.getAsInteger(10, CloneID)) | |
| return error("Unknown BB ID"); | |
| lex(); | |
| } else { | |
| if (getUnsigned(BaseID)) | |
| return error("Unknown BB ID"); | |
| lex(); | |
| if (Token.is(MIToken::comma) || Token.is(MIToken::dot)) { | |
| lex(); | |
| if (getUnsigned(CloneID)) | |
| return error("Unknown Clone ID"); | |
| lex(); | |
| } else 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::parsePrefetchTarget(CallsiteID &Target) { | |
| lex(); | |
| std::optional<UniqueBBID> BBID; | |
| if (parseBBID(BBID)) | |
| return true; | |
| Target.BBID = *BBID; | |
| if (expectAndConsume(MIToken::comma)) | |
| return true; | |
| return getUnsigned(Target.CallsiteIndex); | |
| } | |
| bool MIParser::parseBasicBlockDefinition( | |
| DenseMap<unsigned, MachineBasicBlock *> &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; | |
| bool IsEHScopeEntry = false; | |
| std::optional<MBBSectionID> SectionID; | |
| uint64_t Alignment = 0; | |
| std::optional<UniqueBBID> 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_ehscope_entry: | |
| IsEHScopeEntry = 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<BasicBlock>( | |
| 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, BBID); | |
| 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); | |
| MBB->setIsEHScopeEntry(IsEHScopeEntry); | |
| if (SectionID) { | |
| MBB->setSectionID(*SectionID); | |
| MF.setBBSectionsType(BasicBlockSection::List); | |
| } | |
| MBB->setCallFrameSize(CallFrameSize); | |
| return false; | |
| } | |
| bool MIParser::parseBasicBlockDefinitions( | |
| DenseMap<unsigned, MachineBasicBlock *> &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<MachineBasicBlock*,4> 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<ParsedMachineOperand, 8> Operands; | |
| while (Token.isRegister() || Token.isRegisterFlag()) { | |
| auto Loc = Token.location(); | |
| std::optional<unsigned> 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_mmra) && | |
| Token.isNot(MIToken::kw_cfi_type) && | |
| Token.isNot(MIToken::kw_deactivation_symbol) && | |
| 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<unsigned> 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; | |
| MDNode *MMRA = nullptr; | |
| if (Token.is(MIToken::kw_mmra) && parseMMRA(MMRA)) | |
| 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(); | |
| } | |
| GlobalValue *DS = nullptr; | |
| if (Token.is(MIToken::kw_deactivation_symbol)) { | |
| lex(); | |
| if (parseGlobalValue(DS)) | |
| return true; | |
| 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<DILocation>(Node)) | |
| return error("referenced metadata is not a DILocation"); | |
| DebugLocation = DebugLoc(Node); | |
| } | |
| // Parse the machine memory operands. | |
| SmallVector<MachineMemOperand *, 2> 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 (OpCode == TargetOpcode::BUNDLE && Token.is(MIToken::lbrace)) | |
| 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 (MMRA) | |
| MI->setMMRAMetadata(MF, MMRA); | |
| if (CFIType) | |
| MI->setCFIType(MF, CFIType); | |
| if (DS) | |
| MI->setDeactivationSymbol(MF, DS); | |
| 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 { | |
| auto [It, Inserted] = PFS.MachineMetadataNodes.try_emplace(ID); | |
| if (!Inserted) | |
| return error("Metadata id is already used"); | |
| It->second.reset(MD); | |
| } | |
| return false; | |
| } | |
| bool MIParser::parseMDTuple(MDNode *&MD, bool IsDistinct) { | |
| SmallVector<Metadata *, 16> Elts; | |
| if (parseMDNodeVector(Elts)) | |
| return true; | |
| MD = (IsDistinct ? MDTuple::getDistinct | |
| : MDTuple::get)(MF.getFunction().getContext(), Elts); | |
| return false; | |
| } | |
| bool MIParser::parseMDNodeVector(SmallVectorImpl<Metadata *> &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(), {}), 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<ParsedMachineOperand> Operands) { | |
| for (const auto &I : Operands) { | |
| if (ImplicitOperand.isIdenticalTo(I.Operand)) | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool MIParser::verifyImplicitOperands(ArrayRef<ParsedMachineOperand> 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<MachineOperand, 4> 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) || | |
| Token.is(MIToken::kw_nusw) || | |
| Token.is(MIToken::kw_samesign) || | |
| Token.is(MIToken::kw_inbounds)) { | |
| // 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; | |
| if (Token.is(MIToken::kw_nusw)) | |
| Flags |= MachineInstr::NoUSWrap; | |
| if (Token.is(MIToken::kw_samesign)) | |
| Flags |= MachineInstr::SameSign; | |
| if (Token.is(MIToken::kw_inbounds)) | |
| Flags |= MachineInstr::InBounds; | |
| 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(RegState &Flags) { | |
| const RegState 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) { | |
| assert(Token.is(MIToken::kw_tied_def)); | |
| lex(); | |
| if (Token.isNot(MIToken::IntegerLiteral)) | |
| return error("expected an integer literal after 'tied-def'"); | |
| if (getUnsigned(TiedDefIdx)) | |
| return true; | |
| lex(); | |
| return expectAndConsume(MIToken::rparen); | |
| } | |
| bool MIParser::assignRegisterTies(MachineInstr &MI, | |
| ArrayRef<ParsedMachineOperand> Operands) { | |
| SmallVector<std::pair<unsigned, unsigned>, 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<unsigned> &TiedDefIdx, | |
| bool IsDef) { | |
| RegState Flags = getDefRegState(IsDef); | |
| while (Token.isRegisterFlag()) { | |
| if (parseRegisterFlag(Flags)) | |
| return true; | |
| } | |
| // Update IsDef as we may have read a def flag. | |
| IsDef = hasRegState(Flags, RegState::Define); | |
| 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; | |
| } | |
| if (consumeIfPresent(MIToken::lparen)) { | |
| // For a def, we only expect a type. For use we expect either a type or a | |
| // tied-def. Additionally, for physical registers, we don't expect a type. | |
| if (Token.is(MIToken::kw_tied_def)) { | |
| if (IsDef) | |
| return error("tied-def not supported for defs"); | |
| unsigned Idx; | |
| if (parseRegisterTiedDefIndex(Idx)) | |
| return true; | |
| TiedDefIdx = Idx; | |
| } else { | |
| if (!Reg.isVirtual()) | |
| return error("unexpected type on physical register"); | |
| LLT Ty; | |
| // If type parsing fails, forwad the parse error for defs. | |
| if (parseLowLevelType(Token.location(), Ty)) | |
| return IsDef ? true | |
| : error("expected tied-def or low-level type after '('"); | |
| if (expectAndConsume(MIToken::rparen)) | |
| return true; | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| if (MRI.getType(Reg).isValid() && MRI.getType(Reg) != Ty) | |
| return error("inconsistent type for generic virtual register"); | |
| MRI.setRegClassOrRegBank(Reg, static_cast<RegisterBank *>(nullptr)); | |
| MRI.setType(Reg, Ty); | |
| MRI.noteNewVirtualRegister(Reg); | |
| } | |
| } else if (IsDef && Reg.isVirtual()) { | |
| // Generic virtual registers defs must have a type. | |
| if (RegInfo->Kind == VRegInfo::GENERIC || | |
| RegInfo->Kind == VRegInfo::REGBANK) | |
| return error("generic virtual registers must have a type"); | |
| } | |
| if (IsDef) { | |
| if (hasRegState(Flags, RegState::Kill)) | |
| return error("cannot have a killed def operand"); | |
| } else { | |
| if (hasRegState(Flags, RegState::Dead)) | |
| return error("cannot have a dead use operand"); | |
| } | |
| Dest = MachineOperand::CreateReg( | |
| Reg, IsDef, hasRegState(Flags, RegState::Implicit), | |
| hasRegState(Flags, RegState::Kill), hasRegState(Flags, RegState::Dead), | |
| hasRegState(Flags, RegState::Undef), | |
| hasRegState(Flags, RegState::EarlyClobber), SubReg, | |
| hasRegState(Flags, RegState::Debug), | |
| hasRegState(Flags, RegState::InternalRead), | |
| hasRegState(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::parseSymbolicInlineAsmOperand(unsigned OpIdx, | |
| MachineOperand &Dest) { | |
| assert(OpIdx >= InlineAsm::MIOp_ExtraInfo); | |
| assert(Token.is(MIToken::Identifier) && | |
| "expected symbolic inline asm operand"); | |
| // Parse ExtraInfo flags. | |
| if (OpIdx == InlineAsm::MIOp_ExtraInfo) { | |
| unsigned ExtraInfo = 0; | |
| for (;;) { | |
| if (Token.isNot(MIToken::Identifier)) | |
| break; | |
| StringRef FlagName = Token.stringValue(); | |
| unsigned Flag = StringSwitch<unsigned>(FlagName) | |
| .Case("sideeffect", InlineAsm::Extra_HasSideEffects) | |
| .Case("mayload", InlineAsm::Extra_MayLoad) | |
| .Case("maystore", InlineAsm::Extra_MayStore) | |
| .Case("isconvergent", InlineAsm::Extra_IsConvergent) | |
| .Case("alignstack", InlineAsm::Extra_IsAlignStack) | |
| .Case("unwind", InlineAsm::Extra_MayUnwind) | |
| .Case("attdialect", 0) | |
| .Case("inteldialect", InlineAsm::Extra_AsmDialect) | |
| .Default(~0u); | |
| if (Flag == ~0u) | |
| return error("unknown inline asm extra info flag '" + FlagName + "'"); | |
| ExtraInfo |= Flag; | |
| lex(); | |
| } | |
| Dest = MachineOperand::CreateImm(ExtraInfo); | |
| return false; | |
| } | |
| // Parse symbolic form: kind[:constraint]. | |
| StringRef KindStr = Token.stringValue(); | |
| constexpr auto InvalidKind = static_cast<InlineAsm::Kind>(0); | |
| InlineAsm::Kind K = | |
| StringSwitch<InlineAsm::Kind>(KindStr) | |
| .Case("regdef", InlineAsm::Kind::RegDef) | |
| .Case("reguse", InlineAsm::Kind::RegUse) | |
| .Case("regdef-ec", InlineAsm::Kind::RegDefEarlyClobber) | |
| .Case("clobber", InlineAsm::Kind::Clobber) | |
| .Case("imm", InlineAsm::Kind::Imm) | |
| .Case("mem", InlineAsm::Kind::Mem) | |
| .Default(InvalidKind); | |
| if (K == InvalidKind) | |
| return error("unknown inline asm operand kind '" + KindStr + "'"); | |
| lex(); | |
| // Create the flag with default of 1 operand. | |
| InlineAsm::Flag F(K, 1); | |
| // Parse optional tiedto constraint: tiedto:$N. | |
| if (Token.is(MIToken::Identifier) && Token.stringValue() == "tiedto") { | |
| lex(); | |
| if (Token.isNot(MIToken::colon)) | |
| return error("expected ':' after 'tiedto'"); | |
| lex(); | |
| if (Token.isNot(MIToken::NamedRegister)) | |
| return error("expected '$N' operand number after 'tiedto:'"); | |
| unsigned OperandNo; | |
| if (Token.stringValue().getAsInteger(10, OperandNo)) | |
| return error("invalid operand number in tiedto constraint"); | |
| lex(); | |
| F.setMatchingOp(OperandNo); | |
| Dest = MachineOperand::CreateImm(F); | |
| return false; | |
| } | |
| // Parse optional constraint after ':'. | |
| if (Token.isNot(MIToken::colon)) { | |
| Dest = MachineOperand::CreateImm(F); | |
| return false; | |
| } | |
| lex(); | |
| if (Token.isNot(MIToken::Identifier)) | |
| return error("expected register class or memory constraint name after ':'"); | |
| StringRef ConstraintStr = Token.stringValue(); | |
| if (K == InlineAsm::Kind::Mem) { | |
| InlineAsm::ConstraintCode CC = | |
| StringSwitch<InlineAsm::ConstraintCode>(ConstraintStr) | |
| .Case("es", InlineAsm::ConstraintCode::es) | |
| .Case("i", InlineAsm::ConstraintCode::i) | |
| .Case("k", InlineAsm::ConstraintCode::k) | |
| .Case("m", InlineAsm::ConstraintCode::m) | |
| .Case("o", InlineAsm::ConstraintCode::o) | |
| .Case("v", InlineAsm::ConstraintCode::v) | |
| .Case("A", InlineAsm::ConstraintCode::A) | |
| .Case("Q", InlineAsm::ConstraintCode::Q) | |
| .Case("R", InlineAsm::ConstraintCode::R) | |
| .Case("S", InlineAsm::ConstraintCode::S) | |
| .Case("T", InlineAsm::ConstraintCode::T) | |
| .Case("Um", InlineAsm::ConstraintCode::Um) | |
| .Case("Un", InlineAsm::ConstraintCode::Un) | |
| .Case("Uq", InlineAsm::ConstraintCode::Uq) | |
| .Case("Us", InlineAsm::ConstraintCode::Us) | |
| .Case("Ut", InlineAsm::ConstraintCode::Ut) | |
| .Case("Uv", InlineAsm::ConstraintCode::Uv) | |
| .Case("Uy", InlineAsm::ConstraintCode::Uy) | |
| .Case("X", InlineAsm::ConstraintCode::X) | |
| .Case("Z", InlineAsm::ConstraintCode::Z) | |
| .Case("ZB", InlineAsm::ConstraintCode::ZB) | |
| .Case("ZC", InlineAsm::ConstraintCode::ZC) | |
| .Case("Zy", InlineAsm::ConstraintCode::Zy) | |
| .Case("p", InlineAsm::ConstraintCode::p) | |
| .Case("ZQ", InlineAsm::ConstraintCode::ZQ) | |
| .Case("ZR", InlineAsm::ConstraintCode::ZR) | |
| .Case("ZS", InlineAsm::ConstraintCode::ZS) | |
| .Case("ZT", InlineAsm::ConstraintCode::ZT) | |
| .Default(InlineAsm::ConstraintCode::Unknown); | |
| if (CC == InlineAsm::ConstraintCode::Unknown) | |
| return error("unknown memory constraint '" + ConstraintStr + "'"); | |
| F.setMemConstraint(CC); | |
| } else if (K == InlineAsm::Kind::RegDef || K == InlineAsm::Kind::RegUse || | |
| K == InlineAsm::Kind::RegDefEarlyClobber) { | |
| const TargetRegisterClass *RC = | |
| PFS.Target.getRegClass(ConstraintStr.lower()); | |
| if (!RC) | |
| return error("unknown register class '" + ConstraintStr + "'"); | |
| F.setRegClass(RC->getID()); | |
| } | |
| lex(); | |
| Dest = MachineOperand::CreateImm(F); | |
| 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) { | |
| StringRef TypeDigits = Token.range(); | |
| if (TypeDigits.consume_front("s") || TypeDigits.consume_front("i") || | |
| TypeDigits.consume_front("f") || TypeDigits.consume_front("p") || | |
| TypeDigits.consume_front("bf")) { | |
| if (TypeDigits.empty() || !llvm::all_of(TypeDigits, isdigit)) | |
| return error( | |
| "expected integers after 's'/'i'/'f'/'bf'/'p' type identifier"); | |
| } | |
| bool Scalar = Token.range().starts_with("s"); | |
| if (Scalar || Token.range().starts_with("i")) { | |
| auto ScalarSize = APSInt(TypeDigits).getZExtValue(); | |
| if (!ScalarSize) { | |
| Ty = LLT::token(); | |
| lex(); | |
| return false; | |
| } | |
| if (!verifyScalarSize(ScalarSize)) | |
| return error("invalid size for scalar type"); | |
| Ty = Scalar ? LLT::scalar(ScalarSize) : LLT::integer(ScalarSize); | |
| lex(); | |
| return false; | |
| } | |
| if (Token.range().starts_with("p")) { | |
| const DataLayout &DL = MF.getDataLayout(); | |
| uint64_t AS = APSInt(TypeDigits).getZExtValue(); | |
| if (!verifyAddrSpace(AS)) | |
| return error("invalid address space number"); | |
| Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS)); | |
| lex(); | |
| return false; | |
| } | |
| if (Token.range().starts_with("f") || Token.range().starts_with("bf")) { | |
| auto ScalarSize = APSInt(TypeDigits).getZExtValue(); | |
| if (!ScalarSize || !verifyScalarSize(ScalarSize)) | |
| return error("invalid size for scalar type"); | |
| if (Token.range().starts_with("bf") && ScalarSize != 16) | |
| return error("invalid size for bfloat"); | |
| Ty = Token.range().starts_with("bf") ? LLT::bfloat16() | |
| : LLT::floatIEEE(ScalarSize); | |
| lex(); | |
| return false; | |
| } | |
| // Now we're looking for a vector. | |
| if (Token.isNot(MIToken::less)) | |
| return error(Loc, "expected tN, pA, <M x tN>, <M x pA>, <vscale x M x tN>, " | |
| "or <vscale x M x pA> for GlobalISel type, " | |
| "where t = {'s', 'i', 'f', 'bf'}"); | |
| lex(); | |
| bool HasVScale = | |
| Token.is(MIToken::Identifier) && Token.stringValue() == "vscale"; | |
| if (HasVScale) { | |
| lex(); | |
| if (Token.isNot(MIToken::Identifier) || Token.stringValue() != "x") | |
| return error( | |
| "expected <vscale x M x tN>, where t = {'s', 'i', 'f', 'bf', 'p'}"); | |
| lex(); | |
| } | |
| auto GetError = [this, &HasVScale, Loc]() { | |
| if (HasVScale) | |
| return error(Loc, "expected <vscale x M x tN> for vector type, where t = " | |
| "{'s', 'i', 'f', 'bf', 'p'}"); | |
| return error(Loc, "expected <M x tN> for vector type, where t = {'s', 'i', " | |
| "'f', 'bf', 'p'}"); | |
| }; | |
| 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(); | |
| StringRef VectorTyDigits = Token.range(); | |
| if (!VectorTyDigits.consume_front("s") && | |
| !VectorTyDigits.consume_front("i") && | |
| !VectorTyDigits.consume_front("f") && | |
| !VectorTyDigits.consume_front("p") && !VectorTyDigits.consume_front("bf")) | |
| return GetError(); | |
| if (VectorTyDigits.empty() || !llvm::all_of(VectorTyDigits, isdigit)) | |
| return error( | |
| "expected integers after 's'/'i'/'f'/'bf'/'p' type identifier"); | |
| Scalar = Token.range().starts_with("s"); | |
| if (Scalar || Token.range().starts_with("i")) { | |
| auto ScalarSize = APSInt(VectorTyDigits).getZExtValue(); | |
| if (!verifyScalarSize(ScalarSize)) | |
| return error("invalid size for scalar element in vector"); | |
| Ty = Scalar ? LLT::scalar(ScalarSize) : LLT::integer(ScalarSize); | |
| } else if (Token.range().starts_with("p")) { | |
| const DataLayout &DL = MF.getDataLayout(); | |
| uint64_t AS = APSInt(VectorTyDigits).getZExtValue(); | |
| if (!verifyAddrSpace(AS)) | |
| return error("invalid address space number"); | |
| Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS)); | |
| } else if (Token.range().starts_with("f")) { | |
| auto ScalarSize = APSInt(VectorTyDigits).getZExtValue(); | |
| if (!verifyScalarSize(ScalarSize)) | |
| return error("invalid size for float element in vector"); | |
| Ty = LLT::floatIEEE(ScalarSize); | |
| } else if (Token.range().starts_with("bf")) { | |
| auto ScalarSize = APSInt(VectorTyDigits).getZExtValue(); | |
| if (!verifyScalarSize(ScalarSize)) | |
| return error("invalid size for bfloat element in vector"); | |
| Ty = LLT::bfloat16(); | |
| } 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 TypeDigits = Token.range(); | |
| if (!TypeDigits.consume_front("i") && !TypeDigits.consume_front("s") && | |
| !TypeDigits.consume_front("p") && !TypeDigits.consume_front("f") && | |
| !TypeDigits.consume_front("bf")) | |
| return error("a typed immediate operand should start with one of 'i', " | |
| "'s', 'f', 'bf', or 'p'"); | |
| if (TypeDigits.empty() || !llvm::all_of(TypeDigits, isdigit)) | |
| return error( | |
| "expected integers after 'i'/'s'/'f'/'bf'/'p' type identifier"); | |
| 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<ConstantInt>(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<ConstantFP>(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<uint64_t>(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<unsigned>::max()) + 1; | |
| const APSInt &SInt = Token.integerValue(); | |
| if (SInt.isNegative()) | |
| return ErrCB(Token.location(), "expected unsigned integer"); | |
| uint64_t Val64 = SInt.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 <irname> from the bb.<id>.<irname> 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.substr(Read); | |
| 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; | |
| uint64_t AtomGroup = 0; | |
| uint64_t AtomRank = 0; | |
| 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<DIScope>(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<DILocation>(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; | |
| } | |
| if (Token.stringValue() == "atomGroup") { | |
| lex(); | |
| if (expectAndConsume(MIToken::colon)) | |
| return true; | |
| if (Token.isNot(MIToken::IntegerLiteral) || | |
| Token.integerValue().isSigned()) | |
| return error("expected unsigned integer"); | |
| AtomGroup = Token.integerValue().getZExtValue(); | |
| lex(); | |
| continue; | |
| } | |
| if (Token.stringValue() == "atomRank") { | |
| lex(); | |
| if (expectAndConsume(MIToken::colon)) | |
| return true; | |
| if (Token.isNot(MIToken::IntegerLiteral) || | |
| Token.integerValue().isSigned()) | |
| return error("expected unsigned integer"); | |
| AtomRank = Token.integerValue().getZExtValue(); | |
| 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, AtomGroup, AtomRank); | |
| 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(unsigned &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<uint8_t>(Value)); | |
| lex(); | |
| } while (consumeIfPresent(MIToken::comma)); | |
| return false; | |
| } | |
| bool MIParser::parseCFIOperand(MachineOperand &Dest) { | |
| auto Kind = Token.kind(); | |
| lex(); | |
| int Offset; | |
| unsigned 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: { | |
| unsigned 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_aarch64_negate_ra_sign_state_with_pc: | |
| CFIIndex = | |
| MF.addFrameInst(MCCFIInstruction::createNegateRAStateWithPC(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<BasicBlock>( | |
| 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<BasicBlock *>(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<Function>(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. | |
| Intrinsic::ID ID = Intrinsic::lookupIntrinsicID(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<CmpInst::Predicate>(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<CmpInst::Predicate>(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(<integer or undef>, ...)"); | |
| SmallVector<int, 32> 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 ')'."); | |
| if (ShufMask.size() < 2) | |
| return error("shufflemask should have > 1 element"); | |
| ArrayRef<int> 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(<unsigned>, <unsigned>)"); | |
| 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<unsigned>::max() && | |
| "Instruction reference's instruction index is too large"); | |
| lex(); | |
| if (expectAndConsume(MIToken::comma)) | |
| return error("expected syntax dbg-instr-ref(<unsigned>, <unsigned>)"); | |
| 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<unsigned>::max() && | |
| "Instruction reference's operand index is too large"); | |
| lex(); | |
| if (expectAndConsume(MIToken::rparen)) | |
| return error("expected syntax dbg-instr-ref(<unsigned>, <unsigned>)"); | |
| 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.id() / 32] |= 1U << (Reg.id() % 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::parseLaneMaskOperand(MachineOperand &Dest) { | |
| assert(Token.is(MIToken::kw_lanemask)); | |
| lex(); | |
| if (expectAndConsume(MIToken::lparen)) | |
| return true; | |
| // Parse lanemask. | |
| if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::HexLiteral)) | |
| return error("expected a valid lane mask value"); | |
| static_assert(sizeof(LaneBitmask::Type) == sizeof(uint64_t), | |
| "Use correct get-function for lane mask."); | |
| LaneBitmask::Type V; | |
| if (getUint64(V)) | |
| return true; | |
| LaneBitmask LaneMask(V); | |
| lex(); | |
| if (expectAndConsume(MIToken::rparen)) | |
| return true; | |
| Dest = MachineOperand::CreateLaneMask(LaneMask); | |
| 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.id() / 32] |= 1U << (Reg.id() % 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<unsigned> &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: | |
| // TODO: Forbid numeric operands for INLINEASM once the transition to the | |
| // symbolic form is over. | |
| 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: | |
| case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc: | |
| 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_lanemask: | |
| return parseLaneMaskOperand(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: { | |
| bool IsInlineAsm = OpCode == TargetOpcode::INLINEASM || | |
| OpCode == TargetOpcode::INLINEASM_BR; | |
| if (IsInlineAsm) | |
| return parseSymbolicInlineAsmOperand(OpIdx, Dest); | |
| StringRef Id = Token.stringValue(); | |
| if (const auto *RegMask = PFS.Target.getRegMask(Id)) { | |
| Dest = MachineOperand::CreateRegMask(RegMask); | |
| lex(); | |
| break; | |
| } else if (Id == "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<unsigned> &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<AtomicOrdering>(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; | |
| 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"); | |
| LLT MemoryType; | |
| if (Token.is(MIToken::IntegerLiteral)) { | |
| uint64_t Size; | |
| 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)) { | |
| lex(); | |
| } else { | |
| if (expectAndConsume(MIToken::lparen)) | |
| return true; | |
| if (parseLowLevelType(Token.location(), MemoryType)) | |
| return true; | |
| if (expectAndConsume(MIToken::rparen)) | |
| return true; | |
| } | |
| 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 = | |
| MemoryType.isValid() | |
| ? PowerOf2Ceil(MemoryType.getSizeInBytes().getKnownMinValue()) | |
| : 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_noalias_addrspace: | |
| lex(); | |
| if (parseMDNode(AAInfo.NoAliasAddrSpace)) | |
| 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' or '!noalias.addrspace'"); | |
| } | |
| } | |
| 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; | |
| } | |
| bool MIParser::parseMMRA(MDNode *&Node) { | |
| assert(Token.is(MIToken::kw_mmra) && "Invalid token for MMRA!"); | |
| lex(); | |
| if (parseMDNode(Node)) | |
| return true; | |
| 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<unsigned, const BasicBlock *> &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<unsigned, const BasicBlock *> &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<unsigned, const BasicBlock *> 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::parsePrefetchTarget(PerFunctionMIParsingState &PFS, | |
| CallsiteID &Target, StringRef Src, | |
| SMDiagnostic &Error) { | |
| return MIParser(PFS, Error, Src).parsePrefetchTarget(Target); | |
| } | |
| 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); | |
| } |