-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathThreadLocalLowering.cpp
More file actions
127 lines (112 loc) · 4.16 KB
/
ThreadLocalLowering.cpp
File metadata and controls
127 lines (112 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//===-- ThreadLocalLowering.cpp - Cheerp helper -------------------------===//
//
// Cheerp: The C++ compiler for the Web
//
// This file is distributed under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE.TXT for details.
//
// Copyright 2024-2025 Leaning Technologies
//
//===----------------------------------------------------------------------===//
#include "llvm/Cheerp/ThreadLocalLowering.h"
#include "llvm/Cheerp/GlobalDepsAnalyzer.h"
#include "llvm/Cheerp/LinearMemoryHelper.h"
#include "llvm/Cheerp/InvokeWrapping.h"
#include "llvm/Cheerp/Registerize.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/IRBuilder.h"
using namespace llvm;
namespace cheerp
{
static Function* getOrCreateThreadLocalWrapper(Module* M, GlobalDepsAnalyzer& GDA)
{
Type* i8Ty = IntegerType::getInt8Ty(M->getContext());
Type* i8PtrTy = PointerType::get(i8Ty, 0);
Type* i32Ty = IntegerType::getInt32Ty(M->getContext());
Type* argTy[] = {i32Ty};
FunctionType* fTy = FunctionType::get(i8PtrTy,ArrayRef<Type*>(argTy, 1), false);
Function* wrapper = cast<Function>(M->getOrInsertFunction("__getThreadLocalAddress", fTy).getCallee());
if (!wrapper->empty())
return wrapper;
BasicBlock* entry = BasicBlock::Create(M->getContext(),"entry", wrapper);
IRBuilder<> Builder(entry);
// Get the thread local address.
Function* threadPointerIntrinsic = Intrinsic::getDeclaration(M, Intrinsic::cheerp_get_thread_pointer);
Value* threadPointer = Builder.CreateCall(threadPointerIntrinsic);
// Add the offset argument
Value* offset = wrapper->getArg(0);
Value* address = Builder.CreateAdd(threadPointer, offset);
// Bitcast to a pointer
address = Builder.CreateIntToPtr(address, i8PtrTy);
Builder.CreateRet(address);
wrapper->setSection("asmjs");
GDA.insertAsmJSExport(wrapper);
return wrapper;
}
bool replaceThreadLocalIntrinsicWithFunction(Function& F, GlobalDepsAnalyzer& GDA)
{
Module* M = F.getParent();
bool changed = false;
SmallVector<Instruction*, 8> deleteList;
for (BasicBlock& BB: F)
{
for (Instruction& I: BB)
{
if (isa<IntrinsicInst>(I))
{
IntrinsicInst& II = cast<IntrinsicInst>(I);
Intrinsic::ID intrId = II.getIntrinsicID();
if (intrId == Intrinsic::threadlocal_address)
{
IRBuilder<> Builder(&II);
// Replace call to intrinsic with function
// 1. Use an intrinsic that will be the offset for the threadlocal.
Type* argTy[] = {II.getOperand(0)->getType()};
Function* offsetIntrinsic = Intrinsic::getDeclaration(M, Intrinsic::cheerp_get_threadlocal_offset, argTy);
Value* offset = Builder.CreateCall(offsetIntrinsic, II.getOperand(0));
// 2. Pass this offset to the wasm function that will calculate the address from the thread pointer.
Function* newFunc = getOrCreateThreadLocalWrapper(M, GDA);
Value* newCall = Builder.CreateCall(newFunc, offset);
// 3. Bitcast return code from this function to required type.
Type* origType = II.getType();
if (origType != newCall->getType())
newCall = Builder.CreateBitCast(newCall, origType);
I.replaceAllUsesWith(newCall);
deleteList.push_back(&I);
changed = true;
}
}
}
}
for (Instruction* I: deleteList)
I->eraseFromParent();
return changed;
}
PreservedAnalyses ThreadLocalLoweringInnerPass::run(Function& F, FunctionAnalysisManager& FAM)
{
if (F.getSection() == "asmjs")
return PreservedAnalyses::all();
// Find calls to threadlocal.address intrinsic, replace with calls to function.
bool changed = replaceThreadLocalIntrinsicWithFunction(F, GDA);
if (!changed)
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<PointerAnalysis>();
PA.preserve<RegisterizeAnalysis>();
PA.preserve<GlobalDepsAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<InvokeWrappingAnalysis>();
return PA;
}
PreservedAnalyses ThreadLocalLoweringPass::run(Module& M, ModuleAnalysisManager& MAM)
{
FunctionPassManager FPM;
GlobalDepsAnalyzer& GDA = MAM.getResult<GlobalDepsAnalysis>(M);
FPM.addPass(ThreadLocalLoweringInnerPass(GDA));
ModulePassManager MPM;
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
PreservedAnalyses PA = MPM.run(M, MAM);
return PA;
}
}