2015-06-16 07:52:35 +08:00
|
|
|
//===- MIRPrinter.cpp - MIR serialization format printer ------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2015-06-16 07:52:35 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the class that prints out the LLVM IR and machine
|
|
|
|
// functions using the MIR serialization format.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/CodeGen/MIRPrinter.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/None.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2016-09-12 19:20:10 +08:00
|
|
|
#include "llvm/ADT/SmallBitVector.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
2016-04-09 00:26:22 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/CodeGen/MIRYamlMapping.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
2015-07-21 04:51:18 +08:00
|
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
MIR Serialization: Serialize the simple MachineFrameInfo attributes.
This commit serializes the 13 scalar boolean and integer attributes from the
MachineFrameInfo class: IsFrameAddressTaken, IsReturnAddressTaken, HasStackMap,
HasPatchPoint, StackSize, OffsetAdjustment, MaxAlignment, AdjustsStack,
HasCalls, MaxCallFrameSize, HasOpaqueSPAdjustment, HasVAStart, and
HasMustTailInVarArgFunc. These attributes are serialized as part
of the frameInfo YAML mapping, which itself is a part of the machine function's
YAML mapping.
llvm-svn: 241844
2015-07-10 03:55:27 +08:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2016-04-09 00:26:22 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
2015-08-04 07:08:19 +08:00
|
|
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
2015-06-25 03:56:10 +08:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/CodeGen/PseudoSourceValue.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
2019-06-17 17:13:29 +08:00
|
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
2015-06-20 01:43:07 +08:00
|
|
|
#include "llvm/IR/BasicBlock.h"
|
2015-07-29 01:28:03 +08:00
|
|
|
#include "llvm/IR/Constants.h"
|
2016-04-15 02:29:59 +08:00
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/IR/DebugLoc.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalValue.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/IR/IRPrintingPasses.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/IR/InstrTypes.h"
|
2016-04-09 00:26:22 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2016-07-30 04:32:59 +08:00
|
|
|
#include "llvm/IR/Intrinsics.h"
|
2015-06-16 07:52:35 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
2015-07-08 07:27:53 +08:00
|
|
|
#include "llvm/IR/ModuleSlotTracker.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/IR/Value.h"
|
|
|
|
#include "llvm/MC/LaneBitmask.h"
|
[x86/MIR] Implement support for pre- and post-instruction symbols, as
well as MIR parsing support for `MCSymbol` `MachineOperand`s.
The only real way to test pre- and post-instruction symbol support is to
use them in operands, so I ended up implementing that within the patch
as well. I can split out the operand support if folks really want but it
doesn't really seem worth it.
The functional implementation of pre- and post-instruction symbols is
now *completely trivial*. Two tiny bits of code in the (misnamed)
AsmPrinter. It should be completely target independent as well. We emit
these exactly the same way as we emit basic block labels. Most of the
code here is to give full dumping, MIR printing, and MIR parsing support
so that we can write useful tests.
The MIR parsing of MC symbol operands still isn't 100%, as it forces the
symbols to be non-temporary and non-local symbols with names. However,
those names often can encode most (if not all) of the special semantics
desired, and unnamed symbols seem especially annoying to serialize and
de-serialize. While this isn't perfect or full support, it seems plenty
to write tests that exercise usage of these kinds of operands.
The MIR support for pre-and post-instruction symbols was quite
straightforward. I chose to print them out in an as-if-operand syntax
similar to debug locations as this seemed the cleanest way and let me
use nice introducer tokens rather than inventing more magic punctuation
like we use for memoperands.
However, supporting MIR-based parsing of these symbols caused me to
change the design of the symbol support to allow setting arbitrary
symbols. Without this, I don't see any reasonable way to test things
with MIR.
Differential Revision: https://reviews.llvm.org/D50833
llvm-svn: 339962
2018-08-17 07:11:05 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/MC/MCDwarf.h"
|
2015-08-22 05:12:44 +08:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#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"
|
2016-11-19 03:37:24 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/Support/LowLevelTypeImpl.h"
|
|
|
|
#include "llvm/Support/YAMLTraits.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-07-30 04:32:59 +08:00
|
|
|
#include "llvm/Target/TargetIntrinsicInfo.h"
|
2017-06-07 06:22:41 +08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cinttypes>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iterator>
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2015-06-16 07:52:35 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2017-12-01 08:53:10 +08:00
|
|
|
static cl::opt<bool> SimplifyMIR(
|
|
|
|
"simplify-mir", cl::Hidden,
|
2017-05-06 05:09:30 +08:00
|
|
|
cl::desc("Leave out unnecessary information when printing MIR"));
|
|
|
|
|
2015-06-16 07:52:35 +08:00
|
|
|
namespace {
|
|
|
|
|
2015-07-17 07:37:45 +08:00
|
|
|
/// 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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-31 00:54:38 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
2015-06-16 07:52:35 +08:00
|
|
|
/// This class prints out the machine functions using the MIR serialization
|
|
|
|
/// format.
|
|
|
|
class MIRPrinter {
|
|
|
|
raw_ostream &OS;
|
2015-06-30 00:57:06 +08:00
|
|
|
DenseMap<const uint32_t *, unsigned> RegisterMaskIds;
|
2015-07-17 07:37:45 +08:00
|
|
|
/// Maps from stack object indices to operand indices which will be used when
|
|
|
|
/// printing frame index machine operands.
|
|
|
|
DenseMap<int, FrameIndexOperand> StackObjectOperandMapping;
|
2015-06-16 07:52:35 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
MIRPrinter(raw_ostream &OS) : OS(OS) {}
|
|
|
|
|
|
|
|
void print(const MachineFunction &MF);
|
2015-06-20 01:43:07 +08:00
|
|
|
|
2015-07-10 06:23:13 +08:00
|
|
|
void convert(yaml::MachineFunction &MF, const MachineRegisterInfo &RegInfo,
|
|
|
|
const TargetRegisterInfo *TRI);
|
2015-07-30 05:09:09 +08:00
|
|
|
void convert(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
|
|
|
|
const MachineFrameInfo &MFI);
|
2015-07-21 04:51:18 +08:00
|
|
|
void convert(yaml::MachineFunction &MF,
|
|
|
|
const MachineConstantPool &ConstantPool);
|
2015-07-16 07:31:07 +08:00
|
|
|
void convert(ModuleSlotTracker &MST, yaml::MachineJumpTable &YamlJTI,
|
|
|
|
const MachineJumpTableInfo &JTI);
|
2016-12-01 07:48:50 +08:00
|
|
|
void convertStackObjects(yaml::MachineFunction &YMF,
|
|
|
|
const MachineFunction &MF, ModuleSlotTracker &MST);
|
2019-06-27 15:48:06 +08:00
|
|
|
void convertCallSiteObjects(yaml::MachineFunction &YMF,
|
|
|
|
const MachineFunction &MF,
|
|
|
|
ModuleSlotTracker &MST);
|
2015-06-30 00:57:06 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
void initRegisterMaskIds(const MachineFunction &MF);
|
2015-06-16 07:52:35 +08:00
|
|
|
};
|
|
|
|
|
2015-06-23 01:02:30 +08:00
|
|
|
/// This class prints out the machine instructions using the MIR serialization
|
|
|
|
/// format.
|
|
|
|
class MIPrinter {
|
|
|
|
raw_ostream &OS;
|
2015-07-08 07:27:53 +08:00
|
|
|
ModuleSlotTracker &MST;
|
2015-06-30 00:57:06 +08:00
|
|
|
const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds;
|
2015-07-17 07:37:45 +08:00
|
|
|
const DenseMap<int, FrameIndexOperand> &StackObjectOperandMapping;
|
2017-07-12 06:23:00 +08:00
|
|
|
/// Synchronization scope names registered with LLVMContext.
|
|
|
|
SmallVector<StringRef, 8> SSNs;
|
2015-06-23 01:02:30 +08:00
|
|
|
|
2017-05-06 05:09:30 +08:00
|
|
|
bool canPredictBranchProbabilities(const MachineBasicBlock &MBB) const;
|
|
|
|
bool canPredictSuccessors(const MachineBasicBlock &MBB) const;
|
|
|
|
|
2015-06-23 01:02:30 +08:00
|
|
|
public:
|
2015-07-08 07:27:53 +08:00
|
|
|
MIPrinter(raw_ostream &OS, ModuleSlotTracker &MST,
|
2015-07-17 07:37:45 +08:00
|
|
|
const DenseMap<const uint32_t *, unsigned> &RegisterMaskIds,
|
|
|
|
const DenseMap<int, FrameIndexOperand> &StackObjectOperandMapping)
|
|
|
|
: OS(OS), MST(MST), RegisterMaskIds(RegisterMaskIds),
|
|
|
|
StackObjectOperandMapping(StackObjectOperandMapping) {}
|
2015-06-23 01:02:30 +08:00
|
|
|
|
2015-08-14 07:10:16 +08:00
|
|
|
void print(const MachineBasicBlock &MBB);
|
|
|
|
|
2015-06-23 01:02:30 +08:00
|
|
|
void print(const MachineInstr &MI);
|
2015-07-17 07:37:45 +08:00
|
|
|
void printStackObjectReference(int FrameIndex);
|
2017-11-07 05:46:06 +08:00
|
|
|
void print(const MachineInstr &MI, unsigned OpIdx,
|
|
|
|
const TargetRegisterInfo *TRI, bool ShouldPrintRegisterTies,
|
2017-12-07 18:40:31 +08:00
|
|
|
LLT TypeToPrint, bool PrintDef = true);
|
2015-06-23 01:02:30 +08:00
|
|
|
};
|
|
|
|
|
2015-08-14 07:10:16 +08:00
|
|
|
} // end namespace llvm
|
2015-06-16 07:52:35 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2017-06-07 06:22:41 +08:00
|
|
|
|
2015-06-16 07:52:35 +08:00
|
|
|
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
|
|
|
|
|
2017-11-28 20:42:37 +08:00
|
|
|
static void printRegMIR(unsigned Reg, yaml::StringValue &Dest,
|
|
|
|
const TargetRegisterInfo *TRI) {
|
2015-07-25 04:35:40 +08:00
|
|
|
raw_string_ostream OS(Dest.Value);
|
2017-12-01 00:12:24 +08:00
|
|
|
OS << printReg(Reg, TRI);
|
2015-07-25 04:35:40 +08:00
|
|
|
}
|
|
|
|
|
2015-06-16 07:52:35 +08:00
|
|
|
void MIRPrinter::print(const MachineFunction &MF) {
|
2015-06-30 00:57:06 +08:00
|
|
|
initRegisterMaskIds(MF);
|
|
|
|
|
2015-06-16 07:52:35 +08:00
|
|
|
yaml::MachineFunction YamlMF;
|
|
|
|
YamlMF.Name = MF.getName();
|
2015-06-16 08:10:47 +08:00
|
|
|
YamlMF.Alignment = MF.getAlignment();
|
|
|
|
YamlMF.ExposesReturnsTwice = MF.exposesReturnsTwice();
|
2018-10-25 05:07:38 +08:00
|
|
|
YamlMF.HasWinCFI = MF.hasWinCFI();
|
2016-03-29 01:05:30 +08:00
|
|
|
|
2016-08-02 23:10:25 +08:00
|
|
|
YamlMF.Legalized = MF.getProperties().hasProperty(
|
|
|
|
MachineFunctionProperties::Property::Legalized);
|
2016-08-03 00:17:10 +08:00
|
|
|
YamlMF.RegBankSelected = MF.getProperties().hasProperty(
|
|
|
|
MachineFunctionProperties::Property::RegBankSelected);
|
2016-08-03 00:49:19 +08:00
|
|
|
YamlMF.Selected = MF.getProperties().hasProperty(
|
|
|
|
MachineFunctionProperties::Property::Selected);
|
[GlobalISel] Print/Parse FailedISel MachineFunction property
FailedISel MachineFunction property is part of the CodeGen pipeline
state as much as every other property, notably, Legalized,
RegBankSelected, and Selected. Let's make that part of the state also
serializable / de-serializable, so if GlobalISel aborts on some of the
functions of a large module, but not the others, it could be easily seen
and the state of the pipeline could be maintained through llc's
invocations with -stop-after / -start-after.
To make MIR printable and generally to not to break it too much too
soon, this patch also defers cleaning up the vreg -> LLT map until
ResetMachineFunctionPass.
To make MIR with FailedISel: true also machine verifiable, machine
verifier is changed so it treats a MIR-module as non-regbankselected and
non-selected if there is FailedISel property set.
Reviewers: qcolombet, ab
Reviewed By: dsanders
Subscribers: javed.absar, rovka, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D42877
llvm-svn: 326343
2018-03-01 01:55:45 +08:00
|
|
|
YamlMF.FailedISel = MF.getProperties().hasProperty(
|
|
|
|
MachineFunctionProperties::Property::FailedISel);
|
2016-08-02 23:10:25 +08:00
|
|
|
|
2015-07-10 06:23:13 +08:00
|
|
|
convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
|
2017-12-16 06:22:58 +08:00
|
|
|
ModuleSlotTracker MST(MF.getFunction().getParent());
|
|
|
|
MST.incorporateFunction(MF.getFunction());
|
2016-07-29 02:40:00 +08:00
|
|
|
convert(MST, YamlMF.FrameInfo, MF.getFrameInfo());
|
2016-12-01 07:48:50 +08:00
|
|
|
convertStackObjects(YamlMF, MF, MST);
|
2019-06-27 15:48:06 +08:00
|
|
|
convertCallSiteObjects(YamlMF, MF, MST);
|
2015-07-21 04:51:18 +08:00
|
|
|
if (const auto *ConstantPool = MF.getConstantPool())
|
|
|
|
convert(YamlMF, *ConstantPool);
|
2015-07-16 07:31:07 +08:00
|
|
|
if (const auto *JumpTableInfo = MF.getJumpTableInfo())
|
|
|
|
convert(MST, YamlMF.JumpTableInfo, *JumpTableInfo);
|
2019-03-15 06:54:43 +08:00
|
|
|
|
|
|
|
const TargetMachine &TM = MF.getTarget();
|
|
|
|
YamlMF.MachineFuncInfo =
|
|
|
|
std::unique_ptr<yaml::MachineFunctionInfo>(TM.convertFuncInfoToYAML(MF));
|
|
|
|
|
2015-08-14 07:10:16 +08:00
|
|
|
raw_string_ostream StrOS(YamlMF.Body.Value.Value);
|
|
|
|
bool IsNewlineNeeded = false;
|
2015-06-20 01:43:07 +08:00
|
|
|
for (const auto &MBB : MF) {
|
2015-08-14 07:10:16 +08:00
|
|
|
if (IsNewlineNeeded)
|
|
|
|
StrOS << "\n";
|
|
|
|
MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping)
|
|
|
|
.print(MBB);
|
|
|
|
IsNewlineNeeded = true;
|
2015-06-20 01:43:07 +08:00
|
|
|
}
|
2015-08-14 07:10:16 +08:00
|
|
|
StrOS.flush();
|
2015-06-16 07:52:35 +08:00
|
|
|
yaml::Output Out(OS);
|
2017-06-06 16:16:19 +08:00
|
|
|
if (!SimplifyMIR)
|
|
|
|
Out.setWriteDefaultValues(true);
|
2015-06-16 07:52:35 +08:00
|
|
|
Out << YamlMF;
|
|
|
|
}
|
|
|
|
|
2017-03-19 16:14:18 +08:00
|
|
|
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 << ',';
|
2017-12-01 00:12:24 +08:00
|
|
|
OS << printReg(I, TRI);
|
2017-03-19 16:14:18 +08:00
|
|
|
IsRegInRegMaskFound = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << ')';
|
|
|
|
}
|
|
|
|
|
2017-10-25 02:04:54 +08:00
|
|
|
static void printRegClassOrBank(unsigned Reg, yaml::StringValue &Dest,
|
|
|
|
const MachineRegisterInfo &RegInfo,
|
|
|
|
const TargetRegisterInfo *TRI) {
|
|
|
|
raw_string_ostream OS(Dest.Value);
|
2017-12-07 18:40:31 +08:00
|
|
|
OS << printRegClassOrBank(Reg, RegInfo, TRI);
|
2017-10-25 02:04:54 +08:00
|
|
|
}
|
|
|
|
|
2018-04-26 02:58:06 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2017-10-25 02:04:54 +08:00
|
|
|
|
2015-06-25 03:56:10 +08:00
|
|
|
void MIRPrinter::convert(yaml::MachineFunction &MF,
|
2015-07-10 06:23:13 +08:00
|
|
|
const MachineRegisterInfo &RegInfo,
|
|
|
|
const TargetRegisterInfo *TRI) {
|
2015-06-25 03:56:10 +08:00
|
|
|
MF.TracksRegLiveness = RegInfo.tracksLiveness();
|
2015-07-10 06:23:13 +08:00
|
|
|
|
|
|
|
// Print the virtual register definitions.
|
|
|
|
for (unsigned I = 0, E = RegInfo.getNumVirtRegs(); I < E; ++I) {
|
|
|
|
unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
|
|
|
|
yaml::VirtualRegisterDefinition VReg;
|
|
|
|
VReg.ID = I;
|
2018-03-31 02:15:54 +08:00
|
|
|
if (RegInfo.getVRegName(Reg) != "")
|
|
|
|
continue;
|
2017-12-07 18:40:31 +08:00
|
|
|
::printRegClassOrBank(Reg, VReg.Class, RegInfo, TRI);
|
2015-07-25 04:35:40 +08:00
|
|
|
unsigned PreferredReg = RegInfo.getSimpleHint(Reg);
|
|
|
|
if (PreferredReg)
|
2017-11-28 20:42:37 +08:00
|
|
|
printRegMIR(PreferredReg, VReg.PreferredRegister, TRI);
|
2015-07-10 06:23:13 +08:00
|
|
|
MF.VirtualRegisters.push_back(VReg);
|
|
|
|
}
|
2015-07-28 01:42:45 +08:00
|
|
|
|
|
|
|
// Print the live ins.
|
2017-10-17 03:08:41 +08:00
|
|
|
for (std::pair<unsigned, unsigned> LI : RegInfo.liveins()) {
|
2015-07-28 01:42:45 +08:00
|
|
|
yaml::MachineFunctionLiveIn LiveIn;
|
2017-11-28 20:42:37 +08:00
|
|
|
printRegMIR(LI.first, LiveIn.Register, TRI);
|
2017-10-17 03:08:41 +08:00
|
|
|
if (LI.second)
|
2017-11-28 20:42:37 +08:00
|
|
|
printRegMIR(LI.second, LiveIn.VirtualRegister, TRI);
|
2015-07-28 01:42:45 +08:00
|
|
|
MF.LiveIns.push_back(LiveIn);
|
|
|
|
}
|
2017-03-19 16:14:18 +08:00
|
|
|
|
|
|
|
// 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) {
|
2015-08-11 08:32:49 +08:00
|
|
|
yaml::FlowStringValue Reg;
|
2017-11-28 20:42:37 +08:00
|
|
|
printRegMIR(*I, Reg, TRI);
|
2015-08-11 08:32:49 +08:00
|
|
|
CalleeSavedRegisters.push_back(Reg);
|
|
|
|
}
|
2017-03-19 16:14:18 +08:00
|
|
|
MF.CalleeSavedRegisters = CalleeSavedRegisters;
|
2015-08-11 08:32:49 +08:00
|
|
|
}
|
2015-06-25 03:56:10 +08:00
|
|
|
}
|
|
|
|
|
2015-07-30 05:09:09 +08:00
|
|
|
void MIRPrinter::convert(ModuleSlotTracker &MST,
|
|
|
|
yaml::MachineFrameInfo &YamlMFI,
|
MIR Serialization: Serialize the simple MachineFrameInfo attributes.
This commit serializes the 13 scalar boolean and integer attributes from the
MachineFrameInfo class: IsFrameAddressTaken, IsReturnAddressTaken, HasStackMap,
HasPatchPoint, StackSize, OffsetAdjustment, MaxAlignment, AdjustsStack,
HasCalls, MaxCallFrameSize, HasOpaqueSPAdjustment, HasVAStart, and
HasMustTailInVarArgFunc. These attributes are serialized as part
of the frameInfo YAML mapping, which itself is a part of the machine function's
YAML mapping.
llvm-svn: 241844
2015-07-10 03:55:27 +08:00
|
|
|
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.getMaxAlignment();
|
|
|
|
YamlMFI.AdjustsStack = MFI.adjustsStack();
|
|
|
|
YamlMFI.HasCalls = MFI.hasCalls();
|
2017-05-02 06:32:25 +08:00
|
|
|
YamlMFI.MaxCallFrameSize = MFI.isMaxCallFrameSizeComputed()
|
|
|
|
? MFI.getMaxCallFrameSize() : ~0u;
|
[codeview] Emit S_FRAMEPROC and use S_DEFRANGE_FRAMEPOINTER_REL
Summary:
Before this change, LLVM would always describe locals on the stack as
being relative to some specific register, RSP, ESP, EBP, ESI, etc.
Variables in stack memory are pretty common, so there is a special
S_DEFRANGE_FRAMEPOINTER_REL symbol for them. This change uses it to
reduce the size of our debug info.
On top of the size savings, there are cases on 32-bit x86 where local
variables are addressed from ESP, but ESP changes across the function.
Unlike in DWARF, there is no FPO data to describe the stack adjustments
made to push arguments onto the stack and pop them off after the call,
which makes it hard for the debugger to find the local variables in
frames further up the stack.
To handle this, CodeView has a special VFRAME register, which
corresponds to the $T0 variable set by our FPO data in 32-bit. Offsets
to local variables are instead relative to this value.
This is part of PR38857.
Reviewers: hans, zturner, javed.absar
Subscribers: aprantl, hiraditya, JDevlieghere, llvm-commits
Differential Revision: https://reviews.llvm.org/D52217
llvm-svn: 343543
2018-10-02 05:59:45 +08:00
|
|
|
YamlMFI.CVBytesOfCalleeSavedRegisters =
|
|
|
|
MFI.getCVBytesOfCalleeSavedRegisters();
|
MIR Serialization: Serialize the simple MachineFrameInfo attributes.
This commit serializes the 13 scalar boolean and integer attributes from the
MachineFrameInfo class: IsFrameAddressTaken, IsReturnAddressTaken, HasStackMap,
HasPatchPoint, StackSize, OffsetAdjustment, MaxAlignment, AdjustsStack,
HasCalls, MaxCallFrameSize, HasOpaqueSPAdjustment, HasVAStart, and
HasMustTailInVarArgFunc. These attributes are serialized as part
of the frameInfo YAML mapping, which itself is a part of the machine function's
YAML mapping.
llvm-svn: 241844
2015-07-10 03:55:27 +08:00
|
|
|
YamlMFI.HasOpaqueSPAdjustment = MFI.hasOpaqueSPAdjustment();
|
|
|
|
YamlMFI.HasVAStart = MFI.hasVAStart();
|
|
|
|
YamlMFI.HasMustTailInVarArgFunc = MFI.hasMustTailInVarArgFunc();
|
2018-04-06 16:56:25 +08:00
|
|
|
YamlMFI.LocalFrameSize = MFI.getLocalFrameSize();
|
2015-07-30 05:09:09 +08:00
|
|
|
if (MFI.getSavePoint()) {
|
|
|
|
raw_string_ostream StrOS(YamlMFI.SavePoint.Value);
|
2017-12-05 01:18:51 +08:00
|
|
|
StrOS << printMBBReference(*MFI.getSavePoint());
|
2015-07-30 05:09:09 +08:00
|
|
|
}
|
|
|
|
if (MFI.getRestorePoint()) {
|
|
|
|
raw_string_ostream StrOS(YamlMFI.RestorePoint.Value);
|
2017-12-05 01:18:51 +08:00
|
|
|
StrOS << printMBBReference(*MFI.getRestorePoint());
|
2015-07-30 05:09:09 +08:00
|
|
|
}
|
MIR Serialization: Serialize the simple MachineFrameInfo attributes.
This commit serializes the 13 scalar boolean and integer attributes from the
MachineFrameInfo class: IsFrameAddressTaken, IsReturnAddressTaken, HasStackMap,
HasPatchPoint, StackSize, OffsetAdjustment, MaxAlignment, AdjustsStack,
HasCalls, MaxCallFrameSize, HasOpaqueSPAdjustment, HasVAStart, and
HasMustTailInVarArgFunc. These attributes are serialized as part
of the frameInfo YAML mapping, which itself is a part of the machine function's
YAML mapping.
llvm-svn: 241844
2015-07-10 03:55:27 +08:00
|
|
|
}
|
|
|
|
|
2016-12-01 07:48:50 +08:00
|
|
|
void MIRPrinter::convertStackObjects(yaml::MachineFunction &YMF,
|
|
|
|
const MachineFunction &MF,
|
|
|
|
ModuleSlotTracker &MST) {
|
|
|
|
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
|
|
|
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
2015-07-14 02:07:26 +08:00
|
|
|
// Process fixed stack objects.
|
2015-07-11 02:13:57 +08:00
|
|
|
unsigned ID = 0;
|
2019-02-23 03:30:38 +08:00
|
|
|
for (int I = MFI.getObjectIndexBegin(); I < 0; ++I, ++ID) {
|
2015-07-14 02:07:26 +08:00
|
|
|
if (MFI.isDeadObjectIndex(I))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
yaml::FixedMachineStackObject YamlObject;
|
2015-07-17 07:37:45 +08:00
|
|
|
YamlObject.ID = ID;
|
2015-07-14 02:07:26 +08:00
|
|
|
YamlObject.Type = MFI.isSpillSlotObjectIndex(I)
|
|
|
|
? yaml::FixedMachineStackObject::SpillSlot
|
|
|
|
: yaml::FixedMachineStackObject::DefaultType;
|
|
|
|
YamlObject.Offset = MFI.getObjectOffset(I);
|
|
|
|
YamlObject.Size = MFI.getObjectSize(I);
|
|
|
|
YamlObject.Alignment = MFI.getObjectAlignment(I);
|
2019-06-17 17:13:29 +08:00
|
|
|
YamlObject.StackID = (TargetStackID::Value)MFI.getStackID(I);
|
2015-07-14 02:07:26 +08:00
|
|
|
YamlObject.IsImmutable = MFI.isImmutableObjectIndex(I);
|
|
|
|
YamlObject.IsAliased = MFI.isAliasedObjectIndex(I);
|
2016-12-01 07:48:50 +08:00
|
|
|
YMF.FixedStackObjects.push_back(YamlObject);
|
2015-07-17 07:37:45 +08:00
|
|
|
StackObjectOperandMapping.insert(
|
2019-02-23 03:30:38 +08:00
|
|
|
std::make_pair(I, FrameIndexOperand::createFixed(ID)));
|
2015-07-14 02:07:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Process ordinary stack objects.
|
|
|
|
ID = 0;
|
2019-02-23 03:30:38 +08:00
|
|
|
for (int I = 0, E = MFI.getObjectIndexEnd(); I < E; ++I, ++ID) {
|
2015-07-11 02:13:57 +08:00
|
|
|
if (MFI.isDeadObjectIndex(I))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
yaml::MachineStackObject YamlObject;
|
2015-07-17 07:37:45 +08:00
|
|
|
YamlObject.ID = ID;
|
2015-07-16 06:14:49 +08:00
|
|
|
if (const auto *Alloca = MFI.getObjectAllocation(I))
|
|
|
|
YamlObject.Name.Value =
|
|
|
|
Alloca->hasName() ? Alloca->getName() : "<unnamed alloca>";
|
2015-07-11 02:13:57 +08:00
|
|
|
YamlObject.Type = MFI.isSpillSlotObjectIndex(I)
|
|
|
|
? yaml::MachineStackObject::SpillSlot
|
2015-07-14 08:26:26 +08:00
|
|
|
: MFI.isVariableSizedObjectIndex(I)
|
|
|
|
? yaml::MachineStackObject::VariableSized
|
|
|
|
: yaml::MachineStackObject::DefaultType;
|
2015-07-11 02:13:57 +08:00
|
|
|
YamlObject.Offset = MFI.getObjectOffset(I);
|
|
|
|
YamlObject.Size = MFI.getObjectSize(I);
|
|
|
|
YamlObject.Alignment = MFI.getObjectAlignment(I);
|
2019-06-17 17:13:29 +08:00
|
|
|
YamlObject.StackID = (TargetStackID::Value)MFI.getStackID(I);
|
2015-07-11 02:13:57 +08:00
|
|
|
|
2016-12-01 07:48:50 +08:00
|
|
|
YMF.StackObjects.push_back(YamlObject);
|
2015-07-17 07:37:45 +08:00
|
|
|
StackObjectOperandMapping.insert(std::make_pair(
|
2019-02-23 03:30:38 +08:00
|
|
|
I, FrameIndexOperand::create(YamlObject.Name.Value, ID)));
|
2015-07-11 02:13:57 +08:00
|
|
|
}
|
2015-07-25 06:22:50 +08:00
|
|
|
|
|
|
|
for (const auto &CSInfo : MFI.getCalleeSavedInfo()) {
|
2019-05-28 21:08:31 +08:00
|
|
|
if (!CSInfo.isSpilledToReg() && MFI.isDeadObjectIndex(CSInfo.getFrameIdx()))
|
|
|
|
continue;
|
|
|
|
|
2015-07-25 06:22:50 +08:00
|
|
|
yaml::StringValue Reg;
|
2017-11-28 20:42:37 +08:00
|
|
|
printRegMIR(CSInfo.getReg(), Reg, TRI);
|
2018-11-10 00:36:24 +08:00
|
|
|
if (!CSInfo.isSpilledToReg()) {
|
|
|
|
auto StackObjectInfo = StackObjectOperandMapping.find(CSInfo.getFrameIdx());
|
|
|
|
assert(StackObjectInfo != StackObjectOperandMapping.end() &&
|
|
|
|
"Invalid stack object index");
|
|
|
|
const FrameIndexOperand &StackObject = StackObjectInfo->second;
|
|
|
|
if (StackObject.IsFixed) {
|
|
|
|
YMF.FixedStackObjects[StackObject.ID].CalleeSavedRegister = Reg;
|
|
|
|
YMF.FixedStackObjects[StackObject.ID].CalleeSavedRestored =
|
|
|
|
CSInfo.isRestored();
|
|
|
|
} else {
|
|
|
|
YMF.StackObjects[StackObject.ID].CalleeSavedRegister = Reg;
|
|
|
|
YMF.StackObjects[StackObject.ID].CalleeSavedRestored =
|
|
|
|
CSInfo.isRestored();
|
|
|
|
}
|
2017-09-29 02:52:14 +08:00
|
|
|
}
|
2015-07-25 06:22:50 +08:00
|
|
|
}
|
2015-08-18 06:17:42 +08:00
|
|
|
for (unsigned I = 0, E = MFI.getLocalFrameObjectCount(); I < E; ++I) {
|
|
|
|
auto LocalObject = MFI.getLocalFrameObjectMap(I);
|
|
|
|
auto StackObjectInfo = StackObjectOperandMapping.find(LocalObject.first);
|
|
|
|
assert(StackObjectInfo != StackObjectOperandMapping.end() &&
|
|
|
|
"Invalid stack object index");
|
|
|
|
const FrameIndexOperand &StackObject = StackObjectInfo->second;
|
|
|
|
assert(!StackObject.IsFixed && "Expected a locally mapped stack object");
|
2016-12-01 07:48:50 +08:00
|
|
|
YMF.StackObjects[StackObject.ID].LocalOffset = LocalObject.second;
|
2015-08-18 06:17:42 +08:00
|
|
|
}
|
2015-08-19 06:26:26 +08:00
|
|
|
|
|
|
|
// Print the stack object references in the frame information class after
|
|
|
|
// converting the stack objects.
|
|
|
|
if (MFI.hasStackProtectorIndex()) {
|
2016-12-01 07:48:50 +08:00
|
|
|
raw_string_ostream StrOS(YMF.FrameInfo.StackProtector.Value);
|
2015-08-19 06:26:26 +08:00
|
|
|
MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping)
|
|
|
|
.printStackObjectReference(MFI.getStackProtectorIndex());
|
|
|
|
}
|
2015-08-19 08:13:25 +08:00
|
|
|
|
|
|
|
// Print the debug variable information.
|
2016-12-01 07:48:50 +08:00
|
|
|
for (const MachineFunction::VariableDbgInfo &DebugVar :
|
|
|
|
MF.getVariableDbgInfo()) {
|
2015-08-19 08:13:25 +08:00
|
|
|
auto StackObjectInfo = StackObjectOperandMapping.find(DebugVar.Slot);
|
|
|
|
assert(StackObjectInfo != StackObjectOperandMapping.end() &&
|
|
|
|
"Invalid stack object index");
|
|
|
|
const FrameIndexOperand &StackObject = StackObjectInfo->second;
|
2018-04-26 02:58:06 +08:00
|
|
|
if (StackObject.IsFixed) {
|
|
|
|
auto &Object = YMF.FixedStackObjects[StackObject.ID];
|
|
|
|
printStackObjectDbgInfo(DebugVar, Object, MST);
|
|
|
|
} else {
|
|
|
|
auto &Object = YMF.StackObjects[StackObject.ID];
|
|
|
|
printStackObjectDbgInfo(DebugVar, Object, MST);
|
2015-08-19 08:13:25 +08:00
|
|
|
}
|
|
|
|
}
|
2015-07-11 02:13:57 +08:00
|
|
|
}
|
|
|
|
|
2019-06-27 15:48:06 +08:00
|
|
|
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_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()->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;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-07-21 04:51:18 +08:00
|
|
|
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);
|
2017-08-02 19:09:30 +08:00
|
|
|
if (Constant.isMachineConstantPoolEntry()) {
|
|
|
|
Constant.Val.MachineCPVal->print(StrOS);
|
|
|
|
} else {
|
|
|
|
Constant.Val.ConstVal->printAsOperand(StrOS);
|
|
|
|
}
|
|
|
|
|
|
|
|
yaml::MachineConstantPoolValue YamlConstant;
|
2015-07-21 04:51:18 +08:00
|
|
|
YamlConstant.ID = ID++;
|
|
|
|
YamlConstant.Value = StrOS.str();
|
|
|
|
YamlConstant.Alignment = Constant.getAlignment();
|
2017-08-02 19:09:30 +08:00
|
|
|
YamlConstant.IsTargetSpecific = Constant.isMachineConstantPoolEntry();
|
|
|
|
|
2015-07-21 04:51:18 +08:00
|
|
|
MF.Constants.push_back(YamlConstant);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-16 07:31:07 +08:00
|
|
|
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);
|
2017-12-05 01:18:51 +08:00
|
|
|
StrOS << printMBBReference(*MBB);
|
2015-07-16 07:31:07 +08:00
|
|
|
Entry.Blocks.push_back(StrOS.str());
|
|
|
|
Str.clear();
|
|
|
|
}
|
|
|
|
YamlJTI.Entries.push_back(Entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-14 07:10:16 +08:00
|
|
|
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++));
|
|
|
|
}
|
|
|
|
|
2017-05-06 05:09:30 +08:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2015-08-14 07:10:16 +08:00
|
|
|
void MIPrinter::print(const MachineBasicBlock &MBB) {
|
2015-06-27 00:46:11 +08:00
|
|
|
assert(MBB.getNumber() >= 0 && "Invalid MBB number");
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << "bb." << MBB.getNumber();
|
|
|
|
bool HasAttributes = false;
|
2015-07-28 06:42:41 +08:00
|
|
|
if (const auto *BB = MBB.getBasicBlock()) {
|
|
|
|
if (BB->hasName()) {
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << "." << BB->getName();
|
2015-07-28 06:42:41 +08:00
|
|
|
} else {
|
2015-08-14 07:10:16 +08:00
|
|
|
HasAttributes = true;
|
|
|
|
OS << " (";
|
2015-07-28 06:42:41 +08:00
|
|
|
int Slot = MST.getLocalSlot(BB);
|
|
|
|
if (Slot == -1)
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << "<ir-block badref>";
|
2015-07-28 06:42:41 +08:00
|
|
|
else
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << (Twine("%ir-block.") + Twine(Slot)).str();
|
2015-07-28 06:42:41 +08:00
|
|
|
}
|
|
|
|
}
|
2015-08-14 07:10:16 +08:00
|
|
|
if (MBB.hasAddressTaken()) {
|
|
|
|
OS << (HasAttributes ? ", " : " (");
|
|
|
|
OS << "address-taken";
|
|
|
|
HasAttributes = true;
|
|
|
|
}
|
2015-08-28 07:27:47 +08:00
|
|
|
if (MBB.isEHPad()) {
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << (HasAttributes ? ", " : " (");
|
|
|
|
OS << "landing-pad";
|
|
|
|
HasAttributes = true;
|
2015-07-01 02:16:42 +08:00
|
|
|
}
|
2015-08-14 07:10:16 +08:00
|
|
|
if (MBB.getAlignment()) {
|
|
|
|
OS << (HasAttributes ? ", " : " (");
|
|
|
|
OS << "align " << MBB.getAlignment();
|
|
|
|
HasAttributes = true;
|
2015-07-31 00:54:38 +08:00
|
|
|
}
|
2015-08-14 07:10:16 +08:00
|
|
|
if (HasAttributes)
|
|
|
|
OS << ")";
|
|
|
|
OS << ":\n";
|
|
|
|
|
|
|
|
bool HasLineAttributes = false;
|
|
|
|
// Print the successors
|
2017-05-06 05:09:30 +08:00
|
|
|
bool canPredictProbs = canPredictBranchProbabilities(MBB);
|
2017-09-20 07:34:12 +08:00
|
|
|
// 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)) {
|
2015-08-14 07:10:16 +08:00
|
|
|
OS.indent(2) << "successors: ";
|
|
|
|
for (auto I = MBB.succ_begin(), E = MBB.succ_end(); I != E; ++I) {
|
|
|
|
if (I != MBB.succ_begin())
|
|
|
|
OS << ", ";
|
2017-12-05 01:18:51 +08:00
|
|
|
OS << printMBBReference(**I);
|
2017-05-06 05:09:30 +08:00
|
|
|
if (!SimplifyMIR || !canPredictProbs)
|
2016-11-19 03:37:24 +08:00
|
|
|
OS << '('
|
|
|
|
<< format("0x%08" PRIx32, MBB.getSuccProbability(I).getNumerator())
|
|
|
|
<< ')';
|
2015-08-14 07:10:16 +08:00
|
|
|
}
|
|
|
|
OS << "\n";
|
|
|
|
HasLineAttributes = true;
|
|
|
|
}
|
|
|
|
|
2015-07-15 05:24:41 +08:00
|
|
|
// Print the live in registers.
|
2017-01-06 04:01:19 +08:00
|
|
|
const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
|
|
|
|
if (MRI.tracksLiveness() && !MBB.livein_empty()) {
|
|
|
|
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
|
2015-08-14 07:10:16 +08:00
|
|
|
OS.indent(2) << "liveins: ";
|
2015-08-25 06:59:52 +08:00
|
|
|
bool First = true;
|
2015-09-10 02:08:03 +08:00
|
|
|
for (const auto &LI : MBB.liveins()) {
|
2015-08-25 06:59:52 +08:00
|
|
|
if (!First)
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << ", ";
|
2015-08-25 06:59:52 +08:00
|
|
|
First = false;
|
2017-12-01 00:12:24 +08:00
|
|
|
OS << printReg(LI.PhysReg, &TRI);
|
2016-12-15 22:36:06 +08:00
|
|
|
if (!LI.LaneMask.all())
|
2016-10-13 05:06:45 +08:00
|
|
|
OS << ":0x" << PrintLaneMask(LI.LaneMask);
|
2015-08-14 07:10:16 +08:00
|
|
|
}
|
|
|
|
OS << "\n";
|
|
|
|
HasLineAttributes = true;
|
2015-07-15 05:24:41 +08:00
|
|
|
}
|
2015-08-14 07:10:16 +08:00
|
|
|
|
|
|
|
if (HasLineAttributes)
|
|
|
|
OS << "\n";
|
2015-08-15 02:57:24 +08:00
|
|
|
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);
|
2015-08-14 07:10:16 +08:00
|
|
|
print(MI);
|
2015-08-15 02:57:24 +08:00
|
|
|
if (!IsInBundle && MI.getFlag(MachineInstr::BundledSucc)) {
|
|
|
|
OS << " {";
|
|
|
|
IsInBundle = true;
|
|
|
|
}
|
2015-08-14 07:10:16 +08:00
|
|
|
OS << "\n";
|
2015-06-23 01:02:30 +08:00
|
|
|
}
|
2015-08-15 02:57:24 +08:00
|
|
|
if (IsInBundle)
|
|
|
|
OS.indent(2) << "}\n";
|
2015-06-23 01:02:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void MIPrinter::print(const MachineInstr &MI) {
|
2017-10-11 07:50:49 +08:00
|
|
|
const auto *MF = MI.getMF();
|
2016-03-08 05:57:52 +08:00
|
|
|
const auto &MRI = MF->getRegInfo();
|
|
|
|
const auto &SubTarget = MF->getSubtarget();
|
2015-06-24 00:35:26 +08:00
|
|
|
const auto *TRI = SubTarget.getRegisterInfo();
|
|
|
|
assert(TRI && "Expected target register info");
|
2015-06-23 01:02:30 +08:00
|
|
|
const auto *TII = SubTarget.getInstrInfo();
|
|
|
|
assert(TII && "Expected target instruction info");
|
2015-07-22 06:28:27 +08:00
|
|
|
if (MI.isCFIInstruction())
|
|
|
|
assert(MI.getNumOperands() == 1 && "Expected 1 operand in CFI instruction");
|
2015-06-23 01:02:30 +08:00
|
|
|
|
2016-09-12 19:20:10 +08:00
|
|
|
SmallBitVector PrintedTypes(8);
|
2017-12-07 18:40:31 +08:00
|
|
|
bool ShouldPrintRegisterTies = MI.hasComplexRegisterTies();
|
2015-06-24 00:35:26 +08:00
|
|
|
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 << ", ";
|
2017-11-07 05:46:06 +08:00
|
|
|
print(MI, I, TRI, ShouldPrintRegisterTies,
|
2017-12-07 18:40:31 +08:00
|
|
|
MI.getTypeToPrint(I, PrintedTypes, MRI),
|
|
|
|
/*PrintDef=*/false);
|
2015-06-24 00:35:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (I)
|
|
|
|
OS << " = ";
|
2015-07-17 08:24:15 +08:00
|
|
|
if (MI.getFlag(MachineInstr::FrameSetup))
|
|
|
|
OS << "frame-setup ";
|
2018-03-14 03:53:16 +08:00
|
|
|
if (MI.getFlag(MachineInstr::FrameDestroy))
|
2018-01-09 19:33:22 +08:00
|
|
|
OS << "frame-destroy ";
|
2018-05-03 08:07:56 +08:00
|
|
|
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 ";
|
2018-09-12 05:35:32 +08:00
|
|
|
if (MI.getFlag(MachineInstr::NoUWrap))
|
|
|
|
OS << "nuw ";
|
|
|
|
if (MI.getFlag(MachineInstr::NoSWrap))
|
|
|
|
OS << "nsw ";
|
|
|
|
if (MI.getFlag(MachineInstr::IsExact))
|
|
|
|
OS << "exact ";
|
2019-06-06 06:33:10 +08:00
|
|
|
if (MI.getFlag(MachineInstr::FPExcept))
|
|
|
|
OS << "fpexcept ";
|
2018-01-09 19:33:22 +08:00
|
|
|
|
2015-06-23 01:02:30 +08:00
|
|
|
OS << TII->getName(MI.getOpcode());
|
2015-06-24 00:35:26 +08:00
|
|
|
if (I < E)
|
|
|
|
OS << ' ';
|
|
|
|
|
|
|
|
bool NeedComma = false;
|
|
|
|
for (; I < E; ++I) {
|
|
|
|
if (NeedComma)
|
|
|
|
OS << ", ";
|
2017-11-07 05:46:06 +08:00
|
|
|
print(MI, I, TRI, ShouldPrintRegisterTies,
|
2017-12-07 18:40:31 +08:00
|
|
|
MI.getTypeToPrint(I, PrintedTypes, MRI));
|
2015-06-24 00:35:26 +08:00
|
|
|
NeedComma = true;
|
|
|
|
}
|
2015-07-23 05:15:11 +08:00
|
|
|
|
[x86/MIR] Implement support for pre- and post-instruction symbols, as
well as MIR parsing support for `MCSymbol` `MachineOperand`s.
The only real way to test pre- and post-instruction symbol support is to
use them in operands, so I ended up implementing that within the patch
as well. I can split out the operand support if folks really want but it
doesn't really seem worth it.
The functional implementation of pre- and post-instruction symbols is
now *completely trivial*. Two tiny bits of code in the (misnamed)
AsmPrinter. It should be completely target independent as well. We emit
these exactly the same way as we emit basic block labels. Most of the
code here is to give full dumping, MIR printing, and MIR parsing support
so that we can write useful tests.
The MIR parsing of MC symbol operands still isn't 100%, as it forces the
symbols to be non-temporary and non-local symbols with names. However,
those names often can encode most (if not all) of the special semantics
desired, and unnamed symbols seem especially annoying to serialize and
de-serialize. While this isn't perfect or full support, it seems plenty
to write tests that exercise usage of these kinds of operands.
The MIR support for pre-and post-instruction symbols was quite
straightforward. I chose to print them out in an as-if-operand syntax
similar to debug locations as this seemed the cleanest way and let me
use nice introducer tokens rather than inventing more magic punctuation
like we use for memoperands.
However, supporting MIR-based parsing of these symbols caused me to
change the design of the symbol support to allow setting arbitrary
symbols. Without this, I don't see any reasonable way to test things
with MIR.
Differential Revision: https://reviews.llvm.org/D50833
llvm-svn: 339962
2018-08-17 07:11:05 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2018-01-19 19:44:42 +08:00
|
|
|
if (const DebugLoc &DL = MI.getDebugLoc()) {
|
2015-07-23 05:15:11 +08:00
|
|
|
if (NeedComma)
|
|
|
|
OS << ',';
|
|
|
|
OS << " debug-location ";
|
2018-01-19 19:44:42 +08:00
|
|
|
DL->printAsOperand(OS, MST);
|
2015-07-23 05:15:11 +08:00
|
|
|
}
|
2015-08-04 07:08:19 +08:00
|
|
|
|
|
|
|
if (!MI.memoperands_empty()) {
|
|
|
|
OS << " :: ";
|
2017-12-16 06:22:58 +08:00
|
|
|
const LLVMContext &Context = MF->getFunction().getContext();
|
2018-03-15 05:52:13 +08:00
|
|
|
const MachineFrameInfo &MFI = MF->getFrameInfo();
|
2015-08-04 07:08:19 +08:00
|
|
|
bool NeedComma = false;
|
|
|
|
for (const auto *Op : MI.memoperands()) {
|
|
|
|
if (NeedComma)
|
|
|
|
OS << ", ";
|
2018-03-15 05:52:13 +08:00
|
|
|
Op->print(OS, MST, SSNs, Context, &MFI, TII);
|
2015-08-04 07:08:19 +08:00
|
|
|
NeedComma = true;
|
|
|
|
}
|
|
|
|
}
|
2015-06-24 00:35:26 +08:00
|
|
|
}
|
|
|
|
|
2015-07-17 07:37:45 +08:00
|
|
|
void MIPrinter::printStackObjectReference(int FrameIndex) {
|
|
|
|
auto ObjectInfo = StackObjectOperandMapping.find(FrameIndex);
|
|
|
|
assert(ObjectInfo != StackObjectOperandMapping.end() &&
|
|
|
|
"Invalid frame index");
|
|
|
|
const FrameIndexOperand &Operand = ObjectInfo->second;
|
2017-12-16 00:33:45 +08:00
|
|
|
MachineOperand::printStackObjectReference(OS, Operand.ID, Operand.IsFixed,
|
|
|
|
Operand.Name);
|
2015-07-17 07:37:45 +08:00
|
|
|
}
|
|
|
|
|
2017-11-07 05:46:06 +08:00
|
|
|
void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx,
|
|
|
|
const TargetRegisterInfo *TRI,
|
|
|
|
bool ShouldPrintRegisterTies, LLT TypeToPrint,
|
2017-12-07 18:40:31 +08:00
|
|
|
bool PrintDef) {
|
2017-11-07 05:46:06 +08:00
|
|
|
const MachineOperand &Op = MI.getOperand(OpIdx);
|
2015-06-24 00:35:26 +08:00
|
|
|
switch (Op.getType()) {
|
2017-12-09 06:53:21 +08:00
|
|
|
case MachineOperand::MO_Immediate:
|
|
|
|
if (MI.isOperandSubregIdx(OpIdx)) {
|
2017-12-14 18:03:09 +08:00
|
|
|
MachineOperand::printTargetFlags(OS, Op);
|
2018-01-16 18:53:11 +08:00
|
|
|
MachineOperand::printSubRegIdx(OS, Op.getImm(), TRI);
|
2017-12-09 06:53:21 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
LLVM_FALLTHROUGH;
|
2017-12-08 19:40:06 +08:00
|
|
|
case MachineOperand::MO_Register:
|
2017-12-08 19:48:02 +08:00
|
|
|
case MachineOperand::MO_CImmediate:
|
2017-12-20 05:47:00 +08:00
|
|
|
case MachineOperand::MO_FPImmediate:
|
2017-12-13 18:30:45 +08:00
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
2017-12-13 18:30:51 +08:00
|
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
2017-12-13 18:30:59 +08:00
|
|
|
case MachineOperand::MO_TargetIndex:
|
2017-12-14 18:02:58 +08:00
|
|
|
case MachineOperand::MO_JumpTableIndex:
|
2017-12-14 18:03:09 +08:00
|
|
|
case MachineOperand::MO_ExternalSymbol:
|
2017-12-14 18:03:14 +08:00
|
|
|
case MachineOperand::MO_GlobalAddress:
|
2017-12-14 18:03:18 +08:00
|
|
|
case MachineOperand::MO_RegisterLiveOut:
|
2017-12-14 18:03:23 +08:00
|
|
|
case MachineOperand::MO_Metadata:
|
2017-12-20 00:51:52 +08:00
|
|
|
case MachineOperand::MO_MCSymbol:
|
2017-12-20 05:47:05 +08:00
|
|
|
case MachineOperand::MO_CFIIndex:
|
2017-12-20 05:47:10 +08:00
|
|
|
case MachineOperand::MO_IntrinsicID:
|
2017-12-20 05:47:14 +08:00
|
|
|
case MachineOperand::MO_Predicate:
|
|
|
|
case MachineOperand::MO_BlockAddress: {
|
2017-12-07 18:40:31 +08:00
|
|
|
unsigned TiedOperandIdx = 0;
|
2017-12-09 06:53:21 +08:00
|
|
|
if (ShouldPrintRegisterTies && Op.isReg() && Op.isTied() && !Op.isDef())
|
2017-12-07 18:40:31 +08:00
|
|
|
TiedOperandIdx = Op.getParent()->findTiedOperandIdx(OpIdx);
|
|
|
|
const TargetIntrinsicInfo *TII = MI.getMF()->getTarget().getIntrinsicInfo();
|
2018-01-19 02:05:15 +08:00
|
|
|
Op.print(OS, MST, TypeToPrint, PrintDef, /*IsStandalone=*/false,
|
2018-01-19 01:59:06 +08:00
|
|
|
ShouldPrintRegisterTies, TiedOperandIdx, TRI, TII);
|
2015-06-24 00:35:26 +08:00
|
|
|
break;
|
2017-10-25 02:04:54 +08:00
|
|
|
}
|
2015-07-17 07:37:45 +08:00
|
|
|
case MachineOperand::MO_FrameIndex:
|
|
|
|
printStackObjectReference(Op.getIndex());
|
|
|
|
break;
|
2015-06-30 00:57:06 +08:00
|
|
|
case MachineOperand::MO_RegisterMask: {
|
|
|
|
auto RegMaskInfo = RegisterMaskIds.find(Op.getRegMask());
|
|
|
|
if (RegMaskInfo != RegisterMaskIds.end())
|
|
|
|
OS << StringRef(TRI->getRegMaskNames()[RegMaskInfo->second]).lower();
|
|
|
|
else
|
2017-03-19 16:14:18 +08:00
|
|
|
printCustomRegMask(Op.getRegMask(), OS, TRI);
|
2015-06-30 00:57:06 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-06-24 00:35:26 +08:00
|
|
|
}
|
2015-06-20 01:43:07 +08:00
|
|
|
}
|
|
|
|
|
2015-06-16 07:52:35 +08:00
|
|
|
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);
|
|
|
|
}
|