Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: lib/Transforms/NaCl/ExpandTls.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/Transforms/NaCl/ExpandStructRegs.cpp ('k') | lib/Transforms/NaCl/ExpandTlsConstantExpr.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===- ExpandTls.cpp - Convert TLS variables to a concrete layout----------===//
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 // This pass expands out uses of thread-local (TLS) variables into
11 // more primitive operations.
12 //
13 // A reference to the address of a TLS variable is expanded into code
14 // which gets the current thread's thread pointer using
15 // @llvm.nacl.read.tp() and adds a fixed offset.
16 //
17 // This pass allocates the offsets (relative to the thread pointer)
18 // that will be used for TLS variables. It sets up the global
19 // variables __tls_template_start, __tls_template_end etc. to contain
20 // a template for initializing TLS variables' values for each thread.
21 // This is a task normally performed by the linker in ELF systems.
22 //
23 //===----------------------------------------------------------------------===//
24
25 #include <vector>
26
27 #include "llvm/Pass.h"
28 #include "llvm/IR/Constants.h"
29 #include "llvm/IR/DataLayout.h"
30 #include "llvm/IR/DerivedTypes.h"
31 #include "llvm/IR/Instructions.h"
32 #include "llvm/IR/Intrinsics.h"
33 #include "llvm/IR/Module.h"
34 #include "llvm/Transforms/NaCl.h"
35
36 using namespace llvm;
37
38 namespace {
39 struct VarInfo {
40 GlobalVariable *TlsVar;
41 bool IsBss; // Whether variable is in zero-intialized part of template
42 int TemplateIndex;
43 };
44
45 class PassState {
46 public:
47 PassState(Module *M): M(M), DL(M), Offset(0), Alignment(1) {}
48
49 Module *M;
50 DataLayout DL;
51 uint64_t Offset;
52 // 'Alignment' is the maximum variable alignment seen so far, in
53 // bytes. After visiting all TLS variables, this is the overall
54 // alignment required for the TLS template.
55 uint32_t Alignment;
56 };
57
58 class ExpandTls : public ModulePass {
59 public:
60 static char ID; // Pass identification, replacement for typeid
61 ExpandTls() : ModulePass(ID) {
62 initializeExpandTlsPass(*PassRegistry::getPassRegistry());
63 }
64
65 virtual bool runOnModule(Module &M);
66 };
67 }
68
69 char ExpandTls::ID = 0;
70 INITIALIZE_PASS(ExpandTls, "nacl-expand-tls",
71 "Expand out TLS variables and fix TLS variable layout",
72 false, false)
73
74 static void setGlobalVariableValue(Module &M, const char *Name,
75 Constant *Value) {
76 if (GlobalVariable *Var = M.getNamedGlobal(Name)) {
77 if (Var->hasInitializer()) {
78 report_fatal_error(std::string("Variable ") + Name +
79 " already has an initializer");
80 }
81 Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType()));
82 Var->eraseFromParent();
83 }
84 }
85
86 // Insert alignment padding into the TLS template.
87 static void padToAlignment(PassState *State,
88 std::vector<Type*> *FieldTypes,
89 std::vector<Constant*> *FieldValues,
90 unsigned Alignment) {
91 if ((State->Offset & (Alignment - 1)) != 0) {
92 unsigned PadSize = Alignment - (State->Offset & (Alignment - 1));
93 Type *i8 = Type::getInt8Ty(State->M->getContext());
94 Type *PadType = ArrayType::get(i8, PadSize);
95 FieldTypes->push_back(PadType);
96 if (FieldValues)
97 FieldValues->push_back(Constant::getNullValue(PadType));
98 State->Offset += PadSize;
99 }
100 if (State->Alignment < Alignment) {
101 State->Alignment = Alignment;
102 }
103 }
104
105 static void addVarToTlsTemplate(PassState *State,
106 std::vector<Type*> *FieldTypes,
107 std::vector<Constant*> *FieldValues,
108 GlobalVariable *TlsVar) {
109 unsigned Alignment = State->DL.getPreferredAlignment(TlsVar);
110 padToAlignment(State, FieldTypes, FieldValues, Alignment);
111
112 FieldTypes->push_back(TlsVar->getType()->getElementType());
113 if (FieldValues)
114 FieldValues->push_back(TlsVar->getInitializer());
115 State->Offset +=
116 State->DL.getTypeAllocSize(TlsVar->getType()->getElementType());
117 }
118
119 static PointerType *buildTlsTemplate(Module &M, std::vector<VarInfo> *TlsVars) {
120 std::vector<Type*> FieldBssTypes;
121 std::vector<Type*> FieldInitTypes;
122 std::vector<Constant*> FieldInitValues;
123 PassState State(&M);
124
125 for (Module::global_iterator GV = M.global_begin();
126 GV != M.global_end();
127 ++GV) {
128 if (GV->isThreadLocal()) {
129 if (!GV->hasInitializer()) {
130 // Since this is a whole-program transformation, "extern" TLS
131 // variables are not allowed at this point.
132 report_fatal_error(std::string("TLS variable without an initializer: ")
133 + GV->getName());
134 }
135 if (!GV->getInitializer()->isNullValue()) {
136 addVarToTlsTemplate(&State, &FieldInitTypes,
137 &FieldInitValues, GV);
138 VarInfo Info;
139 Info.TlsVar = GV;
140 Info.IsBss = false;
141 Info.TemplateIndex = FieldInitTypes.size() - 1;
142 TlsVars->push_back(Info);
143 }
144 }
145 }
146 // Handle zero-initialized TLS variables in a second pass, because
147 // these should follow non-zero-initialized TLS variables.
148 for (Module::global_iterator GV = M.global_begin();
149 GV != M.global_end();
150 ++GV) {
151 if (GV->isThreadLocal() && GV->getInitializer()->isNullValue()) {
152 addVarToTlsTemplate(&State, &FieldBssTypes, NULL, GV);
153 VarInfo Info;
154 Info.TlsVar = GV;
155 Info.IsBss = true;
156 Info.TemplateIndex = FieldBssTypes.size() - 1;
157 TlsVars->push_back(Info);
158 }
159 }
160 // Add final alignment padding so that
161 // (struct tls_struct *) __nacl_read_tp() - 1
162 // gives the correct, aligned start of the TLS variables given the
163 // x86-style layout we are using. This requires some more bytes to
164 // be memset() to zero at runtime. This wastage doesn't seem
165 // important gives that we're not trying to optimize packing by
166 // reordering to put similarly-aligned variables together.
167 padToAlignment(&State, &FieldBssTypes, NULL, State.Alignment);
168
169 // We create the TLS template structs as "packed" because we insert
170 // alignment padding ourselves, and LLVM's implicit insertion of
171 // padding would interfere with ours. tls_bss_template can start at
172 // a non-aligned address immediately following the last field in
173 // tls_init_template.
174 StructType *InitTemplateType =
175 StructType::create(M.getContext(), "tls_init_template");
176 InitTemplateType->setBody(FieldInitTypes, /*isPacked=*/true);
177 StructType *BssTemplateType =
178 StructType::create(M.getContext(), "tls_bss_template");
179 BssTemplateType->setBody(FieldBssTypes, /*isPacked=*/true);
180
181 StructType *TemplateType = StructType::create(M.getContext(), "tls_struct");
182 SmallVector<Type*, 2> TemplateTopFields;
183 TemplateTopFields.push_back(InitTemplateType);
184 TemplateTopFields.push_back(BssTemplateType);
185 TemplateType->setBody(TemplateTopFields, /*isPacked=*/true);
186 PointerType *TemplatePtrType = PointerType::get(TemplateType, 0);
187
188 // We define the following symbols, which are the same as those
189 // defined by NaCl's original customized binutils linker scripts:
190 // __tls_template_start
191 // __tls_template_tdata_end
192 // __tls_template_end
193 // We also define __tls_template_alignment, which was not defined by
194 // the original linker scripts.
195
196 const char *StartSymbol = "__tls_template_start";
197 Constant *TemplateData = ConstantStruct::get(InitTemplateType,
198 FieldInitValues);
199 GlobalVariable *TemplateDataVar =
200 new GlobalVariable(M, InitTemplateType, /*isConstant=*/true,
201 GlobalValue::InternalLinkage, TemplateData);
202 setGlobalVariableValue(M, StartSymbol, TemplateDataVar);
203 TemplateDataVar->setName(StartSymbol);
204
205 Constant *TdataEnd = ConstantExpr::getGetElementPtr(
206 TemplateDataVar,
207 ConstantInt::get(M.getContext(), APInt(32, 1)));
208 setGlobalVariableValue(M, "__tls_template_tdata_end", TdataEnd);
209
210 Constant *TotalEnd = ConstantExpr::getGetElementPtr(
211 ConstantExpr::getBitCast(TemplateDataVar, TemplatePtrType),
212 ConstantInt::get(M.getContext(), APInt(32, 1)));
213 setGlobalVariableValue(M, "__tls_template_end", TotalEnd);
214
215 const char *AlignmentSymbol = "__tls_template_alignment";
216 Type *i32 = Type::getInt32Ty(M.getContext());
217 GlobalVariable *AlignmentVar = new GlobalVariable(
218 M, i32, /*isConstant=*/true,
219 GlobalValue::InternalLinkage,
220 ConstantInt::get(M.getContext(), APInt(32, State.Alignment)));
221 setGlobalVariableValue(M, AlignmentSymbol, AlignmentVar);
222 AlignmentVar->setName(AlignmentSymbol);
223
224 return TemplatePtrType;
225 }
226
227 static void rewriteTlsVars(Module &M, std::vector<VarInfo> *TlsVars,
228 PointerType *TemplatePtrType) {
229 // Set up the intrinsic that reads the thread pointer.
230 Function *ReadTpFunc = Intrinsic::getDeclaration(&M, Intrinsic::nacl_read_tp);
231
232 for (std::vector<VarInfo>::iterator VarInfo = TlsVars->begin();
233 VarInfo != TlsVars->end();
234 ++VarInfo) {
235 GlobalVariable *Var = VarInfo->TlsVar;
236 while (Var->hasNUsesOrMore(1)) {
237 Use *U = &*Var->use_begin();
238 Instruction *InsertPt = PhiSafeInsertPt(U);
239 Value *RawThreadPtr = CallInst::Create(ReadTpFunc, "tls_raw", InsertPt);
240 Value *TypedThreadPtr = new BitCastInst(RawThreadPtr, TemplatePtrType,
241 "tls_struct", InsertPt);
242 SmallVector<Value*, 3> Indexes;
243 // We use -1 because we use the x86-style TLS layout in which
244 // the TLS data is stored at addresses below the thread pointer.
245 // This is largely because a check in nacl_irt_thread_create()
246 // in irt/irt_thread.c requires the thread pointer to be a
247 // self-pointer on x86-32.
248 // TODO(mseaborn): I intend to remove that check because it is
249 // non-portable. In the mean time, we want PNaCl pexes to work
250 // in older Chromium releases when translated to nexes.
251 Indexes.push_back(ConstantInt::get(
252 M.getContext(), APInt(32, -1)));
253 Indexes.push_back(ConstantInt::get(
254 M.getContext(), APInt(32, VarInfo->IsBss ? 1 : 0)));
255 Indexes.push_back(ConstantInt::get(
256 M.getContext(), APInt(32, VarInfo->TemplateIndex)));
257 Value *TlsField = GetElementPtrInst::Create(TypedThreadPtr, Indexes,
258 "field", InsertPt);
259 PhiSafeReplaceUses(U, TlsField);
260 }
261 VarInfo->TlsVar->eraseFromParent();
262 }
263 }
264
265 static void replaceFunction(Module &M, const char *Name, Value *NewFunc) {
266 if (Function *Func = M.getFunction(Name)) {
267 if (Func->hasLocalLinkage())
268 return;
269 if (!Func->isDeclaration())
270 report_fatal_error(std::string("Function already defined: ") + Name);
271 Func->replaceAllUsesWith(NewFunc);
272 Func->eraseFromParent();
273 }
274 }
275
276 // Provide fixed definitions for NaCl's TLS layout functions,
277 // __nacl_tp_*(). We adopt the x86-style layout: ExpandTls will
278 // output a program that uses the x86-style layout wherever it runs.
279 //
280 // This overrides the architecture-specific definitions of
281 // __nacl_tp_*() that PNaCl's native support code makes available to
282 // non-ABI-stable code.
283 static void defineTlsLayoutFunctions(Module &M) {
284 Type *i32 = Type::getInt32Ty(M.getContext());
285 SmallVector<Type*, 1> ArgTypes;
286 ArgTypes.push_back(i32);
287 FunctionType *FuncType = FunctionType::get(i32, ArgTypes, /*isVarArg=*/false);
288 Function *NewFunc;
289 BasicBlock *BB;
290
291 // Define the function as follows:
292 // uint32_t __nacl_tp_tdb_offset(uint32_t tdb_size) {
293 // return 0;
294 // }
295 // This means the thread pointer points to the TDB.
296 NewFunc = Function::Create(FuncType, GlobalValue::InternalLinkage,
297 "nacl_tp_tdb_offset", &M);
298 BB = BasicBlock::Create(M.getContext(), "entry", NewFunc);
299 ReturnInst::Create(M.getContext(),
300 ConstantInt::get(M.getContext(), APInt(32, 0)), BB);
301 replaceFunction(M, "__nacl_tp_tdb_offset", NewFunc);
302
303 // Define the function as follows:
304 // uint32_t __nacl_tp_tls_offset(uint32_t tls_size) {
305 // return -tls_size;
306 // }
307 // This means the TLS variables are stored below the thread pointer.
308 NewFunc = Function::Create(FuncType, GlobalValue::InternalLinkage,
309 "nacl_tp_tls_offset", &M);
310 BB = BasicBlock::Create(M.getContext(), "entry", NewFunc);
311 Value *Arg = NewFunc->arg_begin();
312 Arg->setName("size");
313 Value *Result = BinaryOperator::CreateNeg(Arg, "result", BB);
314 ReturnInst::Create(M.getContext(), Result, BB);
315 replaceFunction(M, "__nacl_tp_tls_offset", NewFunc);
316 }
317
318 bool ExpandTls::runOnModule(Module &M) {
319 ModulePass *Pass = createExpandTlsConstantExprPass();
320 Pass->runOnModule(M);
321 delete Pass;
322
323 std::vector<VarInfo> TlsVars;
324 PointerType *TemplatePtrType = buildTlsTemplate(M, &TlsVars);
325 rewriteTlsVars(M, &TlsVars, TemplatePtrType);
326
327 defineTlsLayoutFunctions(M);
328
329 return true;
330 }
331
332 ModulePass *llvm::createExpandTlsPass() {
333 return new ExpandTls();
334 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ExpandStructRegs.cpp ('k') | lib/Transforms/NaCl/ExpandTlsConstantExpr.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698