brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.1 KiB · c81f018 Raw
176 lines · cpp
1//===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This transformation is required for targets depending on libgcc style10// emulated thread local storage variables. For every defined TLS variable xyz,11// an __emutls_v.xyz is generated. If there is non-zero initialized value12// an __emutls_t.xyz is also generated.13//14//===----------------------------------------------------------------------===//15 16#include "llvm/CodeGen/LowerEmuTLS.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/Analysis/GlobalsModRef.h"19#include "llvm/Analysis/ModuleSummaryAnalysis.h"20#include "llvm/Analysis/StackSafetyAnalysis.h"21#include "llvm/CodeGen/Passes.h"22#include "llvm/CodeGen/TargetPassConfig.h"23#include "llvm/IR/Constants.h"24#include "llvm/IR/Module.h"25#include "llvm/InitializePasses.h"26#include "llvm/Pass.h"27#include "llvm/Target/TargetMachine.h"28 29using namespace llvm;30 31#define DEBUG_TYPE "lower-emutls"32 33namespace {34 35class LowerEmuTLS : public ModulePass {36public:37  static char ID; // Pass identification, replacement for typeid38  LowerEmuTLS() : ModulePass(ID) {39    initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry());40  }41 42  bool runOnModule(Module &M) override;43};44}45 46static bool addEmuTlsVar(Module &M, const GlobalVariable *GV);47 48static void copyLinkageVisibility(Module &M, const GlobalVariable *from,49                                  GlobalVariable *to) {50  to->setLinkage(from->getLinkage());51  to->setVisibility(from->getVisibility());52  to->setDSOLocal(from->isDSOLocal());53  if (from->hasComdat()) {54    to->setComdat(M.getOrInsertComdat(to->getName()));55    to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind());56  }57}58 59PreservedAnalyses LowerEmuTLSPass::run(Module &M, ModuleAnalysisManager &MAM) {60  bool Changed = false;61  SmallVector<const GlobalVariable *, 8> TlsVars;62  for (const auto &G : M.globals()) {63    if (G.isThreadLocal())64      TlsVars.push_back(&G);65  }66  for (const auto *G : TlsVars)67    Changed |= addEmuTlsVar(M, G);68 69  if (!Changed)70    return PreservedAnalyses::all();71  PreservedAnalyses PA = PreservedAnalyses::all();72  PA.abandon<GlobalsAA>();73  PA.abandon<ModuleSummaryIndexAnalysis>();74  PA.abandon<StackSafetyGlobalAnalysis>();75  return PA;76}77 78char LowerEmuTLS::ID = 0;79 80INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE,81                "Add __emutls_[vt]. variables for emultated TLS model", false,82                false)83 84ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); }85 86bool LowerEmuTLS::runOnModule(Module &M) {87  if (skipModule(M))88    return false;89 90  auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();91  if (!TPC)92    return false;93 94  auto &TM = TPC->getTM<TargetMachine>();95  if (!TM.useEmulatedTLS())96    return false;97 98  bool Changed = false;99  SmallVector<const GlobalVariable*, 8> TlsVars;100  for (const auto &G : M.globals()) {101    if (G.isThreadLocal())102      TlsVars.append({&G});103  }104  for (const auto *const G : TlsVars)105    Changed |= addEmuTlsVar(M, G);106  return Changed;107}108 109bool addEmuTlsVar(Module &M, const GlobalVariable *GV) {110  LLVMContext &C = M.getContext();111  PointerType *VoidPtrType = PointerType::getUnqual(C);112 113  std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str();114  GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName);115  if (EmuTlsVar)116    return false;  // It has been added before.117 118  const DataLayout &DL = M.getDataLayout();119  Constant *NullPtr = ConstantPointerNull::get(VoidPtrType);120 121  // Get non-zero initializer from GV's initializer.122  const Constant *InitValue = nullptr;123  if (GV->hasInitializer()) {124    InitValue = GV->getInitializer();125    const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue);126    // When GV's init value is all 0, omit the EmuTlsTmplVar and let127    // the emutls library function to reset newly allocated TLS variables.128    if (isa<ConstantAggregateZero>(InitValue) ||129        (InitIntValue && InitIntValue->isZero()))130      InitValue = nullptr;131  }132 133  // Create the __emutls_v. symbol, whose type has 4 fields:134  //     word size;   // size of GV in bytes135  //     word align;  // alignment of GV136  //     void *ptr;   // initialized to 0; set at run time per thread.137  //     void *templ; // 0 or point to __emutls_t.*138  // sizeof(word) should be the same as sizeof(void*) on target.139  IntegerType *WordType = DL.getIntPtrType(C);140  PointerType *InitPtrType = PointerType::getUnqual(C);141  Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType};142  StructType *EmuTlsVarType = StructType::create(ElementTypes);143  EmuTlsVar = M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType);144  copyLinkageVisibility(M, GV, EmuTlsVar);145 146  // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined.147  if (!GV->hasInitializer())148    return true;149 150  Type *GVType = GV->getValueType();151  Align GVAlignment = DL.getValueOrABITypeAlignment(GV->getAlign(), GVType);152 153  // Define "__emutls_t.*" if there is InitValue154  GlobalVariable *EmuTlsTmplVar = nullptr;155  if (InitValue) {156    std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str();157    EmuTlsTmplVar = M.getOrInsertGlobal(EmuTlsTmplName, GVType);158    assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer");159    EmuTlsTmplVar->setConstant(true);160    EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue));161    EmuTlsTmplVar->setAlignment(GVAlignment);162    copyLinkageVisibility(M, GV, EmuTlsTmplVar);163  }164 165  // Define "__emutls_v.*" with initializer and alignment.166  Constant *ElementValues[4] = {167      ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)),168      ConstantInt::get(WordType, GVAlignment.value()), NullPtr,169      EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr};170  EmuTlsVar->setInitializer(ConstantStruct::get(EmuTlsVarType, ElementValues));171  Align MaxAlignment =172      std::max(DL.getABITypeAlign(WordType), DL.getABITypeAlign(VoidPtrType));173  EmuTlsVar->setAlignment(MaxAlignment);174  return true;175}176