Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,7 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,

for (unsigned i = 0, e = Decls.size(); i != e; ++i)
if (Decls[i]) {
if (getContext().getTargetInfo().getTriple().isCheerpWasm()) {
if (getContext().getTargetInfo().getTriple().isCheerpWasm() && !Guard.isValid()) {
llvm::GlobalVariable *GuardGV = new llvm::GlobalVariable(CGM.getModule(), Int8Ty, /*isConstant=*/false,
llvm::GlobalVariable::InternalLinkage,
llvm::ConstantInt::get(Int8Ty, 0),
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Driver/ToolChains/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,9 @@ void cheerp::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Add standard libraries
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
if (C.getDriver().CCCIsCXX()) {
Arg *Sanitizers = Args.getLastArg(options::OPT_fsanitize_EQ);
// Always run ASAN with libstdlibs
if (C.getDriver().CCCIsCXX() || (Sanitizers && Sanitizers->containsValue("address"))) {
AddStdLib("libstdlibs.bc");
} else {
AddStdLib("libc.bc");
Expand All @@ -602,7 +604,6 @@ void cheerp::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Add wasm helper if needed
Arg *CheerpLinearOutput = Args.getLastArg(options::OPT_cheerp_linear_output_EQ);

Arg *Sanitizers = Args.getLastArg(options::OPT_fsanitize_EQ);
if (Sanitizers && Sanitizers->containsValue("address")) {
AddLateLib("asmjs/libclang_rt.asan-Cheerp.bc");
if (D.CCCIsCXX())
Expand Down
7 changes: 2 additions & 5 deletions compiler-rt/lib/asan/asan_cheerpwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {}

static void (*tsd_destructor)(void *tsd) = nullptr;

// Cheerp: for now we've removed the initializer for tsd_key's constructor.
// It caused a crash in ASAN because the constructor for the global is run after the asan module constructor has already used and set it.
// Originally the global is meant to be a thread_local, but thread_local constructors and destructors are not yet supported.
struct tsd_key {
tsd_key() {}
tsd_key() : key(nullptr) {}
~tsd_key() {
CHECK(tsd_destructor);
if (key)
Expand All @@ -52,7 +49,7 @@ struct tsd_key {
void *key;
};

static /*thread_local*/ struct tsd_key key;
static thread_local struct tsd_key key;

void AsanTSDInit(void (*destructor)(void *tsd)) {
CHECK(!tsd_destructor);
Expand Down
2 changes: 1 addition & 1 deletion libcxxabi/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ endif()
if(CHEERP)
# Remove files which are not currently supported
list(REMOVE_ITEM LIBCXXABI_SOURCES cxa_default_handlers.cpp cxa_exception.cpp cxa_handlers.cpp cxa_exception_storage.cpp cxa_unexpected.cpp cxa_personality.cpp)
list(APPEND LIBCXXABI_SOURCES cxa_cheerp.cpp)
list(APPEND LIBCXXABI_SOURCES cxa_cheerp.cpp cxa_thread_atexit.cpp)
endif()

if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN)
Expand Down
4 changes: 4 additions & 0 deletions libcxxabi/src/cxa_thread_atexit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ extern "C" {
#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
#else
#ifndef __CHEERP__
if (__cxa_thread_atexit_impl) {
return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
} else {
#endif // __CHEERP__
// Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
// one-time initialization and __cxa_atexit() for destruction)
static DtorsManager manager;
Expand All @@ -137,7 +139,9 @@ extern "C" {
dtors = head;

return 0;
#ifndef __CHEERP__
}
#endif // __CHEERP__
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
}

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Cheerp/WasmWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ class CheerpWasmWriter final : public CheerpBaseWriter
void compileSignedInteger(WasmBuffer& code, const llvm::Value* v, bool forComparison);
void compileUnsignedInteger(WasmBuffer& code, const llvm::Value* v);
void compileTypedZero(WasmBuffer& code, const llvm::Type* t);
void compileThreadLocalLoad(WasmBuffer& code, const llvm::GlobalVariable* GV);
static void encodeInst(WasmOpcode opcode, WasmBuffer& code);
static void encodeInst(WasmS32Opcode opcode, int32_t immediate, WasmBuffer& code);
static void encodeInst(WasmS64Opcode opcode, int64_t immediate, WasmBuffer& code);
Expand Down
47 changes: 34 additions & 13 deletions llvm/lib/CheerpUtils/ConstantExprLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target
bool Changed = false;
hasI64 = false;

Module* M = F.getParent();
Function* getThreadLocalAddress = M->getFunction("__getThreadLocalAddress");
DL = &F.getParent()->getDataLayout();

std::set<ConstantExpr*> visitedCE;
Expand Down Expand Up @@ -102,28 +104,55 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target

std::map<ConstantExpr*, Value*> mapCEToValue;
std::map<GlobalValue*, Instruction*> mapGVToInst;
// This is the insert point for the instructionized CEs. We update it so that
// new ones are inserted before earlier ones.
Instruction* ceInsertPt = F.getEntryBlock().getFirstNonPHI();

// 2. Iterate on the collected ConstantExpr, converting them to Instructions
// Note that given the specific order of the visit, operands will be processed later (= will end up dominating their users)
for (ConstantExpr* CE : toBeInstructionized)
{
Instruction* Conv = CE->getAsInstruction();
Conv->insertBefore(ceInsertPt);
ceInsertPt = Conv;
for (auto& O: Conv->operands())
{
// 3. Process non-CE operands if needed. New instructions created
// here go before all the CE instructions
Value* NewC = O.get();
if (auto *GV = dyn_cast<GlobalVariable>(NewC))
{
// In asmjs, addresses of globals are just integers
// Ask LinearMemoryHelper for the value and cast to the pointer type
if (!WasmSharedModule && GV->GlobalValue::getSection() == StringRef("asmjs"))
if (!WasmSharedModule && GV->GlobalValue::getSection() == StringRef("asmjs") && !GV->isThreadLocal())
{
if (mapGVToInst.count(GV) == 0)
auto it = mapGVToInst.find(GV);
if (it == mapGVToInst.end())
{
auto *CI = ConstantInt::get(IntegerType::get(Conv->getContext(), 32), LH->getGlobalVariableAddress(GV));
mapGVToInst[GV] = CastInst::Create(Instruction::IntToPtr, CI, NewC->getType());
it = mapGVToInst.emplace(GV, CastInst::Create(Instruction::IntToPtr, CI, NewC->getType())).first;
// Insert before all the CEs
it->second->insertBefore(F.getEntryBlock().getFirstNonPHI());
}

NewC = mapGVToInst.at(GV);
NewC = it->second;
}
else if (GV->isThreadLocal() && F.getSection() != "asmjs")
{
auto it = mapGVToInst.find(GV);
if (it == mapGVToInst.end())
{
// Insert before all the CEs
Instruction* insertPt = F.getEntryBlock().getFirstNonPHI();
// Access thread locals via the __getThreadLocalAddress wrapper
Type* argTy = GV->getType();
Function* getThreadLocalOffset = Intrinsic::getDeclaration(M, Intrinsic::cheerp_get_threadlocal_offset, argTy);
auto* offset = CallInst::Create(getThreadLocalOffset, {GV}, "tl.offset", insertPt);
Instruction* addr = CallInst::Create(getThreadLocalAddress, {offset}, "tl.addr", insertPt);
if (addr->getType() != GV->getType())
addr = CastInst::CreateBitOrPointerCast(addr, argTy, "tl.cast", insertPt);
it = mapGVToInst.emplace(GV, addr).first;
}
NewC = it->second;
}
}
else if (isa<UndefValue>(NewC) && NewC->getType()->isFloatingPointTy())
Expand All @@ -134,17 +163,9 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target
}
O.set(NewC);
}
Conv->insertBefore(F.getEntryBlock().getFirstNonPHI());
Changed = true;
mapCEToValue[CE] = Conv;
}

// 3. Insert also PtrToIntInst that has been created while folding GV
for (auto& pair : mapGVToInst)
{
pair.second->insertBefore(F.getEntryBlock().getFirstNonPHI());
}

// 4. Actually substitute any ConstantExpr operand with the mapped Instruction (that will be in the Function entry BB)
std::map<ConstantVector*, Value*> mapCVToValue;
for (Instruction& I : instructions(F))
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/CheerpUtils/GlobalDepsAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,15 @@ bool GlobalDepsAnalyzer::runOnModule( llvm::Module & module )
llvm::errs() << "warning: _startPreThread function point not found, and -pthread is linked\n";
}

// Keep the __getThreadLocalAddress function alive if it exists.
llvm::Function* getThreadLocalAddress = module.getFunction("__getThreadLocalAddress");
if (getThreadLocalAddress)
{
extendLifetime(getThreadLocalAddress);
// __getThreadLocalAddress is always tagged asmjs.
asmJSExportedFunctions.insert(getThreadLocalAddress);
}

// Flush out all functions
processEnqueuedFunctions();

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CheerpUtils/TypeOptimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ Function* TypeOptimizer::rewriteIntrinsic(Function* F, FunctionType* FT)
{
case Intrinsic::cheerp_allocate:
case Intrinsic::cheerp_allocate_array:
case Intrinsic::threadlocal_address:
{
Type* localTys[] = { FT->getReturnType()};
newTys.insert(newTys.end(),localTys,localTys+1);
Expand Down
23 changes: 17 additions & 6 deletions llvm/lib/CheerpWriter/CheerpWasmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1379,7 +1379,7 @@ void CheerpWasmWriter::compileGEP(WasmBuffer& code, const llvm::User* gep_inst,
const llvm::Value *p = linearHelper.compileGEP(gep_inst, &gepWriter, &PA);
if(const GlobalVariable* GV = dyn_cast<GlobalVariable>(p))
{
if(WasmSharedModule)
if(WasmSharedModule || GV->isThreadLocal())
gepWriter.addValue(p, 1);
else
gepWriter.addConst(linearHelper.getGlobalVariableAddress(GV));
Expand Down Expand Up @@ -1476,6 +1476,16 @@ void CheerpWasmWriter::compileTypedZero(WasmBuffer& code, const llvm::Type* t)
}
}

void CheerpWasmWriter::compileThreadLocalLoad(WasmBuffer& code, const llvm::GlobalVariable* GV)
{
assert(GV->isThreadLocal());
int32_t offset = linearHelper.getThreadLocalOffset(GV);
encodeInst(WasmU32Opcode::GET_GLOBAL, THREAD_POINTER_GLOBAL, code);
encodeInst(WasmS32Opcode::I32_CONST, offset, code);
encodeInst(WasmOpcode::I32_ADD, code);

}

void CheerpWasmWriter::compileConstantExpr(WasmBuffer& code, const ConstantExpr* ce)
{
switch(ce->getOpcode())
Expand Down Expand Up @@ -1655,6 +1665,10 @@ void CheerpWasmWriter::compileConstant(WasmBuffer& code, const Constant* c, bool
encodeInst(WasmU32Opcode::GET_GLOBAL, it->second, code);
}
}
else if (GV->isThreadLocal())
{
compileThreadLocalLoad(code, GV);
}
else
{
uint32_t address = linearHelper.getGlobalVariableAddress(GV);
Expand Down Expand Up @@ -2090,7 +2104,7 @@ uint32_t CheerpWasmWriter::compileLoadStorePointer(WasmBuffer& code, const Value
auto p = linearHelper.compileGEP(ptrOp, &gepWriter, &PA);
if(const GlobalVariable* GV = dyn_cast<GlobalVariable>(p))
{
if(WasmSharedModule)
if(WasmSharedModule || GV->isThreadLocal())
gepWriter.addValue(p, 1);
else
gepWriter.addConst(linearHelper.getGlobalVariableAddress(GV));
Expand Down Expand Up @@ -3052,10 +3066,7 @@ bool CheerpWasmWriter::compileInlineInstruction(WasmBuffer& code, const Instruct
{
// We encode this as an offset from the thread pointer.
const GlobalVariable *GV = dyn_cast<GlobalVariable>(I.getOperand(0));
int32_t offset = linearHelper.getThreadLocalOffset(GV);
encodeInst(WasmU32Opcode::GET_GLOBAL, THREAD_POINTER_GLOBAL, code);
encodeInst(WasmS32Opcode::I32_CONST, offset, code);
encodeInst(WasmOpcode::I32_ADD, code);
compileThreadLocalLoad(code, GV);
return false;
}
case Intrinsic::cheerp_locals_stack:
Expand Down
Loading