OLD | NEW |
(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 } |
OLD | NEW |