| OLD | NEW |
| 1 //===- ExpandTls.cpp - Convert TLS variables to a concrete layout----------===// | 1 //===- ExpandTls.cpp - Convert TLS variables to a concrete layout----------===// |
| 2 // | 2 // |
| 3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 // | 9 // |
| 10 // This pass expands out uses of thread-local (TLS) variables into | 10 // This pass expands out uses of thread-local (TLS) variables into |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 #include "llvm/IR/DataLayout.h" | 52 #include "llvm/IR/DataLayout.h" |
| 53 #include "llvm/IR/DerivedTypes.h" | 53 #include "llvm/IR/DerivedTypes.h" |
| 54 #include "llvm/IR/Instructions.h" | 54 #include "llvm/IR/Instructions.h" |
| 55 #include "llvm/IR/Intrinsics.h" | 55 #include "llvm/IR/Intrinsics.h" |
| 56 #include "llvm/IR/Module.h" | 56 #include "llvm/IR/Module.h" |
| 57 #include "llvm/Transforms/NaCl.h" | 57 #include "llvm/Transforms/NaCl.h" |
| 58 | 58 |
| 59 using namespace llvm; | 59 using namespace llvm; |
| 60 | 60 |
| 61 namespace { | 61 namespace { |
| 62 class PassState { | |
| 63 public: | |
| 64 PassState(Module *M): M(M), DL(M), Offset(0), Alignment(1) {} | |
| 65 | |
| 66 Module *M; | |
| 67 DataLayout DL; | |
| 68 uint32_t Offset; | |
| 69 // 'Alignment' is the maximum variable alignment seen so far, in | |
| 70 // bytes. After visiting all TLS variables, this is the overall | |
| 71 // alignment required for the TLS template. | |
| 72 uint32_t Alignment; | |
| 73 }; | |
| 74 | |
| 75 class ExpandTls : public ModulePass { | 62 class ExpandTls : public ModulePass { |
| 76 public: | 63 public: |
| 77 static char ID; // Pass identification, replacement for typeid | 64 static char ID; // Pass identification, replacement for typeid |
| 78 ExpandTls() : ModulePass(ID) { | 65 ExpandTls() : ModulePass(ID) { |
| 79 initializeExpandTlsPass(*PassRegistry::getPassRegistry()); | 66 initializeExpandTlsPass(*PassRegistry::getPassRegistry()); |
| 80 } | 67 } |
| 81 | 68 |
| 82 virtual bool runOnModule(Module &M); | 69 virtual bool runOnModule(Module &M); |
| 83 }; | 70 }; |
| 84 } | 71 } |
| 85 | 72 |
| 86 char ExpandTls::ID = 0; | 73 char ExpandTls::ID = 0; |
| 87 INITIALIZE_PASS(ExpandTls, "nacl-expand-tls", | 74 INITIALIZE_PASS(ExpandTls, "nacl-expand-tls", |
| 88 "Expand out TLS variables and fix TLS variable layout", | 75 "Expand out TLS variables and fix TLS variable layout", |
| 89 false, false) | 76 false, false) |
| 90 | 77 |
| 91 static void setGlobalVariableValue(Module &M, const char *Name, | 78 static void setGlobalVariableValue(Module &M, const char *Name, |
| 92 Constant *Value) { | 79 Constant *Value) { |
| 93 if (GlobalVariable *Var = M.getNamedGlobal(Name)) { | 80 if (GlobalVariable *Var = M.getNamedGlobal(Name)) { |
| 94 if (Var->hasInitializer()) { | 81 if (Var->hasInitializer()) { |
| 95 report_fatal_error(std::string("Variable ") + Name + | 82 report_fatal_error(std::string("Variable ") + Name + |
| 96 " already has an initializer"); | 83 " already has an initializer"); |
| 97 } | 84 } |
| 98 Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType())); | 85 Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType())); |
| 99 Var->eraseFromParent(); | 86 Var->eraseFromParent(); |
| 100 } | 87 } |
| 101 } | 88 } |
| 102 | 89 |
| 103 // Insert alignment padding into the TLS template. | |
| 104 static void padToAlignment(PassState *State, | |
| 105 std::vector<Constant*> *FieldValues, | |
| 106 unsigned Alignment) { | |
| 107 if ((State->Offset & (Alignment - 1)) != 0) { | |
| 108 unsigned PadSize = Alignment - (State->Offset & (Alignment - 1)); | |
| 109 Type *i8 = Type::getInt8Ty(State->M->getContext()); | |
| 110 Type *PadType = ArrayType::get(i8, PadSize); | |
| 111 if (FieldValues) | |
| 112 FieldValues->push_back(Constant::getNullValue(PadType)); | |
| 113 State->Offset += PadSize; | |
| 114 } | |
| 115 if (State->Alignment < Alignment) { | |
| 116 State->Alignment = Alignment; | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 static uint32_t addVarToTlsTemplate(PassState *State, | |
| 121 std::vector<Constant*> *FieldValues, | |
| 122 GlobalVariable *TlsVar) { | |
| 123 unsigned Alignment = State->DL.getPreferredAlignment(TlsVar); | |
| 124 padToAlignment(State, FieldValues, Alignment); | |
| 125 | |
| 126 if (FieldValues) | |
| 127 FieldValues->push_back(TlsVar->getInitializer()); | |
| 128 uint32_t Offset = State->Offset; | |
| 129 State->Offset += | |
| 130 State->DL.getTypeAllocSize(TlsVar->getType()->getElementType()); | |
| 131 return Offset; | |
| 132 } | |
| 133 | |
| 134 // This is similar to ConstantStruct::getAnon(), but we give a name to the | 90 // This is similar to ConstantStruct::getAnon(), but we give a name to the |
| 135 // struct type to make the IR output more readable. | 91 // struct type to make the IR output more readable. |
| 136 static Constant *makeInitStruct(Module &M, ArrayRef<Constant *> Elements) { | 92 static Constant *makeInitStruct(Module &M, ArrayRef<Constant *> Elements) { |
| 137 SmallVector<Type *, 32> FieldTypes; | 93 SmallVector<Type *, 32> FieldTypes; |
| 138 FieldTypes.reserve(Elements.size()); | 94 FieldTypes.reserve(Elements.size()); |
| 139 for (Constant *Val : Elements) | 95 for (Constant *Val : Elements) |
| 140 FieldTypes.push_back(Val->getType()); | 96 FieldTypes.push_back(Val->getType()); |
| 141 | 97 |
| 142 // We create the TLS template struct as "packed" because we insert | 98 // We create the TLS template struct as "packed" because we insert |
| 143 // alignment padding ourselves. | 99 // alignment padding ourselves. |
| 144 StructType *Ty = StructType::create(M.getContext(), FieldTypes, | 100 StructType *Ty = StructType::create(M.getContext(), FieldTypes, |
| 145 "tls_init_template", /*isPacked=*/ true); | 101 "tls_init_template", /*isPacked=*/ true); |
| 146 return ConstantStruct::get(Ty, Elements); | 102 return ConstantStruct::get(Ty, Elements); |
| 147 } | 103 } |
| 148 | 104 |
| 149 void llvm::buildTlsTemplate(Module &M, TlsTemplate *Result) { | 105 void llvm::buildTlsTemplate(Module &M, TlsTemplate *Result) { |
| 150 std::vector<Constant*> FieldInitValues; | 106 std::vector<Constant*> FieldInitValues; |
| 151 PassState State(&M); | 107 DataLayout DL(&M); |
| 108 uint32_t CurrentOffset = 0; |
| 109 uint32_t OverallAlignment = 1; |
| 110 |
| 111 auto addVarToTlsTemplate = [&](GlobalVariable *TlsVar, bool IsBss) { |
| 112 // Add alignment padding if necessary. |
| 113 uint32_t VarAlignment = DL.getPreferredAlignment(TlsVar); |
| 114 if ((CurrentOffset & (VarAlignment - 1)) != 0) { |
| 115 uint32_t PadSize = VarAlignment - (CurrentOffset & (VarAlignment - 1)); |
| 116 CurrentOffset += PadSize; |
| 117 if (!IsBss) { |
| 118 Type *I8 = Type::getInt8Ty(M.getContext()); |
| 119 Type *PadType = ArrayType::get(I8, PadSize); |
| 120 FieldInitValues.push_back(Constant::getNullValue(PadType)); |
| 121 } |
| 122 } |
| 123 if (OverallAlignment < VarAlignment) |
| 124 OverallAlignment = VarAlignment; |
| 125 |
| 126 TlsVarInfo Info; |
| 127 Info.TlsVar = TlsVar; |
| 128 Info.Offset = CurrentOffset; |
| 129 Result->TlsVars.push_back(Info); |
| 130 |
| 131 CurrentOffset += DL.getTypeAllocSize(TlsVar->getType()->getElementType()); |
| 132 if (!IsBss) |
| 133 FieldInitValues.push_back(TlsVar->getInitializer()); |
| 134 }; |
| 152 | 135 |
| 153 for (GlobalVariable &GV : M.globals()) { | 136 for (GlobalVariable &GV : M.globals()) { |
| 154 if (GV.isThreadLocal()) { | 137 if (GV.isThreadLocal()) { |
| 155 if (!GV.hasInitializer()) { | 138 if (!GV.hasInitializer()) { |
| 156 // Since this is a whole-program transformation, "extern" TLS | 139 // Since this is a whole-program transformation, "extern" TLS |
| 157 // variables are not allowed at this point. | 140 // variables are not allowed at this point. |
| 158 report_fatal_error(std::string("TLS variable without an initializer: ") | 141 report_fatal_error(std::string("TLS variable without an initializer: ") |
| 159 + GV.getName()); | 142 + GV.getName()); |
| 160 } | 143 } |
| 161 if (!GV.getInitializer()->isNullValue()) { | 144 if (!GV.getInitializer()->isNullValue()) |
| 162 TlsVarInfo Info; | 145 addVarToTlsTemplate(&GV, /*IsBss=*/ false); |
| 163 Info.TlsVar = &GV; | |
| 164 Info.Offset = addVarToTlsTemplate(&State, &FieldInitValues, &GV); | |
| 165 Result->TlsVars.push_back(Info); | |
| 166 } | |
| 167 } | 146 } |
| 168 } | 147 } |
| 169 Result->DataSize = State.Offset; | 148 Result->DataSize = CurrentOffset; |
| 170 // Handle zero-initialized TLS variables in a second pass, because | 149 // Handle zero-initialized TLS variables in a second pass, because |
| 171 // these should follow non-zero-initialized TLS variables. | 150 // these should follow non-zero-initialized TLS variables. |
| 172 for (GlobalVariable &GV : M.globals()) { | 151 for (GlobalVariable &GV : M.globals()) { |
| 173 if (GV.isThreadLocal() && GV.getInitializer()->isNullValue()) { | 152 if (GV.isThreadLocal() && GV.getInitializer()->isNullValue()) |
| 174 TlsVarInfo Info; | 153 addVarToTlsTemplate(&GV, /*IsBss=*/ true); |
| 175 Info.TlsVar = &GV; | |
| 176 Info.Offset = addVarToTlsTemplate(&State, NULL, &GV); | |
| 177 Result->TlsVars.push_back(Info); | |
| 178 } | |
| 179 } | 154 } |
| 180 Result->TotalSize = State.Offset; | 155 Result->TotalSize = CurrentOffset; |
| 181 Result->Alignment = State.Alignment; | 156 Result->Alignment = OverallAlignment; |
| 182 Result->Data = makeInitStruct(M, FieldInitValues); | 157 Result->Data = makeInitStruct(M, FieldInitValues); |
| 183 } | 158 } |
| 184 | 159 |
| 185 static void adjustToX86StyleLayout(TlsTemplate *Templ) { | 160 static void adjustToX86StyleLayout(TlsTemplate *Templ) { |
| 186 // Add final alignment padding so that | 161 // Add final alignment padding so that |
| 187 // (struct tls_struct *) __nacl_read_tp() - 1 | 162 // (struct tls_struct *) __nacl_read_tp() - 1 |
| 188 // gives the correct, aligned start of the TLS variables given the | 163 // gives the correct, aligned start of the TLS variables given the |
| 189 // x86-style layout we are using. This requires some more bytes to | 164 // x86-style layout we are using. This requires some more bytes to |
| 190 // be memset() to zero at runtime. This wastage doesn't seem | 165 // be memset() to zero at runtime. This wastage doesn't seem |
| 191 // important gives that we're not trying to optimize packing by | 166 // important gives that we're not trying to optimize packing by |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 rewriteTlsVars(M, &Templ.TlsVars); | 301 rewriteTlsVars(M, &Templ.TlsVars); |
| 327 | 302 |
| 328 defineTlsLayoutFunctions(M); | 303 defineTlsLayoutFunctions(M); |
| 329 | 304 |
| 330 return true; | 305 return true; |
| 331 } | 306 } |
| 332 | 307 |
| 333 ModulePass *llvm::createExpandTlsPass() { | 308 ModulePass *llvm::createExpandTlsPass() { |
| 334 return new ExpandTls(); | 309 return new ExpandTls(); |
| 335 } | 310 } |
| OLD | NEW |