[llvm] r269750 - Factor PrologEpilogInserter around spilling, frame finalization, and scavenging
Derek Schuff via llvm-commits
llvm-commits at lists.llvm.org
Tue May 17 01:50:00 PDT 2016
Author: dschuff
Date: Tue May 17 03:49:59 2016
New Revision: 269750
URL: http://llvm.org/viewvc/llvm-project?rev=269750&view=rev
Log:
Factor PrologEpilogInserter around spilling, frame finalization, and scavenging
PrologEpilogInserter has these 3 phases, which are related, but not
all of them are needed by all targets. This patch reorganizes PEI's
varous functions around those phases for more clear separation. It also
introduces a new TargetMachine hook, usesPhysRegsForPEI, which is true
for non-virtual targets. When it is true, all the phases operate as
before, and PEI requires the AllVRegsAllocated property on
MachineFunctions. Otherwise, CSR spilling and scavenging are skipped and
only prolog/epilog insertion/frame finalization is done.
Differential Revision: http://reviews.llvm.org/D18366
Modified:
llvm/trunk/include/llvm/CodeGen/Passes.h
llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h
llvm/trunk/include/llvm/Target/TargetMachine.h
llvm/trunk/lib/CodeGen/PrologEpilogInserter.cpp
llvm/trunk/lib/CodeGen/TargetPassConfig.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
+++ llvm/trunk/include/llvm/CodeGen/Passes.h Tue May 17 03:49:59 2016
@@ -152,6 +152,7 @@ namespace llvm {
/// PrologEpilogCodeInserter - This pass inserts prolog and epilog code,
/// and eliminates abstract frame references.
extern char &PrologEpilogCodeInserterID;
+ MachineFunctionPass *createPrologEpilogInserterPass(const TargetMachine *TM);
/// ExpandPostRAPseudos - This pass expands pseudo instructions after
/// register allocation.
Modified: llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h (original)
+++ llvm/trunk/include/llvm/CodeGen/TargetPassConfig.h Tue May 17 03:49:59 2016
@@ -178,6 +178,10 @@ public:
/// If no substitution exists, return StandardID.
IdentifyingPassPtr getPassSubstitution(AnalysisID StandardID) const;
+ /// Return true if the pass has been substituted by the target or
+ /// overridden on the command line.
+ bool isPassSubstitutedOrOverridden(AnalysisID ID) const;
+
/// Return true if the optimized regalloc pipeline is enabled.
bool getOptimizeRegAlloc() const;
Modified: llvm/trunk/include/llvm/Target/TargetMachine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetMachine.h?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/TargetMachine.h (original)
+++ llvm/trunk/include/llvm/Target/TargetMachine.h Tue May 17 03:49:59 2016
@@ -264,6 +264,12 @@ public:
void getNameWithPrefix(SmallVectorImpl<char> &Name, const GlobalValue *GV,
Mangler &Mang, bool MayAlwaysUsePrivate = false) const;
MCSymbol *getSymbol(const GlobalValue *GV, Mangler &Mang) const;
+
+ /// True if the target uses physical regs at Prolog/Epilog insertion
+ /// time. If true (most machines), all vregs must be allocated before
+ /// PEI. If false (virtual-register machines), then callee-save register
+ /// spilling and scavenging are not needed or used.
+ virtual bool usesPhysRegsForPEI() const { return true; }
};
/// This class describes a target machine that is implemented with the LLVM
Modified: llvm/trunk/lib/CodeGen/PrologEpilogInserter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/PrologEpilogInserter.cpp?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/PrologEpilogInserter.cpp (original)
+++ llvm/trunk/lib/CodeGen/PrologEpilogInserter.cpp Tue May 17 03:49:59 2016
@@ -47,19 +47,41 @@ using namespace llvm;
#define DEBUG_TYPE "pei"
+typedef SmallVector<MachineBasicBlock *, 4> MBBVector;
+static void doSpillCalleeSavedRegs(MachineFunction &MF, RegScavenger *RS,
+ unsigned &MinCSFrameIndex,
+ unsigned &MaxCXFrameIndex,
+ const MBBVector &SaveBlocks,
+ const MBBVector &RestoreBlocks);
+
+static void doScavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger *RS);
+
namespace {
class PEI : public MachineFunctionPass {
public:
static char ID;
- PEI() : MachineFunctionPass(ID) {
+ explicit PEI(const TargetMachine *TM = nullptr) : MachineFunctionPass(ID) {
initializePEIPass(*PassRegistry::getPassRegistry());
+
+ if (TM && (!TM->usesPhysRegsForPEI())) {
+ SpillCalleeSavedRegisters = [](MachineFunction &, RegScavenger *,
+ unsigned &, unsigned &, const MBBVector &,
+ const MBBVector &) {};
+ ScavengeFrameVirtualRegs = [](MachineFunction &, RegScavenger *) {};
+ } else {
+ SpillCalleeSavedRegisters = doSpillCalleeSavedRegs;
+ ScavengeFrameVirtualRegs = doScavengeFrameVirtualRegs;
+ UsesCalleeSaves = true;
+ }
}
void getAnalysisUsage(AnalysisUsage &AU) const override;
MachineFunctionProperties getRequiredProperties() const override {
- return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties MFP;
+ if (UsesCalleeSaves)
+ MFP.set(MachineFunctionProperties::Property::AllVRegsAllocated);
+ return MFP;
}
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract
@@ -68,32 +90,40 @@ public:
bool runOnMachineFunction(MachineFunction &Fn) override;
private:
+ std::function<void(MachineFunction &MF, RegScavenger *RS,
+ unsigned &MinCSFrameIndex, unsigned &MaxCSFrameIndex,
+ const MBBVector &SaveBlocks,
+ const MBBVector &RestoreBlocks)>
+ SpillCalleeSavedRegisters;
+ std::function<void(MachineFunction &MF, RegScavenger *RS)>
+ ScavengeFrameVirtualRegs;
+
+ bool UsesCalleeSaves = false;
+
RegScavenger *RS;
// MinCSFrameIndex, MaxCSFrameIndex - Keeps the range of callee saved
// stack frame indexes.
- unsigned MinCSFrameIndex, MaxCSFrameIndex;
+ unsigned MinCSFrameIndex = std::numeric_limits<unsigned>::max();
+ unsigned MaxCSFrameIndex = 0;
// Save and Restore blocks of the current function. Typically there is a
// single save block, unless Windows EH funclets are involved.
- SmallVector<MachineBasicBlock *, 1> SaveBlocks;
- SmallVector<MachineBasicBlock *, 4> RestoreBlocks;
+ MBBVector SaveBlocks;
+ MBBVector RestoreBlocks;
// Flag to control whether to use the register scavenger to resolve
// frame index materialization registers. Set according to
// TRI->requiresFrameIndexScavenging() for the current function.
bool FrameIndexVirtualScavenging;
- void calculateSets(MachineFunction &Fn);
- void calculateCallsInformation(MachineFunction &Fn);
- void assignCalleeSavedSpillSlots(MachineFunction &Fn,
- const BitVector &SavedRegs);
- void insertCSRSpillsAndRestores(MachineFunction &Fn);
+ void calculateCallFrameInfo(MachineFunction &Fn);
+ void calculateSaveRestoreBlocks(MachineFunction &Fn);
+
void calculateFrameObjectOffsets(MachineFunction &Fn);
void replaceFrameIndices(MachineFunction &Fn);
void replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn,
int &SPAdj);
- void scavengeFrameVirtualRegs(MachineFunction &Fn);
void insertPrologEpilogCode(MachineFunction &Fn);
};
} // namespace
@@ -106,14 +136,19 @@ WarnStackSize("warn-stack-size", cl::Hid
cl::desc("Warn for stack size bigger than the given"
" number"));
-INITIALIZE_PASS_BEGIN(PEI, "prologepilog",
- "Prologue/Epilogue Insertion", false, false)
+INITIALIZE_TM_PASS_BEGIN(PEI, "prologepilog", "Prologue/Epilogue Insertion",
+ false, false)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(StackProtector)
-INITIALIZE_PASS_END(PEI, "prologepilog",
- "Prologue/Epilogue Insertion & Frame Finalization",
- false, false)
+INITIALIZE_TM_PASS_END(PEI, "prologepilog",
+ "Prologue/Epilogue Insertion & Frame Finalization",
+ false, false)
+
+MachineFunctionPass *
+llvm::createPrologEpilogInserterPass(const TargetMachine *TM) {
+ return new PEI(TM);
+}
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
STATISTIC(NumBytesStackSpace,
@@ -127,36 +162,6 @@ void PEI::getAnalysisUsage(AnalysisUsage
MachineFunctionPass::getAnalysisUsage(AU);
}
-/// Compute the set of return blocks
-void PEI::calculateSets(MachineFunction &Fn) {
- const MachineFrameInfo *MFI = Fn.getFrameInfo();
-
- // Even when we do not change any CSR, we still want to insert the
- // prologue and epilogue of the function.
- // So set the save points for those.
-
- // Use the points found by shrink-wrapping, if any.
- if (MFI->getSavePoint()) {
- SaveBlocks.push_back(MFI->getSavePoint());
- assert(MFI->getRestorePoint() && "Both restore and save must be set");
- MachineBasicBlock *RestoreBlock = MFI->getRestorePoint();
- // If RestoreBlock does not have any successor and is not a return block
- // then the end point is unreachable and we do not need to insert any
- // epilogue.
- if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
- RestoreBlocks.push_back(RestoreBlock);
- return;
- }
-
- // Save refs to entry and return blocks.
- SaveBlocks.push_back(&Fn.front());
- for (MachineBasicBlock &MBB : Fn) {
- if (MBB.isEHFuncletEntry())
- SaveBlocks.push_back(&MBB);
- if (MBB.isReturnBlock())
- RestoreBlocks.push_back(&MBB);
- }
-}
/// StackObjSet - A set of stack object indexes
typedef SmallSetVector<int, 8> StackObjSet;
@@ -169,30 +174,21 @@ bool PEI::runOnMachineFunction(MachineFu
const TargetRegisterInfo *TRI = Fn.getSubtarget().getRegisterInfo();
const TargetFrameLowering *TFI = Fn.getSubtarget().getFrameLowering();
- assert(!Fn.getRegInfo().getNumVirtRegs() && "Regalloc must assign all vregs");
-
RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : nullptr;
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn);
// Calculate the MaxCallFrameSize and AdjustsStack variables for the
// function's frame information. Also eliminates call frame pseudo
// instructions.
- calculateCallsInformation(Fn);
+ calculateCallFrameInfo(Fn);
- // Determine which of the registers in the callee save list should be saved.
- BitVector SavedRegs;
- TFI->determineCalleeSaves(Fn, SavedRegs, RS);
-
- // Insert spill code for any callee saved registers that are modified.
- assignCalleeSavedSpillSlots(Fn, SavedRegs);
-
- // Determine placement of CSR spill/restore code:
+ // Determine placement of CSR spill/restore code and prolog/epilog code:
// place all spills in the entry block, all restores in return blocks.
- calculateSets(Fn);
+ calculateSaveRestoreBlocks(Fn);
- // Add the code to save and restore the callee saved registers.
- if (!F->hasFnAttribute(Attribute::Naked))
- insertCSRSpillsAndRestores(Fn);
+ // Handle CSR spilling and restoring, for targets that need it.
+ SpillCalleeSavedRegisters(Fn, RS, MinCSFrameIndex, MaxCSFrameIndex,
+ SaveBlocks, RestoreBlocks);
// Allow the target machine to make final modifications to the function
// before the frame layout is finalized.
@@ -217,11 +213,12 @@ bool PEI::runOnMachineFunction(MachineFu
// If register scavenging is needed, as we've enabled doing it as a
// post-pass, scavenge the virtual registers that frame index elimination
// inserted.
- if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging)
- scavengeFrameVirtualRegs(Fn);
+ if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging) {
+ ScavengeFrameVirtualRegs(Fn, RS);
- // Clear any vregs created by virtual scavenging.
- Fn.getRegInfo().clearVirtRegs();
+ // Clear any vregs created by virtual scavenging.
+ Fn.getRegInfo().clearVirtRegs();
+ }
// Warn on stack size when we exceeds the given limit.
MachineFrameInfo *MFI = Fn.getFrameInfo();
@@ -239,10 +236,10 @@ bool PEI::runOnMachineFunction(MachineFu
return true;
}
-/// calculateCallsInformation - Calculate the MaxCallFrameSize and AdjustsStack
+/// Calculate the MaxCallFrameSize and AdjustsStack
/// variables for the function's frame information and eliminate call frame
/// pseudo instructions.
-void PEI::calculateCallsInformation(MachineFunction &Fn) {
+void PEI::calculateCallFrameInfo(MachineFunction &Fn) {
const TargetInstrInfo &TII = *Fn.getSubtarget().getInstrInfo();
const TargetFrameLowering *TFI = Fn.getSubtarget().getFrameLowering();
MachineFrameInfo *MFI = Fn.getFrameInfo();
@@ -293,12 +290,42 @@ void PEI::calculateCallsInformation(Mach
}
}
-void PEI::assignCalleeSavedSpillSlots(MachineFunction &F,
- const BitVector &SavedRegs) {
- // These are used to keep track the callee-save area. Initialize them.
- MinCSFrameIndex = INT_MAX;
- MaxCSFrameIndex = 0;
+/// Compute the sets of entry and return blocks for saving and restoring
+/// callee-saved registers, and placing prolog and epilog code.
+void PEI::calculateSaveRestoreBlocks(MachineFunction &Fn) {
+ const MachineFrameInfo *MFI = Fn.getFrameInfo();
+
+ // Even when we do not change any CSR, we still want to insert the
+ // prologue and epilogue of the function.
+ // So set the save points for those.
+
+ // Use the points found by shrink-wrapping, if any.
+ if (MFI->getSavePoint()) {
+ SaveBlocks.push_back(MFI->getSavePoint());
+ assert(MFI->getRestorePoint() && "Both restore and save must be set");
+ MachineBasicBlock *RestoreBlock = MFI->getRestorePoint();
+ // If RestoreBlock does not have any successor and is not a return block
+ // then the end point is unreachable and we do not need to insert any
+ // epilogue.
+ if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
+ RestoreBlocks.push_back(RestoreBlock);
+ return;
+ }
+
+ // Save refs to entry and return blocks.
+ SaveBlocks.push_back(&Fn.front());
+ for (MachineBasicBlock &MBB : Fn) {
+ if (MBB.isEHFuncletEntry())
+ SaveBlocks.push_back(&MBB);
+ if (MBB.isReturnBlock())
+ RestoreBlocks.push_back(&MBB);
+ }
+}
+static void assignCalleeSavedSpillSlots(MachineFunction &F,
+ const BitVector &SavedRegs,
+ unsigned &MinCSFrameIndex,
+ unsigned &MaxCSFrameIndex) {
if (SavedRegs.empty())
return;
@@ -429,7 +456,9 @@ static void updateLiveness(MachineFuncti
/// insertCSRSpillsAndRestores - Insert spill and restore code for
/// callee saved registers used in the function.
///
-void PEI::insertCSRSpillsAndRestores(MachineFunction &Fn) {
+static void insertCSRSpillsAndRestores(MachineFunction &Fn,
+ const MBBVector &SaveBlocks,
+ const MBBVector &RestoreBlocks) {
// Get callee saved register information.
MachineFrameInfo *MFI = Fn.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
@@ -498,6 +527,28 @@ void PEI::insertCSRSpillsAndRestores(Mac
}
}
+static void doSpillCalleeSavedRegs(MachineFunction &Fn, RegScavenger *RS,
+ unsigned &MinCSFrameIndex,
+ unsigned &MaxCSFrameIndex,
+ const MBBVector &SaveBlocks,
+ const MBBVector &RestoreBlocks) {
+ const Function *F = Fn.getFunction();
+ const TargetFrameLowering *TFI = Fn.getSubtarget().getFrameLowering();
+ MinCSFrameIndex = std::numeric_limits<unsigned>::max();
+ MaxCSFrameIndex = 0;
+
+ // Determine which of the registers in the callee save list should be saved.
+ BitVector SavedRegs;
+ TFI->determineCalleeSaves(Fn, SavedRegs, RS);
+
+ // Assign stack slots for any callee-saved registers that must be spilled.
+ assignCalleeSavedSpillSlots(Fn, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
+
+ // Add the code to save and restore the callee saved registers.
+ if (!F->hasFnAttribute(Attribute::Naked))
+ insertCSRSpillsAndRestores(Fn, SaveBlocks, RestoreBlocks);
+}
+
/// AdjustStackOffset - Helper function used to adjust the stack frame offset.
static inline void
AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx,
@@ -604,8 +655,8 @@ void PEI::calculateFrameObjectOffsets(Ma
MFI->setObjectOffset(i, -Offset); // Set the computed offset
}
} else {
- int MaxCSFI = MaxCSFrameIndex, MinCSFI = MinCSFrameIndex;
- for (int i = MaxCSFI; i >= MinCSFI ; --i) {
+ unsigned MaxCSFI = MaxCSFrameIndex, MinCSFI = MinCSFrameIndex;
+ for (unsigned i = MaxCSFI; i >= MinCSFI; --i) {
unsigned Align = MFI->getObjectAlignment(i);
// Adjust to alignment boundary
Offset = alignTo(Offset, Align, Skew);
@@ -977,15 +1028,15 @@ void PEI::replaceFrameIndices(MachineBas
}
}
-/// scavengeFrameVirtualRegs - Replace all frame index virtual registers
+/// doScavengeFrameVirtualRegs - Replace all frame index virtual registers
/// with physical registers. Use the register scavenger to find an
/// appropriate register to use.
///
/// FIXME: Iterating over the instruction stream is unnecessary. We can simply
/// iterate over the vreg use list, which at this point only contains machine
/// operands for which eliminateFrameIndex need a new scratch reg.
-void
-PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
+static void
+doScavengeFrameVirtualRegs(MachineFunction &Fn, RegScavenger *RS) {
// Run through the instructions and find any virtual registers.
for (MachineFunction::iterator BB = Fn.begin(),
E = Fn.end(); BB != E; ++BB) {
Modified: llvm/trunk/lib/CodeGen/TargetPassConfig.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetPassConfig.cpp?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/TargetPassConfig.cpp (original)
+++ llvm/trunk/lib/CodeGen/TargetPassConfig.cpp Tue May 17 03:49:59 2016
@@ -312,6 +312,13 @@ IdentifyingPassPtr TargetPassConfig::get
return I->second;
}
+bool TargetPassConfig::isPassSubstitutedOrOverridden(AnalysisID ID) const {
+ IdentifyingPassPtr TargetID = getPassSubstitution(ID);
+ IdentifyingPassPtr FinalPtr = overridePass(ID, TargetID);
+ return !FinalPtr.isValid() || FinalPtr.isInstance() ||
+ FinalPtr.getID() != ID;
+}
+
/// Add a pass to the PassManager if that pass is supposed to be run. If the
/// Started/Stopped flags indicate either that the compilation should start at
/// a later pass or that it should stop after an earlier pass, then do not add
@@ -565,7 +572,10 @@ void TargetPassConfig::addMachinePasses(
if (getOptLevel() != CodeGenOpt::None)
addPass(&ShrinkWrapID);
- addPass(&PrologEpilogCodeInserterID);
+ // Prolog/Epilog inserter needs a TargetMachine to instantiate. But only
+ // do so if it hasn't been disabled, substituted, or overridden.
+ if (!isPassSubstitutedOrOverridden(&PrologEpilogCodeInserterID))
+ addPass(createPrologEpilogInserterPass(TM));
/// Add passes that optimize machine instructions after register allocation.
if (getOptLevel() != CodeGenOpt::None)
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Tue May 17 03:49:59 2016
@@ -167,9 +167,6 @@ void WebAssemblyPassConfig::addPostRegAl
// Has no asserts of its own, but was not written to handle virtual regs.
disablePass(&ShrinkWrapID);
- // We use our own PrologEpilogInserter which is very slightly modified to
- // tolerate virtual registers.
- disablePass(&PrologEpilogCodeInserterID);
// These functions all require the AllVRegsAllocated property.
disablePass(&MachineCopyPropagationID);
@@ -180,11 +177,6 @@ void WebAssemblyPassConfig::addPostRegAl
disablePass(&PatchableFunctionID);
TargetPassConfig::addPostRegAlloc();
-
- // Run WebAssembly's version of the PrologEpilogInserter. Target-independent
- // PEI runs after PostRegAlloc and after ShrinkWrap. Putting it here will run
- // PEI before ShrinkWrap but otherwise in the same position in the order.
- addPass(createWebAssemblyPEI());
}
void WebAssemblyPassConfig::addPreEmitPass() {
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.h?rev=269750&r1=269749&r2=269750&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.h Tue May 17 03:49:59 2016
@@ -44,6 +44,8 @@ public:
/// \brief Get the TargetIRAnalysis for this target.
TargetIRAnalysis getTargetIRAnalysis() override;
+
+ bool usesPhysRegsForPEI() const override { return false; }
};
} // end namespace llvm
More information about the llvm-commits
mailing list