]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- XCoreLowerThreadLocal - Lower thread local variables --------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | /// | |
10 | /// \file | |
11 | /// \brief This file contains a pass that lowers thread local variables on the | |
12 | /// XCore. | |
13 | /// | |
14 | //===----------------------------------------------------------------------===// | |
15 | ||
16 | #include "XCore.h" | |
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" | |
28 | ||
29 | #define DEBUG_TYPE "xcore-lower-thread-local" | |
30 | ||
31 | using namespace llvm; | |
32 | ||
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)); | |
37 | ||
38 | namespace { | |
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 { | |
43 | static char ID; | |
44 | ||
45 | XCoreLowerThreadLocal() : ModulePass(ID) { | |
46 | initializeXCoreLowerThreadLocalPass(*PassRegistry::getPassRegistry()); | |
47 | } | |
48 | ||
49 | bool lowerGlobal(GlobalVariable *GV); | |
50 | ||
51 | bool runOnModule(Module &M) override; | |
52 | }; | |
53 | } | |
54 | ||
55 | char XCoreLowerThreadLocal::ID = 0; | |
56 | ||
57 | INITIALIZE_PASS(XCoreLowerThreadLocal, "xcore-lower-thread-local", | |
58 | "Lower thread local variables", false, false) | |
59 | ||
60 | ModulePass *llvm::createXCoreLowerThreadLocalPass() { | |
61 | return new XCoreLowerThreadLocal(); | |
62 | } | |
63 | ||
64 | static ArrayType *createLoweredType(Type *OriginalType) { | |
65 | return ArrayType::get(OriginalType, MaxThreads); | |
66 | } | |
67 | ||
68 | static Constant * | |
69 | createLoweredInitializer(ArrayType *NewType, Constant *OriginalInitializer) { | |
70 | SmallVector<Constant *, 8> Elements(MaxThreads); | |
71 | for (unsigned i = 0; i != MaxThreads; ++i) { | |
72 | Elements[i] = OriginalInitializer; | |
73 | } | |
74 | return ConstantArray::get(NewType, Elements); | |
75 | } | |
76 | ||
77 | static Instruction * | |
78 | createReplacementInstr(ConstantExpr *CE, Instruction *Instr) { | |
79 | IRBuilder<true,NoFolder> Builder(Instr); | |
80 | unsigned OpCode = CE->getOpcode(); | |
81 | switch (OpCode) { | |
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(CEOps[0], | |
86 | CEOps.slice(1))); | |
87 | } | |
88 | case Instruction::Add: | |
89 | case Instruction::Sub: | |
90 | case Instruction::Mul: | |
91 | case Instruction::UDiv: | |
92 | case Instruction::SDiv: | |
93 | case Instruction::FDiv: | |
94 | case Instruction::URem: | |
95 | case Instruction::SRem: | |
96 | case Instruction::FRem: | |
97 | case Instruction::Shl: | |
98 | case Instruction::LShr: | |
99 | case Instruction::AShr: | |
100 | case Instruction::And: | |
101 | case Instruction::Or: | |
102 | case Instruction::Xor: | |
103 | return dyn_cast<Instruction>( | |
104 | Builder.CreateBinOp((Instruction::BinaryOps)OpCode, | |
105 | CE->getOperand(0), CE->getOperand(1), | |
106 | CE->getName())); | |
107 | case Instruction::Trunc: | |
108 | case Instruction::ZExt: | |
109 | case Instruction::SExt: | |
110 | case Instruction::FPToUI: | |
111 | case Instruction::FPToSI: | |
112 | case Instruction::UIToFP: | |
113 | case Instruction::SIToFP: | |
114 | case Instruction::FPTrunc: | |
115 | case Instruction::FPExt: | |
116 | case Instruction::PtrToInt: | |
117 | case Instruction::IntToPtr: | |
118 | case Instruction::BitCast: | |
119 | return dyn_cast<Instruction>( | |
120 | Builder.CreateCast((Instruction::CastOps)OpCode, | |
121 | CE->getOperand(0), CE->getType(), | |
122 | CE->getName())); | |
123 | default: | |
124 | llvm_unreachable("Unhandled constant expression!\n"); | |
125 | } | |
126 | } | |
127 | ||
128 | static bool replaceConstantExprOp(ConstantExpr *CE, Pass *P) { | |
129 | do { | |
130 | SmallVector<WeakVH,8> WUsers(CE->user_begin(), CE->user_end()); | |
131 | std::sort(WUsers.begin(), WUsers.end()); | |
132 | WUsers.erase(std::unique(WUsers.begin(), WUsers.end()), WUsers.end()); | |
133 | while (!WUsers.empty()) | |
134 | if (WeakVH WU = WUsers.pop_back_val()) { | |
135 | if (PHINode *PN = dyn_cast<PHINode>(WU)) { | |
136 | for (int I = 0, E = PN->getNumIncomingValues(); I < E; ++I) | |
137 | if (PN->getIncomingValue(I) == CE) { | |
138 | BasicBlock *PredBB = PN->getIncomingBlock(I); | |
139 | if (PredBB->getTerminator()->getNumSuccessors() > 1) | |
140 | PredBB = SplitEdge(PredBB, PN->getParent(), P); | |
141 | Instruction *InsertPos = PredBB->getTerminator(); | |
142 | Instruction *NewInst = createReplacementInstr(CE, InsertPos); | |
143 | PN->setOperand(I, NewInst); | |
144 | } | |
145 | } else if (Instruction *Instr = dyn_cast<Instruction>(WU)) { | |
146 | Instruction *NewInst = createReplacementInstr(CE, Instr); | |
147 | Instr->replaceUsesOfWith(CE, NewInst); | |
148 | } else { | |
149 | ConstantExpr *CExpr = dyn_cast<ConstantExpr>(WU); | |
150 | if (!CExpr || !replaceConstantExprOp(CExpr, P)) | |
151 | return false; | |
152 | } | |
153 | } | |
154 | } while (CE->hasNUsesOrMore(1)); // We need to check because a recursive | |
155 | // sibling may have used 'CE' when createReplacementInstr was called. | |
156 | CE->destroyConstant(); | |
157 | return true; | |
158 | } | |
159 | ||
160 | static bool rewriteNonInstructionUses(GlobalVariable *GV, Pass *P) { | |
161 | SmallVector<WeakVH,8> WUsers; | |
162 | for (User *U : GV->users()) | |
163 | if (!isa<Instruction>(U)) | |
164 | WUsers.push_back(WeakVH(U)); | |
165 | while (!WUsers.empty()) | |
166 | if (WeakVH WU = WUsers.pop_back_val()) { | |
167 | ConstantExpr *CE = dyn_cast<ConstantExpr>(WU); | |
168 | if (!CE || !replaceConstantExprOp(CE, P)) | |
169 | return false; | |
170 | } | |
171 | return true; | |
172 | } | |
173 | ||
174 | static bool isZeroLengthArray(Type *Ty) { | |
175 | ArrayType *AT = dyn_cast<ArrayType>(Ty); | |
176 | return AT && (AT->getNumElements() == 0); | |
177 | } | |
178 | ||
179 | bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable *GV) { | |
180 | Module *M = GV->getParent(); | |
181 | LLVMContext &Ctx = M->getContext(); | |
182 | if (!GV->isThreadLocal()) | |
183 | return false; | |
184 | ||
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())) | |
188 | return false; | |
189 | ||
190 | // Create replacement global. | |
191 | ArrayType *NewType = createLoweredType(GV->getType()->getElementType()); | |
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()); | |
202 | ||
203 | // Update uses. | |
204 | SmallVector<User *, 16> Users(GV->user_begin(), GV->user_end()); | |
205 | for (unsigned I = 0, E = Users.size(); I != E; ++I) { | |
206 | User *U = Users[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 | SmallVector<Value *, 2> Indices; | |
213 | Indices.push_back(Constant::getNullValue(Type::getInt64Ty(Ctx))); | |
214 | Indices.push_back(ThreadID); | |
215 | Value *Addr = Builder.CreateInBoundsGEP(NewGV, Indices); | |
216 | U->replaceUsesOfWith(GV, Addr); | |
217 | } | |
218 | ||
219 | // Remove old global. | |
220 | NewGV->takeName(GV); | |
221 | GV->eraseFromParent(); | |
222 | return true; | |
223 | } | |
224 | ||
225 | bool XCoreLowerThreadLocal::runOnModule(Module &M) { | |
226 | // Find thread local globals. | |
227 | bool MadeChange = false; | |
228 | SmallVector<GlobalVariable *, 16> ThreadLocalGlobals; | |
229 | for (Module::global_iterator GVI = M.global_begin(), E = M.global_end(); | |
230 | GVI != E; ++GVI) { | |
231 | GlobalVariable *GV = GVI; | |
232 | if (GV->isThreadLocal()) | |
233 | ThreadLocalGlobals.push_back(GV); | |
234 | } | |
235 | for (unsigned I = 0, E = ThreadLocalGlobals.size(); I != E; ++I) { | |
236 | MadeChange |= lowerGlobal(ThreadLocalGlobals[I]); | |
237 | } | |
238 | return MadeChange; | |
239 | } |