[llvm] r369395 - [CodeGen] Add a pass to do block predication on SSA machine IR.
Roman Lebedev via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 20 08:54:24 PDT 2019
Where did the tests go?
On Tue, Aug 20, 2019 at 6:53 PM Thomas Raoux via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
>
> Author: thomasraoux
> Date: Tue Aug 20 08:54:59 2019
> New Revision: 369395
>
> URL: http://llvm.org/viewvc/llvm-project?rev=369395&view=rev
> Log:
> [CodeGen] Add a pass to do block predication on SSA machine IR.
>
> For targets requiring aggressive scheduling and/or software pipeline we need to
> apply predication before preRA scheduling. This adds a pass re-using the early
> if-cvt infrastructure but generating predicated instructions instead of
> speculatively executing instructions. It allows doing if conversion on blocks
> containing instructions with side-effects. The pass re-use the target hook from
> postRA if-conversion to let the target decide on the heuristic to apply.
>
> Differential Revision: https://reviews.llvm.org/D66190
>
> Modified:
> llvm/trunk/include/llvm/CodeGen/Passes.h
> llvm/trunk/include/llvm/InitializePasses.h
> llvm/trunk/lib/CodeGen/CodeGen.cpp
> llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp
>
> Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=369395&r1=369394&r2=369395&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/Passes.h Tue Aug 20 08:54:59 2019
> @@ -226,6 +226,10 @@ namespace llvm {
> /// inserting cmov instructions.
> extern char &EarlyIfConverterID;
>
> + /// EarlyIfPredicator - This pass performs if-conversion on SSA form by
> + /// predicating if/else block and insert select at the join point.
> + extern char &EarlyIfPredicatorID;
> +
> /// This pass performs instruction combining using trace metrics to estimate
> /// critical-path and resource depth.
> extern char &MachineCombinerID;
>
> Modified: llvm/trunk/include/llvm/InitializePasses.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=369395&r1=369394&r2=369395&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/InitializePasses.h (original)
> +++ llvm/trunk/include/llvm/InitializePasses.h Tue Aug 20 08:54:59 2019
> @@ -132,6 +132,7 @@ void initializeDwarfEHPreparePass(PassRe
> void initializeEarlyCSELegacyPassPass(PassRegistry&);
> void initializeEarlyCSEMemSSALegacyPassPass(PassRegistry&);
> void initializeEarlyIfConverterPass(PassRegistry&);
> +void initializeEarlyIfPredicatorPass(PassRegistry &);
> void initializeEarlyMachineLICMPass(PassRegistry&);
> void initializeEarlyTailDuplicatePass(PassRegistry&);
> void initializeEdgeBundlesPass(PassRegistry&);
>
> Modified: llvm/trunk/lib/CodeGen/CodeGen.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGen.cpp?rev=369395&r1=369394&r2=369395&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/CodeGen.cpp (original)
> +++ llvm/trunk/lib/CodeGen/CodeGen.cpp Tue Aug 20 08:54:59 2019
> @@ -28,6 +28,7 @@ void llvm::initializeCodeGen(PassRegistr
> initializeDetectDeadLanesPass(Registry);
> initializeDwarfEHPreparePass(Registry);
> initializeEarlyIfConverterPass(Registry);
> + initializeEarlyIfPredicatorPass(Registry);
> initializeEarlyMachineLICMPass(Registry);
> initializeEarlyTailDuplicatePass(Registry);
> initializeExpandMemCmpPassPass(Registry);
>
> Modified: llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp?rev=369395&r1=369394&r2=369395&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp (original)
> +++ llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp Tue Aug 20 08:54:59 2019
> @@ -25,6 +25,7 @@
> #include "llvm/CodeGen/MachineDominators.h"
> #include "llvm/CodeGen/MachineFunction.h"
> #include "llvm/CodeGen/MachineFunctionPass.h"
> +#include "llvm/CodeGen/MachineInstr.h"
> #include "llvm/CodeGen/MachineLoopInfo.h"
> #include "llvm/CodeGen/MachineRegisterInfo.h"
> #include "llvm/CodeGen/MachineTraceMetrics.h"
> @@ -140,6 +141,18 @@ private:
> /// speculated.
> bool canSpeculateInstrs(MachineBasicBlock *MBB);
>
> + /// Return true if all non-terminator instructions in MBB can be safely
> + /// predicated.
> + bool canPredicateInstrs(MachineBasicBlock *MBB);
> +
> + /// Scan through instruction dependencies and update InsertAfter array.
> + /// Return false if any dependency is incompatible with if conversion.
> + bool InstrDependenciesAllowIfConv(MachineInstr *I);
> +
> + /// Predicate all instructions of the basic block with current condition
> + /// except for terminators. Reverse the condition if ReversePredicate is set.
> + void PredicateBlock(MachineBasicBlock *MBB, bool ReversePredicate);
> +
> /// Find a valid insertion point in Head.
> bool findInsertionPoint();
>
> @@ -163,11 +176,14 @@ public:
>
> /// canConvertIf - If the sub-CFG headed by MBB can be if-converted,
> /// initialize the internal state, and return true.
> - bool canConvertIf(MachineBasicBlock *MBB);
> + /// If predicate is set try to predicate the block otherwise try to
> + /// speculatively execute it.
> + bool canConvertIf(MachineBasicBlock *MBB, bool Predicate = false);
>
> /// convertIf - If-convert the last block passed to canConvertIf(), assuming
> /// it is possible. Add any erased blocks to RemovedBlocks.
> - void convertIf(SmallVectorImpl<MachineBasicBlock*> &RemovedBlocks);
> + void convertIf(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks,
> + bool Predicate = false);
> };
> } // end anonymous namespace
>
> @@ -225,37 +241,112 @@ bool SSAIfConv::canSpeculateInstrs(Machi
> }
>
> // Check for any dependencies on Head instructions.
> - for (const MachineOperand &MO : I->operands()) {
> - if (MO.isRegMask()) {
> - LLVM_DEBUG(dbgs() << "Won't speculate regmask: " << *I);
> - return false;
> - }
> - if (!MO.isReg())
> - continue;
> - Register Reg = MO.getReg();
> + if (!InstrDependenciesAllowIfConv(&(*I)))
> + return false;
> + }
> + return true;
> +}
>
> - // Remember clobbered regunits.
> - if (MO.isDef() && Register::isPhysicalRegister(Reg))
> - for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units)
> - ClobberedRegUnits.set(*Units);
> +/// Check that there is no dependencies preventing if conversion.
> +///
> +/// If instruction uses any values that are defined in the head basic block,
> +/// the defining instructions are added to InsertAfter.
> +bool SSAIfConv::InstrDependenciesAllowIfConv(MachineInstr *I) {
> + for (const MachineOperand &MO : I->operands()) {
> + if (MO.isRegMask()) {
> + LLVM_DEBUG(dbgs() << "Won't speculate regmask: " << *I);
> + return false;
> + }
> + if (!MO.isReg())
> + continue;
> + Register Reg = MO.getReg();
>
> - if (!MO.readsReg() || !Register::isVirtualRegister(Reg))
> - continue;
> - MachineInstr *DefMI = MRI->getVRegDef(Reg);
> - if (!DefMI || DefMI->getParent() != Head)
> - continue;
> - if (InsertAfter.insert(DefMI).second)
> - LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " depends on "
> - << *DefMI);
> - if (DefMI->isTerminator()) {
> - LLVM_DEBUG(dbgs() << "Can't insert instructions below terminator.\n");
> - return false;
> - }
> + // Remember clobbered regunits.
> + if (MO.isDef() && Register::isPhysicalRegister(Reg))
> + for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units)
> + ClobberedRegUnits.set(*Units);
> +
> + if (!MO.readsReg() || !Register::isVirtualRegister(Reg))
> + continue;
> + MachineInstr *DefMI = MRI->getVRegDef(Reg);
> + if (!DefMI || DefMI->getParent() != Head)
> + continue;
> + if (InsertAfter.insert(DefMI).second)
> + LLVM_DEBUG(dbgs() << printMBBReference(*I->getParent()) << " depends on "
> + << *DefMI);
> + if (DefMI->isTerminator()) {
> + LLVM_DEBUG(dbgs() << "Can't insert instructions below terminator.\n");
> + return false;
> + }
> + }
> + return true;
> +}
> +
> +/// canPredicateInstrs - Returns true if all the instructions in MBB can safely
> +/// be predicates. The terminators are not considered.
> +///
> +/// If instructions use any values that are defined in the head basic block,
> +/// the defining instructions are added to InsertAfter.
> +///
> +/// Any clobbered regunits are added to ClobberedRegUnits.
> +///
> +bool SSAIfConv::canPredicateInstrs(MachineBasicBlock *MBB) {
> + // Reject any live-in physregs. It's probably CPSR/EFLAGS, and very hard to
> + // get right.
> + if (!MBB->livein_empty()) {
> + LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " has live-ins.\n");
> + return false;
> + }
> +
> + unsigned InstrCount = 0;
> +
> + // Check all instructions, except the terminators. It is assumed that
> + // terminators never have side effects or define any used register values.
> + for (MachineBasicBlock::iterator I = MBB->begin(),
> + E = MBB->getFirstTerminator();
> + I != E; ++I) {
> + if (I->isDebugInstr())
> + continue;
> +
> + if (++InstrCount > BlockInstrLimit && !Stress) {
> + LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << " has more than "
> + << BlockInstrLimit << " instructions.\n");
> + return false;
> }
> +
> + // There shouldn't normally be any phis in a single-predecessor block.
> + if (I->isPHI()) {
> + LLVM_DEBUG(dbgs() << "Can't predicate: " << *I);
> + return false;
> + }
> +
> + // Check that instruction is predicable and that it is not already
> + // predicated.
> + if (!TII->isPredicable(*I) || TII->isPredicated(*I)) {
> + return false;
> + }
> +
> + // Check for any dependencies on Head instructions.
> + if (!InstrDependenciesAllowIfConv(&(*I)))
> + return false;
> }
> return true;
> }
>
> +// Apply predicate to all instructions in the machine block.
> +void SSAIfConv::PredicateBlock(MachineBasicBlock *MBB, bool ReversePredicate) {
> + auto Condition = Cond;
> + if (ReversePredicate)
> + TII->reverseBranchCondition(Condition);
> + // Terminators don't need to be predicated as they will be removed.
> + for (MachineBasicBlock::iterator I = MBB->begin(),
> + E = MBB->getFirstTerminator();
> + I != E; ++I) {
> + if (I->isDebugInstr())
> + continue;
> + TII->PredicateInstruction(*I, Condition);
> + }
> +}
>
> /// Find an insertion point in Head for the speculated instructions. The
> /// insertion point must be:
> @@ -337,7 +428,7 @@ bool SSAIfConv::findInsertionPoint() {
> /// canConvertIf - analyze the sub-cfg rooted in MBB, and return true if it is
> /// a potential candidate for if-conversion. Fill out the internal state.
> ///
> -bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB) {
> +bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB, bool Predicate) {
> Head = MBB;
> TBB = FBB = Tail = nullptr;
>
> @@ -378,8 +469,9 @@ bool SSAIfConv::canConvertIf(MachineBasi
> }
>
> // This is a triangle or a diamond.
> - // If Tail doesn't have any phis, there must be side effects.
> - if (Tail->empty() || !Tail->front().isPHI()) {
> + // Skip if we cannot predicate and there are no phis skip as there must be
> + // side effects that can only be handled with predication.
> + if (!Predicate && (Tail->empty() || !Tail->front().isPHI())) {
> LLVM_DEBUG(dbgs() << "No phis in tail.\n");
> return false;
> }
> @@ -437,10 +529,17 @@ bool SSAIfConv::canConvertIf(MachineBasi
> // Check that the conditional instructions can be speculated.
> InsertAfter.clear();
> ClobberedRegUnits.reset();
> - if (TBB != Tail && !canSpeculateInstrs(TBB))
> - return false;
> - if (FBB != Tail && !canSpeculateInstrs(FBB))
> - return false;
> + if (Predicate) {
> + if (TBB != Tail && !canPredicateInstrs(TBB))
> + return false;
> + if (FBB != Tail && !canPredicateInstrs(FBB))
> + return false;
> + } else {
> + if (TBB != Tail && !canSpeculateInstrs(TBB))
> + return false;
> + if (FBB != Tail && !canSpeculateInstrs(FBB))
> + return false;
> + }
>
> // Try to find a valid insertion point for the speculated instructions in the
> // head basic block.
> @@ -521,7 +620,8 @@ void SSAIfConv::rewritePHIOperands() {
> ///
> /// Any basic blocks erased will be added to RemovedBlocks.
> ///
> -void SSAIfConv::convertIf(SmallVectorImpl<MachineBasicBlock*> &RemovedBlocks) {
> +void SSAIfConv::convertIf(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks,
> + bool Predicate) {
> assert(Head && Tail && TBB && FBB && "Call canConvertIf first.");
>
> // Update statistics.
> @@ -531,11 +631,16 @@ void SSAIfConv::convertIf(SmallVectorImp
> ++NumDiamondsConv;
>
> // Move all instructions into Head, except for the terminators.
> - if (TBB != Tail)
> + if (TBB != Tail) {
> + if (Predicate)
> + PredicateBlock(TBB, /*ReversePredicate=*/false);
> Head->splice(InsertionPoint, TBB, TBB->begin(), TBB->getFirstTerminator());
> - if (FBB != Tail)
> + }
> + if (FBB != Tail) {
> + if (Predicate)
> + PredicateBlock(FBB, /*ReversePredicate=*/true);
> Head->splice(InsertionPoint, FBB, FBB->begin(), FBB->getFirstTerminator());
> -
> + }
> // Are there extra Tail predecessors?
> bool ExtraPreds = Tail->pred_size() != 2;
> if (ExtraPreds)
> @@ -587,7 +692,6 @@ void SSAIfConv::convertIf(SmallVectorImp
> LLVM_DEBUG(dbgs() << *Head);
> }
>
> -
> //===----------------------------------------------------------------------===//
> // EarlyIfConverter Pass
> //===----------------------------------------------------------------------===//
> @@ -613,8 +717,6 @@ public:
>
> private:
> bool tryConvertIf(MachineBasicBlock*);
> - void updateDomTree(ArrayRef<MachineBasicBlock*> Removed);
> - void updateLoops(ArrayRef<MachineBasicBlock*> Removed);
> void invalidateTraces();
> bool shouldConvertIf();
> };
> @@ -642,32 +744,36 @@ void EarlyIfConverter::getAnalysisUsage(
> MachineFunctionPass::getAnalysisUsage(AU);
> }
>
> +namespace {
> /// Update the dominator tree after if-conversion erased some blocks.
> -void EarlyIfConverter::updateDomTree(ArrayRef<MachineBasicBlock*> Removed) {
> +void updateDomTree(MachineDominatorTree *DomTree, const SSAIfConv &IfConv,
> + ArrayRef<MachineBasicBlock *> Removed) {
> // convertIf can remove TBB, FBB, and Tail can be merged into Head.
> // TBB and FBB should not dominate any blocks.
> // Tail children should be transferred to Head.
> MachineDomTreeNode *HeadNode = DomTree->getNode(IfConv.Head);
> - for (unsigned i = 0, e = Removed.size(); i != e; ++i) {
> - MachineDomTreeNode *Node = DomTree->getNode(Removed[i]);
> + for (auto B : Removed) {
> + MachineDomTreeNode *Node = DomTree->getNode(B);
> assert(Node != HeadNode && "Cannot erase the head node");
> while (Node->getNumChildren()) {
> assert(Node->getBlock() == IfConv.Tail && "Unexpected children");
> DomTree->changeImmediateDominator(Node->getChildren().back(), HeadNode);
> }
> - DomTree->eraseNode(Removed[i]);
> + DomTree->eraseNode(B);
> }
> }
>
> /// Update LoopInfo after if-conversion.
> -void EarlyIfConverter::updateLoops(ArrayRef<MachineBasicBlock*> Removed) {
> +void updateLoops(MachineLoopInfo *Loops,
> + ArrayRef<MachineBasicBlock *> Removed) {
> if (!Loops)
> return;
> // If-conversion doesn't change loop structure, and it doesn't mess with back
> // edges, so updating LoopInfo is simply removing the dead blocks.
> - for (unsigned i = 0, e = Removed.size(); i != e; ++i)
> - Loops->removeBlock(Removed[i]);
> + for (auto B : Removed)
> + Loops->removeBlock(B);
> }
> +} // namespace
>
> /// Invalidate MachineTraceMetrics before if-conversion.
> void EarlyIfConverter::invalidateTraces() {
> @@ -783,8 +889,8 @@ bool EarlyIfConverter::tryConvertIf(Mach
> SmallVector<MachineBasicBlock*, 4> RemovedBlocks;
> IfConv.convertIf(RemovedBlocks);
> Changed = true;
> - updateDomTree(RemovedBlocks);
> - updateLoops(RemovedBlocks);
> + updateDomTree(DomTree, IfConv, RemovedBlocks);
> + updateLoops(Loops, RemovedBlocks);
> }
> return Changed;
> }
> @@ -811,6 +917,135 @@ bool EarlyIfConverter::runOnMachineFunct
>
> bool Changed = false;
> IfConv.runOnMachineFunction(MF);
> +
> + // Visit blocks in dominator tree post-order. The post-order enables nested
> + // if-conversion in a single pass. The tryConvertIf() function may erase
> + // blocks, but only blocks dominated by the head block. This makes it safe to
> + // update the dominator tree while the post-order iterator is still active.
> + for (auto DomNode : post_order(DomTree))
> + if (tryConvertIf(DomNode->getBlock()))
> + Changed = true;
> +
> + return Changed;
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// EarlyIfPredicator Pass
> +//===----------------------------------------------------------------------===//
> +
> +namespace {
> +class EarlyIfPredicator : public MachineFunctionPass {
> + const TargetInstrInfo *TII;
> + const TargetRegisterInfo *TRI;
> + TargetSchedModel SchedModel;
> + MachineRegisterInfo *MRI;
> + MachineDominatorTree *DomTree;
> + MachineLoopInfo *Loops;
> + SSAIfConv IfConv;
> +
> +public:
> + static char ID;
> + EarlyIfPredicator() : MachineFunctionPass(ID) {}
> + void getAnalysisUsage(AnalysisUsage &AU) const override;
> + bool runOnMachineFunction(MachineFunction &MF) override;
> + StringRef getPassName() const override { return "Early If-predicator"; }
> +
> +protected:
> + bool tryConvertIf(MachineBasicBlock *);
> + bool shouldConvertIf();
> +};
> +} // end anonymous namespace
> +
> +#undef DEBUG_TYPE
> +#define DEBUG_TYPE "early-if-predicator"
> +
> +char EarlyIfPredicator::ID = 0;
> +char &llvm::EarlyIfPredicatorID = EarlyIfPredicator::ID;
> +
> +INITIALIZE_PASS_BEGIN(EarlyIfPredicator, DEBUG_TYPE, "Early If Predicator",
> + false, false)
> +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
> +INITIALIZE_PASS_END(EarlyIfPredicator, DEBUG_TYPE, "Early If Predicator", false,
> + false)
> +
> +void EarlyIfPredicator::getAnalysisUsage(AnalysisUsage &AU) const {
> + AU.addRequired<MachineDominatorTree>();
> + AU.addPreserved<MachineDominatorTree>();
> + AU.addRequired<MachineLoopInfo>();
> + AU.addPreserved<MachineLoopInfo>();
> + MachineFunctionPass::getAnalysisUsage(AU);
> +}
> +
> +/// Apply the target heuristic to decide if the transformation is profitable.
> +bool EarlyIfPredicator::shouldConvertIf() {
> + if (IfConv.isTriangle()) {
> + MachineBasicBlock &IfBlock =
> + (IfConv.TBB == IfConv.Tail) ? *IfConv.FBB : *IfConv.TBB;
> +
> + unsigned ExtraPredCost = 0;
> + unsigned Cycles = 0;
> + for (MachineInstr &I : IfBlock) {
> + unsigned NumCycles = SchedModel.computeInstrLatency(&I, false);
> + if (NumCycles > 1)
> + Cycles += NumCycles - 1;
> + ExtraPredCost += TII->getPredicationCost(I);
> + }
> +
> + return TII->isProfitableToIfCvt(IfBlock, Cycles, ExtraPredCost,
> + BranchProbability::getUnknown());
> + }
> + unsigned TExtra = 0;
> + unsigned FExtra = 0;
> + unsigned TCycle = 0;
> + unsigned FCycle = 0;
> + for (MachineInstr &I : *IfConv.TBB) {
> + unsigned NumCycles = SchedModel.computeInstrLatency(&I, false);
> + if (NumCycles > 1)
> + TCycle += NumCycles - 1;
> + TExtra += TII->getPredicationCost(I);
> + }
> + for (MachineInstr &I : *IfConv.FBB) {
> + unsigned NumCycles = SchedModel.computeInstrLatency(&I, false);
> + if (NumCycles > 1)
> + FCycle += NumCycles - 1;
> + FExtra += TII->getPredicationCost(I);
> + }
> + return TII->isProfitableToIfCvt(*IfConv.TBB, TCycle, TExtra, *IfConv.FBB,
> + FCycle, FExtra,
> + BranchProbability::getUnknown());
> +}
> +
> +/// Attempt repeated if-conversion on MBB, return true if successful.
> +///
> +bool EarlyIfPredicator::tryConvertIf(MachineBasicBlock *MBB) {
> + bool Changed = false;
> + while (IfConv.canConvertIf(MBB, /*Predicate*/ true) && shouldConvertIf()) {
> + // If-convert MBB and update analyses.
> + SmallVector<MachineBasicBlock *, 4> RemovedBlocks;
> + IfConv.convertIf(RemovedBlocks, /*Predicate*/ true);
> + Changed = true;
> + updateDomTree(DomTree, IfConv, RemovedBlocks);
> + updateLoops(Loops, RemovedBlocks);
> + }
> + return Changed;
> +}
> +
> +bool EarlyIfPredicator::runOnMachineFunction(MachineFunction &MF) {
> + LLVM_DEBUG(dbgs() << "********** EARLY IF-PREDICATOR **********\n"
> + << "********** Function: " << MF.getName() << '\n');
> + if (skipFunction(MF.getFunction()))
> + return false;
> +
> + const TargetSubtargetInfo &STI = MF.getSubtarget();
> + TII = STI.getInstrInfo();
> + TRI = STI.getRegisterInfo();
> + MRI = &MF.getRegInfo();
> + SchedModel.init(&STI);
> + DomTree = &getAnalysis<MachineDominatorTree>();
> + Loops = getAnalysisIfAvailable<MachineLoopInfo>();
> +
> + bool Changed = false;
> + IfConv.runOnMachineFunction(MF);
>
> // Visit blocks in dominator tree post-order. The post-order enables nested
> // if-conversion in a single pass. The tryConvertIf() function may erase
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list