diff --git a/lib/Target/XCore/XCoreLowerThreadLocal.cpp b/lib/Target/XCore/XCoreLowerThreadLocal.cpp index 7340b2f9666..afce753dec5 100644 --- a/lib/Target/XCore/XCoreLowerThreadLocal.cpp +++ b/lib/Target/XCore/XCoreLowerThreadLocal.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/NoFolder.h" #include "llvm/Support/ValueHandle.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #define DEBUG_TYPE "xcore-lower-thread-local" @@ -124,32 +125,42 @@ createReplacementInstr(ConstantExpr *CE, Instruction *Instr) { } } -static bool replaceConstantExprOp(ConstantExpr *CE) { +static bool replaceConstantExprOp(ConstantExpr *CE, Pass *P) { do { SmallVector WUsers; for (Value::use_iterator I = CE->use_begin(), E = CE->use_end(); I != E; ++I) WUsers.push_back(WeakVH(*I)); + std::sort(WUsers.begin(), WUsers.end()); + WUsers.erase(std::unique(WUsers.begin(), WUsers.end()), WUsers.end()); while (!WUsers.empty()) if (WeakVH WU = WUsers.pop_back_val()) { - if (Instruction *Instr = dyn_cast(WU)) { + if (PHINode *PN = dyn_cast(WU)) { + for (int I = 0, E = PN->getNumIncomingValues(); I < E; ++I) + if (PN->getIncomingValue(I) == CE) { + BasicBlock *PredBB = PN->getIncomingBlock(I); + if (PredBB->getTerminator()->getNumSuccessors() > 1) + PredBB = SplitEdge(PredBB, PN->getParent(), P); + Instruction *InsertPos = PredBB->getTerminator(); + Instruction *NewInst = createReplacementInstr(CE, InsertPos); + PN->setOperand(I, NewInst); + } + } else if (Instruction *Instr = dyn_cast(WU)) { Instruction *NewInst = createReplacementInstr(CE, Instr); - assert(NewInst && "Must build an instruction\n"); - // If NewInst uses a CE being handled in an earlier recursion the - // earlier recursion's do-while-hasNUsesOrMore(1) will run again. Instr->replaceUsesOfWith(CE, NewInst); } else { ConstantExpr *CExpr = dyn_cast(WU); - if (!CExpr || !replaceConstantExprOp(CExpr)) + if (!CExpr || !replaceConstantExprOp(CExpr, P)) return false; } } - } while (CE->hasNUsesOrMore(1)); // Does a recursion's NewInst use CE? + } while (CE->hasNUsesOrMore(1)); // We need to check becasue a recursive + // sibbling may have used 'CE' when createReplacementInstr was called. CE->destroyConstant(); return true; } -static bool rewriteNonInstructionUses(GlobalVariable *GV) { +static bool rewriteNonInstructionUses(GlobalVariable *GV, Pass *P) { SmallVector WUsers; for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I) if (!isa(*I)) @@ -157,7 +168,7 @@ static bool rewriteNonInstructionUses(GlobalVariable *GV) { while (!WUsers.empty()) if (WeakVH WU = WUsers.pop_back_val()) { ConstantExpr *CE = dyn_cast(WU); - if (!CE || !replaceConstantExprOp(CE)) + if (!CE || !replaceConstantExprOp(CE, P)) return false; } return true; @@ -175,7 +186,7 @@ bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable *GV) { return false; // Skip globals that we can't lower and leave it for the backend to error. - if (!rewriteNonInstructionUses(GV) || + if (!rewriteNonInstructionUses(GV, this) || !GV->getType()->isSized() || isZeroLengthArray(GV->getType())) return false; diff --git a/test/CodeGen/XCore/threads.ll b/test/CodeGen/XCore/threads.ll index b56b16b5fa9..c50da1d5934 100644 --- a/test/CodeGen/XCore/threads.ll +++ b/test/CodeGen/XCore/threads.ll @@ -1,4 +1,5 @@ ; RUN: llc -march=xcore < %s | FileCheck %s +; RUN: llc -march=xcore -O=0 < %s | FileCheck %s -check-prefix=PHINODE declare i8 addrspace(1)* @llvm.xcore.getst.p1i8.p1i8(i8 addrspace(1)* %r) declare void @llvm.xcore.msync.p1i8(i8 addrspace(1)* %r) @@ -102,5 +103,43 @@ define i32 @f_tlExpr () { i32 ptrtoint( i32* getelementptr inbounds ([2 x i32]* @tle, i32 0, i32 0) to i32)) } +define void @phiNode1() { +; N.B. lowering of duplicate constexpr in a PHI node requires -O=0 +; PHINODE-LABEL: phiNode1: +; PHINODE: get r11, id +; PHINODE-LABEL: .LBB11_1: +; PHINODE: get r11, id +; PHINODE: bu .LBB11_1 +entry: + br label %ConstantExpPhiNode +ConstantExpPhiNode: + %ptr = phi i32* [ getelementptr inbounds ([3 x i32]* @tl, i32 0, i32 0), %entry ], + [ getelementptr inbounds ([3 x i32]* @tl, i32 0, i32 0), %ConstantExpPhiNode ] + br label %ConstantExpPhiNode +exit: + ret void +} + +define void @phiNode2( i1 %bool) { +; N.B. check an extra 'Node_crit_edge' (LBB12_1) is inserted +; PHINODE-LABEL: phiNode2: +; PHINODE: bf {{r[0-9]}}, .LBB12_3 +; PHINODE: bu .LBB12_1 +; PHINODE-LABEL: .LBB12_1: +; PHINODE: get r11, id +; PHINODE-LABEL: .LBB12_2: +; PHINODE: get r11, id +; PHINODE: bu .LBB12_2 +; PHINODE-LABEL: .LBB12_3: +entry: + br i1 %bool, label %ConstantExpPhiNode, label %exit +ConstantExpPhiNode: + %ptr = phi i32* [ getelementptr inbounds ([3 x i32]* @tl, i32 0, i32 0), %entry ], + [ getelementptr inbounds ([3 x i32]* @tl, i32 0, i32 0), %ConstantExpPhiNode ] + br label %ConstantExpPhiNode +exit: + ret void +} + ; CHECK-LABEL: tl: ; CHECK: .space 96