https://github.com/aheejin created https://github.com/llvm/llvm-project/pull/213826
When accessing a thread local variable, Clang generates a thread local wrapper function that checks if the variable has been initialized, and if it isn't, initializes it. This is a function call, so if this is within a funclet (i.e., within a `catchpad` or `cleanuppad`), it needs the funclet bundle argument, which was missing before. If it lacks a funclet argument, it will be considered invalid and removed in WinEHPrepare. Fixes https://github.com/emscripten-core/emscripten/issues/27448. >From 5096df7bff2dd74b3a0b6c7b10b0ecafb633235d Mon Sep 17 00:00:00 2001 From: Heejin Ahn <[email protected]> Date: Tue, 4 Aug 2026 03:02:52 +0000 Subject: [PATCH] [WebAssembly] Add funclet bundle to thread local wrapper calls When accessing a thread local variable, Clang generates a thread local wrapper function that checks if the variable has been initialized, and if it isn't, initializes it. This is a function call, so if this is within a funclet (i.e., within a `catchpad` or `cleanuppad`), it needs the funclet bundle argument, which was missing before. If it lacks a funclet argument, it will be considered invalid and removed in WinEHPrepare. Fixes https://github.com/emscripten-core/emscripten/issues/27448. --- clang/lib/CodeGen/ItaniumCXXABI.cpp | 3 ++- clang/test/CodeGenCXX/wasm-eh.cpp | 32 +++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 5c5fefe32c06c..9ff0c37ca77fc 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -3441,7 +3441,8 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD); llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val); - llvm::CallInst *CallVal = CGF.Builder.CreateCall(Wrapper); + llvm::CallInst *CallVal = + CGF.Builder.CreateCall(Wrapper, {}, CGF.getBundlesForFunclet(Wrapper)); CallVal->setCallingConv(Wrapper->getCallingConv()); LValue LV; diff --git a/clang/test/CodeGenCXX/wasm-eh.cpp b/clang/test/CodeGenCXX/wasm-eh.cpp index f243f37ecb435..0b87107e476c7 100644 --- a/clang/test/CodeGenCXX/wasm-eh.cpp +++ b/clang/test/CodeGenCXX/wasm-eh.cpp @@ -41,7 +41,7 @@ void multiple_catches_wo_catch_all() { // CHECK-NEXT: %[[EXN:.*]] = call ptr @llvm.wasm.get.exception(token %[[CATCHPAD]]) // CHECK-NEXT: store ptr %[[EXN]], ptr %exn.slot // CHECK-NEXT: %[[SELECTOR:.*]] = call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]]) -// CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) #7 +// CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) {{.*}} // CHECK-NEXT: %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]] // CHECK-NEXT: br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]] @@ -58,7 +58,7 @@ void multiple_catches_wo_catch_all() { // CHECK-NEXT: br label %[[TRY_CONT_BB:.*]] // CHECK: [[CATCH_FALLTHROUGH_BB]] -// CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTId) #7 +// CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTId) {{.*}} // CHECK-NEXT: %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]] // CHECK-NEXT: br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]] @@ -388,6 +388,34 @@ void noexcept_throw() noexcept { throw 3; } +int get_val() { return 42; } +thread_local int tls = get_val(); + +// CHECK-LABEL: @_Z26tls_wrapper_within_funcletv() +// CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller + +// CHECK: [[CATCHSTART_BB]]: +// CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr null] +// CHECK-NEXT: %[[EXN:.*]] = call ptr @llvm.wasm.get.exception(token %[[CATCHPAD]]) +// CHECK-NEXT: store ptr %[[EXN]], ptr %exn.slot +// CHECK-NEXT: {{.*}} call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]]) +// CHECK-NEXT: br label %[[CATCH_ALL_BB:.*]] + +// CHECK: [[CATCH_ALL_BB]]: +// CHECK-NEXT: %[[EXN_LOAD:.*]] = load ptr, ptr %exn.slot +// CHECK-NEXT: call ptr @__cxa_begin_catch(ptr %[[EXN_LOAD]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] +// CHECK-NEXT: call {{.*}} @_ZTW3tls() [ "funclet"(token %[[CATCHPAD]]) ] + +// Thread-local wrapper calls within a funclet should have a catchpad/cleanuppad +// funclet bundle argument. +int tls_wrapper_within_funclet() { + try { + throw 1; + } catch (...) { + return tls; + } +} + // CATCH-LABEL: define void @_Z14noexcept_throwv() // CHECK: %{{.*}} = cleanuppad within none [] // CHECK-NEXT: call void @_ZSt9terminatev() _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
