summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Lytton <robert@xmos.com>2013-10-11 10:26:48 +0000
committerRobert Lytton <robert@xmos.com>2013-10-11 10:26:48 +0000
commit9715375c25bc1f985fd2dbbbad61fd43e334a1e9 (patch)
tree48c2717eea68c5f2fa81333de70466a7aea7bce7
parent3139db02c8cdf83a71f04a9aeb4e295031b1e57c (diff)
downloadbcm5719-llvm-9715375c25bc1f985fd2dbbbad61fd43e334a1e9.tar.gz
bcm5719-llvm-9715375c25bc1f985fd2dbbbad61fd43e334a1e9.zip
XCore target: fix bug in XCoreLowerThreadLocal.cpp
When a ConstantExpr which uses a thread local is part of a PHI node instruction, the insruction that replaces the ConstantExpr must be inserted in the predecessor block, in front of the terminator instruction. If the predecessor block has multiple successors, the edge is first split. llvm-svn: 192432
-rw-r--r--llvm/lib/Target/XCore/XCoreLowerThreadLocal.cpp31
-rw-r--r--llvm/test/CodeGen/XCore/threads.ll39
2 files changed, 60 insertions, 10 deletions
diff --git a/llvm/lib/Target/XCore/XCoreLowerThreadLocal.cpp b/llvm/lib/Target/XCore/XCoreLowerThreadLocal.cpp
index 7340b2f9666..afce753dec5 100644
--- a/llvm/lib/Target/XCore/XCoreLowerThreadLocal.cpp
+++ b/llvm/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<WeakVH,8> 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<Instruction>(WU)) {
+ if (PHINode *PN = dyn_cast<PHINode>(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<Instruction>(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<ConstantExpr>(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<WeakVH,8> WUsers;
for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I)
if (!isa<Instruction>(*I))
@@ -157,7 +168,7 @@ static bool rewriteNonInstructionUses(GlobalVariable *GV) {
while (!WUsers.empty())
if (WeakVH WU = WUsers.pop_back_val()) {
ConstantExpr *CE = dyn_cast<ConstantExpr>(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/llvm/test/CodeGen/XCore/threads.ll b/llvm/test/CodeGen/XCore/threads.ll
index b56b16b5fa9..c50da1d5934 100644
--- a/llvm/test/CodeGen/XCore/threads.ll
+++ b/llvm/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
OpenPOWER on IntegriCloud