| //===- 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/STLExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/AsmParser/Parser.h" |
| #include "llvm/AsmParser/SlotMapping.h" |
| #include "llvm/CodeGen/GlobalISel/RegisterBank.h" |
| #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.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/DebugInfo.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 <memory> |
| |
| using namespace llvm; |
| |
| namespace llvm { |
| |
| /// This class implements the parsing of LLVM IR that's embedded inside a MIR |
| /// file. |
| class MIRParserImpl { |
| SourceMgr SM; |
| yaml::Input In; |
| StringRef Filename; |
| LLVMContext &Context; |
| SlotMapping IRSlots; |
| std::unique_ptr<PerTargetMIParsingState> 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<void(Function &)> ProcessIRFunction; |
| |
| public: |
| MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, StringRef Filename, |
| LLVMContext &Context, |
| std::function<void(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<Module> parseIRModule(); |
| |
| /// 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<CalleeSavedInfo> &CSIInfo, |
| const yaml::StringValue &RegisterSource, |
| bool IsRestored, int FrameIdx); |
| |
| template <typename T> |
| 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); |
| |
| private: |
| bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, |
| const yaml::StringValue &Source); |
| |
| bool parseMBBReference(PerFunctionMIParsingState &PFS, |
| MachineBasicBlock *&MBB, |
| 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); |
| }; |
| |
| } // end namespace llvm |
| |
| static void handleYAMLDiag(const SMDiagnostic &Diag, void *Context) { |
| reinterpret_cast<MIRParserImpl *>(Context)->reportDiagnostic(Diag); |
| } |
| |
| MIRParserImpl::MIRParserImpl(std::unique_ptr<MemoryBuffer> Contents, |
| StringRef Filename, LLVMContext &Context, |
| std::function<void(Function &)> Callback) |
| : SM(), |
| In(SM.getMemoryBuffer(SM.AddNewSourceBuffer(std::move(Contents), SMLoc())) |
| ->getBuffer(), |
| nullptr, handleYAMLDiag, this), |
| Filename(Filename), Context(Context), 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<Module> MIRParserImpl::parseIRModule() { |
| if (!In.setCurrentDocument()) { |
| if (In.error()) |
| return nullptr; |
| // Create an empty module when the MIR file is empty. |
| NoMIRDocuments = true; |
| return std::make_unique<Module>(Filename, Context); |
| } |
| |
| std::unique_ptr<Module> 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<yaml::BlockScalarNode>(In.getCurrentNode())) { |
| SMDiagnostic Error; |
| M = parseAssembly(MemoryBufferRef(BSN->getValue(), Filename), Error, |
| Context, &IRSlots, /*UpgradeDebugInfo=*/false); |
| 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<Module>(Filename, Context); |
| 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<yaml::MachineFunctionInfo>( |
| 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) { |
| unsigned Reg = Register::index2VirtReg(I); |
| if (!MRI.hasOneDef(Reg) && !MRI.def_empty(Reg)) |
| return false; |
| } |
| return true; |
| } |
| |
| void MIRParserImpl::computeFunctionProperties(MachineFunction &MF) { |
| MachineFunctionProperties &Properties = MF.getProperties(); |
| |
| bool HasPHI = false; |
| bool HasInlineAsm = false; |
| for (const MachineBasicBlock &MBB : MF) { |
| for (const MachineInstr &MI : MBB) { |
| if (MI.isPHI()) |
| HasPHI = true; |
| if (MI.isInlineAsm()) |
| HasInlineAsm = true; |
| } |
| } |
| if (!HasPHI) |
| Properties.set(MachineFunctionProperties::Property::NoPHIs); |
| MF.setHasInlineAsm(HasInlineAsm); |
| |
| 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) { |
| unsigned Reg = 0; |
| if (parseNamedRegisterReference(PFS, Reg, ArgRegPair.Reg.Value, Error)) |
| return error(Error, ArgRegPair.Reg.SourceRange); |
| CSInfo.emplace_back(Reg, ArgRegPair.ArgNo); |
| } |
| |
| if (TM.Options.EnableDebugEntryValues) |
| MF.addCallArgsForwardingRegs(&*CallI, std::move(CSInfo)); |
| } |
| |
| if (YamlMF.CallSitesInfo.size() && !TM.Options.EnableDebugEntryValues) |
| return error(Twine("Call site info provided but not used")); |
| return false; |
| } |
| |
| 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())); |
| } |
| |
| if (YamlMF.Alignment) |
| MF.setAlignment(Align(YamlMF.Alignment)); |
| MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); |
| MF.setHasWinCFI(YamlMF.HasWinCFI); |
| |
| 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); |
| |
| 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; |
| } |
| |
| 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; |
| } |
| 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; |
| |
| 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) { |
| unsigned Reg = 0; |
| if (parseNamedRegisterReference(PFS, Reg, LiveIn.Register.Value, Error)) |
| return error(Error, LiveIn.Register.SourceRange); |
| unsigned VReg = 0; |
| 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<MCPhysReg, 16> CalleeSavedRegisters; |
| for (const auto &RegSource : YamlMF.CalleeSavedRegisters.getValue()) { |
| unsigned Reg = 0; |
| 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(); |
| bool Error = false; |
| // Create VRegs |
| auto populateVRegInfo = [&] (const VRegInfo &Info, Twine Name) { |
| unsigned 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: |
| 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 (auto I = PFS.VRegInfosNamed.begin(), E = PFS.VRegInfosNamed.end(); |
| I != E; I++) { |
| const VRegInfo &Info = *I->second; |
| populateVRegInfo(Info, Twine(I->first())); |
| } |
| |
| for (auto P : PFS.VRegInfos) { |
| const VRegInfo &Info = *P.second; |
| populateVRegInfo(Info, Twine(P.first)); |
| } |
| |
| // Compute MachineRegisterInfo::UsedPhysRegMask |
| for (const MachineBasicBlock &MBB : MF) { |
| 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(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.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<CalleeSavedInfo> 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); |
| 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; |
| } |
| |
| // 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<AllocaInst>( |
| 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, Alloca); |
| else |
| ObjectIdx = MFI.CreateStackObject( |
| Object.Size, Object.Alignment, |
| 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.getValue()); |
| 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); |
| } |
| return false; |
| } |
| |
| bool MIRParserImpl::parseCalleeSavedRegister(PerFunctionMIParsingState &PFS, |
| std::vector<CalleeSavedInfo> &CSIInfo, |
| const yaml::StringValue &RegisterSource, bool IsRestored, int FrameIdx) { |
| if (RegisterSource.Value.empty()) |
| return false; |
| unsigned Reg = 0; |
| 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 <typename T> |
| static bool typecheckMDNode(T *&Result, MDNode *Node, |
| const yaml::StringValue &Source, |
| StringRef TypeString, MIRParserImpl &Parser) { |
| if (!Node) |
| return false; |
| Result = dyn_cast<T>(Node); |
| if (!Result) |
| return Parser.error(Source.SourceRange.Start, |
| "expected a reference to a '" + TypeString + |
| "' metadata node"); |
| return false; |
| } |
| |
| template <typename T> |
| bool MIRParserImpl::parseStackObjectsDebugInfo(PerFunctionMIParsingState &PFS, |
| const T &Object, int FrameIdx) { |
| // Debug information can only be attached to stack objects; Fixed stack |
| // objects aren't supported. |
| MDNode *Var = nullptr, *Expr = nullptr, *Loc = nullptr; |
| if (parseMDNode(PFS, Var, Object.DebugVar) || |
| parseMDNode(PFS, Expr, Object.DebugExpr) || |
| parseMDNode(PFS, Loc, Object.DebugLoc)) |
| return true; |
| if (!Var && !Expr && !Loc) |
| return false; |
| DILocalVariable *DIVar = nullptr; |
| DIExpression *DIExpr = nullptr; |
| DILocation *DILoc = nullptr; |
| if (typecheckMDNode(DIVar, Var, Object.DebugVar, "DILocalVariable", *this) || |
| typecheckMDNode(DIExpr, Expr, Object.DebugExpr, "DIExpression", *this) || |
| typecheckMDNode(DILoc, Loc, Object.DebugLoc, "DILocation", *this)) |
| return true; |
| PFS.MF.setVariableDbgInfo(DIVar, DIExpr, FrameIdx, 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<unsigned, unsigned> &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<Constant>( |
| parseConstantValue(YamlConstant.Value.Value, Error, M)); |
| if (!Value) |
| return error(Error, YamlConstant.Value.SourceRange); |
| unsigned Alignment = |
| YamlConstant.Alignment |
| ? YamlConstant.Alignment |
| : M.getDataLayout().getPrefTypeAlignment(Value->getType()); |
| 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<MachineBasicBlock *> 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; |
| } |
| |
| 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(), None, |
| 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<MIRParserImpl> Impl) |
| : Impl(std::move(Impl)) {} |
| |
| MIRParser::~MIRParser() {} |
| |
| std::unique_ptr<Module> MIRParser::parseIRModule() { |
| return Impl->parseIRModule(); |
| } |
| |
| bool MIRParser::parseMachineFunctions(Module &M, MachineModuleInfo &MMI) { |
| return Impl->parseMachineFunctions(M, MMI); |
| } |
| |
| std::unique_ptr<MIRParser> llvm::createMIRParserFromFile( |
| StringRef Filename, SMDiagnostic &Error, LLVMContext &Context, |
| std::function<void(Function &)> ProcessIRFunction) { |
| auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename); |
| 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<MIRParser> |
| llvm::createMIRParser(std::unique_ptr<MemoryBuffer> Contents, |
| LLVMContext &Context, |
| std::function<void(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<MIRParser>(std::make_unique<MIRParserImpl>( |
| std::move(Contents), Filename, Context, ProcessIRFunction)); |
| } |