LLVM 22.0.0git
XCoreLowerThreadLocal.cpp
Go to the documentation of this file.
1//===-- XCoreLowerThreadLocal - Lower thread local 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-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file contains a pass that lowers thread local variables on the
11/// XCore.
12///
13//===----------------------------------------------------------------------===//
14
15#include "XCore.h"
16#include "llvm/IR/Constants.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/Intrinsics.h"
21#include "llvm/IR/IntrinsicsXCore.h"
22#include "llvm/IR/Module.h"
23#include "llvm/IR/ValueHandle.h"
24#include "llvm/Pass.h"
27
28#define DEBUG_TYPE "xcore-lower-thread-local"
29
30using namespace llvm;
31
33 "xcore-max-threads", cl::Optional,
34 cl::desc("Maximum number of threads (for emulation thread-local storage)"),
35 cl::Hidden, cl::value_desc("number"), cl::init(8));
36
37namespace {
38 /// Lowers thread local variables on the XCore. Each thread local variable is
39 /// expanded to an array of n elements indexed by the thread ID where n is the
40 /// fixed number hardware threads supported by the device.
41 struct XCoreLowerThreadLocal : public ModulePass {
42 static char ID;
43
44 XCoreLowerThreadLocal() : ModulePass(ID) {}
45
46 bool lowerGlobal(GlobalVariable *GV);
47
48 bool runOnModule(Module &M) override;
49 };
50}
51
52char XCoreLowerThreadLocal::ID = 0;
53
54INITIALIZE_PASS(XCoreLowerThreadLocal, "xcore-lower-thread-local",
55 "Lower thread local variables", false, false)
56
58 return new XCoreLowerThreadLocal();
59}
60
61static ArrayType *createLoweredType(Type *OriginalType) {
62 return ArrayType::get(OriginalType, MaxThreads);
63}
64
65static Constant *
66createLoweredInitializer(ArrayType *NewType, Constant *OriginalInitializer) {
68 for (unsigned i = 0; i != MaxThreads; ++i) {
69 Elements[i] = OriginalInitializer;
70 }
71 return ConstantArray::get(NewType, Elements);
72}
73
74
76 do {
77 SmallVector<WeakTrackingVH, 8> WUsers(CE->users());
78 llvm::sort(WUsers);
79 WUsers.erase(llvm::unique(WUsers), WUsers.end());
80 while (!WUsers.empty())
81 if (WeakTrackingVH WU = WUsers.pop_back_val()) {
82 if (PHINode *PN = dyn_cast<PHINode>(WU)) {
83 for (int I = 0, E = PN->getNumIncomingValues(); I < E; ++I)
84 if (PN->getIncomingValue(I) == CE) {
85 BasicBlock *PredBB = PN->getIncomingBlock(I);
86 if (PredBB->getTerminator()->getNumSuccessors() > 1)
87 PredBB = SplitEdge(PredBB, PN->getParent());
88 BasicBlock::iterator InsertPos =
89 PredBB->getTerminator()->getIterator();
90 Instruction *NewInst = CE->getAsInstruction();
91 NewInst->insertBefore(*PredBB, InsertPos);
92 PN->setOperand(I, NewInst);
93 }
94 } else if (Instruction *Instr = dyn_cast<Instruction>(WU)) {
95 Instruction *NewInst = CE->getAsInstruction();
96 NewInst->insertBefore(*Instr->getParent(), Instr->getIterator());
97 Instr->replaceUsesOfWith(CE, NewInst);
98 } else {
100 if (!CExpr || !replaceConstantExprOp(CExpr, P))
101 return false;
102 }
103 }
104 } while (CE->hasNUsesOrMore(1)); // We need to check because a recursive
105 // sibling may have used 'CE' when getAsInstruction was called.
106 CE->destroyConstant();
107 return true;
108}
109
112 for (User *U : GV->users())
113 if (!isa<Instruction>(U))
114 WUsers.push_back(WeakTrackingVH(U));
115 while (!WUsers.empty())
116 if (WeakTrackingVH WU = WUsers.pop_back_val()) {
118 if (!CE || !replaceConstantExprOp(CE, P))
119 return false;
120 }
121 return true;
122}
123
124static bool isZeroLengthArray(Type *Ty) {
126 return AT && (AT->getNumElements() == 0);
127}
128
129bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable *GV) {
130 Module *M = GV->getParent();
131 if (!GV->isThreadLocal())
132 return false;
133
134 // Skip globals that we can't lower and leave it for the backend to error.
135 if (!rewriteNonInstructionUses(GV, this) ||
136 !GV->getType()->isSized() || isZeroLengthArray(GV->getType()))
137 return false;
138
139 // Create replacement global.
140 ArrayType *NewType = createLoweredType(GV->getValueType());
141 Constant *NewInitializer = nullptr;
142 if (GV->hasInitializer())
143 NewInitializer = createLoweredInitializer(NewType,
144 GV->getInitializer());
145 GlobalVariable *NewGV =
146 new GlobalVariable(*M, NewType, GV->isConstant(), GV->getLinkage(),
147 NewInitializer, "", nullptr,
148 GlobalVariable::NotThreadLocal,
149 GV->getType()->getAddressSpace(),
151
152 // Update uses.
154 for (User *U : Users) {
156 IRBuilder<> Builder(Inst);
157 Value *ThreadID = Builder.CreateIntrinsic(Intrinsic::xcore_getid, {});
158 Value *Addr = Builder.CreateInBoundsGEP(NewGV->getValueType(), NewGV,
159 {Builder.getInt64(0), ThreadID});
160 U->replaceUsesOfWith(GV, Addr);
161 }
162
163 // Remove old global.
164 NewGV->takeName(GV);
165 GV->eraseFromParent();
166 return true;
167}
168
169bool XCoreLowerThreadLocal::runOnModule(Module &M) {
170 // Find thread local globals.
171 bool MadeChange = false;
172 SmallVector<GlobalVariable *, 16> ThreadLocalGlobals;
173 for (GlobalVariable &GV : M.globals())
174 if (GV.isThreadLocal())
175 ThreadLocalGlobals.push_back(&GV);
176 for (GlobalVariable *GV : ThreadLocalGlobals)
177 MadeChange |= lowerGlobal(GV);
178 return MadeChange;
179}
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Module.h This file contains the declarations for the Module class.
iv Induction Variable Users
Definition IVUsers.cpp:48
#define I(x, y, z)
Definition MD5.cpp:58
Machine Check Debug Module
#define P(N)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool replaceConstantExprOp(ConstantExpr *CE, Pass *P)
static bool isZeroLengthArray(Type *Ty)
static Constant * createLoweredInitializer(ArrayType *NewType, Constant *OriginalInitializer)
static cl::opt< unsigned > MaxThreads("xcore-max-threads", cl::Optional, cl::desc("Maximum number of threads (for emulation thread-local storage)"), cl::Hidden, cl::value_desc("number"), cl::init(8))
static bool rewriteNonInstructionUses(GlobalVariable *GV, Pass *P)
static ArrayType * createLoweredType(Type *OriginalType)
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Definition BasicBlock.h:233
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
A constant value that is initialized with an expression using other constant values.
Definition Constants.h:1120
This is an important base class in LLVM.
Definition Constant.h:43
bool isThreadLocal() const
If the value is "Thread Local", its value isn't shared by the threads.
LinkageTypes getLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
PointerType * getType() const
Global values are always pointers.
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool isExternallyInitialized() const
bool hasInitializer() const
Definitions have initializers, declarations don't.
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
LLVM_ABI void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition Globals.cpp:507
LLVM_ABI unsigned getNumSuccessors() const LLVM_READONLY
Return the number of successors that this instruction has.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
Pass interface - Implemented by all 'passes'.
Definition Pass.h:99
unsigned getAddressSpace() const
Return the address space of the Pointer type.
iterator erase(const_iterator CI)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
Definition Type.h:311
iterator_range< user_iterator > users()
Definition Value.h:426
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:396
Value handle that is nullable, but tries to track the Value.
self_iterator getIterator()
Definition ilist_node.h:134
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
initializer< Ty > init(const Ty &Val)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2078
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:548
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
ModulePass * createXCoreLowerThreadLocalPass()
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:565
LLVM_ABI BasicBlock * SplitEdge(BasicBlock *From, BasicBlock *To, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the edge connecting the specified blocks, and return the newly created basic block between From...