| //===- MIRPrinter.cpp - MIR serialization format printer ------------------===// |
| // |
| // 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 prints out the LLVM IR and machine |
| // functions using the MIR serialization format. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/CodeGen/MIRPrinter.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/None.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallBitVector.h" |
| #include "llvm/ADT/SmallPtrSet.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/CodeGen/GlobalISel/RegisterBank.h" |
| #include "llvm/CodeGen/MIRYamlMapping.h" |
| #include "llvm/CodeGen/MachineBasicBlock.h" |
| #include "llvm/CodeGen/MachineConstantPool.h" |
| #include "llvm/CodeGen/MachineFrameInfo.h" |
| #include "llvm/CodeGen/MachineFunction.h" |
| #include "llvm/CodeGen/MachineInstr.h" |
| #include "llvm/CodeGen/MachineJumpTableInfo.h" |
| #include "llvm/CodeGen/MachineMemOperand.h" |
| #include "llvm/CodeGen/MachineModuleSlotTracker.h" |
| #include "llvm/CodeGen/MachineOperand.h" |
| #include "llvm/CodeGen/MachineRegisterInfo.h" |
| #include "llvm/CodeGen/PseudoSourceValue.h" |
| #include "llvm/CodeGen/TargetFrameLowering.h" |
| #include "llvm/CodeGen/TargetInstrInfo.h" |
| #include "llvm/CodeGen/TargetRegisterInfo.h" |
| #include "llvm/CodeGen/TargetSubtargetInfo.h" |
| #include "llvm/IR/BasicBlock.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/DebugInfo.h" |
| #include "llvm/IR/DebugLoc.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/GlobalValue.h" |
| #include "llvm/IR/IRPrintingPasses.h" |
| #include "llvm/IR/InstrTypes.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/Intrinsics.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/ModuleSlotTracker.h" |
| #include "llvm/IR/Value.h" |
| #include "llvm/MC/LaneBitmask.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/MC/MCDwarf.h" |
| #include "llvm/MC/MCSymbol.h" |
| #include "llvm/Support/AtomicOrdering.h" |
| #include "llvm/Support/BranchProbability.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/LowLevelTypeImpl.h" |
| #include "llvm/Support/YAMLTraits.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Target/TargetIntrinsicInfo.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <cinttypes> |
| #include <cstdint> |
| #include <iterator> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| using namespace llvm; |
| |
| static cl::opt<bool> SimplifyMIR( |
| "simplify-mir", cl::Hidden, |
| cl::desc("Leave out unnecessary information when printing MIR")); |
| |
| static cl::opt<bool> PrintLocations("mir-debug-loc", cl::Hidden, cl::init(true), |
| cl::desc("Print MIR debug-locations")); |
| |
| namespace { |
| |
| /// This structure describes how to print out stack object references. |
| struct FrameIndexOperand { |
| std::string Name; |
| unsigned ID; |
| bool IsFixed; |
| |
| FrameIndexOperand(StringRef Name, unsigned ID, bool IsFixed) |
| : Name(Name.str()), ID(ID), IsFixed(IsFixed) {} |
| |
| /// Return an ordinary stack object reference. |
| static FrameIndexOperand create(StringRef Name, unsigned ID) { |
| return FrameIndexOperand(Name, ID, /*IsFixed=*/false); |
| } |
| |
| /// Return a fixed stack object reference. |
| static FrameIndexOperand createFixed(unsigned ID) { |
| return FrameIndexOperand("", ID, /*IsFixed=*/true); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| namespace llvm { |
| |
| /// This class prints out the machine functions using the MIR serialization |
| /// format. |
| class MIRPrinter { |
| raw_ostream &OS; |
| DenseMap<const uint32_t *, unsigned> RegisterMaskIds; |
| /// Maps from stack object indices to operand indices which will be used when |
| /// printing frame index machine operands. |
| DenseMap<int, FrameIndexOperand> StackObjectOperandMapping; |
| |
| public: |
| MIRPrinter(raw_ostream &OS) : OS(OS) {} |
| |
| void print(const MachineFunction &MF); |
| |
| void convert(yaml::MachineFunction &MF, const MachineRegisterInfo &RegInfo, |
| const TargetRegisterInfo *TRI); |
| void convert(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI, |
| const MachineFrameInfo &MFI); |
| void convert(yaml::MachineFunction &MF, |
| const MachineConstantPool &ConstantPool); |
| void convert(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI, |
| const MachineJumpTableInfo &JTI); |
| void convertStackObjects(yaml::MachineFunction &YMF, |
| const MachineFunction &MF, ModuleSlotTracker &MST); |
| void convertCallSiteObjects(yaml::MachineFunction &YMF, |
| const MachineFunction &MF, |
| ModuleSlotTracker &MST); |
| void convertMachineMetadataNodes(yaml::MachineFunction &YMF, |
| const MachineFunction &MF, |
| MachineModuleSlotTracker &MST); |
| |
| private: |
| void initRegisterMaskIds(const MachineFunction &MF); |
| }; |
| |
| /// This class prints out the machine instructions using the MIR serialization |
| /// format. |
| class MIPrinter { |
| raw_ostream &OS; |
| ModuleSlotTracker &MST; |
| const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds; |
| const DenseMap<int, FrameIndexOperand> &StackObjectOperandMapping; |
| /// Synchronization scope names registered with LLVMContext. |
| SmallVector<StringRef, 8> SSNs; |
| |
| bool canPredictBranchProbabilities(const MachineBasicBlock &MBB) const; |
| bool canPredictSuccessors(const MachineBasicBlock &MBB) const; |
| |
| public: |
| MIPrinter(raw_ostream &OS, ModuleSlotTracker &MST, |
| const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds, |
| const DenseMap<int, FrameIndexOperand> &StackObjectOperandMapping) |
| : OS(OS), MST(MST), RegisterMaskIds(RegisterMaskIds), |
| StackObjectOperandMapping(StackObjectOperandMapping) {} |
| |
| void print(const MachineBasicBlock &MBB); |
| |
| void print(const MachineInstr &MI); |
| void printStackObjectReference(int FrameIndex); |
| void print(const MachineInstr &MI, unsigned OpIdx, |
| const TargetRegisterInfo *TRI, const TargetInstrInfo *TII, |
| bool ShouldPrintRegisterTies, LLT TypeToPrint, |
| bool PrintDef = true); |
| }; |
| |
| } // end namespace llvm |
| |
| namespace llvm { |
| namespace yaml { |
| |
| /// This struct serializes the LLVM IR module. |
| template <> struct BlockScalarTraits<Module> { |
| static void output(const Module &Mod, void *Ctxt, raw_ostream &OS) { |
| Mod.print(OS, nullptr); |
| } |
| |
| static StringRef input(StringRef Str, void *Ctxt, Module &Mod) { |
| llvm_unreachable("LLVM Module is supposed to be parsed separately"); |
| return ""; |
| } |
| }; |
| |
| } // end namespace yaml |
| } // end namespace llvm |
| |
| static void printRegMIR(unsigned Reg, yaml::StringValue &Dest, |
| const TargetRegisterInfo *TRI) { |
| raw_string_ostream OS(Dest.Value); |
| OS << printReg(Reg, TRI); |
| } |
| |
| void MIRPrinter::print(const MachineFunction &MF) { |
| initRegisterMaskIds(MF); |
| |
| yaml::MachineFunction YamlMF; |
| YamlMF.Name = MF.getName(); |
| YamlMF.Alignment = MF.getAlignment(); |
| YamlMF.ExposesReturnsTwice = MF.exposesReturnsTwice(); |
| YamlMF.HasWinCFI = MF.hasWinCFI(); |
| |
| YamlMF.Legalized = MF.getProperties().hasProperty( |
| MachineFunctionProperties::Property::Legalized); |
| YamlMF.RegBankSelected = MF.getProperties().hasProperty( |
| MachineFunctionProperties::Property::RegBankSelected); |
| YamlMF.Selected = MF.getProperties().hasProperty( |
| MachineFunctionProperties::Property::Selected); |
| YamlMF.FailedISel = MF.getProperties().hasProperty( |
| MachineFunctionProperties::Property::FailedISel); |
| YamlMF.FailsVerification = MF.getProperties().hasProperty( |
| MachineFunctionProperties::Property::FailsVerification); |
| |
| convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo()); |
| MachineModuleSlotTracker MST(&MF); |
| MST.incorporateFunction(MF.getFunction()); |
| convert(MST, YamlMF.FrameInfo, MF.getFrameInfo()); |
| convertStackObjects(YamlMF, MF, MST); |
| convertCallSiteObjects(YamlMF, MF, MST); |
| for (const auto &Sub : MF.DebugValueSubstitutions) { |
| const auto &SubSrc = Sub.Src; |
| const auto &SubDest = Sub.Dest; |
| YamlMF.DebugValueSubstitutions.push_back({SubSrc.first, SubSrc.second, |
| SubDest.first, |
| SubDest.second, |
| Sub.Subreg}); |
| } |
| if (const auto *ConstantPool = MF.getConstantPool()) |
| convert(YamlMF, *ConstantPool); |
| if (const auto *JumpTableInfo = MF.getJumpTableInfo()) |
| convert(MST, YamlMF.JumpTableInfo, *JumpTableInfo); |
| |
| const TargetMachine &TM = MF.getTarget(); |
| YamlMF.MachineFuncInfo = |
| std::unique_ptr<yaml::MachineFunctionInfo>(TM.convertFuncInfoToYAML(MF)); |
| |
| raw_string_ostream StrOS(YamlMF.Body.Value.Value); |
| bool IsNewlineNeeded = false; |
| for (const auto &MBB : MF) { |
| if (IsNewlineNeeded) |
| StrOS << "\n"; |
| MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping) |
| .print(MBB); |
| IsNewlineNeeded = true; |
| } |
| StrOS.flush(); |
| // Convert machine metadata collected during the print of the machine |
| // function. |
| convertMachineMetadataNodes(YamlMF, MF, MST); |
| |
| yaml::Output Out(OS); |
| if (!SimplifyMIR) |
| Out.setWriteDefaultValues(true); |
| Out << YamlMF; |
| } |
| |
| static void printCustomRegMask(const uint32_t *RegMask, raw_ostream &OS, |
| const TargetRegisterInfo *TRI) { |
| assert(RegMask && "Can't print an empty register mask"); |
| OS << StringRef("CustomRegMask("); |
| |
| bool IsRegInRegMaskFound = false; |
| for (int I = 0, E = TRI->getNumRegs(); I < E; I++) { |
| // Check whether the register is asserted in regmask. |
| if (RegMask[I / 32] & (1u << (I % 32))) { |
| if (IsRegInRegMaskFound) |
| OS << ','; |
| OS << printReg(I, TRI); |
| IsRegInRegMaskFound = true; |
| } |
| } |
| |
| OS << ')'; |
| } |
| |
| static void printRegClassOrBank(unsigned Reg, yaml::StringValue &Dest, |
| const MachineRegisterInfo &RegInfo, |
| const TargetRegisterInfo *TRI) { |
| raw_string_ostream OS(Dest.Value); |
| OS << printRegClassOrBank(Reg, RegInfo, TRI); |
| } |
| |
| template <typename T> |
| static void |
| printStackObjectDbgInfo(const MachineFunction::VariableDbgInfo &DebugVar, |
| T &Object, ModuleSlotTracker &MST) { |
| std::array<std::string *, 3> Outputs{{&Object.DebugVar.Value, |
| &Object.DebugExpr.Value, |
| &Object.DebugLoc.Value}}; |
| std::array<const Metadata *, 3> Metas{{DebugVar.Var, |
| DebugVar.Expr, |
| DebugVar.Loc}}; |
| for (unsigned i = 0; i < 3; ++i) { |
| raw_string_ostream StrOS(*Outputs[i]); |
| Metas[i]->printAsOperand(StrOS, MST); |
| } |
| } |
| |
| void MIRPrinter::convert(yaml::MachineFunction &MF, |
| const MachineRegisterInfo &RegInfo, |
| const TargetRegisterInfo *TRI) { |
| MF.TracksRegLiveness = RegInfo.tracksLiveness(); |
| |
| // Print the virtual register definitions. |
| for (unsigned I = 0, E = RegInfo.getNumVirtRegs(); I < E; ++I) { |
| unsigned Reg = Register::index2VirtReg(I); |
| yaml::VirtualRegisterDefinition VReg; |
| VReg.ID = I; |
| if (RegInfo.getVRegName(Reg) != "") |
| continue; |
| ::printRegClassOrBank(Reg, VReg.Class, RegInfo, TRI); |
| unsigned PreferredReg = RegInfo.getSimpleHint(Reg); |
| if (PreferredReg) |
| printRegMIR(PreferredReg, VReg.PreferredRegister, TRI); |
| MF.VirtualRegisters.push_back(VReg); |
| } |
| |
| // Print the live ins. |
| for (std::pair<unsigned, unsigned> LI : RegInfo.liveins()) { |
| yaml::MachineFunctionLiveIn LiveIn; |
| printRegMIR(LI.first, LiveIn.Register, TRI); |
| if (LI.second) |
| printRegMIR(LI.second, LiveIn.VirtualRegister, TRI); |
| MF.LiveIns.push_back(LiveIn); |
| } |
| |
| // Prints the callee saved registers. |
| if (RegInfo.isUpdatedCSRsInitialized()) { |
| const MCPhysReg *CalleeSavedRegs = RegInfo.getCalleeSavedRegs(); |
| std::vector<yaml::FlowStringValue> CalleeSavedRegisters; |
| for (const MCPhysReg *I = CalleeSavedRegs; *I; ++I) { |
| yaml::FlowStringValue Reg; |
| printRegMIR(*I, Reg, TRI); |
| CalleeSavedRegisters.push_back(Reg); |
| } |
| MF.CalleeSavedRegisters = CalleeSavedRegisters; |
| } |
| } |
| |
| void MIRPrinter::convert(ModuleSlotTracker &MST, |
| yaml::MachineFrameInfo &YamlMFI, |
| const MachineFrameInfo &MFI) { |
| YamlMFI.IsFrameAddressTaken = MFI.isFrameAddressTaken(); |
| YamlMFI.IsReturnAddressTaken = MFI.isReturnAddressTaken(); |
| YamlMFI.HasStackMap = MFI.hasStackMap(); |
| YamlMFI.HasPatchPoint = MFI.hasPatchPoint(); |
| YamlMFI.StackSize = MFI.getStackSize(); |
| YamlMFI.OffsetAdjustment = MFI.getOffsetAdjustment(); |
| YamlMFI.MaxAlignment = MFI.getMaxAlign().value(); |
| YamlMFI.AdjustsStack = MFI.adjustsStack(); |
| YamlMFI.HasCalls = MFI.hasCalls(); |
| YamlMFI.MaxCallFrameSize = MFI.isMaxCallFrameSizeComputed() |
| ? MFI.getMaxCallFrameSize() : ~0u; |
| YamlMFI.CVBytesOfCalleeSavedRegisters = |
| MFI.getCVBytesOfCalleeSavedRegisters(); |
| YamlMFI.HasOpaqueSPAdjustment = MFI.hasOpaqueSPAdjustment(); |
| YamlMFI.HasVAStart = MFI.hasVAStart(); |
| YamlMFI.HasMustTailInVarArgFunc = MFI.hasMustTailInVarArgFunc(); |
| YamlMFI.HasTailCall = MFI.hasTailCall(); |
| YamlMFI.LocalFrameSize = MFI.getLocalFrameSize(); |
| if (MFI.getSavePoint()) { |
| raw_string_ostream StrOS(YamlMFI.SavePoint.Value); |
| StrOS << printMBBReference(*MFI.getSavePoint()); |
| } |
| if (MFI.getRestorePoint()) { |
| raw_string_ostream StrOS(YamlMFI.RestorePoint.Value); |
| StrOS << printMBBReference(*MFI.getRestorePoint()); |
| } |
| } |
| |
| void MIRPrinter::convertStackObjects(yaml::MachineFunction &YMF, |
| const MachineFunction &MF, |
| ModuleSlotTracker &MST) { |
| const MachineFrameInfo &MFI = MF.getFrameInfo(); |
| const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); |
| |
| // Process fixed stack objects. |
| assert(YMF.FixedStackObjects.empty()); |
| SmallVector<int, 32> FixedStackObjectsIdx; |
| const int BeginIdx = MFI.getObjectIndexBegin(); |
| if (BeginIdx < 0) |
| FixedStackObjectsIdx.reserve(-BeginIdx); |
| |
| unsigned ID = 0; |
| for (int I = BeginIdx; I < 0; ++I, ++ID) { |
| FixedStackObjectsIdx.push_back(-1); // Fill index for possible dead. |
| if (MFI.isDeadObjectIndex(I)) |
| continue; |
| |
| yaml::FixedMachineStackObject YamlObject; |
| YamlObject.ID = ID; |
| YamlObject.Type = MFI.isSpillSlotObjectIndex(I) |
| ? yaml::FixedMachineStackObject::SpillSlot |
| : yaml::FixedMachineStackObject::DefaultType; |
| YamlObject.Offset = MFI.getObjectOffset(I); |
| YamlObject.Size = MFI.getObjectSize(I); |
| YamlObject.Alignment = MFI.getObjectAlign(I); |
| YamlObject.StackID = (TargetStackID::Value)MFI.getStackID(I); |
| YamlObject.IsImmutable = MFI.isImmutableObjectIndex(I); |
| YamlObject.IsAliased = MFI.isAliasedObjectIndex(I); |
| // Save the ID' position in FixedStackObjects storage vector. |
| FixedStackObjectsIdx[ID] = YMF.FixedStackObjects.size(); |
| YMF.FixedStackObjects.push_back(YamlObject); |
| StackObjectOperandMapping.insert( |
| std::make_pair(I, FrameIndexOperand::createFixed(ID))); |
| } |
| |
| // Process ordinary stack objects. |
| assert(YMF.StackObjects.empty()); |
| SmallVector<unsigned, 32> StackObjectsIdx; |
| const int EndIdx = MFI.getObjectIndexEnd(); |
| if (EndIdx > 0) |
| StackObjectsIdx.reserve(EndIdx); |
| ID = 0; |
| for (int I = 0; I < EndIdx; ++I, ++ID) { |
| StackObjectsIdx.push_back(-1); // Fill index for possible dead. |
| if (MFI.isDeadObjectIndex(I)) |
| continue; |
| |
| yaml::MachineStackObject YamlObject; |
| YamlObject.ID = ID; |
| if (const auto *Alloca = MFI.getObjectAllocation(I)) |
| YamlObject.Name.Value = std::string( |
| Alloca->hasName() ? Alloca->getName() : ""); |
| YamlObject.Type = MFI.isSpillSlotObjectIndex(I) |
| ? yaml::MachineStackObject::SpillSlot |
| : MFI.isVariableSizedObjectIndex(I) |
| ? yaml::MachineStackObject::VariableSized |
| : yaml::MachineStackObject::DefaultType; |
| YamlObject.Offset = MFI.getObjectOffset(I); |
| YamlObject.Size = MFI.getObjectSize(I); |
| YamlObject.Alignment = MFI.getObjectAlign(I); |
| YamlObject.StackID = (TargetStackID::Value)MFI.getStackID(I); |
| |
| // Save the ID' position in StackObjects storage vector. |
| StackObjectsIdx[ID] = YMF.StackObjects.size(); |
| YMF.StackObjects.push_back(YamlObject); |
| StackObjectOperandMapping.insert(std::make_pair( |
| I, FrameIndexOperand::create(YamlObject.Name.Value, ID))); |
| } |
| |
| for (const auto &CSInfo : MFI.getCalleeSavedInfo()) { |
| const int FrameIdx = CSInfo.getFrameIdx(); |
| if (!CSInfo.isSpilledToReg() && MFI.isDeadObjectIndex(FrameIdx)) |
| continue; |
| |
| yaml::StringValue Reg; |
| printRegMIR(CSInfo.getReg(), Reg, TRI); |
| if (!CSInfo.isSpilledToReg()) { |
| assert(FrameIdx >= MFI.getObjectIndexBegin() && |
| FrameIdx < MFI.getObjectIndexEnd() && |
| "Invalid stack object index"); |
| if (FrameIdx < 0) { // Negative index means fixed objects. |
| auto &Object = |
| YMF.FixedStackObjects |
| [FixedStackObjectsIdx[FrameIdx + MFI.getNumFixedObjects()]]; |
| Object.CalleeSavedRegister = Reg; |
| Object.CalleeSavedRestored = CSInfo.isRestored(); |
| } else { |
| auto &Object = YMF.StackObjects[StackObjectsIdx[FrameIdx]]; |
| Object.CalleeSavedRegister = Reg; |
| Object.CalleeSavedRestored = CSInfo.isRestored(); |
| } |
| } |
| } |
| for (unsigned I = 0, E = MFI.getLocalFrameObjectCount(); I < E; ++I) { |
| auto LocalObject = MFI.getLocalFrameObjectMap(I); |
| assert(LocalObject.first >= 0 && "Expected a locally mapped stack object"); |
| YMF.StackObjects[StackObjectsIdx[LocalObject.first]].LocalOffset = |
| LocalObject.second; |
| } |
| |
| // Print the stack object references in the frame information class after |
| // converting the stack objects. |
| if (MFI.hasStackProtectorIndex()) { |
| raw_string_ostream StrOS(YMF.FrameInfo.StackProtector.Value); |
| MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping) |
| .printStackObjectReference(MFI.getStackProtectorIndex()); |
| } |
| |
| // Print the debug variable information. |
| for (const MachineFunction::VariableDbgInfo &DebugVar : |
| MF.getVariableDbgInfo()) { |
| assert(DebugVar.Slot >= MFI.getObjectIndexBegin() && |
| DebugVar.Slot < MFI.getObjectIndexEnd() && |
| "Invalid stack object index"); |
| if (DebugVar.Slot < 0) { // Negative index means fixed objects. |
| auto &Object = |
| YMF.FixedStackObjects[FixedStackObjectsIdx[DebugVar.Slot + |
| MFI.getNumFixedObjects()]]; |
| printStackObjectDbgInfo(DebugVar, Object, MST); |
| } else { |
| auto &Object = YMF.StackObjects[StackObjectsIdx[DebugVar.Slot]]; |
| printStackObjectDbgInfo(DebugVar, Object, MST); |
| } |
| } |
| } |
| |
| void MIRPrinter::convertCallSiteObjects(yaml::MachineFunction &YMF, |
| const MachineFunction &MF, |
| ModuleSlotTracker &MST) { |
| const auto *TRI = MF.getSubtarget().getRegisterInfo(); |
| for (auto CSInfo : MF.getCallSitesInfo()) { |
| yaml::CallSiteInfo YmlCS; |
| yaml::CallSiteInfo::MachineInstrLoc CallLocation; |
| |
| // Prepare instruction position. |
| MachineBasicBlock::const_instr_iterator CallI = CSInfo.first->getIterator(); |
| CallLocation.BlockNum = CallI->getParent()->getNumber(); |
| // Get call instruction offset from the beginning of block. |
| CallLocation.Offset = |
| std::distance(CallI->getParent()->instr_begin(), CallI); |
| YmlCS.CallLocation = CallLocation; |
| // Construct call arguments and theirs forwarding register info. |
| for (auto ArgReg : CSInfo.second) { |
| yaml::CallSiteInfo::ArgRegPair YmlArgReg; |
| YmlArgReg.ArgNo = ArgReg.ArgNo; |
| printRegMIR(ArgReg.Reg, YmlArgReg.Reg, TRI); |
| YmlCS.ArgForwardingRegs.emplace_back(YmlArgReg); |
| } |
| YMF.CallSitesInfo.push_back(YmlCS); |
| } |
| |
| // Sort call info by position of call instructions. |
| llvm::sort(YMF.CallSitesInfo.begin(), YMF.CallSitesInfo.end(), |
| [](yaml::CallSiteInfo A, yaml::CallSiteInfo B) { |
| if (A.CallLocation.BlockNum == B.CallLocation.BlockNum) |
| return A.CallLocation.Offset < B.CallLocation.Offset; |
| return A.CallLocation.BlockNum < B.CallLocation.BlockNum; |
| }); |
| } |
| |
| void MIRPrinter::convertMachineMetadataNodes(yaml::MachineFunction &YMF, |
| const MachineFunction &MF, |
| MachineModuleSlotTracker &MST) { |
| MachineModuleSlotTracker::MachineMDNodeListType MDList; |
| MST.collectMachineMDNodes(MDList); |
| for (auto &MD : MDList) { |
| std::string NS; |
| raw_string_ostream StrOS(NS); |
| MD.second->print(StrOS, MST, MF.getFunction().getParent()); |
| YMF.MachineMetadataNodes.push_back(StrOS.str()); |
| } |
| } |
| |
| void MIRPrinter::convert(yaml::MachineFunction &MF, |
| const MachineConstantPool &ConstantPool) { |
| unsigned ID = 0; |
| for (const MachineConstantPoolEntry &Constant : ConstantPool.getConstants()) { |
| std::string Str; |
| raw_string_ostream StrOS(Str); |
| if (Constant.isMachineConstantPoolEntry()) { |
| Constant.Val.MachineCPVal->print(StrOS); |
| } else { |
| Constant.Val.ConstVal->printAsOperand(StrOS); |
| } |
| |
| yaml::MachineConstantPoolValue YamlConstant; |
| YamlConstant.ID = ID++; |
| YamlConstant.Value = StrOS.str(); |
| YamlConstant.Alignment = Constant.getAlign(); |
| YamlConstant.IsTargetSpecific = Constant.isMachineConstantPoolEntry(); |
| |
| MF.Constants.push_back(YamlConstant); |
| } |
| } |
| |
| void MIRPrinter::convert(ModuleSlotTracker &MST, |
| yaml::MachineJumpTable &YamlJTI, |
| const MachineJumpTableInfo &JTI) { |
| YamlJTI.Kind = JTI.getEntryKind(); |
| unsigned ID = 0; |
| for (const auto &Table : JTI.getJumpTables()) { |
| std::string Str; |
| yaml::MachineJumpTable::Entry Entry; |
| Entry.ID = ID++; |
| for (const auto *MBB : Table.MBBs) { |
| raw_string_ostream StrOS(Str); |
| StrOS << printMBBReference(*MBB); |
| Entry.Blocks.push_back(StrOS.str()); |
| Str.clear(); |
| } |
| YamlJTI.Entries.push_back(Entry); |
| } |
| } |
| |
| void MIRPrinter::initRegisterMaskIds(const MachineFunction &MF) { |
| const auto *TRI = MF.getSubtarget().getRegisterInfo(); |
| unsigned I = 0; |
| for (const uint32_t *Mask : TRI->getRegMasks()) |
| RegisterMaskIds.insert(std::make_pair(Mask, I++)); |
| } |
| |
| void llvm::guessSuccessors(const MachineBasicBlock &MBB, |
| SmallVectorImpl<MachineBasicBlock*> &Result, |
| bool &IsFallthrough) { |
| SmallPtrSet<MachineBasicBlock*,8> Seen; |
| |
| for (const MachineInstr &MI : MBB) { |
| if (MI.isPHI()) |
| continue; |
| for (const MachineOperand &MO : MI.operands()) { |
| if (!MO.isMBB()) |
| continue; |
| MachineBasicBlock *Succ = MO.getMBB(); |
| auto RP = Seen.insert(Succ); |
| if (RP.second) |
| Result.push_back(Succ); |
| } |
| } |
| MachineBasicBlock::const_iterator I = MBB.getLastNonDebugInstr(); |
| IsFallthrough = I == MBB.end() || !I->isBarrier(); |
| } |
| |
| bool |
| MIPrinter::canPredictBranchProbabilities(const MachineBasicBlock &MBB) const { |
| if (MBB.succ_size() <= 1) |
| return true; |
| if (!MBB.hasSuccessorProbabilities()) |
| return true; |
| |
| SmallVector<BranchProbability,8> Normalized(MBB.Probs.begin(), |
| MBB.Probs.end()); |
| BranchProbability::normalizeProbabilities(Normalized.begin(), |
| Normalized.end()); |
| SmallVector<BranchProbability,8> Equal(Normalized.size()); |
| BranchProbability::normalizeProbabilities(Equal.begin(), Equal.end()); |
| |
| return std::equal(Normalized.begin(), Normalized.end(), Equal.begin()); |
| } |
| |
| bool MIPrinter::canPredictSuccessors(const MachineBasicBlock &MBB) const { |
| SmallVector<MachineBasicBlock*,8> GuessedSuccs; |
| bool GuessedFallthrough; |
| guessSuccessors(MBB, GuessedSuccs, GuessedFallthrough); |
| if (GuessedFallthrough) { |
| const MachineFunction &MF = *MBB.getParent(); |
| MachineFunction::const_iterator NextI = std::next(MBB.getIterator()); |
| if (NextI != MF.end()) { |
| MachineBasicBlock *Next = const_cast<MachineBasicBlock*>(&*NextI); |
| if (!is_contained(GuessedSuccs, Next)) |
| GuessedSuccs.push_back(Next); |
| } |
| } |
| if (GuessedSuccs.size() != MBB.succ_size()) |
| return false; |
| return std::equal(MBB.succ_begin(), MBB.succ_end(), GuessedSuccs.begin()); |
| } |
| |
| void MIPrinter::print(const MachineBasicBlock &MBB) { |
| assert(MBB.getNumber() >= 0 && "Invalid MBB number"); |
| MBB.printName(OS, |
| MachineBasicBlock::PrintNameIr | |
| MachineBasicBlock::PrintNameAttributes, |
| &MST); |
| OS << ":\n"; |
| |
| bool HasLineAttributes = false; |
| // Print the successors |
| bool canPredictProbs = canPredictBranchProbabilities(MBB); |
| // Even if the list of successors is empty, if we cannot guess it, |
| // we need to print it to tell the parser that the list is empty. |
| // This is needed, because MI model unreachable as empty blocks |
| // with an empty successor list. If the parser would see that |
| // without the successor list, it would guess the code would |
| // fallthrough. |
| if ((!MBB.succ_empty() && !SimplifyMIR) || !canPredictProbs || |
| !canPredictSuccessors(MBB)) { |
| OS.indent(2) << "successors: "; |
| for (auto I = MBB.succ_begin(), E = MBB.succ_end(); I != E; ++I) { |
| if (I != MBB.succ_begin()) |
| OS << ", "; |
| OS << printMBBReference(**I); |
| if (!SimplifyMIR || !canPredictProbs) |
| OS << '(' |
| << format("0x%08" PRIx32, MBB.getSuccProbability(I).getNumerator()) |
| << ')'; |
| } |
| OS << "\n"; |
| HasLineAttributes = true; |
| } |
| |
| // Print the live in registers. |
| const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); |
| if (MRI.tracksLiveness() && !MBB.livein_empty()) { |
| const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); |
| OS.indent(2) << "liveins: "; |
| bool First = true; |
| for (const auto &LI : MBB.liveins()) { |
| if (!First) |
| OS << ", "; |
| First = false; |
| OS << printReg(LI.PhysReg, &TRI); |
| if (!LI.LaneMask.all()) |
| OS << ":0x" << PrintLaneMask(LI.LaneMask); |
| } |
| OS << "\n"; |
| HasLineAttributes = true; |
| } |
| |
| if (HasLineAttributes) |
| OS << "\n"; |
| bool IsInBundle = false; |
| for (auto I = MBB.instr_begin(), E = MBB.instr_end(); I != E; ++I) { |
| const MachineInstr &MI = *I; |
| if (IsInBundle && !MI.isInsideBundle()) { |
| OS.indent(2) << "}\n"; |
| IsInBundle = false; |
| } |
| OS.indent(IsInBundle ? 4 : 2); |
| print(MI); |
| if (!IsInBundle && MI.getFlag(MachineInstr::BundledSucc)) { |
| OS << " {"; |
| IsInBundle = true; |
| } |
| OS << "\n"; |
| } |
| if (IsInBundle) |
| OS.indent(2) << "}\n"; |
| } |
| |
| void MIPrinter::print(const MachineInstr &MI) { |
| const auto *MF = MI.getMF(); |
| const auto &MRI = MF->getRegInfo(); |
| const auto &SubTarget = MF->getSubtarget(); |
| const auto *TRI = SubTarget.getRegisterInfo(); |
| assert(TRI && "Expected target register info"); |
| const auto *TII = SubTarget.getInstrInfo(); |
| assert(TII && "Expected target instruction info"); |
| if (MI.isCFIInstruction()) |
| assert(MI.getNumOperands() == 1 && "Expected 1 operand in CFI instruction"); |
| |
| SmallBitVector PrintedTypes(8); |
| bool ShouldPrintRegisterTies = MI.hasComplexRegisterTies(); |
| unsigned I = 0, E = MI.getNumOperands(); |
| for (; I < E && MI.getOperand(I).isReg() && MI.getOperand(I).isDef() && |
| !MI.getOperand(I).isImplicit(); |
| ++I) { |
| if (I) |
| OS << ", "; |
| print(MI, I, TRI, TII, ShouldPrintRegisterTies, |
| MI.getTypeToPrint(I, PrintedTypes, MRI), |
| /*PrintDef=*/false); |
| } |
| |
| if (I) |
| OS << " = "; |
| if (MI.getFlag(MachineInstr::FrameSetup)) |
| OS << "frame-setup "; |
| if (MI.getFlag(MachineInstr::FrameDestroy)) |
| OS << "frame-destroy "; |
| if (MI.getFlag(MachineInstr::FmNoNans)) |
| OS << "nnan "; |
| if (MI.getFlag(MachineInstr::FmNoInfs)) |
| OS << "ninf "; |
| if (MI.getFlag(MachineInstr::FmNsz)) |
| OS << "nsz "; |
| if (MI.getFlag(MachineInstr::FmArcp)) |
| OS << "arcp "; |
| if (MI.getFlag(MachineInstr::FmContract)) |
| OS << "contract "; |
| if (MI.getFlag(MachineInstr::FmAfn)) |
| OS << "afn "; |
| if (MI.getFlag(MachineInstr::FmReassoc)) |
| OS << "reassoc "; |
| if (MI.getFlag(MachineInstr::NoUWrap)) |
| OS << "nuw "; |
| if (MI.getFlag(MachineInstr::NoSWrap)) |
| OS << "nsw "; |
| if (MI.getFlag(MachineInstr::IsExact)) |
| OS << "exact "; |
| if (MI.getFlag(MachineInstr::NoFPExcept)) |
| OS << "nofpexcept "; |
| if (MI.getFlag(MachineInstr::NoMerge)) |
| OS << "nomerge "; |
| |
| OS << TII->getName(MI.getOpcode()); |
| if (I < E) |
| OS << ' '; |
| |
| bool NeedComma = false; |
| for (; I < E; ++I) { |
| if (NeedComma) |
| OS << ", "; |
| print(MI, I, TRI, TII, ShouldPrintRegisterTies, |
| MI.getTypeToPrint(I, PrintedTypes, MRI)); |
| NeedComma = true; |
| } |
| |
| // Print any optional symbols attached to this instruction as-if they were |
| // operands. |
| if (MCSymbol *PreInstrSymbol = MI.getPreInstrSymbol()) { |
| if (NeedComma) |
| OS << ','; |
| OS << " pre-instr-symbol "; |
| MachineOperand::printSymbol(OS, *PreInstrSymbol); |
| NeedComma = true; |
| } |
| if (MCSymbol *PostInstrSymbol = MI.getPostInstrSymbol()) { |
| if (NeedComma) |
| OS << ','; |
| OS << " post-instr-symbol "; |
| MachineOperand::printSymbol(OS, *PostInstrSymbol); |
| NeedComma = true; |
| } |
| if (MDNode *HeapAllocMarker = MI.getHeapAllocMarker()) { |
| if (NeedComma) |
| OS << ','; |
| OS << " heap-alloc-marker "; |
| HeapAllocMarker->printAsOperand(OS, MST); |
| NeedComma = true; |
| } |
| |
| if (auto Num = MI.peekDebugInstrNum()) { |
| if (NeedComma) |
| OS << ','; |
| OS << " debug-instr-number " << Num; |
| NeedComma = true; |
| } |
| |
| if (PrintLocations) { |
| if (const DebugLoc &DL = MI.getDebugLoc()) { |
| if (NeedComma) |
| OS << ','; |
| OS << " debug-location "; |
| DL->printAsOperand(OS, MST); |
| } |
| } |
| |
| if (!MI.memoperands_empty()) { |
| OS << " :: "; |
| const LLVMContext &Context = MF->getFunction().getContext(); |
| const MachineFrameInfo &MFI = MF->getFrameInfo(); |
| bool NeedComma = false; |
| for (const auto *Op : MI.memoperands()) { |
| if (NeedComma) |
| OS << ", "; |
| Op->print(OS, MST, SSNs, Context, &MFI, TII); |
| NeedComma = true; |
| } |
| } |
| } |
| |
| void MIPrinter::printStackObjectReference(int FrameIndex) { |
| auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex); |
| assert(ObjectInfo != StackObjectOperandMapping.end() && |
| "Invalid frame index"); |
| const FrameIndexOperand &Operand = ObjectInfo->second; |
| MachineOperand::printStackObjectReference(OS, Operand.ID, Operand.IsFixed, |
| Operand.Name); |
| } |
| |
| static std::string formatOperandComment(std::string Comment) { |
| if (Comment.empty()) |
| return Comment; |
| return std::string(" /* " + Comment + " */"); |
| } |
| |
| void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx, |
| const TargetRegisterInfo *TRI, |
| const TargetInstrInfo *TII, |
| bool ShouldPrintRegisterTies, LLT TypeToPrint, |
| bool PrintDef) { |
| const MachineOperand &Op = MI.getOperand(OpIdx); |
| std::string MOComment = TII->createMIROperandComment(MI, Op, OpIdx, TRI); |
| |
| switch (Op.getType()) { |
| case MachineOperand::MO_Immediate: |
| if (MI.isOperandSubregIdx(OpIdx)) { |
| MachineOperand::printTargetFlags(OS, Op); |
| MachineOperand::printSubRegIdx(OS, Op.getImm(), TRI); |
| break; |
| } |
| LLVM_FALLTHROUGH; |
| case MachineOperand::MO_Register: |
| case MachineOperand::MO_CImmediate: |
| case MachineOperand::MO_FPImmediate: |
| case MachineOperand::MO_MachineBasicBlock: |
| case MachineOperand::MO_ConstantPoolIndex: |
| case MachineOperand::MO_TargetIndex: |
| case MachineOperand::MO_JumpTableIndex: |
| case MachineOperand::MO_ExternalSymbol: |
| case MachineOperand::MO_GlobalAddress: |
| case MachineOperand::MO_RegisterLiveOut: |
| case MachineOperand::MO_Metadata: |
| case MachineOperand::MO_MCSymbol: |
| case MachineOperand::MO_CFIIndex: |
| case MachineOperand::MO_IntrinsicID: |
| case MachineOperand::MO_Predicate: |
| case MachineOperand::MO_BlockAddress: |
| case MachineOperand::MO_ShuffleMask: { |
| unsigned TiedOperandIdx = 0; |
| if (ShouldPrintRegisterTies && Op.isReg() && Op.isTied() && !Op.isDef()) |
| TiedOperandIdx = Op.getParent()->findTiedOperandIdx(OpIdx); |
| const TargetIntrinsicInfo *TII = MI.getMF()->getTarget().getIntrinsicInfo(); |
| Op.print(OS, MST, TypeToPrint, OpIdx, PrintDef, /*IsStandalone=*/false, |
| ShouldPrintRegisterTies, TiedOperandIdx, TRI, TII); |
| OS << formatOperandComment(MOComment); |
| break; |
| } |
| case MachineOperand::MO_FrameIndex: |
| printStackObjectReference(Op.getIndex()); |
| break; |
| case MachineOperand::MO_RegisterMask: { |
| auto RegMaskInfo = RegisterMaskIds.find(Op.getRegMask()); |
| if (RegMaskInfo != RegisterMaskIds.end()) |
| OS << StringRef(TRI->getRegMaskNames()[RegMaskInfo->second]).lower(); |
| else |
| printCustomRegMask(Op.getRegMask(), OS, TRI); |
| break; |
| } |
| } |
| } |
| |
| void MIRFormatter::printIRValue(raw_ostream &OS, const Value &V, |
| ModuleSlotTracker &MST) { |
| if (isa<GlobalValue>(V)) { |
| V.printAsOperand(OS, /*PrintType=*/false, MST); |
| return; |
| } |
| if (isa<Constant>(V)) { |
| // Machine memory operands can load/store to/from constant value pointers. |
| OS << '`'; |
| V.printAsOperand(OS, /*PrintType=*/true, MST); |
| OS << '`'; |
| return; |
| } |
| OS << "%ir."; |
| if (V.hasName()) { |
| printLLVMNameWithoutPrefix(OS, V.getName()); |
| return; |
| } |
| int Slot = MST.getCurrentFunction() ? MST.getLocalSlot(&V) : -1; |
| MachineOperand::printIRSlotNumber(OS, Slot); |
| } |
| |
| void llvm::printMIR(raw_ostream &OS, const Module &M) { |
| yaml::Output Out(OS); |
| Out << const_cast<Module &>(M); |
| } |
| |
| void llvm::printMIR(raw_ostream &OS, const MachineFunction &MF) { |
| MIRPrinter Printer(OS); |
| Printer.print(MF); |
| } |