diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 874571c76c63..dd7417c39d0d 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -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), diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index ea86202bad20..4c797024e89a 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -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"); @@ -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()) diff --git a/compiler-rt/lib/asan/asan_cheerpwasm.cpp b/compiler-rt/lib/asan/asan_cheerpwasm.cpp index dc1b47e0f470..59589c8e7866 100644 --- a/compiler-rt/lib/asan/asan_cheerpwasm.cpp +++ b/compiler-rt/lib/asan/asan_cheerpwasm.cpp @@ -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) @@ -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); diff --git a/libcxxabi/src/CMakeLists.txt b/libcxxabi/src/CMakeLists.txt index 7981b5aed4f2..0b5c00bd75bb 100644 --- a/libcxxabi/src/CMakeLists.txt +++ b/libcxxabi/src/CMakeLists.txt @@ -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) diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp index 665f9e55694a..4a616436ba87 100644 --- a/libcxxabi/src/cxa_thread_atexit.cpp +++ b/libcxxabi/src/cxa_thread_atexit.cpp @@ -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; @@ -137,7 +139,9 @@ extern "C" { dtors = head; return 0; +#ifndef __CHEERP__ } +#endif // __CHEERP__ #endif // HAVE___CXA_THREAD_ATEXIT_IMPL } diff --git a/llvm/include/llvm/Cheerp/WasmWriter.h b/llvm/include/llvm/Cheerp/WasmWriter.h index dc8b855752ee..b11c76c647a6 100644 --- a/llvm/include/llvm/Cheerp/WasmWriter.h +++ b/llvm/include/llvm/Cheerp/WasmWriter.h @@ -510,6 +510,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); diff --git a/llvm/lib/CheerpUtils/ConstantExprLowering.cpp b/llvm/lib/CheerpUtils/ConstantExprLowering.cpp index 8ef623140e29..308d9c158736 100644 --- a/llvm/lib/CheerpUtils/ConstantExprLowering.cpp +++ b/llvm/lib/CheerpUtils/ConstantExprLowering.cpp @@ -115,7 +115,7 @@ bool ConstantExprLowering::runOnFunction(Function& F, bool& hasI64, const Target { // 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) { diff --git a/llvm/lib/CheerpUtils/TypeOptimizer.cpp b/llvm/lib/CheerpUtils/TypeOptimizer.cpp index c4f015d0ec2e..04e35219c1eb 100644 --- a/llvm/lib/CheerpUtils/TypeOptimizer.cpp +++ b/llvm/lib/CheerpUtils/TypeOptimizer.cpp @@ -1100,6 +1100,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); diff --git a/llvm/lib/CheerpWriter/CheerpWasmWriter.cpp b/llvm/lib/CheerpWriter/CheerpWasmWriter.cpp index a5f6ea9ccb1e..fae623ff26da 100644 --- a/llvm/lib/CheerpWriter/CheerpWasmWriter.cpp +++ b/llvm/lib/CheerpWriter/CheerpWasmWriter.cpp @@ -1366,7 +1366,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(p)) { - if(WasmSharedModule) + if(WasmSharedModule || GV->isThreadLocal()) gepWriter.addValue(p, 1); else gepWriter.addConst(linearHelper.getGlobalVariableAddress(GV)); @@ -1463,6 +1463,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()) @@ -1642,6 +1652,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); @@ -2077,7 +2091,7 @@ uint32_t CheerpWasmWriter::compileLoadStorePointer(WasmBuffer& code, const Value auto p = linearHelper.compileGEP(ptrOp, &gepWriter, &PA); if(const GlobalVariable* GV = dyn_cast(p)) { - if(WasmSharedModule) + if(WasmSharedModule || GV->isThreadLocal()) gepWriter.addValue(p, 1); else gepWriter.addConst(linearHelper.getGlobalVariableAddress(GV)); @@ -3038,10 +3052,7 @@ bool CheerpWasmWriter::compileInlineInstruction(WasmBuffer& code, const Instruct { // We encode this as an offset from the thread pointer. const GlobalVariable *GV = dyn_cast(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: