1 //===-- XCoreLowerThreadLocal - Lower thread local variables --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file contains a pass that lowers thread local variables on the
14 //===----------------------------------------------------------------------===//
17 #include "llvm/IR/Constants.h"
18 #include "llvm/IR/DerivedTypes.h"
19 #include "llvm/IR/GlobalVariable.h"
20 #include "llvm/IR/IRBuilder.h"
21 #include "llvm/IR/Intrinsics.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/IR/NoFolder.h"
24 #include "llvm/IR/ValueHandle.h"
25 #include "llvm/Pass.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
29 #define DEBUG_TYPE "xcore-lower-thread-local"
33 static cl::opt
<unsigned> MaxThreads(
34 "xcore-max-threads", cl::Optional
,
35 cl::desc("Maximum number of threads (for emulation thread-local storage)"),
36 cl::Hidden
, cl::value_desc("number"), cl::init(8));
39 /// Lowers thread local variables on the XCore. Each thread local variable is
40 /// expanded to an array of n elements indexed by the thread ID where n is the
41 /// fixed number hardware threads supported by the device.
42 struct XCoreLowerThreadLocal
: public ModulePass
{
45 XCoreLowerThreadLocal() : ModulePass(ID
) {
46 initializeXCoreLowerThreadLocalPass(*PassRegistry::getPassRegistry());
49 bool lowerGlobal(GlobalVariable
*GV
);
51 bool runOnModule(Module
&M
) override
;
55 char XCoreLowerThreadLocal::ID
= 0;
57 INITIALIZE_PASS(XCoreLowerThreadLocal
, "xcore-lower-thread-local",
58 "Lower thread local variables", false, false)
60 ModulePass
*llvm::createXCoreLowerThreadLocalPass() {
61 return new XCoreLowerThreadLocal();
64 static ArrayType
*createLoweredType(Type
*OriginalType
) {
65 return ArrayType::get(OriginalType
, MaxThreads
);
69 createLoweredInitializer(ArrayType
*NewType
, Constant
*OriginalInitializer
) {
70 SmallVector
<Constant
*, 8> Elements(MaxThreads
);
71 for (unsigned i
= 0; i
!= MaxThreads
; ++i
) {
72 Elements
[i
] = OriginalInitializer
;
74 return ConstantArray::get(NewType
, Elements
);
78 createReplacementInstr(ConstantExpr
*CE
, Instruction
*Instr
) {
79 IRBuilder
<NoFolder
> Builder(Instr
);
80 unsigned OpCode
= CE
->getOpcode();
82 case Instruction::GetElementPtr
: {
83 SmallVector
<Value
*,4> CEOpVec(CE
->op_begin(), CE
->op_end());
84 ArrayRef
<Value
*> CEOps(CEOpVec
);
85 return dyn_cast
<Instruction
>(Builder
.CreateInBoundsGEP(
86 cast
<GEPOperator
>(CE
)->getSourceElementType(), CEOps
[0],
89 case Instruction::Add
:
90 case Instruction::Sub
:
91 case Instruction::Mul
:
92 case Instruction::UDiv
:
93 case Instruction::SDiv
:
94 case Instruction::FDiv
:
95 case Instruction::URem
:
96 case Instruction::SRem
:
97 case Instruction::FRem
:
98 case Instruction::Shl
:
99 case Instruction::LShr
:
100 case Instruction::AShr
:
101 case Instruction::And
:
102 case Instruction::Or
:
103 case Instruction::Xor
:
104 return dyn_cast
<Instruction
>(
105 Builder
.CreateBinOp((Instruction::BinaryOps
)OpCode
,
106 CE
->getOperand(0), CE
->getOperand(1),
108 case Instruction::Trunc
:
109 case Instruction::ZExt
:
110 case Instruction::SExt
:
111 case Instruction::FPToUI
:
112 case Instruction::FPToSI
:
113 case Instruction::UIToFP
:
114 case Instruction::SIToFP
:
115 case Instruction::FPTrunc
:
116 case Instruction::FPExt
:
117 case Instruction::PtrToInt
:
118 case Instruction::IntToPtr
:
119 case Instruction::BitCast
:
120 return dyn_cast
<Instruction
>(
121 Builder
.CreateCast((Instruction::CastOps
)OpCode
,
122 CE
->getOperand(0), CE
->getType(),
125 llvm_unreachable("Unhandled constant expression!\n");
129 static bool replaceConstantExprOp(ConstantExpr
*CE
, Pass
*P
) {
131 SmallVector
<WeakTrackingVH
, 8> WUsers(CE
->user_begin(), CE
->user_end());
132 llvm::sort(WUsers
.begin(), WUsers
.end());
133 WUsers
.erase(std::unique(WUsers
.begin(), WUsers
.end()), WUsers
.end());
134 while (!WUsers
.empty())
135 if (WeakTrackingVH WU
= WUsers
.pop_back_val()) {
136 if (PHINode
*PN
= dyn_cast
<PHINode
>(WU
)) {
137 for (int I
= 0, E
= PN
->getNumIncomingValues(); I
< E
; ++I
)
138 if (PN
->getIncomingValue(I
) == CE
) {
139 BasicBlock
*PredBB
= PN
->getIncomingBlock(I
);
140 if (PredBB
->getTerminator()->getNumSuccessors() > 1)
141 PredBB
= SplitEdge(PredBB
, PN
->getParent());
142 Instruction
*InsertPos
= PredBB
->getTerminator();
143 Instruction
*NewInst
= createReplacementInstr(CE
, InsertPos
);
144 PN
->setOperand(I
, NewInst
);
146 } else if (Instruction
*Instr
= dyn_cast
<Instruction
>(WU
)) {
147 Instruction
*NewInst
= createReplacementInstr(CE
, Instr
);
148 Instr
->replaceUsesOfWith(CE
, NewInst
);
150 ConstantExpr
*CExpr
= dyn_cast
<ConstantExpr
>(WU
);
151 if (!CExpr
|| !replaceConstantExprOp(CExpr
, P
))
155 } while (CE
->hasNUsesOrMore(1)); // We need to check because a recursive
156 // sibling may have used 'CE' when createReplacementInstr was called.
157 CE
->destroyConstant();
161 static bool rewriteNonInstructionUses(GlobalVariable
*GV
, Pass
*P
) {
162 SmallVector
<WeakTrackingVH
, 8> WUsers
;
163 for (User
*U
: GV
->users())
164 if (!isa
<Instruction
>(U
))
165 WUsers
.push_back(WeakTrackingVH(U
));
166 while (!WUsers
.empty())
167 if (WeakTrackingVH WU
= WUsers
.pop_back_val()) {
168 ConstantExpr
*CE
= dyn_cast
<ConstantExpr
>(WU
);
169 if (!CE
|| !replaceConstantExprOp(CE
, P
))
175 static bool isZeroLengthArray(Type
*Ty
) {
176 ArrayType
*AT
= dyn_cast
<ArrayType
>(Ty
);
177 return AT
&& (AT
->getNumElements() == 0);
180 bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable
*GV
) {
181 Module
*M
= GV
->getParent();
182 if (!GV
->isThreadLocal())
185 // Skip globals that we can't lower and leave it for the backend to error.
186 if (!rewriteNonInstructionUses(GV
, this) ||
187 !GV
->getType()->isSized() || isZeroLengthArray(GV
->getType()))
190 // Create replacement global.
191 ArrayType
*NewType
= createLoweredType(GV
->getValueType());
192 Constant
*NewInitializer
= nullptr;
193 if (GV
->hasInitializer())
194 NewInitializer
= createLoweredInitializer(NewType
,
195 GV
->getInitializer());
196 GlobalVariable
*NewGV
=
197 new GlobalVariable(*M
, NewType
, GV
->isConstant(), GV
->getLinkage(),
198 NewInitializer
, "", nullptr,
199 GlobalVariable::NotThreadLocal
,
200 GV
->getType()->getAddressSpace(),
201 GV
->isExternallyInitialized());
204 SmallVector
<User
*, 16> Users(GV
->user_begin(), GV
->user_end());
205 for (unsigned I
= 0, E
= Users
.size(); I
!= E
; ++I
) {
207 Instruction
*Inst
= cast
<Instruction
>(U
);
208 IRBuilder
<> Builder(Inst
);
209 Function
*GetID
= Intrinsic::getDeclaration(GV
->getParent(),
210 Intrinsic::xcore_getid
);
211 Value
*ThreadID
= Builder
.CreateCall(GetID
, {});
212 Value
*Addr
= Builder
.CreateInBoundsGEP(NewGV
->getValueType(), NewGV
,
213 {Builder
.getInt64(0), ThreadID
});
214 U
->replaceUsesOfWith(GV
, Addr
);
217 // Remove old global.
219 GV
->eraseFromParent();
223 bool XCoreLowerThreadLocal::runOnModule(Module
&M
) {
224 // Find thread local globals.
225 bool MadeChange
= false;
226 SmallVector
<GlobalVariable
*, 16> ThreadLocalGlobals
;
227 for (GlobalVariable
&GV
: M
.globals())
228 if (GV
.isThreadLocal())
229 ThreadLocalGlobals
.push_back(&GV
);
230 for (unsigned I
= 0, E
= ThreadLocalGlobals
.size(); I
!= E
; ++I
) {
231 MadeChange
|= lowerGlobal(ThreadLocalGlobals
[I
]);