<div dir="ltr">Hi Chad,<div><br></div><div>After more digging, I found out that floating-point factorization is indeed ok for fast-math operations.</div><div><br></div><div>The attached patch should fix the mixing of regular and fast operations without break fast-math factorization.</div><div><br></div><div>Best,</div><div><br></div><div>Mehdi</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">2014-11-05 23:09 GMT-08:00 Mehdi Amini <span dir="ltr"><<a href="mailto:joker.eph@gmail.com" target="_blank">joker.eph@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Chad,<br>
<br>
This commit does not only bring reassociation but also factorization, which I am not sure is allowed for floating point even in fast-math.<br>
The attached patch disables floating point refactorization while keeping reassociation.<br>
<br>
Moreover I have a crash currently when mixing fast and regular operation, see test/Transforms/Reassociate/<u></u>mixed-fast-nonfast-fp.ll in the patch.<br>
<br>
Best,<br>
<br>
Mehdi<br>
<br>
<br>
<br>
<br>
On 8/14/14, 8:23 AM, Chad Rosier wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Author: mcrosier<br>
Date: Thu Aug 14 10:23:01 2014<br>
New Revision: 215647<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=215647&view=rev" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project?rev=215647&view=rev</a><br>
Log:<br>
[Reassociation] Add support for reassociation with unsafe algebra.<br>
<br>
Vector instructions are (still) not supported for either integer or floating<br>
point. Hopefully, that work will be landed shortly.<br>
<br>
Added:<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>AgressiveSubMove.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ArrayOutOfBounds.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-MissedTree.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ReassociateVector.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>SubReassociate.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-basictest.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-fp-commute.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-mightymul.ll<br>
llvm/trunk/test/Transforms/<u></u>Reassociate/fast-multistep.ll<br>
Modified:<br>
llvm/trunk/lib/Transforms/<u></u>Scalar/Reassociate.cpp<br>
<br>
Modified: llvm/trunk/lib/Transforms/<u></u>Scalar/Reassociate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/Reassociate.cpp?rev=215647&r1=215646&r2=215647&view=diff" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/lib/<u></u>Transforms/Scalar/Reassociate.<u></u>cpp?rev=215647&r1=215646&r2=<u></u>215647&view=diff</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/lib/Transforms/<u></u>Scalar/Reassociate.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/<u></u>Scalar/Reassociate.cpp Thu Aug 14 10:23:01 2014<br>
@@ -240,6 +240,15 @@ static BinaryOperator *isReassociableOp(<br>
return nullptr;<br>
}<br>
+static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode1,<br>
+ unsigned Opcode2) {<br>
+ if (V->hasOneUse() && isa<Instruction>(V) &&<br>
+ (cast<Instruction>(V)-><u></u>getOpcode() == Opcode1 ||<br>
+ cast<Instruction>(V)-><u></u>getOpcode() == Opcode2))<br>
+ return cast<BinaryOperator>(V);<br>
+ return nullptr;<br>
+}<br>
+<br>
static bool isUnmovableInstruction(<u></u>Instruction *I) {<br>
switch (I->getOpcode()) {<br>
case Instruction::PHI:<br>
@@ -304,8 +313,10 @@ unsigned Reassociate::getRank(Value *V)<br>
// If this is a not or neg instruction, do not count it for rank. This<br>
// assures us that X and ~X will have the same rank.<br>
- if (!I->getType()->isIntegerTy() ||<br>
- (!BinaryOperator::isNot(I) && !BinaryOperator::isNeg(I)))<br>
+ Type *Ty = V->getType();<br>
+ if ((!Ty->isIntegerTy() && !Ty->isFloatingPointTy()) ||<br>
+ (!BinaryOperator::isNot(I) && !BinaryOperator::isNeg(I) &&<br>
+ !BinaryOperator::isFNeg(I)))<br>
++Rank;<br>
//DEBUG(dbgs() << "Calculated Rank[" << V->getName() << "] = "<br>
@@ -314,14 +325,50 @@ unsigned Reassociate::getRank(Value *V)<br>
return ValueRankMap[I] = Rank;<br>
}<br>
+static BinaryOperator *CreateAdd(Value *S1, Value *S2, const Twine &Name,<br>
+ Instruction *InsertBefore, Value *FlagsOp) {<br>
+ if (S1->getType()->isIntegerTy())<br>
+ return BinaryOperator::CreateAdd(S1, S2, Name, InsertBefore);<br>
+ else {<br>
+ BinaryOperator *Res =<br>
+ BinaryOperator::CreateFAdd(S1, S2, Name, InsertBefore);<br>
+ Res->setFastMathFlags(cast<<u></u>FPMathOperator>(FlagsOp)-><u></u>getFastMathFlags());<br>
+ return Res;<br>
+ }<br>
+}<br>
+<br>
+static BinaryOperator *CreateMul(Value *S1, Value *S2, const Twine &Name,<br>
+ Instruction *InsertBefore, Value *FlagsOp) {<br>
+ if (S1->getType()->isIntegerTy())<br>
+ return BinaryOperator::CreateMul(S1, S2, Name, InsertBefore);<br>
+ else {<br>
+ BinaryOperator *Res =<br>
+ BinaryOperator::CreateFMul(S1, S2, Name, InsertBefore);<br>
+ Res->setFastMathFlags(cast<<u></u>FPMathOperator>(FlagsOp)-><u></u>getFastMathFlags());<br>
+ return Res;<br>
+ }<br>
+}<br>
+<br>
+static BinaryOperator *CreateNeg(Value *S1, const Twine &Name,<br>
+ Instruction *InsertBefore, Value *FlagsOp) {<br>
+ if (S1->getType()->isIntegerTy())<br>
+ return BinaryOperator::CreateNeg(S1, Name, InsertBefore);<br>
+ else {<br>
+ BinaryOperator *Res = BinaryOperator::CreateFNeg(S1, Name, InsertBefore);<br>
+ Res->setFastMathFlags(cast<<u></u>FPMathOperator>(FlagsOp)-><u></u>getFastMathFlags());<br>
+ return Res;<br>
+ }<br>
+}<br>
+<br>
/// LowerNegateToMultiply - Replace 0-X with X*-1.<br>
///<br>
static BinaryOperator *LowerNegateToMultiply(<u></u>Instruction *Neg) {<br>
- Constant *Cst = Constant::getAllOnesValue(Neg-<u></u>>getType());<br>
+ Type *Ty = Neg->getType();<br>
+ Constant *NegOne = Ty->isIntegerTy() ? ConstantInt::getAllOnesValue(<u></u>Ty)<br>
+ : ConstantFP::get(Ty, -1.0);<br>
- BinaryOperator *Res =<br>
- BinaryOperator::CreateMul(Neg-<u></u>>getOperand(1), Cst, "",Neg);<br>
- Neg->setOperand(1, Constant::getNullValue(Neg-><u></u>getType())); // Drop use of op.<br>
+ BinaryOperator *Res = CreateMul(Neg->getOperand(1), NegOne, "", Neg, Neg);<br>
+ Neg->setOperand(1, Constant::getNullValue(Ty)); // Drop use of op.<br>
Res->takeName(Neg);<br>
Neg->replaceAllUsesWith(Res);<br>
Res->setDebugLoc(Neg-><u></u>getDebugLoc());<br>
@@ -377,13 +424,14 @@ static void IncorporateWeight(APInt &LHS<br>
LHS = 0; // 1 + 1 === 0 modulo 2.<br>
return;<br>
}<br>
- if (Opcode == Instruction::Add) {<br>
+ if (Opcode == Instruction::Add || Opcode == Instruction::FAdd) {<br>
// TODO: Reduce the weight by exploiting nsw/nuw?<br>
LHS += RHS;<br>
return;<br>
}<br>
- assert(Opcode == Instruction::Mul && "Unknown associative operation!");<br>
+ assert((Opcode == Instruction::Mul || Opcode == Instruction::FMul) &&<br>
+ "Unknown associative operation!");<br>
unsigned Bitwidth = LHS.getBitWidth();<br>
// If CM is the Carmichael number then a weight W satisfying W >= CM+Bitwidth<br>
// can be replaced with W-CM. That's because x^W=x^(W-CM) for every Bitwidth<br>
@@ -499,8 +547,7 @@ static bool LinearizeExprTree(BinaryOper<br>
DEBUG(dbgs() << "LINEARIZE: " << *I << '\n');<br>
unsigned Bitwidth = I->getType()->getScalarType()-<u></u>>getPrimitiveSizeInBits();<br>
unsigned Opcode = I->getOpcode();<br>
- assert(Instruction::<u></u>isAssociative(Opcode) &&<br>
- Instruction::isCommutative(<u></u>Opcode) &&<br>
+ assert(I->isAssociative() && I->isCommutative() &&<br>
"Expected an associative and commutative operation!");<br>
// Visit all operands of the expression, keeping track of their weight (the<br>
@@ -619,15 +666,16 @@ static bool LinearizeExprTree(BinaryOper<br>
// If this is a multiply expression, turn any internal negations into<br>
// multiplies by -1 so they can be reassociated.<br>
- BinaryOperator *BO = dyn_cast<BinaryOperator>(Op);<br>
- if (Opcode == Instruction::Mul && BO && BinaryOperator::isNeg(BO)) {<br>
- DEBUG(dbgs() << "MORPH LEAF: " << *Op << " (" << Weight << ") TO ");<br>
- BO = LowerNegateToMultiply(BO);<br>
- DEBUG(dbgs() << *BO << 'n');<br>
- Worklist.push_back(std::make_<u></u>pair(BO, Weight));<br>
- MadeChange = true;<br>
- continue;<br>
- }<br>
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Op))<br>
+ if ((Opcode == Instruction::Mul && BinaryOperator::isNeg(BO)) ||<br>
+ (Opcode == Instruction::FMul && BinaryOperator::isFNeg(BO))) {<br>
+ DEBUG(dbgs() << "MORPH LEAF: " << *Op << " (" << Weight << ") TO ");<br>
+ BO = LowerNegateToMultiply(BO);<br>
+ DEBUG(dbgs() << *BO << '\n');<br>
+ Worklist.push_back(std::make_<u></u>pair(BO, Weight));<br>
+ MadeChange = true;<br>
+ continue;<br>
+ }<br>
// Failed to morph into an expression of the right type. This really is<br>
// a leaf.<br>
@@ -798,6 +846,8 @@ void Reassociate::RewriteExprTree(<u></u>Binary<br>
Constant *Undef = UndefValue::get(I->getType());<br>
NewOp = BinaryOperator::Create(<u></u>Instruction::BinaryOps(Opcode)<u></u>,<br>
Undef, Undef, "", I);<br>
+ if (NewOp->getType()-><u></u>isFloatingPointTy())<br>
+ NewOp->setFastMathFlags(I-><u></u>getFastMathFlags());<br>
} else {<br>
NewOp = NodesToRewrite.pop_back_val();<br>
}<br>
@@ -817,7 +867,14 @@ void Reassociate::RewriteExprTree(<u></u>Binary<br>
// expression tree is dominated by all of Ops.<br>
if (ExpressionChanged)<br>
do {<br>
- ExpressionChanged-><u></u>clearSubclassOptionalData();<br>
+ // Preserve FastMathFlags.<br>
+ if (isa<FPMathOperator>(I)) {<br>
+ FastMathFlags Flags = I->getFastMathFlags();<br>
+ ExpressionChanged-><u></u>clearSubclassOptionalData();<br>
+ ExpressionChanged-><u></u>setFastMathFlags(Flags);<br>
+ } else<br>
+ ExpressionChanged-><u></u>clearSubclassOptionalData();<br>
+<br>
if (ExpressionChanged == I)<br>
break;<br>
ExpressionChanged->moveBefore(<u></u>I);<br>
@@ -834,6 +891,8 @@ void Reassociate::RewriteExprTree(<u></u>Binary<br>
/// version of the value is returned, and BI is left pointing at the instruction<br>
/// that should be processed next by the reassociation pass.<br>
static Value *NegateValue(Value *V, Instruction *BI) {<br>
+ if (ConstantFP *C = dyn_cast<ConstantFP>(V))<br>
+ return ConstantExpr::getFNeg(C);<br>
if (Constant *C = dyn_cast<Constant>(V))<br>
return ConstantExpr::getNeg(C);<br>
@@ -846,7 +905,8 @@ static Value *NegateValue(Value *V, Inst<br>
// the constants. We assume that instcombine will clean up the mess later if<br>
// we introduce tons of unnecessary negation instructions.<br>
//<br>
- if (BinaryOperator *I = isReassociableOp(V, Instruction::Add)) {<br>
+ if (BinaryOperator *I =<br>
+ isReassociableOp(V, Instruction::Add, Instruction::FAdd)) {<br>
// Push the negates through the add.<br>
I->setOperand(0, NegateValue(I->getOperand(0), BI));<br>
I->setOperand(1, NegateValue(I->getOperand(1), BI));<br>
@@ -864,7 +924,8 @@ static Value *NegateValue(Value *V, Inst<br>
// Okay, we need to materialize a negated version of V with an instruction.<br>
// Scan the use lists of V to see if we have one already.<br>
for (User *U : V->users()) {<br>
- if (!BinaryOperator::isNeg(U)) continue;<br>
+ if (!BinaryOperator::isNeg(U) && !BinaryOperator::isFNeg(U))<br>
+ continue;<br>
// We found one! Now we have to make sure that the definition dominates<br>
// this use. We do this by moving it to the entry block (if it is a<br>
@@ -894,27 +955,30 @@ static Value *NegateValue(Value *V, Inst<br>
// Insert a 'neg' instruction that subtracts the value from zero to get the<br>
// negation.<br>
- return BinaryOperator::CreateNeg(V, V->getName() + ".neg", BI);<br>
+ return CreateNeg(V, V->getName() + ".neg", BI, BI);<br>
}<br>
/// ShouldBreakUpSubtract - Return true if we should break up this subtract of<br>
/// X-Y into (X + -Y).<br>
static bool ShouldBreakUpSubtract(<u></u>Instruction *Sub) {<br>
// If this is a negation, we can't split it up!<br>
- if (BinaryOperator::isNeg(Sub))<br>
+ if (BinaryOperator::isNeg(Sub) || BinaryOperator::isFNeg(Sub))<br>
return false;<br>
// Don't bother to break this up unless either the LHS is an associable add or<br>
// subtract or if this is only used by one.<br>
- if (isReassociableOp(Sub-><u></u>getOperand(0), Instruction::Add) ||<br>
- isReassociableOp(Sub-><u></u>getOperand(0), Instruction::Sub))<br>
+ Value *V0 = Sub->getOperand(0);<br>
+ if (isReassociableOp(V0, Instruction::Add, Instruction::FAdd) ||<br>
+ isReassociableOp(V0, Instruction::Sub, Instruction::FSub))<br>
return true;<br>
- if (isReassociableOp(Sub-><u></u>getOperand(1), Instruction::Add) ||<br>
- isReassociableOp(Sub-><u></u>getOperand(1), Instruction::Sub))<br>
+ Value *V1 = Sub->getOperand(1);<br>
+ if (isReassociableOp(V1, Instruction::Add, Instruction::FAdd) ||<br>
+ isReassociableOp(V1, Instruction::Sub, Instruction::FSub))<br>
return true;<br>
+ Value *VB = Sub->user_back();<br>
if (Sub->hasOneUse() &&<br>
- (isReassociableOp(Sub->user_<u></u>back(), Instruction::Add) ||<br>
- isReassociableOp(Sub->user_<u></u>back(), Instruction::Sub)))<br>
+ (isReassociableOp(VB, Instruction::Add, Instruction::FAdd) ||<br>
+ isReassociableOp(VB, Instruction::Sub, Instruction::FSub)))<br>
return true;<br>
return false;<br>
@@ -931,8 +995,7 @@ static BinaryOperator *BreakUpSubtract(I<br>
// and set it as the RHS of the add instruction we just made.<br>
//<br>
Value *NegVal = NegateValue(Sub->getOperand(1)<u></u>, Sub);<br>
- BinaryOperator *New =<br>
- BinaryOperator::CreateAdd(Sub-<u></u>>getOperand(0), NegVal, "", Sub);<br>
+ BinaryOperator *New = CreateAdd(Sub->getOperand(0), NegVal, "", Sub, Sub);<br>
Sub->setOperand(0, Constant::getNullValue(Sub-><u></u>getType())); // Drop use of op.<br>
Sub->setOperand(1, Constant::getNullValue(Sub-><u></u>getType())); // Drop use of op.<br>
New->takeName(Sub);<br>
@@ -988,15 +1051,16 @@ static Value *EmitAddTreeOfValues(Instru<br>
Value *V1 = Ops.back();<br>
Ops.pop_back();<br>
Value *V2 = EmitAddTreeOfValues(I, Ops);<br>
- return BinaryOperator::CreateAdd(V2, V1, "tmp", I);<br>
+ return CreateAdd(V2, V1, "tmp", I, I);<br>
}<br>
/// RemoveFactorFromExpression - If V is an expression tree that is a<br>
/// multiplication sequence, and if this sequence contains a multiply by Factor,<br>
/// remove Factor from the tree and return the new tree.<br>
Value *Reassociate::<u></u>RemoveFactorFromExpression(<u></u>Value *V, Value *Factor) {<br>
- BinaryOperator *BO = isReassociableOp(V, Instruction::Mul);<br>
- if (!BO) return nullptr;<br>
+ BinaryOperator *BO = isReassociableOp(V, Instruction::Mul, Instruction::FMul);<br>
+ if (!BO)<br>
+ return nullptr;<br>
SmallVector<RepeatedValue, 8> Tree;<br>
MadeChange |= LinearizeExprTree(BO, Tree);<br>
@@ -1018,13 +1082,25 @@ Value *Reassociate::<u></u>RemoveFactorFromExpr<br>
}<br>
// If this is a negative version of this factor, remove it.<br>
- if (ConstantInt *FC1 = dyn_cast<ConstantInt>(Factor))<br>
+ if (ConstantInt *FC1 = dyn_cast<ConstantInt>(Factor)) {<br>
if (ConstantInt *FC2 = dyn_cast<ConstantInt>(Factors[<u></u>i].Op))<br>
if (FC1->getValue() == -FC2->getValue()) {<br>
FoundFactor = NeedsNegate = true;<br>
Factors.erase(Factors.begin()+<u></u>i);<br>
break;<br>
}<br>
+ } else if (ConstantFP *FC1 = dyn_cast<ConstantFP>(Factor)) {<br>
+ if (ConstantFP *FC2 = dyn_cast<ConstantFP>(Factors[<u></u>i].Op)) {<br>
+ APFloat F1(FC1->getValueAPF());<br>
+ APFloat F2(FC2->getValueAPF());<br>
+ F2.changeSign();<br>
+ if (F1.compare(F2) == APFloat::cmpEqual) {<br>
+ FoundFactor = NeedsNegate = true;<br>
+ Factors.erase(Factors.begin() + i);<br>
+ break;<br>
+ }<br>
+ }<br>
+ }<br>
}<br>
if (!FoundFactor) {<br>
@@ -1046,7 +1122,7 @@ Value *Reassociate::<u></u>RemoveFactorFromExpr<br>
}<br>
if (NeedsNegate)<br>
- V = BinaryOperator::CreateNeg(V, "neg", InsertPt);<br>
+ V = CreateNeg(V, "neg", InsertPt, BO);<br>
return V;<br>
}<br>
@@ -1058,7 +1134,7 @@ Value *Reassociate::<u></u>RemoveFactorFromExpr<br>
static void FindSingleUseMultiplyFactors(<u></u>Value *V,<br>
SmallVectorImpl<Value*> &Factors,<br>
const SmallVectorImpl<ValueEntry> &Ops) {<br>
- BinaryOperator *BO = isReassociableOp(V, Instruction::Mul);<br>
+ BinaryOperator *BO = isReassociableOp(V, Instruction::Mul, Instruction::FMul);<br>
if (!BO) {<br>
Factors.push_back(V);<br>
return;<br>
@@ -1389,13 +1465,15 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
++NumFactor;<br>
// Insert a new multiply.<br>
- Value *Mul = ConstantInt::get(cast<<u></u>IntegerType>(I->getType()), NumFound);<br>
- Mul = BinaryOperator::CreateMul(<u></u>TheOp, Mul, "factor", I);<br>
+ Type *Ty = TheOp->getType();<br>
+ Constant *C = Ty->isIntegerTy() ? ConstantInt::get(Ty, NumFound)<br>
+ : ConstantFP::get(Ty, NumFound);<br>
+ Instruction *Mul = CreateMul(TheOp, C, "factor", I, I);<br>
// Now that we have inserted a multiply, optimize it. This allows us to<br>
// handle cases that require multiple factoring steps, such as this:<br>
// (X*2) + (X*2) + (X*2) -> (X*2)*3 -> X*6<br>
- RedoInsts.insert(cast<<u></u>Instruction>(Mul));<br>
+ RedoInsts.insert(Mul);<br>
// If every add operand was a duplicate, return the multiply.<br>
if (Ops.empty())<br>
@@ -1412,11 +1490,12 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
}<br>
// Check for X and -X or X and ~X in the operand list.<br>
- if (!BinaryOperator::isNeg(TheOp) && !BinaryOperator::isNot(TheOp))<br>
+ if (!BinaryOperator::isNeg(TheOp) && !BinaryOperator::isFNeg(TheOp) &&<br>
+ !BinaryOperator::isNot(TheOp))<br>
continue;<br>
Value *X = nullptr;<br>
- if (BinaryOperator::isNeg(TheOp))<br>
+ if (BinaryOperator::isNeg(TheOp) || BinaryOperator::isFNeg(TheOp))<br>
X = BinaryOperator::<u></u>getNegArgument(TheOp);<br>
else if (BinaryOperator::isNot(TheOp))<br>
X = BinaryOperator::<u></u>getNotArgument(TheOp);<br>
@@ -1426,7 +1505,8 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
continue;<br>
// Remove X and -X from the operand list.<br>
- if (Ops.size() == 2 && BinaryOperator::isNeg(TheOp))<br>
+ if (Ops.size() == 2 &&<br>
+ (BinaryOperator::isNeg(TheOp) || BinaryOperator::isFNeg(TheOp))<u></u>)<br>
return Constant::getNullValue(X-><u></u>getType());<br>
// Remove X and ~X from the operand list.<br>
@@ -1463,7 +1543,8 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
unsigned MaxOcc = 0;<br>
Value *MaxOccVal = nullptr;<br>
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {<br>
- BinaryOperator *BOp = isReassociableOp(Ops[i].Op, Instruction::Mul);<br>
+ BinaryOperator *BOp =<br>
+ isReassociableOp(Ops[i].Op, Instruction::Mul, Instruction::FMul);<br>
if (!BOp)<br>
continue;<br>
@@ -1476,23 +1557,43 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
SmallPtrSet<Value*, 8> Duplicates;<br>
for (unsigned i = 0, e = Factors.size(); i != e; ++i) {<br>
Value *Factor = Factors[i];<br>
- if (!Duplicates.insert(Factor)) continue;<br>
+ if (!Duplicates.insert(Factor))<br>
+ continue;<br>
unsigned Occ = ++FactorOccurrences[Factor];<br>
- if (Occ > MaxOcc) { MaxOcc = Occ; MaxOccVal = Factor; }<br>
+ if (Occ > MaxOcc) {<br>
+ MaxOcc = Occ;<br>
+ MaxOccVal = Factor;<br>
+ }<br>
// If Factor is a negative constant, add the negated value as a factor<br>
// because we can percolate the negate out. Watch for minint, which<br>
// cannot be positivified.<br>
- if (ConstantInt *CI = dyn_cast<ConstantInt>(Factor))<br>
+ if (ConstantInt *CI = dyn_cast<ConstantInt>(Factor)) {<br>
if (CI->isNegative() && !CI->isMinValue(true)) {<br>
Factor = ConstantInt::get(CI-><u></u>getContext(), -CI->getValue());<br>
assert(!Duplicates.count(<u></u>Factor) &&<br>
"Shouldn't have two constant factors, missed a canonicalize");<br>
-<br>
unsigned Occ = ++FactorOccurrences[Factor];<br>
- if (Occ > MaxOcc) { MaxOcc = Occ; MaxOccVal = Factor; }<br>
+ if (Occ > MaxOcc) {<br>
+ MaxOcc = Occ;<br>
+ MaxOccVal = Factor;<br>
+ }<br>
}<br>
+ } else if (ConstantFP *CF = dyn_cast<ConstantFP>(Factor)) {<br>
+ if (CF->isNegative()) {<br>
+ APFloat F(CF->getValueAPF());<br>
+ F.changeSign();<br>
+ Factor = ConstantFP::get(CF-><u></u>getContext(), F);<br>
+ assert(!Duplicates.count(<u></u>Factor) &&<br>
+ "Shouldn't have two constant factors, missed a canonicalize");<br>
+ unsigned Occ = ++FactorOccurrences[Factor];<br>
+ if (Occ > MaxOcc) {<br>
+ MaxOcc = Occ;<br>
+ MaxOccVal = Factor;<br>
+ }<br>
+ }<br>
+ }<br>
}<br>
}<br>
@@ -1505,11 +1606,16 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
// this, we could otherwise run into situations where removing a factor<br>
// from an expression will drop a use of maxocc, and this can cause<br>
// RemoveFactorFromExpression on successive values to behave differently.<br>
- Instruction *DummyInst = BinaryOperator::CreateAdd(<u></u>MaxOccVal, MaxOccVal);<br>
+ Instruction *DummyInst =<br>
+ I->getType()->isIntegerTy()<br>
+ ? BinaryOperator::CreateAdd(<u></u>MaxOccVal, MaxOccVal)<br>
+ : BinaryOperator::CreateFAdd(<u></u>MaxOccVal, MaxOccVal);<br>
+<br>
SmallVector<WeakVH, 4> NewMulOps;<br>
for (unsigned i = 0; i != Ops.size(); ++i) {<br>
// Only try to remove factors from expressions we're allowed to.<br>
- BinaryOperator *BOp = isReassociableOp(Ops[i].Op, Instruction::Mul);<br>
+ BinaryOperator *BOp =<br>
+ isReassociableOp(Ops[i].Op, Instruction::Mul, Instruction::FMul);<br>
if (!BOp)<br>
continue;<br>
@@ -1542,7 +1648,7 @@ Value *Reassociate::OptimizeAdd(<u></u>Instruct<br>
RedoInsts.insert(VI);<br>
// Create the multiply.<br>
- Instruction *V2 = BinaryOperator::CreateMul(V, MaxOccVal, "tmp", I);<br>
+ Instruction *V2 = CreateMul(V, MaxOccVal, "tmp", I, I);<br>
// Rerun associate on the multiply in case the inner expression turned into<br>
// a multiply. We want to make sure that we keep things in canonical form.<br>
@@ -1632,7 +1738,10 @@ static Value *buildMultiplyTree(IRBuilde<br>
Value *LHS = Ops.pop_back_val();<br>
do {<br>
- LHS = Builder.CreateMul(LHS, Ops.pop_back_val());<br>
+ if (LHS->getType()->isIntegerTy()<u></u>)<br>
+ LHS = Builder.CreateMul(LHS, Ops.pop_back_val());<br>
+ else<br>
+ LHS = Builder.CreateFMul(LHS, Ops.pop_back_val());<br>
} while (!Ops.empty());<br>
return LHS;<br>
@@ -1765,11 +1874,13 @@ Value *Reassociate::<u></u>OptimizeExpression(B<br>
break;<br>
case Instruction::Add:<br>
+ case Instruction::FAdd:<br>
if (Value *Result = OptimizeAdd(I, Ops))<br>
return Result;<br>
break;<br>
case Instruction::Mul:<br>
+ case Instruction::FMul:<br>
if (Value *Result = OptimizeMul(I, Ops))<br>
return Result;<br>
break;<br>
@@ -1810,8 +1921,7 @@ void Reassociate::OptimizeInst(<u></u>Instructi<br>
if (!isa<BinaryOperator>(I))<br>
return;<br>
- if (I->getOpcode() == Instruction::Shl &&<br>
- isa<ConstantInt>(I-><u></u>getOperand(1)))<br>
+ if (I->getOpcode() == Instruction::Shl && isa<ConstantInt>(I-><u></u>getOperand(1)))<br>
// If an operand of this shift is a reassociable multiply, or if the shift<br>
// is used by a reassociable multiply or add, turn into a multiply.<br>
if (isReassociableOp(I-><u></u>getOperand(0), Instruction::Mul) ||<br>
@@ -1824,28 +1934,33 @@ void Reassociate::OptimizeInst(<u></u>Instructi<br>
I = NI;<br>
}<br>
- // Floating point binary operators are not associative, but we can still<br>
- // commute (some) of them, to canonicalize the order of their operands.<br>
- // This can potentially expose more CSE opportunities, and makes writing<br>
- // other transformations simpler.<br>
- if ((I->getType()-><u></u>isFloatingPointTy() || I->getType()->isVectorTy())) {<br>
- // FAdd and FMul can be commuted.<br>
- if (I->getOpcode() != Instruction::FMul &&<br>
- I->getOpcode() != Instruction::FAdd)<br>
- return;<br>
+ // Commute floating point binary operators, to canonicalize the order of their<br>
+ // operands. This can potentially expose more CSE opportunities, and makes<br>
+ // writing other transformations simpler.<br>
+ if (I->getType()-><u></u>isFloatingPointTy() || I->getType()->isVectorTy()) {<br>
- Value *LHS = I->getOperand(0);<br>
- Value *RHS = I->getOperand(1);<br>
- unsigned LHSRank = getRank(LHS);<br>
- unsigned RHSRank = getRank(RHS);<br>
-<br>
- // Sort the operands by rank.<br>
- if (RHSRank < LHSRank) {<br>
- I->setOperand(0, RHS);<br>
- I->setOperand(1, LHS);<br>
+ // FAdd and FMul can be commuted.<br>
+ if (I->getOpcode() == Instruction::FMul ||<br>
+ I->getOpcode() == Instruction::FAdd) {<br>
+ Value *LHS = I->getOperand(0);<br>
+ Value *RHS = I->getOperand(1);<br>
+ unsigned LHSRank = getRank(LHS);<br>
+ unsigned RHSRank = getRank(RHS);<br>
+<br>
+ // Sort the operands by rank.<br>
+ if (RHSRank < LHSRank) {<br>
+ I->setOperand(0, RHS);<br>
+ I->setOperand(1, LHS);<br>
+ }<br>
}<br>
- return;<br>
+ // FIXME: We should commute vector instructions as well. However, this<br>
+ // requires further analysis to determine the effect on later passes.<br>
+<br>
+ // Don't try to optimize vector instructions or anything that doesn't have<br>
+ // unsafe algebra.<br>
+ if (I->getType()->isVectorTy() || !I->hasUnsafeAlgebra())<br>
+ return;<br>
}<br>
// Do not reassociate boolean (i1) expressions. We want to preserve the<br>
@@ -1877,6 +1992,24 @@ void Reassociate::OptimizeInst(<u></u>Instructi<br>
I = NI;<br>
}<br>
}<br>
+ } else if (I->getOpcode() == Instruction::FSub) {<br>
+ if (ShouldBreakUpSubtract(I)) {<br>
+ Instruction *NI = BreakUpSubtract(I);<br>
+ RedoInsts.insert(I);<br>
+ MadeChange = true;<br>
+ I = NI;<br>
+ } else if (BinaryOperator::isFNeg(I)) {<br>
+ // Otherwise, this is a negation. See if the operand is a multiply tree<br>
+ // and if this is not an inner node of a multiply tree.<br>
+ if (isReassociableOp(I-><u></u>getOperand(1), Instruction::FMul) &&<br>
+ (!I->hasOneUse() ||<br>
+ !isReassociableOp(I->user_<u></u>back(), Instruction::FMul))) {<br>
+ Instruction *NI = LowerNegateToMultiply(I);<br>
+ RedoInsts.insert(I);<br>
+ MadeChange = true;<br>
+ I = NI;<br>
+ }<br>
+ }<br>
}<br>
// If this instruction is an associative binary operator, process it.<br>
@@ -1894,11 +2027,16 @@ void Reassociate::OptimizeInst(<u></u>Instructi<br>
if (BO->hasOneUse() && BO->getOpcode() == Instruction::Add &&<br>
cast<Instruction>(BO->user_<u></u>back())->getOpcode() == Instruction::Sub)<br>
return;<br>
+ if (BO->hasOneUse() && BO->getOpcode() == Instruction::FAdd &&<br>
+ cast<Instruction>(BO->user_<u></u>back())->getOpcode() == Instruction::FSub)<br>
+ return;<br>
ReassociateExpression(BO);<br>
}<br>
void Reassociate::<u></u>ReassociateExpression(<u></u>BinaryOperator *I) {<br>
+ assert(!I->getType()-><u></u>isVectorTy() &&<br>
+ "Reassociation of vector instructions is not supported.");<br>
// First, walk the expression tree, linearizing the tree, collecting the<br>
// operand information.<br>
@@ -1943,12 +2081,21 @@ void Reassociate::<u></u>ReassociateExpression(<br>
// this is a multiply tree used only by an add, and the immediate is a -1.<br>
// In this case we reassociate to put the negation on the outside so that we<br>
// can fold the negation into the add: (-X)*Y + Z -> Z-X*Y<br>
- if (I->getOpcode() == Instruction::Mul && I->hasOneUse() &&<br>
- cast<Instruction>(I->user_<u></u>back())->getOpcode() == Instruction::Add &&<br>
- isa<ConstantInt>(Ops.back().<u></u>Op) &&<br>
- cast<ConstantInt>(Ops.back().<u></u>Op)->isAllOnesValue()) {<br>
- ValueEntry Tmp = Ops.pop_back_val();<br>
- Ops.insert(Ops.begin(), Tmp);<br>
+ if (I->hasOneUse()) {<br>
+ if (I->getOpcode() == Instruction::Mul &&<br>
+ cast<Instruction>(I->user_<u></u>back())->getOpcode() == Instruction::Add &&<br>
+ isa<ConstantInt>(Ops.back().<u></u>Op) &&<br>
+ cast<ConstantInt>(Ops.back().<u></u>Op)->isAllOnesValue()) {<br>
+ ValueEntry Tmp = Ops.pop_back_val();<br>
+ Ops.insert(Ops.begin(), Tmp);<br>
+ } else if (I->getOpcode() == Instruction::FMul &&<br>
+ cast<Instruction>(I->user_<u></u>back())->getOpcode() ==<br>
+ Instruction::FAdd &&<br>
+ isa<ConstantFP>(Ops.back().Op) &&<br>
+ cast<ConstantFP>(Ops.back().<u></u>Op)->isExactlyValue(-1.0)) {<br>
+ ValueEntry Tmp = Ops.pop_back_val();<br>
+ Ops.insert(Ops.begin(), Tmp);<br>
+ }<br>
}<br>
DEBUG(dbgs() << "RAOut:\t"; PrintOps(I, Ops); dbgs() << '\n');<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>AgressiveSubMove.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-AgressiveSubMove.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>AgressiveSubMove.ll?rev=<u></u>215647&view=auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>AgressiveSubMove.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>AgressiveSubMove.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,24 @@<br>
+; RUN: opt < %s -reassociate -S | FileCheck %s<br>
+<br>
+define float @test1(float %A) {<br>
+; CHECK-LABEL: test1<br>
+; CHECK-NEXT: %X = fadd float 1.000000e+00, %A<br>
+; CHECK-NEXT: %Y = fadd float 1.000000e+00, %A<br>
+; CHECK-NEXT: %r = fsub float %X, %Y<br>
+; CHECK-NEXT: ret float %r<br>
+<br>
+ %X = fadd float %A, 1.000000e+00<br>
+ %Y = fadd float %A, 1.000000e+00<br>
+ %r = fsub float %X, %Y<br>
+ ret float %r<br>
+}<br>
+<br>
+define float @test2(float %A) {<br>
+; CHECK-LABEL: test2<br>
+; CHECK-NEXT: ret float 0.000000e+00<br>
+<br>
+ %X = fadd fast float 1.000000e+00, %A<br>
+ %Y = fadd fast float 1.000000e+00, %A<br>
+ %r = fsub fast float %X, %Y<br>
+ ret float %r<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ArrayOutOfBounds.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-ArrayOutOfBounds.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>ArrayOutOfBounds.ll?rev=<u></u>215647&view=auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ArrayOutOfBounds.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ArrayOutOfBounds.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,65 @@<br>
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s<br>
+<br>
+; Not marked as fast, so must not change.<br>
+define float @test1(float %a0, float %a1, float %a2, float %a3, float %a4) {<br>
+; CHECK-LABEL: test1<br>
+; CHECK-NEXT: %tmp.2 = fadd float %a3, %a4<br>
+; CHECK-NEXT: %tmp.4 = fadd float %tmp.2, %a2<br>
+; CHECK-NEXT: %tmp.6 = fadd float %tmp.4, %a1<br>
+; CHECK-NEXT: %tmp.8 = fadd float %tmp.6, %a0<br>
+; CHECK-NEXT: %tmp.11 = fadd float %a2, %a3<br>
+; CHECK-NEXT: %tmp.13 = fadd float %tmp.11, %a1<br>
+; CHECK-NEXT: %tmp.15 = fadd float %tmp.13, %a0<br>
+; CHECK-NEXT: %tmp.18 = fadd float %a1, %a2<br>
+; CHECK-NEXT: %tmp.20 = fadd float %tmp.18, %a0<br>
+; CHECK-NEXT: %tmp.23 = fadd float %a0, %a1<br>
+; CHECK-NEXT: %tmp.26 = fsub float %tmp.8, %tmp.15<br>
+; CHECK-NEXT: %tmp.28 = fadd float %tmp.20, %tmp.26<br>
+; CHECK-NEXT: %tmp.30 = fsub float %tmp.28, %tmp.23<br>
+; CHECK-NEXT: %tmp.32 = fsub float %tmp.30, %a4<br>
+; CHECK-NEXT: %tmp.34 = fsub float %tmp.32, %a2<br>
+; CHECK-NEXT: %T = fmul float %tmp.34, %tmp.34<br>
+; CHECK-NEXT: ret float %T<br>
+<br>
+ %tmp.2 = fadd float %a4, %a3<br>
+ %tmp.4 = fadd float %tmp.2, %a2<br>
+ %tmp.6 = fadd float %tmp.4, %a1<br>
+ %tmp.8 = fadd float %tmp.6, %a0<br>
+ %tmp.11 = fadd float %a3, %a2<br>
+ %tmp.13 = fadd float %tmp.11, %a1<br>
+ %tmp.15 = fadd float %tmp.13, %a0<br>
+ %tmp.18 = fadd float %a2, %a1<br>
+ %tmp.20 = fadd float %tmp.18, %a0<br>
+ %tmp.23 = fadd float %a1, %a0<br>
+ %tmp.26 = fsub float %tmp.8, %tmp.15<br>
+ %tmp.28 = fadd float %tmp.26, %tmp.20<br>
+ %tmp.30 = fsub float %tmp.28, %tmp.23<br>
+ %tmp.32 = fsub float %tmp.30, %a4<br>
+ %tmp.34 = fsub float %tmp.32, %a2<br>
+ %T = fmul float %tmp.34, %tmp.34<br>
+ ret float %T<br>
+}<br>
+<br>
+; Should be able to eliminate everything.<br>
+define float @test2(float %a0, float %a1, float %a2, float %a3, float %a4) {<br>
+; CHECK-LABEL: test2<br>
+; CHECK: ret float 0.000000e+00<br>
+<br>
+ %tmp.2 = fadd fast float %a4, %a3<br>
+ %tmp.4 = fadd fast float %tmp.2, %a2<br>
+ %tmp.6 = fadd fast float %tmp.4, %a1<br>
+ %tmp.8 = fadd fast float %tmp.6, %a0<br>
+ %tmp.11 = fadd fast float %a3, %a2<br>
+ %tmp.13 = fadd fast float %tmp.11, %a1<br>
+ %tmp.15 = fadd fast float %tmp.13, %a0<br>
+ %tmp.18 = fadd fast float %a2, %a1<br>
+ %tmp.20 = fadd fast float %tmp.18, %a0<br>
+ %tmp.23 = fadd fast float %a1, %a0<br>
+ %tmp.26 = fsub fast float %tmp.8, %tmp.15<br>
+ %tmp.28 = fadd fast float %tmp.26, %tmp.20<br>
+ %tmp.30 = fsub fast float %tmp.28, %tmp.23<br>
+ %tmp.32 = fsub fast float %tmp.30, %a4<br>
+ %tmp.34 = fsub fast float %tmp.32, %a2<br>
+ %T = fmul fast float %tmp.34, %tmp.34<br>
+ ret float %T<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-MissedTree.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-MissedTree.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>MissedTree.ll?rev=215647&view=<u></u>auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-MissedTree.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-MissedTree.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,11 @@<br>
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s<br>
+<br>
+define float @test1(float %A, float %B) {<br>
+; CHECK-LABEL: test1<br>
+; CHECK: %Z = fadd fast float %A, %B<br>
+; CHECK: ret float %Z<br>
+ %W = fadd fast float %B, -5.0<br>
+ %Y = fadd fast float %A, 5.0<br>
+ %Z = fadd fast float %W, %Y<br>
+ ret float %Z<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ReassociateVector.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-ReassociateVector.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>ReassociateVector.ll?rev=<u></u>215647&view=auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ReassociateVector.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>ReassociateVector.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,25 @@<br>
+; RUN: opt < %s -reassociate -S | FileCheck %s<br>
+<br>
+; Don't handle floating point vector operations.<br>
+define <4 x float> @test1() {<br>
+; CHECK-LABEL: test1<br>
+; CHECK-NEXT: %tmp1 = fsub fast <4 x float> zeroinitializer, zeroinitializer<br>
+; CHECK-NEXT: %tmp2 = fmul fast <4 x float> zeroinitializer, %tmp1<br>
+<br>
+ %tmp1 = fsub fast <4 x float> zeroinitializer, zeroinitializer<br>
+ %tmp2 = fmul fast <4 x float> zeroinitializer, %tmp1<br>
+ ret <4 x float> %tmp2<br>
+}<br>
+<br>
+; We don't currently commute integer vector operations.<br>
+define <2 x i32> @test2(<2 x i32> %x, <2 x i32> %y) {<br>
+; CHECK-LABEL: test2<br>
+; CHECK-NEXT: %tmp1 = add <2 x i32> %x, %y<br>
+; CHECK-NEXT: %tmp2 = add <2 x i32> %y, %x<br>
+; CHECK-NEXT: %tmp3 = add <2 x i32> %tmp1, %tmp2<br>
+<br>
+ %tmp1 = add <2 x i32> %x, %y<br>
+ %tmp2 = add <2 x i32> %y, %x<br>
+ %tmp3 = add <2 x i32> %tmp1, %tmp2<br>
+ ret <2 x i32> %tmp3<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>SubReassociate.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-SubReassociate.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>SubReassociate.ll?rev=215647&<u></u>view=auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>SubReassociate.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-<u></u>SubReassociate.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,70 @@<br>
+; RUN: opt < %s -reassociate -constprop -instcombine -S | FileCheck %s<br>
+<br>
+define float @test1(float %A, float %B) {<br>
+; CHECK-LABEL: test1<br>
+; CHECK-NEXT: %W = fadd float %B, 5.000000e+00<br>
+; CHECK-NEXT: %X = fadd float %A, -7.000000e+00<br>
+; CHECK-NEXT: %Y = fsub float %X, %W<br>
+; CHECK-NEXT: %Z = fadd float %Y, 1.200000e+01<br>
+; CHECK-NEXT: ret float %Z<br>
+<br>
+ %W = fadd float 5.0, %B<br>
+ %X = fadd float -7.0, %A<br>
+ %Y = fsub float %X, %W<br>
+ %Z = fadd float %Y, 12.0<br>
+ ret float %Z<br>
+}<br>
+<br>
+; With sub reassociation, constant folding can eliminate all of the constants.<br>
+define float @test2(float %A, float %B) {<br>
+; CHECK-LABEL: test2<br>
+; CHECK-NEXT: %Z = fsub fast float %A, %B<br>
+; CHECK-NEXT: ret float %Z<br>
+<br>
+ %W = fadd fast float %B, 5.000000e+00<br>
+ %X = fadd fast float %A, -7.000000e+00<br>
+ %Y = fsub fast float %X, %W<br>
+ %Z = fadd fast float %Y, 1.200000e+01<br>
+ ret float %Z<br>
+<br>
+}<br>
+<br>
+define float @test3(float %A, float %B, float %C, float %D) {<br>
+; CHECK-LABEL: test3<br>
+; CHECK-NEXT: %M = fadd float %A, 1.200000e+01<br>
+; CHECK-NEXT: %N = fadd float %M, %B<br>
+; CHECK-NEXT: %O = fadd float %N, %C<br>
+; CHECK-NEXT: %P = fsub float %D, %O<br>
+; CHECK-NEXT: %Q = fadd float %P, 1.200000e+01<br>
+; CHECK-NEXT: ret float %Q<br>
+<br>
+ %M = fadd float %A, 1.200000e+01<br>
+ %N = fadd float %M, %B<br>
+ %O = fadd float %N, %C<br>
+ %P = fsub float %D, %O<br>
+ %Q = fadd float %P, 1.200000e+01<br>
+ ret float %Q<br>
+}<br>
+<br>
+; With sub reassociation, constant folding can eliminate the two 12 constants.<br>
+define float @test4(float %A, float %B, float %C, float %D) {<br>
+; CHECK-LABEL: test4<br>
+; CHECK-NEXT: %B.neg = fsub fast float -0.000000e+00, %B<br>
+; CHECK-NEXT: %O.neg = fsub fast float %B.neg, %A<br>
+; CHECK-NEXT: %P = fsub fast float %O.neg, %C<br>
+; CHECK-NEXT: %Q = fadd fast float %P, %D<br>
+; CHECK-NEXT: ret float %Q<br>
+<br>
+; FIXME: InstCombine should be able to get us to the following:<br>
+; %sum = fadd fast float %B, %A<br>
+; %sum1 = fadd fast float %sum, %C<br>
+; %Q = fsub fast float %D, %sum1<br>
+; ret i32 %Q<br>
+<br>
+ %M = fadd fast float 1.200000e+01, %A<br>
+ %N = fadd fast float %M, %B<br>
+ %O = fadd fast float %N, %C<br>
+ %P = fsub fast float %D, %O<br>
+ %Q = fadd fast float 1.200000e+01, %P<br>
+ ret float %Q<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-basictest.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-basictest.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>basictest.ll?rev=215647&view=<u></u>auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-basictest.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-basictest.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,285 @@<br>
+; RUN: opt < %s -reassociate -gvn -instcombine -S | FileCheck %s<br>
+<br>
+; With reassociation, constant folding can eliminate the 12 and -12 constants.<br>
+define float @test1(float %arg) {<br>
+; CHECK-LABEL: @test1<br>
+; CHECK-NEXT: fsub fast float -0.000000e+00, %arg<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %tmp1 = fsub fast float -1.200000e+01, %arg<br>
+ %tmp2 = fadd fast float %tmp1, 1.200000e+01<br>
+ ret float %tmp2<br>
+}<br>
+<br>
+define float @test2(float %reg109, float %reg1111) {<br>
+; CHECK-LABEL: @test2<br>
+; CHECK-NEXT: fadd float %reg109, -3.000000e+01<br>
+; CHECK-NEXT: fadd float %reg115, %reg1111<br>
+; CHECK-NEXT: fadd float %reg116, 3.000000e+01<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %reg115 = fadd float %reg109, -3.000000e+01<br>
+ %reg116 = fadd float %reg115, %reg1111<br>
+ %reg117 = fadd float %reg116, 3.000000e+01<br>
+ ret float %reg117<br>
+}<br>
+<br>
+define float @test3(float %reg109, float %reg1111) {<br>
+; CHECK-LABEL: @test3<br>
+; CHECK-NEXT: %reg117 = fadd fast float %reg109, %reg1111<br>
+; CHECK-NEXT: ret float %reg117<br>
+<br>
+ %reg115 = fadd fast float %reg109, -3.000000e+01<br>
+ %reg116 = fadd fast float %reg115, %reg1111<br>
+ %reg117 = fadd fast float %reg116, 3.000000e+01<br>
+ ret float %reg117<br>
+}<br>
+<br>
+@fe = external global float<br>
+@fa = external global float<br>
+@fb = external global float<br>
+@fc = external global float<br>
+@ff = external global float<br>
+<br>
+define void @test4() {<br>
+; CHECK-LABEL: @test4<br>
+; CHECK: fadd fast float<br>
+; CHECK: fadd fast float<br>
+; CHECK-NOT: fadd fast float<br>
+; CHECK: ret void<br>
+<br>
+ %A = load float* @fa<br>
+ %B = load float* @fb<br>
+ %C = load float* @fc<br>
+ %t1 = fadd fast float %A, %B<br>
+ %t2 = fadd fast float %t1, %C<br>
+ %t3 = fadd fast float %C, %A<br>
+ %t4 = fadd fast float %t3, %B<br>
+ ; e = (a+b)+c;<br>
+ store float %t2, float* @fe<br>
+ ; f = (a+c)+b<br>
+ store float %t4, float* @ff<br>
+ ret void<br>
+}<br>
+<br>
+define void @test5() {<br>
+; CHECK-LABEL: @test5<br>
+; CHECK: fadd fast float<br>
+; CHECK: fadd fast float<br>
+; CHECK-NOT: fadd<br>
+; CHECK: ret void<br>
+<br>
+ %A = load float* @fa<br>
+ %B = load float* @fb<br>
+ %C = load float* @fc<br>
+ %t1 = fadd fast float %A, %B<br>
+ %t2 = fadd fast float %t1, %C<br>
+ %t3 = fadd fast float %C, %A<br>
+ %t4 = fadd fast float %t3, %B<br>
+ ; e = c+(a+b)<br>
+ store float %t2, float* @fe<br>
+ ; f = (c+a)+b<br>
+ store float %t4, float* @ff<br>
+ ret void<br>
+}<br>
+<br>
+define void @test6() {<br>
+; CHECK-LABEL: @test6<br>
+; CHECK: fadd fast float<br>
+; CHECK: fadd fast float<br>
+; CHECK-NOT: fadd<br>
+; CHECK: ret void<br>
+<br>
+ %A = load float* @fa<br>
+ %B = load float* @fb<br>
+ %C = load float* @fc<br>
+ %t1 = fadd fast float %B, %A<br>
+ %t2 = fadd fast float %t1, %C<br>
+ %t3 = fadd fast float %C, %A<br>
+ %t4 = fadd fast float %t3, %B<br>
+ ; e = c+(b+a)<br>
+ store float %t2, float* @fe<br>
+ ; f = (c+a)+b<br>
+ store float %t4, float* @ff<br>
+ ret void<br>
+}<br>
+<br>
+define float @test7(float %A, float %B, float %C) {<br>
+; CHECK-LABEL: @test7<br>
+; CHECK-NEXT: fadd fast float %C, %B<br>
+; CHECK-NEXT: fmul fast float %A, %A<br>
+; CHECK-NEXT: fmul fast float %1, %tmp2<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %aa = fmul fast float %A, %A<br>
+ %aab = fmul fast float %aa, %B<br>
+ %ac = fmul fast float %A, %C<br>
+ %aac = fmul fast float %ac, %A<br>
+ %r = fadd fast float %aab, %aac<br>
+ ret float %r<br>
+}<br>
+<br>
+define float @test8(float %X, float %Y, float %Z) {<br>
+; CHECK-LABEL: @test8<br>
+; CHECK-NEXT: fmul fast float %Y, %X<br>
+; CHECK-NEXT: fsub fast float %Z<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %A = fsub fast float 0.0, %X<br>
+ %B = fmul fast float %A, %Y<br>
+ ; (-X)*Y + Z -> Z-X*Y<br>
+ %C = fadd fast float %B, %Z<br>
+ ret float %C<br>
+}<br>
+<br>
+define float @test9(float %X) {<br>
+; CHECK-LABEL: @test9<br>
+; CHECK-NEXT: fmul fast float %X, 9.400000e+01<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %Y = fmul fast float %X, 4.700000e+01<br>
+ %Z = fadd fast float %Y, %Y<br>
+ ret float %Z<br>
+}<br>
+<br>
+define float @test10(float %X) {<br>
+; CHECK-LABEL: @test10<br>
+; CHECK-NEXT: fmul fast float %X, 3.000000e+00<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %Y = fadd fast float %X ,%X<br>
+ %Z = fadd fast float %Y, %X<br>
+ ret float %Z<br>
+}<br>
+<br>
+define float @test11(float %W) {<br>
+; CHECK-LABEL: test11<br>
+; CHECK-NEXT: fmul fast float %W, 3.810000e+02<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %X = fmul fast float %W, 127.0<br>
+ %Y = fadd fast float %X ,%X<br>
+ %Z = fadd fast float %Y, %X<br>
+ ret float %Z<br>
+}<br>
+<br>
+define float @test12(float %X) {<br>
+; CHECK-LABEL: @test12<br>
+; CHECK-NEXT: fmul fast float %X, -3.000000e+00<br>
+; CHECK-NEXT: fadd fast float %factor, 6.000000e+00<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %A = fsub fast float 1.000000e+00, %X<br>
+ %B = fsub fast float 2.000000e+00, %X<br>
+ %C = fsub fast float 3.000000e+00, %X<br>
+ %Y = fadd fast float %A ,%B<br>
+ %Z = fadd fast float %Y, %C<br>
+ ret float %Z<br>
+}<br>
+<br>
+define float @test13(float %X1, float %X2, float %X3) {<br>
+; CHECK-LABEL: @test13<br>
+; CHECK-NEXT: fsub fast float %X3, %X2<br>
+; CHECK-NEXT: fmul fast float {{.*}}, %X1<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %A = fsub fast float 0.000000e+00, %X1<br>
+ %B = fmul fast float %A, %X2 ; -X1*X2<br>
+ %C = fmul fast float %X1, %X3 ; X1*X3<br>
+ %D = fadd fast float %B, %C ; -X1*X2 + X1*X3 -> X1*(X3-X2)<br>
+ ret float %D<br>
+}<br>
+<br>
+define float @test14(float %X1, float %X2) {<br>
+; CHECK-LABEL: @test14<br>
+; CHECK-NEXT: fsub fast float %X1, %X2<br>
+; CHECK-NEXT: fmul fast float %tmp, 4.700000e+01<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %B = fmul fast float %X1, 47. ; X1*47<br>
+ %C = fmul fast float %X2, -47. ; X2*-47<br>
+ %D = fadd fast float %B, %C ; X1*47 + X2*-47 -> 47*(X1-X2)<br>
+ ret float %D<br>
+}<br>
+<br>
+define float @test15(float %arg) {<br>
+; CHECK-LABEL: test15<br>
+; CHECK-NEXT: fmul fast float %arg, 1.440000e+02<br>
+; CHECK-NEXT: ret float %tmp2<br>
+<br>
+ %tmp1 = fmul fast float 1.200000e+01, %arg<br>
+ %tmp2 = fmul fast float %tmp1, 1.200000e+01<br>
+ ret float %tmp2<br>
+}<br>
+<br>
+; (b+(a+1234))+-a -> b+1234<br>
+define float @test16(float %b, float %a) {<br>
+; CHECK-LABEL: @test16<br>
+; CHECK-NEXT: fadd fast float %b, 1.234000e+03<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %1 = fadd fast float %a, 1234.0<br>
+ %2 = fadd fast float %b, %1<br>
+ %3 = fsub fast float 0.0, %a<br>
+ %4 = fadd fast float %2, %3<br>
+ ret float %4<br>
+}<br>
+<br>
+; Test that we can turn things like X*-(Y*Z) -> X*-1*Y*Z.<br>
+<br>
+define float @test17(float %a, float %b, float %z) {<br>
+; CHECK-LABEL: test17<br>
+; CHECK-NEXT: fmul fast float %a, 1.234500e+04<br>
+; CHECK-NEXT: fmul fast float %e, %b<br>
+; CHECK-NEXT: fmul fast float %f, %z<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %c = fsub fast float 0.000000e+00, %z<br>
+ %d = fmul fast float %a, %b<br>
+ %e = fmul fast float %c, %d<br>
+ %f = fmul fast float %e, 1.234500e+04<br>
+ %g = fsub fast float 0.000000e+00, %f<br>
+ ret float %g<br>
+}<br>
+<br>
+define float @test18(float %a, float %b, float %z) {<br>
+; CHECK-LABEL: test18<br>
+; CHECK-NEXT: fmul fast float %a, 4.000000e+01<br>
+; CHECK-NEXT: fmul fast float %e, %z<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %d = fmul fast float %z, 4.000000e+01<br>
+ %c = fsub fast float 0.000000e+00, %d<br>
+ %e = fmul fast float %a, %c<br>
+ %f = fsub fast float 0.000000e+00, %e<br>
+ ret float %f<br>
+}<br>
+<br>
+; With sub reassociation, constant folding can eliminate the 12 and -12 constants.<br>
+define float @test19(float %A, float %B) {<br>
+; CHECK-LABEL: @test19<br>
+; CHECK-NEXT: fsub fast float %A, %B<br>
+; CHECK-NEXT: ret float<br>
+ %X = fadd fast float -1.200000e+01, %A<br>
+ %Y = fsub fast float %X, %B<br>
+ %Z = fadd fast float %Y, 1.200000e+01<br>
+ ret float %Z<br>
+}<br>
+<br>
+; With sub reassociation, constant folding can eliminate the uses of %a.<br>
+define float @test20(float %a, float %b, float %c) nounwind {<br>
+; CHECK-LABEL: @test20<br>
+; CHECK-NEXT: fsub fast float -0.000000e+00, %b<br>
+; CHECK-NEXT: fsub fast float %b.neg, %c<br>
+; CHECK-NEXT: ret float<br>
+<br>
+; FIXME: Should be able to generate the below, which may expose more<br>
+; opportunites for FAdd reassociation.<br>
+; %sum = fadd fast float %c, %b<br>
+; %tmp7 = fsub fast float 0, %sum<br>
+<br>
+ %tmp3 = fsub fast float %a, %b<br>
+ %tmp5 = fsub fast float %tmp3, %c<br>
+ %tmp7 = fsub fast float %tmp5, %a<br>
+ ret float %tmp7<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-fp-commute.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-fp-commute.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>fp-commute.ll?rev=215647&view=<u></u>auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-fp-commute.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-fp-commute.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,44 @@<br>
+; RUN: opt -reassociate -S < %s | FileCheck %s<br>
+<br>
+declare void @use(float)<br>
+<br>
+define void @test1(float %x, float %y) {<br>
+; CHECK-LABEL: test1<br>
+; CHECK: fmul fast float %y, %x<br>
+; CHECK: fmul fast float %y, %x<br>
+; CHECK: fsub fast float %1, %2<br>
+; CHECK: call void @use(float %{{.*}})<br>
+; CHECK: call void @use(float %{{.*}})<br>
+<br>
+ %1 = fmul fast float %x, %y<br>
+ %2 = fmul fast float %y, %x<br>
+ %3 = fsub fast float %1, %2<br>
+ call void @use(float %1)<br>
+ call void @use(float %3)<br>
+ ret void<br>
+}<br>
+<br>
+define float @test2(float %x, float %y) {<br>
+; CHECK-LABEL: test2<br>
+; CHECK-NEXT: fmul fast float %y, %x<br>
+; CHECK-NEXT: fmul fast float %y, %x<br>
+; CHECK-NEXT: fsub fast float %1, %2<br>
+; CHECK-NEXT: ret float %3<br>
+<br>
+ %1 = fmul fast float %x, %y<br>
+ %2 = fmul fast float %y, %x<br>
+ %3 = fsub fast float %1, %2<br>
+ ret float %3<br>
+}<br>
+<br>
+define float @test3(float %x, float %y) {<br>
+; CHECK-LABEL: test3<br>
+; CHECK-NEXT: %factor = fmul fast float 2.000000e+00, %y<br>
+; CHECK-NEXT: %tmp1 = fmul fast float %factor, %x<br>
+; CHECK-NEXT: ret float %tmp1<br>
+<br>
+ %1 = fmul fast float %x, %y<br>
+ %2 = fmul fast float %y, %x<br>
+ %3 = fadd fast float %1, %2<br>
+ ret float %3<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-mightymul.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-mightymul.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>mightymul.ll?rev=215647&view=<u></u>auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-mightymul.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-mightymul.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,35 @@<br>
+; RUN: opt < %s -reassociate -disable-output<br>
+; PR13021<br>
+<br>
+define float @test2(float %x) {<br>
+ %t0 = fmul fast float %x, %x<br>
+ %t1 = fmul fast float %t0, %t0<br>
+ %t2 = fmul fast float %t1, %t1<br>
+ %t3 = fmul fast float %t2, %t2<br>
+ %t4 = fmul fast float %t3, %t3<br>
+ %t5 = fmul fast float %t4, %t4<br>
+ %t6 = fmul fast float %t5, %t5<br>
+ %t7 = fmul fast float %t6, %t6<br>
+ %t8 = fmul fast float %t7, %t7<br>
+ %t9 = fmul fast float %t8, %t8<br>
+ %t10 = fmul fast float %t9, %t9<br>
+ %t11 = fmul fast float %t10, %t10<br>
+ %t12 = fmul fast float %t11, %t11<br>
+ %t13 = fmul fast float %t12, %t12<br>
+ %t14 = fmul fast float %t13, %t13<br>
+ %t15 = fmul fast float %t14, %t14<br>
+ %t16 = fmul fast float %t15, %t15<br>
+ %t17 = fmul fast float %t16, %t16<br>
+ %t18 = fmul fast float %t17, %t17<br>
+ %t19 = fmul fast float %t18, %t18<br>
+ %t20 = fmul fast float %t19, %t19<br>
+ %t21 = fmul fast float %t20, %t20<br>
+ %t22 = fmul fast float %t21, %t21<br>
+ %t23 = fmul fast float %t22, %t22<br>
+ %t24 = fmul fast float %t23, %t23<br>
+ %t25 = fmul fast float %t24, %t24<br>
+ %t26 = fmul fast float %t25, %t25<br>
+ %t27 = fmul fast float %t26, %t26<br>
+ %t28 = fmul fast float %t27, %t27<br>
+ ret float %t28<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/<u></u>Reassociate/fast-multistep.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Reassociate/fast-multistep.ll?rev=215647&view=auto" target="_blank">http://llvm.org/viewvc/llvm-<u></u>project/llvm/trunk/test/<u></u>Transforms/Reassociate/fast-<u></u>multistep.ll?rev=215647&view=<u></u>auto</a><br>
==============================<u></u>==============================<u></u>==================<br>
--- llvm/trunk/test/Transforms/<u></u>Reassociate/fast-multistep.ll (added)<br>
+++ llvm/trunk/test/Transforms/<u></u>Reassociate/fast-multistep.ll Thu Aug 14 10:23:01 2014<br>
@@ -0,0 +1,32 @@<br>
+; RUN: opt < %s -reassociate -S | FileCheck %s<br>
+<br>
+define float @fmultistep1(float %a, float %b, float %c) {<br>
+; Check that a*a*b+a*a*c is turned into a*(a*(b+c)).<br>
+; CHECK-LABEL: @fmultistep1<br>
+; CHECK-NEXT: fadd fast float %c, %b<br>
+; CHECK-NEXT: fmul fast float %a, %tmp2<br>
+; CHECK-NEXT: fmul fast float %tmp3, %a<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %t0 = fmul fast float %a, %b<br>
+ %t1 = fmul fast float %a, %t0 ; a*(a*b)<br>
+ %t2 = fmul fast float %a, %c<br>
+ %t3 = fmul fast float %a, %t2 ; a*(a*c)<br>
+ %t4 = fadd fast float %t1, %t3<br>
+ ret float %t4<br>
+}<br>
+<br>
+define float @fmultistep2(float %a, float %b, float %c, float %d) {<br>
+; Check that a*b+a*c+d is turned into a*(b+c)+d.<br>
+; CHECK-LABEL: @fmultistep2<br>
+; CHECK-NEXT: fadd fast float %c, %b<br>
+; CHECK-NEXT: fmul fast float %tmp, %a<br>
+; CHECK-NEXT: fadd fast float %tmp1, %d<br>
+; CHECK-NEXT: ret float<br>
+<br>
+ %t0 = fmul fast float %a, %b<br>
+ %t1 = fmul fast float %a, %c<br>
+ %t2 = fadd fast float %t1, %d ; a*c+d<br>
+ %t3 = fadd fast float %t0, %t2 ; a*b+(a*c+d)<br>
+ ret float %t3<br>
+}<br>
<br>
<br>
______________________________<u></u>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/llvm-commits</a><br>
</blockquote>
<br>
<br>_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
<br></blockquote></div><br></div>