//===- MIRParser.cpp - MIR serialization format 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 class that parses the optional LLVM IR and machine // functions that are stored in MIR files. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/MIRParser/MIRParser.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/AsmParser/Parser.h" #include "llvm/AsmParser/SlotMapping.h" #include "llvm/CodeGen/MIRParser/MIParser.h" #include "llvm/CodeGen/MIRYamlMapping.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Target/TargetMachine.h" #include using namespace llvm; namespace llvm { class MDNode; class RegisterBank; /// This class implements the parsing of LLVM IR that's embedded inside a MIR /// file. class MIRParserImpl { SourceMgr SM; LLVMContext &Context; yaml::Input In; StringRef Filename; SlotMapping IRSlots; std::unique_ptr Target; /// True when the MIR file doesn't have LLVM IR. Dummy IR functions are /// created and inserted into the given module when this is true. bool NoLLVMIR = false; /// True when a well formed MIR file does not contain any MIR/machine function /// parts. bool NoMIRDocuments = false; std::function ProcessIRFunction; public: MIRParserImpl(std::unique_ptr Contents, StringRef Filename, LLVMContext &Context, std::function ProcessIRFunction); void reportDiagnostic(const SMDiagnostic &Diag); /// Report an error with the given message at unknown location. /// /// Always returns true. bool error(const Twine &Message); /// Report an error with the given message at the given location. /// /// Always returns true. bool error(SMLoc Loc, const Twine &Message); /// Report a given error with the location translated from the location in an /// embedded string literal to a location in the MIR file. /// /// Always returns true. bool error(const SMDiagnostic &Error, SMRange SourceRange); /// Try to parse the optional LLVM module and the machine functions in the MIR /// file. /// /// Return null if an error occurred. std::unique_ptr parseIRModule(DataLayoutCallbackTy DataLayoutCallback); /// Create an empty function with the given name. Function *createDummyFunction(StringRef Name, Module &M); bool parseMachineFunctions(Module &M, MachineModuleInfo &MMI); /// Parse the machine function in the current YAML document. /// /// /// Return true if an error occurred. bool parseMachineFunction(Module &M, MachineModuleInfo &MMI); /// Initialize the machine function to the state that's described in the MIR /// file. /// /// Return true if error occurred. bool initializeMachineFunction(const yaml::MachineFunction &YamlMF, MachineFunction &MF); bool parseRegisterInfo(PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); bool setupRegisterInfo(const PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); bool initializeFrameInfo(PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); bool initializeCallSiteInfo(PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); bool parseCalleeSavedRegister(PerFunctionMIParsingState &PFS, std::vector &CSIInfo, const yaml::StringValue &RegisterSource, bool IsRestored, int FrameIdx); struct VarExprLoc { DILocalVariable *DIVar = nullptr; DIExpression *DIExpr = nullptr; DILocation *DILoc = nullptr; }; std::optional parseVarExprLoc(PerFunctionMIParsingState &PFS, const yaml::StringValue &VarStr, const yaml::StringValue &ExprStr, const yaml::StringValue &LocStr); template bool parseStackObjectsDebugInfo(PerFunctionMIParsingState &PFS, const T &Object, int FrameIdx); bool initializeConstantPool(PerFunctionMIParsingState &PFS, MachineConstantPool &ConstantPool, const yaml::MachineFunction &YamlMF); bool initializeJumpTableInfo(PerFunctionMIParsingState &PFS, const yaml::MachineJumpTable &YamlJTI); bool parseMachineMetadataNodes(PerFunctionMIParsingState &PFS, MachineFunction &MF, const yaml::MachineFunction &YMF); private: bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, const yaml::StringValue &Source); bool parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, const yaml::StringValue &Source); bool parseMachineMetadata(PerFunctionMIParsingState &PFS, const yaml::StringValue &Source); /// Return a MIR diagnostic converted from an MI string diagnostic. SMDiagnostic diagFromMIStringDiag(const SMDiagnostic &Error, SMRange SourceRange); /// Return a MIR diagnostic converted from a diagnostic located in a YAML /// block scalar string. SMDiagnostic diagFromBlockStringDiag(const SMDiagnostic &Error, SMRange SourceRange); void computeFunctionProperties(MachineFunction &MF); void setupDebugValueTracking(MachineFunction &MF, PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); }; } // end namespace llvm static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) { reinterpret_cast(Context)->reportDiagnostic(Diag); } MIRParserImpl::MIRParserImpl(std::unique_ptr Contents, StringRef Filename, LLVMContext &Context, std::function Callback) : Context(Context), In(SM.getMemoryBuffer(SM.AddNewSourceBuffer(std::move(Contents), SMLoc())) ->getBuffer(), nullptr, handleYAMLDiag, this), Filename(Filename), ProcessIRFunction(Callback) { In.setContext(&In); } bool MIRParserImpl::error(const Twine &Message) { Context.diagnose(DiagnosticInfoMIRParser( DS_Error, SMDiagnostic(Filename, SourceMgr::DK_Error, Message.str()))); return true; } bool MIRParserImpl::error(SMLoc Loc, const Twine &Message) { Context.diagnose(DiagnosticInfoMIRParser( DS_Error, SM.GetMessage(Loc, SourceMgr::DK_Error, Message))); return true; } bool MIRParserImpl::error(const SMDiagnostic &Error, SMRange SourceRange) { assert(Error.getKind() == SourceMgr::DK_Error && "Expected an error"); reportDiagnostic(diagFromMIStringDiag(Error, SourceRange)); return true; } void MIRParserImpl::reportDiagnostic(const SMDiagnostic &Diag) { DiagnosticSeverity Kind; switch (Diag.getKind()) { case SourceMgr::DK_Error: Kind = DS_Error; break; case SourceMgr::DK_Warning: Kind = DS_Warning; break; case SourceMgr::DK_Note: Kind = DS_Note; break; case SourceMgr::DK_Remark: llvm_unreachable("remark unexpected"); break; } Context.diagnose(DiagnosticInfoMIRParser(Kind, Diag)); } std::unique_ptr MIRParserImpl::parseIRModule(DataLayoutCallbackTy DataLayoutCallback) { if (!In.setCurrentDocument()) { if (In.error()) return nullptr; // Create an empty module when the MIR file is empty. NoMIRDocuments = true; auto M = std::make_unique(Filename, Context); if (auto LayoutOverride = DataLayoutCallback(M->getTargetTriple(), M->getDataLayoutStr())) M->setDataLayout(*LayoutOverride); return M; } std::unique_ptr M; // Parse the block scalar manually so that we can return unique pointer // without having to go trough YAML traits. if (const auto *BSN = dyn_cast_or_null(In.getCurrentNode())) { SMDiagnostic Error; M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error, Context, &IRSlots, DataLayoutCallback); if (!M) { reportDiagnostic(diagFromBlockStringDiag(Error, BSN->getSourceRange())); return nullptr; } In.nextDocument(); if (!In.setCurrentDocument()) NoMIRDocuments = true; } else { // Create an new, empty module. M = std::make_unique(Filename, Context); if (auto LayoutOverride = DataLayoutCallback(M->getTargetTriple(), M->getDataLayoutStr())) M->setDataLayout(*LayoutOverride); NoLLVMIR = true; } return M; } bool MIRParserImpl::parseMachineFunctions(Module &M, MachineModuleInfo &MMI) { if (NoMIRDocuments) return false; // Parse the machine functions. do { if (parseMachineFunction(M, MMI)) return true; In.nextDocument(); } while (In.setCurrentDocument()); return false; } Function *MIRParserImpl::createDummyFunction(StringRef Name, Module &M) { auto &Context = M.getContext(); Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Context), false), Function::ExternalLinkage, Name, M); BasicBlock *BB = BasicBlock::Create(Context, "entry", F); new UnreachableInst(Context, BB); if (ProcessIRFunction) ProcessIRFunction(*F); return F; } bool MIRParserImpl::parseMachineFunction(Module &M, MachineModuleInfo &MMI) { // Parse the yaml. yaml::MachineFunction YamlMF; yaml::EmptyContext Ctx; const LLVMTargetMachine &TM = MMI.getTarget(); YamlMF.MachineFuncInfo = std::unique_ptr( TM.createDefaultFuncInfoYAML()); yaml::yamlize(In, YamlMF, false, Ctx); if (In.error()) return true; // Search for the corresponding IR function. StringRef FunctionName = YamlMF.Name; Function *F = M.getFunction(FunctionName); if (!F) { if (NoLLVMIR) { F = createDummyFunction(FunctionName, M); } else { return error(Twine("function '") + FunctionName + "' isn't defined in the provided LLVM IR"); } } if (MMI.getMachineFunction(*F) != nullptr) return error(Twine("redefinition of machine function '") + FunctionName + "'"); // Create the MachineFunction. MachineFunction &MF = MMI.getOrCreateMachineFunction(*F); if (initializeMachineFunction(YamlMF, MF)) return true; return false; } static bool isSSA(const MachineFunction &MF) { const MachineRegisterInfo &MRI = MF.getRegInfo(); for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { Register Reg = Register::index2VirtReg(I); if (!MRI.hasOneDef(Reg) && !MRI.def_empty(Reg)) return false; // Subregister defs are invalid in SSA. const MachineOperand *RegDef = MRI.getOneDef(Reg); if (RegDef && RegDef->getSubReg() != 0) return false; } return true; } void MIRParserImpl::computeFunctionProperties(MachineFunction &MF) { MachineFunctionProperties &Properties = MF.getProperties(); bool HasPHI = false; bool HasInlineAsm = false; bool AllTiedOpsRewritten = true, HasTiedOps = false; for (const MachineBasicBlock &MBB : MF) { for (const MachineInstr &MI : MBB) { if (MI.isPHI()) HasPHI = true; if (MI.isInlineAsm()) HasInlineAsm = true; for (unsigned I = 0; I < MI.getNumOperands(); ++I) { const MachineOperand &MO = MI.getOperand(I); if (!MO.isReg() || !MO.getReg()) continue; unsigned DefIdx; if (MO.isUse() && MI.isRegTiedToDefOperand(I, &DefIdx)) { HasTiedOps = true; if (MO.getReg() != MI.getOperand(DefIdx).getReg()) AllTiedOpsRewritten = false; } } } } if (!HasPHI) Properties.set(MachineFunctionProperties::Property::NoPHIs); MF.setHasInlineAsm(HasInlineAsm); if (HasTiedOps && AllTiedOpsRewritten) Properties.set(MachineFunctionProperties::Property::TiedOpsRewritten); if (isSSA(MF)) Properties.set(MachineFunctionProperties::Property::IsSSA); else Properties.reset(MachineFunctionProperties::Property::IsSSA); const MachineRegisterInfo &MRI = MF.getRegInfo(); if (MRI.getNumVirtRegs() == 0) Properties.set(MachineFunctionProperties::Property::NoVRegs); } bool MIRParserImpl::initializeCallSiteInfo( PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { MachineFunction &MF = PFS.MF; SMDiagnostic Error; const LLVMTargetMachine &TM = MF.getTarget(); for (auto &YamlCSInfo : YamlMF.CallSitesInfo) { yaml::CallSiteInfo::MachineInstrLoc MILoc = YamlCSInfo.CallLocation; if (MILoc.BlockNum >= MF.size()) return error(Twine(MF.getName()) + Twine(" call instruction block out of range.") + " Unable to reference bb:" + Twine(MILoc.BlockNum)); auto CallB = std::next(MF.begin(), MILoc.BlockNum); if (MILoc.Offset >= CallB->size()) return error(Twine(MF.getName()) + Twine(" call instruction offset out of range.") + " Unable to reference instruction at bb: " + Twine(MILoc.BlockNum) + " at offset:" + Twine(MILoc.Offset)); auto CallI = std::next(CallB->instr_begin(), MILoc.Offset); if (!CallI->isCall(MachineInstr::IgnoreBundle)) return error(Twine(MF.getName()) + Twine(" call site info should reference call " "instruction. Instruction at bb:") + Twine(MILoc.BlockNum) + " at offset:" + Twine(MILoc.Offset) + " is not a call instruction"); MachineFunction::CallSiteInfo CSInfo; for (auto ArgRegPair : YamlCSInfo.ArgForwardingRegs) { Register Reg; if (parseNamedRegisterReference(PFS, Reg, ArgRegPair.Reg.Value, Error)) return error(Error, ArgRegPair.Reg.SourceRange); CSInfo.emplace_back(Reg, ArgRegPair.ArgNo); } if (TM.Options.EmitCallSiteInfo) MF.addCallArgsForwardingRegs(&*CallI, std::move(CSInfo)); } if (YamlMF.CallSitesInfo.size() && !TM.Options.EmitCallSiteInfo) return error(Twine("Call site info provided but not used")); return false; } void MIRParserImpl::setupDebugValueTracking( MachineFunction &MF, PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { // Compute the value of the "next instruction number" field. unsigned MaxInstrNum = 0; for (auto &MBB : MF) for (auto &MI : MBB) MaxInstrNum = std::max((unsigned)MI.peekDebugInstrNum(), MaxInstrNum); MF.setDebugInstrNumberingCount(MaxInstrNum); // Load any substitutions. for (const auto &Sub : YamlMF.DebugValueSubstitutions) { MF.makeDebugValueSubstitution({Sub.SrcInst, Sub.SrcOp}, {Sub.DstInst, Sub.DstOp}, Sub.Subreg); } // Flag for whether we're supposed to be using DBG_INSTR_REF. MF.setUseDebugInstrRef(YamlMF.UseDebugInstrRef); } bool MIRParserImpl::initializeMachineFunction(const yaml::MachineFunction &YamlMF, MachineFunction &MF) { // TODO: Recreate the machine function. if (Target) { // Avoid clearing state if we're using the same subtarget again. Target->setTarget(MF.getSubtarget()); } else { Target.reset(new PerTargetMIParsingState(MF.getSubtarget())); } MF.setAlignment(YamlMF.Alignment.valueOrOne()); MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); MF.setHasWinCFI(YamlMF.HasWinCFI); MF.setCallsEHReturn(YamlMF.CallsEHReturn); MF.setCallsUnwindInit(YamlMF.CallsUnwindInit); MF.setHasEHCatchret(YamlMF.HasEHCatchret); MF.setHasEHScopes(YamlMF.HasEHScopes); MF.setHasEHFunclets(YamlMF.HasEHFunclets); MF.setIsOutlined(YamlMF.IsOutlined); if (YamlMF.Legalized) MF.getProperties().set(MachineFunctionProperties::Property::Legalized); if (YamlMF.RegBankSelected) MF.getProperties().set( MachineFunctionProperties::Property::RegBankSelected); if (YamlMF.Selected) MF.getProperties().set(MachineFunctionProperties::Property::Selected); if (YamlMF.FailedISel) MF.getProperties().set(MachineFunctionProperties::Property::FailedISel); if (YamlMF.FailsVerification) MF.getProperties().set( MachineFunctionProperties::Property::FailsVerification); if (YamlMF.TracksDebugUserValues) MF.getProperties().set( MachineFunctionProperties::Property::TracksDebugUserValues); PerFunctionMIParsingState PFS(MF, SM, IRSlots, *Target); if (parseRegisterInfo(PFS, YamlMF)) return true; if (!YamlMF.Constants.empty()) { auto *ConstantPool = MF.getConstantPool(); assert(ConstantPool && "Constant pool must be created"); if (initializeConstantPool(PFS, *ConstantPool, YamlMF)) return true; } if (!YamlMF.MachineMetadataNodes.empty() && parseMachineMetadataNodes(PFS, MF, YamlMF)) return true; StringRef BlockStr = YamlMF.Body.Value.Value; SMDiagnostic Error; SourceMgr BlockSM; BlockSM.AddNewSourceBuffer( MemoryBuffer::getMemBuffer(BlockStr, "",/*RequiresNullTerminator=*/false), SMLoc()); PFS.SM = &BlockSM; if (parseMachineBasicBlockDefinitions(PFS, BlockStr, Error)) { reportDiagnostic( diagFromBlockStringDiag(Error, YamlMF.Body.Value.SourceRange)); return true; } // Check Basic Block Section Flags. if (MF.getTarget().getBBSectionsType() == BasicBlockSection::Labels) { MF.setBBSectionsType(BasicBlockSection::Labels); } else if (MF.hasBBSections()) { MF.assignBeginEndSections(); } PFS.SM = &SM; // Initialize the frame information after creating all the MBBs so that the // MBB references in the frame information can be resolved. if (initializeFrameInfo(PFS, YamlMF)) return true; // Initialize the jump table after creating all the MBBs so that the MBB // references can be resolved. if (!YamlMF.JumpTableInfo.Entries.empty() && initializeJumpTableInfo(PFS, YamlMF.JumpTableInfo)) return true; // Parse the machine instructions after creating all of the MBBs so that the // parser can resolve the MBB references. StringRef InsnStr = YamlMF.Body.Value.Value; SourceMgr InsnSM; InsnSM.AddNewSourceBuffer( MemoryBuffer::getMemBuffer(InsnStr, "", /*RequiresNullTerminator=*/false), SMLoc()); PFS.SM = &InsnSM; if (parseMachineInstructions(PFS, InsnStr, Error)) { reportDiagnostic( diagFromBlockStringDiag(Error, YamlMF.Body.Value.SourceRange)); return true; } PFS.SM = &SM; if (setupRegisterInfo(PFS, YamlMF)) return true; if (YamlMF.MachineFuncInfo) { const LLVMTargetMachine &TM = MF.getTarget(); // Note this is called after the initial constructor of the // MachineFunctionInfo based on the MachineFunction, which may depend on the // IR. SMRange SrcRange; if (TM.parseMachineFunctionInfo(*YamlMF.MachineFuncInfo, PFS, Error, SrcRange)) { return error(Error, SrcRange); } } // Set the reserved registers after parsing MachineFuncInfo. The target may // have been recording information used to select the reserved registers // there. // FIXME: This is a temporary workaround until the reserved registers can be // serialized. MachineRegisterInfo &MRI = MF.getRegInfo(); MRI.freezeReservedRegs(MF); computeFunctionProperties(MF); if (initializeCallSiteInfo(PFS, YamlMF)) return false; setupDebugValueTracking(MF, PFS, YamlMF); MF.getSubtarget().mirFileLoaded(MF); MF.verify(); return false; } bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { MachineFunction &MF = PFS.MF; MachineRegisterInfo &RegInfo = MF.getRegInfo(); assert(RegInfo.tracksLiveness()); if (!YamlMF.TracksRegLiveness) RegInfo.invalidateLiveness(); SMDiagnostic Error; // Parse the virtual register information. for (const auto &VReg : YamlMF.VirtualRegisters) { VRegInfo &Info = PFS.getVRegInfo(VReg.ID.Value); if (Info.Explicit) return error(VReg.ID.SourceRange.Start, Twine("redefinition of virtual register '%") + Twine(VReg.ID.Value) + "'"); Info.Explicit = true; if (StringRef(VReg.Class.Value).equals("_")) { Info.Kind = VRegInfo::GENERIC; Info.D.RegBank = nullptr; } else { const auto *RC = Target->getRegClass(VReg.Class.Value); if (RC) { Info.Kind = VRegInfo::NORMAL; Info.D.RC = RC; } else { const RegisterBank *RegBank = Target->getRegBank(VReg.Class.Value); if (!RegBank) return error( VReg.Class.SourceRange.Start, Twine("use of undefined register class or register bank '") + VReg.Class.Value + "'"); Info.Kind = VRegInfo::REGBANK; Info.D.RegBank = RegBank; } } if (!VReg.PreferredRegister.Value.empty()) { if (Info.Kind != VRegInfo::NORMAL) return error(VReg.Class.SourceRange.Start, Twine("preferred register can only be set for normal vregs")); if (parseRegisterReference(PFS, Info.PreferredReg, VReg.PreferredRegister.Value, Error)) return error(Error, VReg.PreferredRegister.SourceRange); } } // Parse the liveins. for (const auto &LiveIn : YamlMF.LiveIns) { Register Reg; if (parseNamedRegisterReference(PFS, Reg, LiveIn.Register.Value, Error)) return error(Error, LiveIn.Register.SourceRange); Register VReg; if (!LiveIn.VirtualRegister.Value.empty()) { VRegInfo *Info; if (parseVirtualRegisterReference(PFS, Info, LiveIn.VirtualRegister.Value, Error)) return error(Error, LiveIn.VirtualRegister.SourceRange); VReg = Info->VReg; } RegInfo.addLiveIn(Reg, VReg); } // Parse the callee saved registers (Registers that will // be saved for the caller). if (YamlMF.CalleeSavedRegisters) { SmallVector CalleeSavedRegisters; for (const auto &RegSource : *YamlMF.CalleeSavedRegisters) { Register Reg; if (parseNamedRegisterReference(PFS, Reg, RegSource.Value, Error)) return error(Error, RegSource.SourceRange); CalleeSavedRegisters.push_back(Reg); } RegInfo.setCalleeSavedRegs(CalleeSavedRegisters); } return false; } bool MIRParserImpl::setupRegisterInfo(const PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { MachineFunction &MF = PFS.MF; MachineRegisterInfo &MRI = MF.getRegInfo(); const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); bool Error = false; // Create VRegs auto populateVRegInfo = [&](const VRegInfo &Info, Twine Name) { Register Reg = Info.VReg; switch (Info.Kind) { case VRegInfo::UNKNOWN: error(Twine("Cannot determine class/bank of virtual register ") + Name + " in function '" + MF.getName() + "'"); Error = true; break; case VRegInfo::NORMAL: if (!Info.D.RC->isAllocatable()) { error(Twine("Cannot use non-allocatable class '") + TRI->getRegClassName(Info.D.RC) + "' for virtual register " + Name + " in function '" + MF.getName() + "'"); Error = true; break; } MRI.setRegClass(Reg, Info.D.RC); if (Info.PreferredReg != 0) MRI.setSimpleHint(Reg, Info.PreferredReg); break; case VRegInfo::GENERIC: break; case VRegInfo::REGBANK: MRI.setRegBank(Reg, *Info.D.RegBank); break; } }; for (const auto &P : PFS.VRegInfosNamed) { const VRegInfo &Info = *P.second; populateVRegInfo(Info, Twine(P.first())); } for (auto P : PFS.VRegInfos) { const VRegInfo &Info = *P.second; populateVRegInfo(Info, Twine(P.first)); } // Compute MachineRegisterInfo::UsedPhysRegMask for (const MachineBasicBlock &MBB : MF) { // Make sure MRI knows about registers clobbered by unwinder. if (MBB.isEHPad()) if (auto *RegMask = TRI->getCustomEHPadPreservedMask(MF)) MRI.addPhysRegsUsedFromRegMask(RegMask); for (const MachineInstr &MI : MBB) { for (const MachineOperand &MO : MI.operands()) { if (!MO.isRegMask()) continue; MRI.addPhysRegsUsedFromRegMask(MO.getRegMask()); } } } return Error; } bool MIRParserImpl::initializeFrameInfo(PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { MachineFunction &MF = PFS.MF; MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); const Function &F = MF.getFunction(); const yaml::MachineFrameInfo &YamlMFI = YamlMF.FrameInfo; MFI.setFrameAddressIsTaken(YamlMFI.IsFrameAddressTaken); MFI.setReturnAddressIsTaken(YamlMFI.IsReturnAddressTaken); MFI.setHasStackMap(YamlMFI.HasStackMap); MFI.setHasPatchPoint(YamlMFI.HasPatchPoint); MFI.setStackSize(YamlMFI.StackSize); MFI.setOffsetAdjustment(YamlMFI.OffsetAdjustment); if (YamlMFI.MaxAlignment) MFI.ensureMaxAlignment(Align(YamlMFI.MaxAlignment)); MFI.setAdjustsStack(YamlMFI.AdjustsStack); MFI.setHasCalls(YamlMFI.HasCalls); if (YamlMFI.MaxCallFrameSize != ~0u) MFI.setMaxCallFrameSize(YamlMFI.MaxCallFrameSize); MFI.setCVBytesOfCalleeSavedRegisters(YamlMFI.CVBytesOfCalleeSavedRegisters); MFI.setHasOpaqueSPAdjustment(YamlMFI.HasOpaqueSPAdjustment); MFI.setHasVAStart(YamlMFI.HasVAStart); MFI.setHasMustTailInVarArgFunc(YamlMFI.HasMustTailInVarArgFunc); MFI.setHasTailCall(YamlMFI.HasTailCall); MFI.setLocalFrameSize(YamlMFI.LocalFrameSize); if (!YamlMFI.SavePoint.Value.empty()) { MachineBasicBlock *MBB = nullptr; if (parseMBBReference(PFS, MBB, YamlMFI.SavePoint)) return true; MFI.setSavePoint(MBB); } if (!YamlMFI.RestorePoint.Value.empty()) { MachineBasicBlock *MBB = nullptr; if (parseMBBReference(PFS, MBB, YamlMFI.RestorePoint)) return true; MFI.setRestorePoint(MBB); } std::vector CSIInfo; // Initialize the fixed frame objects. for (const auto &Object : YamlMF.FixedStackObjects) { int ObjectIdx; if (Object.Type != yaml::FixedMachineStackObject::SpillSlot) ObjectIdx = MFI.CreateFixedObject(Object.Size, Object.Offset, Object.IsImmutable, Object.IsAliased); else ObjectIdx = MFI.CreateFixedSpillStackObject(Object.Size, Object.Offset); if (!TFI->isSupportedStackID(Object.StackID)) return error(Object.ID.SourceRange.Start, Twine("StackID is not supported by target")); MFI.setStackID(ObjectIdx, Object.StackID); MFI.setObjectAlignment(ObjectIdx, Object.Alignment.valueOrOne()); if (!PFS.FixedStackObjectSlots.insert(std::make_pair(Object.ID.Value, ObjectIdx)) .second) return error(Object.ID.SourceRange.Start, Twine("redefinition of fixed stack object '%fixed-stack.") + Twine(Object.ID.Value) + "'"); if (parseCalleeSavedRegister(PFS, CSIInfo, Object.CalleeSavedRegister, Object.CalleeSavedRestored, ObjectIdx)) return true; if (parseStackObjectsDebugInfo(PFS, Object, ObjectIdx)) return true; } for (const auto &Object : YamlMF.EntryValueObjects) { SMDiagnostic Error; Register Reg; if (parseNamedRegisterReference(PFS, Reg, Object.EntryValueRegister.Value, Error)) return error(Error, Object.EntryValueRegister.SourceRange); if (!Reg.isPhysical()) return error(Object.EntryValueRegister.SourceRange.Start, "Expected physical register for entry value field"); std::optional MaybeInfo = parseVarExprLoc( PFS, Object.DebugVar, Object.DebugExpr, Object.DebugLoc); if (!MaybeInfo) return true; if (MaybeInfo->DIVar || MaybeInfo->DIExpr || MaybeInfo->DILoc) PFS.MF.setVariableDbgInfo(MaybeInfo->DIVar, MaybeInfo->DIExpr, Reg.asMCReg(), MaybeInfo->DILoc); } // Initialize the ordinary frame objects. for (const auto &Object : YamlMF.StackObjects) { int ObjectIdx; const AllocaInst *Alloca = nullptr; const yaml::StringValue &Name = Object.Name; if (!Name.Value.empty()) { Alloca = dyn_cast_or_null( F.getValueSymbolTable()->lookup(Name.Value)); if (!Alloca) return error(Name.SourceRange.Start, "alloca instruction named '" + Name.Value + "' isn't defined in the function '" + F.getName() + "'"); } if (!TFI->isSupportedStackID(Object.StackID)) return error(Object.ID.SourceRange.Start, Twine("StackID is not supported by target")); if (Object.Type == yaml::MachineStackObject::VariableSized) ObjectIdx = MFI.CreateVariableSizedObject(Object.Alignment.valueOrOne(), Alloca); else ObjectIdx = MFI.CreateStackObject( Object.Size, Object.Alignment.valueOrOne(), Object.Type == yaml::MachineStackObject::SpillSlot, Alloca, Object.StackID); MFI.setObjectOffset(ObjectIdx, Object.Offset); if (!PFS.StackObjectSlots.insert(std::make_pair(Object.ID.Value, ObjectIdx)) .second) return error(Object.ID.SourceRange.Start, Twine("redefinition of stack object '%stack.") + Twine(Object.ID.Value) + "'"); if (parseCalleeSavedRegister(PFS, CSIInfo, Object.CalleeSavedRegister, Object.CalleeSavedRestored, ObjectIdx)) return true; if (Object.LocalOffset) MFI.mapLocalFrameObject(ObjectIdx, *Object.LocalOffset); if (parseStackObjectsDebugInfo(PFS, Object, ObjectIdx)) return true; } MFI.setCalleeSavedInfo(CSIInfo); if (!CSIInfo.empty()) MFI.setCalleeSavedInfoValid(true); // Initialize the various stack object references after initializing the // stack objects. if (!YamlMFI.StackProtector.Value.empty()) { SMDiagnostic Error; int FI; if (parseStackObjectReference(PFS, FI, YamlMFI.StackProtector.Value, Error)) return error(Error, YamlMFI.StackProtector.SourceRange); MFI.setStackProtectorIndex(FI); } if (!YamlMFI.FunctionContext.Value.empty()) { SMDiagnostic Error; int FI; if (parseStackObjectReference(PFS, FI, YamlMFI.FunctionContext.Value, Error)) return error(Error, YamlMFI.FunctionContext.SourceRange); MFI.setFunctionContextIndex(FI); } return false; } bool MIRParserImpl::parseCalleeSavedRegister(PerFunctionMIParsingState &PFS, std::vector &CSIInfo, const yaml::StringValue &RegisterSource, bool IsRestored, int FrameIdx) { if (RegisterSource.Value.empty()) return false; Register Reg; SMDiagnostic Error; if (parseNamedRegisterReference(PFS, Reg, RegisterSource.Value, Error)) return error(Error, RegisterSource.SourceRange); CalleeSavedInfo CSI(Reg, FrameIdx); CSI.setRestored(IsRestored); CSIInfo.push_back(CSI); return false; } /// Verify that given node is of a certain type. Return true on error. template static bool typecheckMDNode(T *&Result, MDNode *Node, const yaml::StringValue &Source, StringRef TypeString, MIRParserImpl &Parser) { if (!Node) return false; Result = dyn_cast(Node); if (!Result) return Parser.error(Source.SourceRange.Start, "expected a reference to a '" + TypeString + "' metadata node"); return false; } std::optional MIRParserImpl::parseVarExprLoc( PerFunctionMIParsingState &PFS, const yaml::StringValue &VarStr, const yaml::StringValue &ExprStr, const yaml::StringValue &LocStr) { MDNode *Var = nullptr; MDNode *Expr = nullptr; MDNode *Loc = nullptr; if (parseMDNode(PFS, Var, VarStr) || parseMDNode(PFS, Expr, ExprStr) || parseMDNode(PFS, Loc, LocStr)) return std::nullopt; DILocalVariable *DIVar = nullptr; DIExpression *DIExpr = nullptr; DILocation *DILoc = nullptr; if (typecheckMDNode(DIVar, Var, VarStr, "DILocalVariable", *this) || typecheckMDNode(DIExpr, Expr, ExprStr, "DIExpression", *this) || typecheckMDNode(DILoc, Loc, LocStr, "DILocation", *this)) return std::nullopt; return VarExprLoc{DIVar, DIExpr, DILoc}; } template bool MIRParserImpl::parseStackObjectsDebugInfo(PerFunctionMIParsingState &PFS, const T &Object, int FrameIdx) { std::optional MaybeInfo = parseVarExprLoc(PFS, Object.DebugVar, Object.DebugExpr, Object.DebugLoc); if (!MaybeInfo) return true; // Debug information can only be attached to stack objects; Fixed stack // objects aren't supported. if (MaybeInfo->DIVar || MaybeInfo->DIExpr || MaybeInfo->DILoc) PFS.MF.setVariableDbgInfo(MaybeInfo->DIVar, MaybeInfo->DIExpr, FrameIdx, MaybeInfo->DILoc); return false; } bool MIRParserImpl::parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, const yaml::StringValue &Source) { if (Source.Value.empty()) return false; SMDiagnostic Error; if (llvm::parseMDNode(PFS, Node, Source.Value, Error)) return error(Error, Source.SourceRange); return false; } bool MIRParserImpl::initializeConstantPool(PerFunctionMIParsingState &PFS, MachineConstantPool &ConstantPool, const yaml::MachineFunction &YamlMF) { DenseMap &ConstantPoolSlots = PFS.ConstantPoolSlots; const MachineFunction &MF = PFS.MF; const auto &M = *MF.getFunction().getParent(); SMDiagnostic Error; for (const auto &YamlConstant : YamlMF.Constants) { if (YamlConstant.IsTargetSpecific) // FIXME: Support target-specific constant pools return error(YamlConstant.Value.SourceRange.Start, "Can't parse target-specific constant pool entries yet"); const Constant *Value = dyn_cast_or_null( parseConstantValue(YamlConstant.Value.Value, Error, M)); if (!Value) return error(Error, YamlConstant.Value.SourceRange); const Align PrefTypeAlign = M.getDataLayout().getPrefTypeAlign(Value->getType()); const Align Alignment = YamlConstant.Alignment.value_or(PrefTypeAlign); unsigned Index = ConstantPool.getConstantPoolIndex(Value, Alignment); if (!ConstantPoolSlots.insert(std::make_pair(YamlConstant.ID.Value, Index)) .second) return error(YamlConstant.ID.SourceRange.Start, Twine("redefinition of constant pool item '%const.") + Twine(YamlConstant.ID.Value) + "'"); } return false; } bool MIRParserImpl::initializeJumpTableInfo(PerFunctionMIParsingState &PFS, const yaml::MachineJumpTable &YamlJTI) { MachineJumpTableInfo *JTI = PFS.MF.getOrCreateJumpTableInfo(YamlJTI.Kind); for (const auto &Entry : YamlJTI.Entries) { std::vector Blocks; for (const auto &MBBSource : Entry.Blocks) { MachineBasicBlock *MBB = nullptr; if (parseMBBReference(PFS, MBB, MBBSource.Value)) return true; Blocks.push_back(MBB); } unsigned Index = JTI->createJumpTableIndex(Blocks); if (!PFS.JumpTableSlots.insert(std::make_pair(Entry.ID.Value, Index)) .second) return error(Entry.ID.SourceRange.Start, Twine("redefinition of jump table entry '%jump-table.") + Twine(Entry.ID.Value) + "'"); } return false; } bool MIRParserImpl::parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, const yaml::StringValue &Source) { SMDiagnostic Error; if (llvm::parseMBBReference(PFS, MBB, Source.Value, Error)) return error(Error, Source.SourceRange); return false; } bool MIRParserImpl::parseMachineMetadata(PerFunctionMIParsingState &PFS, const yaml::StringValue &Source) { SMDiagnostic Error; if (llvm::parseMachineMetadata(PFS, Source.Value, Source.SourceRange, Error)) return error(Error, Source.SourceRange); return false; } bool MIRParserImpl::parseMachineMetadataNodes( PerFunctionMIParsingState &PFS, MachineFunction &MF, const yaml::MachineFunction &YMF) { for (const auto &MDS : YMF.MachineMetadataNodes) { if (parseMachineMetadata(PFS, MDS)) return true; } // Report missing definitions from forward referenced nodes. if (!PFS.MachineForwardRefMDNodes.empty()) return error(PFS.MachineForwardRefMDNodes.begin()->second.second, "use of undefined metadata '!" + Twine(PFS.MachineForwardRefMDNodes.begin()->first) + "'"); return false; } SMDiagnostic MIRParserImpl::diagFromMIStringDiag(const SMDiagnostic &Error, SMRange SourceRange) { assert(SourceRange.isValid() && "Invalid source range"); SMLoc Loc = SourceRange.Start; bool HasQuote = Loc.getPointer() < SourceRange.End.getPointer() && *Loc.getPointer() == '\''; // Translate the location of the error from the location in the MI string to // the corresponding location in the MIR file. Loc = Loc.getFromPointer(Loc.getPointer() + Error.getColumnNo() + (HasQuote ? 1 : 0)); // TODO: Translate any source ranges as well. return SM.GetMessage(Loc, Error.getKind(), Error.getMessage(), std::nullopt, Error.getFixIts()); } SMDiagnostic MIRParserImpl::diagFromBlockStringDiag(const SMDiagnostic &Error, SMRange SourceRange) { assert(SourceRange.isValid()); // Translate the location of the error from the location in the llvm IR string // to the corresponding location in the MIR file. auto LineAndColumn = SM.getLineAndColumn(SourceRange.Start); unsigned Line = LineAndColumn.first + Error.getLineNo() - 1; unsigned Column = Error.getColumnNo(); StringRef LineStr = Error.getLineContents(); SMLoc Loc = Error.getLoc(); // Get the full line and adjust the column number by taking the indentation of // LLVM IR into account. for (line_iterator L(*SM.getMemoryBuffer(SM.getMainFileID()), false), E; L != E; ++L) { if (L.line_number() == Line) { LineStr = *L; Loc = SMLoc::getFromPointer(LineStr.data()); auto Indent = LineStr.find(Error.getLineContents()); if (Indent != StringRef::npos) Column += Indent; break; } } return SMDiagnostic(SM, Loc, Filename, Line, Column, Error.getKind(), Error.getMessage(), LineStr, Error.getRanges(), Error.getFixIts()); } MIRParser::MIRParser(std::unique_ptr Impl) : Impl(std::move(Impl)) {} MIRParser::~MIRParser() = default; std::unique_ptr MIRParser::parseIRModule(DataLayoutCallbackTy DataLayoutCallback) { return Impl->parseIRModule(DataLayoutCallback); } bool MIRParser::parseMachineFunctions(Module &M, MachineModuleInfo &MMI) { return Impl->parseMachineFunctions(M, MMI); } std::unique_ptr llvm::createMIRParserFromFile( StringRef Filename, SMDiagnostic &Error, LLVMContext &Context, std::function ProcessIRFunction) { auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); if (std::error_code EC = FileOrErr.getError()) { Error = SMDiagnostic(Filename, SourceMgr::DK_Error, "Could not open input file: " + EC.message()); return nullptr; } return createMIRParser(std::move(FileOrErr.get()), Context, ProcessIRFunction); } std::unique_ptr llvm::createMIRParser(std::unique_ptr Contents, LLVMContext &Context, std::function ProcessIRFunction) { auto Filename = Contents->getBufferIdentifier(); if (Context.shouldDiscardValueNames()) { Context.diagnose(DiagnosticInfoMIRParser( DS_Error, SMDiagnostic( Filename, SourceMgr::DK_Error, "Can't read MIR with a Context that discards named Values"))); return nullptr; } return std::make_unique(std::make_unique( std::move(Contents), Filename, Context, ProcessIRFunction)); }