[llvm] r264596 - [SimlifyCFG] Prevent passes from destroying canonical loop structure, especially for nested loops
Hyojin Sung via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 28 21:41:45 PDT 2016
My apologies. I fixed the patch, checked it compiles, and submitted a new
commit.
Regards,
Hyojin
From: Reid Kleckner <rnk at google.com>
To: Hyojin Sung/Watson/IBM at IBMUS
Cc: llvm-commits <llvm-commits at lists.llvm.org>
Date: 03/28/2016 02:19 PM
Subject: Re: [llvm] r264596 - [SimlifyCFG] Prevent passes from
destroying canonical loop structure, especially for nested
loops
I reverted this because it didn't compile. You referenced a field of
SimplifyCFGOpt from a static helper function.
On Mon, Mar 28, 2016 at 10:22 AM, Hyojin Sung via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
Author: hsung
Date: Mon Mar 28 12:22:25 2016
New Revision: 264596
URL: http://llvm.org/viewvc/llvm-project?rev=264596&view=rev
Log:
[SimlifyCFG] Prevent passes from destroying canonical loop structure,
especially for nested loops
When eliminating or merging almost empty basic blocks, the existence of
non-trivial PHI nodes
is currently used to recognize potential loops of which the block is the
header and keep the block.
However, the current algorithm fails if the loops' exit condition is
evaluated only with volatile
values hence no PHI nodes in the header. Especially when such a loop is
an outer loop of a nested
loop, the loop is collapsed into a single loop which prevent later
optimizations from being
applied (e.g., transforming nested loops into simplified forms and loop
vectorization).
The patch augments the existing PHI node-based check by adding a pre-test
if the BB actually
belongs to a set of loop headers and not eliminating it if yes.
Modified:
llvm/trunk/include/llvm/Transforms/Utils/Local.h
llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp
llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp
llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
llvm/trunk/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll
llvm/trunk/test/Transforms/LoopUnswitch/infinite-loop.ll
llvm/trunk/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll
llvm/trunk/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll
Modified: llvm/trunk/include/llvm/Transforms/Utils/Local.h
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/Local.h?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/Local.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/Local.h Mon Mar 28 12:22:25
2016
@@ -21,6 +21,7 @@
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Operator.h"
+#include "llvm/ADT/SmallPtrSet.h"
namespace llvm {
@@ -124,13 +125,16 @@ bool TryToSimplifyUncondBranchFromEmptyB
/// values, but instcombine orders them so it usually won't matter.
bool EliminateDuplicatePHINodes(BasicBlock *BB);
-/// This function is used to do simplification of a CFG. For example,
it
-/// adjusts branches to branches to eliminate the extra hop, it
eliminates
-/// unreachable basic blocks, and does other "peephole" optimization of
the CFG.
-/// It returns true if a modification was made, possibly deleting the
basic
-/// block that was pointed to.
+/// This function is used to do simplification of a CFG. For
+/// example, it adjusts branches to branches to eliminate the extra hop,
it
+/// eliminates unreachable basic blocks, and does other "peephole"
optimization
+/// of the CFG. It returns true if a modification was made, possibly
deleting
+/// the basic block that was pointed to. LoopHeaders is an optional
input
+/// parameter, providing the set of loop header that SimplifyCFG should
not
+/// eliminate.
bool SimplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI,
- unsigned BonusInstThreshold, AssumptionCache *AC =
nullptr);
+ unsigned BonusInstThreshold, AssumptionCache *AC =
nullptr,
+ SmallPtrSetImpl<BasicBlock *> *LoopHeaders = nullptr);
/// This function is used to flatten a CFG. For example, it uses
parallel-and
/// and parallel-or mode to collapse if-conditions and merge if-regions
with
Modified: llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp Mon Mar 28
12:22:25 2016
@@ -245,10 +245,13 @@ bool JumpThreading::runOnFunction(Functi
// Can't thread an unconditional jump, but if the block is "almost
// empty", we can replace uses of it with uses of the successor
and make
// this dead.
+ // We should not eliminate the loop header either, because
eliminating
+ // a loop header might later prevent LoopSimplify from
transforming nested
+ // loops into simplified form.
if (BI && BI->isUnconditional() &&
BB != &BB->getParent()->getEntryBlock() &&
// If the terminator is the only non-phi instruction, try to
nuke it.
- BB->getFirstNonPHIOrDbg()->isTerminator()) {
+ BB->getFirstNonPHIOrDbg()->isTerminator()
&& !LoopHeaders.count(BB)) {
// Since TryToSimplifyUncondBranchFromEmptyBlock may delete the
// block, we have to make sure it isn't in the LoopHeaders set.
We
// reinsert afterward if needed.
Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp Mon Mar 28
12:22:25 2016
@@ -28,6 +28,7 @@
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/CFG.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
@@ -130,13 +131,20 @@ static bool iterativelySimplifyCFG(Funct
AssumptionCache *AC,
unsigned BonusInstThreshold) {
bool Changed = false;
- bool LocalChange = true;
+ bool LocalChange = true;
+
+ SmallVector<std::pair<const BasicBlock *, const BasicBlock *>, 32>
Edges;
+ FindFunctionBackedges(F, Edges);
+ SmallPtrSet<BasicBlock *, 16> LoopHeaders;
+ for (unsigned i = 0, e = Edges.size(); i != e; ++i)
+ LoopHeaders.insert(const_cast<BasicBlock *>(Edges[i].second));
+
while (LocalChange) {
LocalChange = false;
// Loop over all of the basic blocks and remove them if they are
unneeded.
for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) {
- if (SimplifyCFG(&*BBIt++, TTI, BonusInstThreshold, AC)) {
+ if (SimplifyCFG(&*BBIt++, TTI, BonusInstThreshold, AC,
&LoopHeaders)) {
LocalChange = true;
++NumSimpl;
}
Modified: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp Mon Mar 28 12:22:25
2016
@@ -135,6 +135,7 @@ class SimplifyCFGOpt {
const DataLayout &DL;
unsigned BonusInstThreshold;
AssumptionCache *AC;
+ SmallPtrSetImpl<BasicBlock *> *LoopHeaders;
Value *isValueEqualityComparison(TerminatorInst *TI);
BasicBlock *GetValueEqualityComparisonCases(TerminatorInst *TI,
std::vector<ValueEqualityComparisonCase>
&Cases);
@@ -157,8 +158,10 @@ class SimplifyCFGOpt {
public:
SimplifyCFGOpt(const TargetTransformInfo &TTI, const DataLayout &DL,
- unsigned BonusInstThreshold, AssumptionCache *AC)
- : TTI(TTI), DL(DL), BonusInstThreshold(BonusInstThreshold), AC(AC)
{}
+ unsigned BonusInstThreshold, AssumptionCache *AC,
+ SmallPtrSetImpl<BasicBlock *> *LoopHeaders)
+ : TTI(TTI), DL(DL), BonusInstThreshold(BonusInstThreshold), AC
(AC),
+ LoopHeaders(LoopHeaders) {}
bool run(BasicBlock *BB);
};
}
@@ -3362,6 +3365,7 @@ bool SimplifyCFGOpt::SimplifySingleResum
// The landingpad is now unreachable. Zap it.
BB->eraseFromParent();
+ if (LoopHeaders) LoopHeaders->erase(BB);
return true;
}
@@ -3480,6 +3484,7 @@ static bool removeEmptyCleanup(CleanupRe
// The cleanup pad is now unreachable. Zap it.
BB->eraseFromParent();
+ if (LoopHeaders) LoopHeaders->erase(BB);
return true;
}
@@ -3560,9 +3565,11 @@ bool SimplifyCFGOpt::SimplifyReturn(Retu
}
// If we eliminated all predecessors of the block, delete the block
now.
- if (pred_empty(BB))
+ if (pred_empty(BB)) {
// We know there are no successors, so just nuke the block.
BB->eraseFromParent();
+ if (LoopHeaders) LoopHeaders->erase(BB);
+ }
return true;
}
@@ -3719,6 +3726,7 @@ bool SimplifyCFGOpt::SimplifyUnreachable
BB != &BB->getParent()->getEntryBlock()) {
// We know there are no successors, so just nuke the block.
BB->eraseFromParent();
+ if (LoopHeaders) LoopHeaders->erase(BB);
return true;
}
@@ -5062,8 +5070,14 @@ bool SimplifyCFGOpt::SimplifyUncondBranc
return true;
// If the Terminator is the only non-phi instruction, simplify the
block.
+ // if LoopHeader is provided, check if the block is a loop header
+ // (This is for early invocations before loop simplify and
vectorization
+ // to keep canonical loop forms for nested loops.
+ // These blocks can be eliminated when the pass is invoked later
+ // in the back-end.)
BasicBlock::iterator I = BB->getFirstNonPHIOrDbg()->getIterator();
if (I->isTerminator() && BB != &BB->getParent()->getEntryBlock() &&
+ (!LoopHeaders || (LoopHeaders && !LoopHeaders->count(BB))) &&
TryToSimplifyUncondBranchFromEmptyBlock(BB))
return true;
@@ -5343,7 +5357,8 @@ bool SimplifyCFGOpt::run(BasicBlock *BB)
/// of the CFG. It returns true if a modification was made.
///
bool llvm::SimplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI,
- unsigned BonusInstThreshold, AssumptionCache *AC)
{
+ unsigned BonusInstThreshold, AssumptionCache *AC,
+ SmallPtrSetImpl<BasicBlock *> *LoopHeaders) {
return SimplifyCFGOpt(TTI, BB->getModule()->getDataLayout(),
- BonusInstThreshold, AC).run(BB);
+ BonusInstThreshold, AC, LoopHeaders).run(BB);
}
Modified: llvm/trunk/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll
(original)
+++ llvm/trunk/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll Mon
Mar 28 12:22:25 2016
@@ -16,23 +16,23 @@ for.body:
%cmp1 = icmp eq i32 %a, 12345
br i1 %cmp1, label %if.then, label %if.else, !prof !0
; CHECK: %cmp1 = icmp eq i32 %a, 12345
-; CHECK-NEXT: br i1 %cmp1, label %if.then.us, label %if.else, !prof !0
+; CHECK-NEXT: br i1 %cmp1, label %for.body.us, label %for.body, !prof !0
if.then: ; preds = %for.body
-; CHECK: if.then.us:
+; CHECK: for.body.us:
; CHECK: add nsw i32 %{{.*}}, 123
; CHECK: %exitcond.us = icmp eq i32 %inc.us, %b
-; CHECK: br i1 %exitcond.us, label %for.cond.cleanup, label %if.then.us
+; CHECK: br i1 %exitcond.us, label %for.cond.cleanup, label %for.body.us
%add = add nsw i32 %add.i, 123
br label %for.inc
if.else: ; preds = %for.body
%mul = mul nsw i32 %mul.i, %b
br label %for.inc
-; CHECK: if.else:
+; CHECK: for.body:
; CHECK: %mul = mul nsw i32 %mul.i, %b
; CHECK: %inc = add nuw nsw i32 %inc.i, 1
; CHECK: %exitcond = icmp eq i32 %inc, %b
-; CHECK: br i1 %exitcond, label %for.cond.cleanup, label %if.else
+; CHECK: br i1 %exitcond, label %for.cond.cleanup, label %for.body
for.inc: ; preds = %if.then,
%if.else
%mul.p = phi i32 [ %b, %if.then ], [ %mul, %if.else ]
%add.p = phi i32 [ %add, %if.then ], [ %a, %if.else ]
Modified: llvm/trunk/test/Transforms/LoopUnswitch/infinite-loop.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopUnswitch/infinite-loop.ll?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopUnswitch/infinite-loop.ll (original)
+++ llvm/trunk/test/Transforms/LoopUnswitch/infinite-loop.ll Mon Mar 28
12:22:25 2016
@@ -16,10 +16,10 @@
; CHECK-NEXT: br i1 %a, label %entry.split, label %abort0.split
; CHECK: entry.split:
-; CHECK-NEXT: br i1 %b, label %cond.end, label %abort1.split
+; CHECK-NEXT: br i1 %b, label %for.body, label %abort1.split
-; CHECK: cond.end:
-; CHECK-NEXT: br label %cond.end
+; CHECK: for.body:
+; CHECK-NEXT: br label %for.body
; CHECK: abort0.split:
; CHECK-NEXT: call void @end0() [[NOR_NUW:#[0-9]+]]
Modified:
llvm/trunk/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll
(original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/2008-05-16-PHIBlockMerge.ll
Mon Mar 28 12:22:25 2016
@@ -1,6 +1,6 @@
; RUN: opt < %s -simplifycfg -S > %t
; RUN: not grep "^BB.tomerge" %t
-; RUN: grep "^BB.nomerge" %t | count 2
+; RUN: grep "^BB.nomerge" %t | count 4
; ModuleID = '<stdin>'
declare i1 @foo()
@@ -54,24 +54,24 @@ Exit: ; preds = %Succ
ret void
}
-; This function can be merged
+; This function can't be merged (for keeping canonical loop structures)
define void @c() {
entry:
- br label %BB.tomerge
+ br label %BB.nomerge
-BB.tomerge: ; preds = %Common, %entry
+BB.nomerge: ; preds = %Common, %entry
br label %Succ
Succ: ; preds = %Common, %BB.tomerge, %Pre-Exit
; This phi has identical values for Common and (through BB)
Common,
; blocks can't be merged
- %b = phi i32 [ 1, %BB.tomerge ], [ 1, %Common ], [ 2, %Pre-Exit ]
+ %b = phi i32 [ 1, %BB.nomerge ], [ 1, %Common ], [ 2, %Pre-Exit ]
%conde = call i1 @foo( ) ; <i1> [#uses=1]
br i1 %conde, label %Common, label %Pre-Exit
Common: ; preds = %Succ
%cond = call i1 @foo( ) ; <i1> [#uses=1]
- br i1 %cond, label %BB.tomerge, label %Succ
+ br i1 %cond, label %BB.nomerge, label %Succ
Pre-Exit: ; preds = %Succ
; This adds a backedge, so the %b phi node gets a third branch
and is
@@ -83,25 +83,25 @@ Exit: ; preds = %Pre-Exit
ret void
}
-; This function can be merged
+; This function can't be merged (for keeping canonical loop structures)
define void @d() {
entry:
- br label %BB.tomerge
+ br label %BB.nomerge
-BB.tomerge: ; preds = %Common, %entry
+BB.nomerge: ; preds = %Common, %entry
; This phi has a matching value (0) with below phi (0), so
blocks
; can be merged.
%a = phi i32 [ 1, %entry ], [ 0, %Common ] ; <i32>
[#uses=1]
br label %Succ
Succ: ; preds = %Common, %BB.tomerge
- %b = phi i32 [ %a, %BB.tomerge ], [ 0, %Common ] ;
<i32> [#uses=0]
+ %b = phi i32 [ %a, %BB.nomerge ], [ 0, %Common ] ;
<i32> [#uses=0]
%conde = call i1 @foo( ) ; <i1> [#uses=1]
br i1 %conde, label %Common, label %Exit
Common: ; preds = %Succ
%cond = call i1 @foo( ) ; <i1> [#uses=1]
- br i1 %cond, label %BB.tomerge, label %Succ
+ br i1 %cond, label %BB.nomerge, label %Succ
Exit: ; preds = %Succ
ret void
@@ -110,21 +110,21 @@ Exit: ; preds = %Succ
; This function can be merged
define void @e() {
entry:
- br label %BB.tomerge
+ br label %Succ
-BB.tomerge: ; preds = %Use, %entry
+Succ: ; preds = %Use, %entry
; This phi is used somewhere else than Succ, but this should not
prevent
; merging this block
%a = phi i32 [ 1, %entry ], [ 0, %Use ] ; <i32> [#uses=1]
- br label %Succ
+ br label %BB.tomerge
-Succ: ; preds = %BB.tomerge
+BB.tomerge: ; preds = %BB.tomerge
%conde = call i1 @foo( ) ; <i1> [#uses=1]
br i1 %conde, label %Use, label %Exit
Use: ; preds = %Succ
%cond = call i1 @bar( i32 %a ) ; <i1> [#uses=1]
- br i1 %cond, label %BB.tomerge, label %Exit
+ br i1 %cond, label %Succ, label %Exit
Exit: ; preds = %Use, %Succ
ret void
Modified:
llvm/trunk/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll
URL:
http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll?rev=264596&r1=264595&r2=264596&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll
(original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/EqualPHIEdgeBlockMerge.ll Mon
Mar 28 12:22:25 2016
@@ -5,7 +5,7 @@
; RUN: not grep X: %t
; RUN: not grep 'switch i32[^U]+%U' %t
; RUN: not grep "^BB.tomerge" %t
-; RUN: grep "^BB.nomerge" %t | count 2
+; RUN: grep "^BB.nomerge" %t | count 4
;
; ModuleID = '<stdin>'
@@ -179,24 +179,24 @@ Exit: ; preds = %Succ
ret void
}
-; This function can be merged
+; This function can't be merged (for keeping canonical loop structures)
define void @c() {
entry:
- br label %BB.tomerge
+ br label %BB.nomerge
-BB.tomerge: ; preds = %Common, %entry
+BB.nomerge: ; preds = %Common, %entry
br label %Succ
Succ: ; preds = %Common, %BB.tomerge, %Pre-Exit
; This phi has identical values for Common and (through BB)
Common,
; blocks can't be merged
- %b = phi i32 [ 1, %BB.tomerge ], [ 1, %Common ], [ 2, %Pre-Exit ]
+ %b = phi i32 [ 1, %BB.nomerge ], [ 1, %Common ], [ 2, %Pre-Exit ]
%conde = call i1 @foo( ) ; <i1> [#uses=1]
br i1 %conde, label %Common, label %Pre-Exit
Common: ; preds = %Succ
%cond = call i1 @foo( ) ; <i1> [#uses=1]
- br i1 %cond, label %BB.tomerge, label %Succ
+ br i1 %cond, label %BB.nomerge, label %Succ
Pre-Exit: ; preds = %Succ
; This adds a backedge, so the %b phi node gets a third branch
and is
@@ -208,25 +208,25 @@ Exit: ; preds = %Pre-Exit
ret void
}
-; This function can be merged
+; This function can't be merged (for keeping canonical loop structures)
define void @d() {
entry:
- br label %BB.tomerge
+ br label %BB.nomerge
-BB.tomerge: ; preds = %Common, %entry
+BB.nomerge: ; preds = %Common, %entry
; This phi has a matching value (0) with below phi (0), so
blocks
; can be merged.
%a = phi i32 [ 1, %entry ], [ 0, %Common ] ; <i32>
[#uses=1]
br label %Succ
Succ: ; preds = %Common, %BB.tomerge
- %b = phi i32 [ %a, %BB.tomerge ], [ 0, %Common ] ;
<i32> [#uses=0]
+ %b = phi i32 [ %a, %BB.nomerge ], [ 0, %Common ] ;
<i32> [#uses=0]
%conde = call i1 @foo( ) ; <i1> [#uses=1]
br i1 %conde, label %Common, label %Exit
Common: ; preds = %Succ
%cond = call i1 @foo( ) ; <i1> [#uses=1]
- br i1 %cond, label %BB.tomerge, label %Succ
+ br i1 %cond, label %BB.nomerge, label %Succ
Exit: ; preds = %Succ
ret void
@@ -235,21 +235,21 @@ Exit: ; preds = %Succ
; This function can be merged
define void @e() {
entry:
- br label %BB.tomerge
+ br label %Succ
-BB.tomerge: ; preds = %Use, %entry
+Succ: ; preds = %Use, %entry
; This phi is used somewhere else than Succ, but this should not
prevent
; merging this block
%a = phi i32 [ 1, %entry ], [ 0, %Use ] ; <i32> [#uses=1]
- br label %Succ
+ br label %BB.tomerge
-Succ: ; preds = %BB.tomerge
+BB.tomerge: ; preds = %Succ
%conde = call i1 @foo( ) ; <i1> [#uses=1]
br i1 %conde, label %Use, label %Exit
Use: ; preds = %Succ
%cond = call i1 @bar( i32 %a ) ; <i1> [#uses=1]
- br i1 %cond, label %BB.tomerge, label %Exit
+ br i1 %cond, label %Succ, label %Exit
Exit: ; preds = %Use, %Succ
ret void
_______________________________________________
llvm-commits mailing list
llvm-commits at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160328/2e3180c1/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: graycol.gif
Type: image/gif
Size: 105 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160328/2e3180c1/attachment.gif>
More information about the llvm-commits
mailing list