From cd117f736c47947af5c6549734549e135e626c5c Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 15 Jun 2012 08:37:50 +0000 Subject: [PATCH] Fix issues (infinite loop and/or crash) with self-referential instructions, for example degenerate phi nodes and binops that use themselves in unreachable code. Thanks to Charles Davis for the testcase that uncovered this can of worms. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@158508 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/Reassociate.cpp | 20 ++++++++++++++------ test/Transforms/Reassociate/crash.ll | 25 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp index 66fa0744b84..2b0d406c15d 100644 --- a/lib/Transforms/Scalar/Reassociate.cpp +++ b/lib/Transforms/Scalar/Reassociate.cpp @@ -132,7 +132,7 @@ namespace { private: void BuildRankMap(Function &F); unsigned getRank(Value *V); - Value *ReassociateExpression(BinaryOperator *I); + void ReassociateExpression(BinaryOperator *I); void RewriteExprTree(BinaryOperator *I, SmallVectorImpl &Ops); Value *OptimizeExpression(BinaryOperator *I, SmallVectorImpl &Ops); @@ -1480,12 +1480,14 @@ void Reassociate::EraseInst(Instruction *I) { ValueRankMap.erase(I); I->eraseFromParent(); // Optimize its operands. + SmallPtrSet Visited; // Detect self-referential nodes. for (unsigned i = 0, e = Ops.size(); i != e; ++i) if (Instruction *Op = dyn_cast(Ops[i])) { // If this is a node in an expression tree, climb to the expression root // and add that since that's where optimization actually happens. unsigned Opcode = Op->getOpcode(); - while (Op->hasOneUse() && Op->use_back()->getOpcode() == Opcode) + while (Op->hasOneUse() && Op->use_back()->getOpcode() == Opcode && + Visited.insert(Op)) Op = Op->use_back(); RedoInsts.insert(Op); } @@ -1585,7 +1587,7 @@ void Reassociate::OptimizeInst(Instruction *I) { ReassociateExpression(BO); } -Value *Reassociate::ReassociateExpression(BinaryOperator *I) { +void Reassociate::ReassociateExpression(BinaryOperator *I) { // First, walk the expression tree, linearizing the tree, collecting the // operand information. @@ -1612,6 +1614,9 @@ Value *Reassociate::ReassociateExpression(BinaryOperator *I) { // OptimizeExpression - Now that we have the expression tree in a convenient // sorted form, optimize it globally if possible. if (Value *V = OptimizeExpression(I, Ops)) { + if (V == I) + // Self-referential expression in unreachable code. + return; // This expression tree simplified to something that isn't a tree, // eliminate it. DEBUG(dbgs() << "Reassoc to scalar: " << *V << '\n'); @@ -1620,7 +1625,7 @@ Value *Reassociate::ReassociateExpression(BinaryOperator *I) { VI->setDebugLoc(I->getDebugLoc()); RedoInsts.insert(I); ++NumAnnihil; - return V; + return; } // We want to sink immediates as deeply as possible except in the case where @@ -1638,19 +1643,22 @@ Value *Reassociate::ReassociateExpression(BinaryOperator *I) { DEBUG(dbgs() << "RAOut:\t"; PrintOps(I, Ops); dbgs() << '\n'); if (Ops.size() == 1) { + if (Ops[0].Op == I) + // Self-referential expression in unreachable code. + return; + // This expression tree simplified to something that isn't a tree, // eliminate it. I->replaceAllUsesWith(Ops[0].Op); if (Instruction *OI = dyn_cast(Ops[0].Op)) OI->setDebugLoc(I->getDebugLoc()); RedoInsts.insert(I); - return Ops[0].Op; + return; } // Now that we ordered and optimized the expressions, splat them back into // the expression tree, removing any unneeded nodes. RewriteExprTree(I, Ops); - return I; } bool Reassociate::runOnFunction(Function &F) { diff --git a/test/Transforms/Reassociate/crash.ll b/test/Transforms/Reassociate/crash.ll index 601b97647dd..bbe4f233e82 100644 --- a/test/Transforms/Reassociate/crash.ll +++ b/test/Transforms/Reassociate/crash.ll @@ -83,3 +83,28 @@ define i128 @foo() { %mul = mul i128 0, 0 ret i128 %mul } + +define void @infinite_loop() { +entry: + br label %loop +loop: + %x = phi i32 [undef, %entry], [%x, %loop] + %dead = add i32 %x, 0 + br label %loop +unreachable1: + %y1 = add i32 %y1, 0 + %z1 = add i32 %y1, 0 + ret void +unreachable2: + %y2 = add i32 %y2, 0 + %z2 = add i32 %y2, %y2 + ret void +unreachable3: + %y3 = add i32 %y3, %y3 + %z3 = add i32 %y3, 0 + ret void +unreachable4: + %y4 = add i32 %y4, %y4 + %z4 = add i32 %y4, %y4 + ret void +}