This is an archive of the discontinued LLVM Phabricator instance.

[WebAssembly] Make EH/SjLj vars unconditionally thread local
ClosedPublic

Authored by aheejin on Feb 16 2022, 11:34 PM.

Details

Summary

This makes three thread local variables (__THREW__, __threwValue,
and __wasm_lpad_context) unconditionally thread local. If the target
doesn't support TLS, they will be downgraded to normal variables in
stripThreadLocals. This makes the object not linkable with other
objects using shared memory, which is what we intend here; these
variables should be thread local when used with shared memory. This is
what we initially tried in D88262.

But D88323 changed this: It only created these variables when threads
were supported, because __THREW__ and __threwValue were always
generated even if Emscripten EH/SjLj was not used, making all objects
built without threads not linkable with shared memory, which was too
restrictive. But sometimes this is not safe. If we build an object using
variables such as __THREW__ without threads, it can be linked to other
objects using shared memory, because the original object's __THREW__
was not created thread local to begin with.

So this CL basically reverts D88323 with some additional improvements:

  • This checks each of the functions and global variables created within LowerEmscriptenEHSjLj pass and removes it if it's not used at the end of the pass. So only modules using those variables will be affected.
  • Moves CoalesceFeaturesAndStripAtomics and AtomicExpand passes after all other IR pasess that can create thread local variables. It is not sufficient to move them to the end of addIRPasses, because __wasm_lpad_context is created in WasmEHPrepare, which runs inside addPassesToHandleExceptions, which runs before addISelPrepare. So we override addISelPrepare and move atomic/TLS stripping and expanding passes there.

This also removes merges TLS and NO-TLS FileCheck lines into one
CHECK line, because in the bitcode level we always create them as
thread local. Also some function declarations are deleted CHECK lines
because they are unused.

Diff Detail

Event Timeline

aheejin created this revision.Feb 16 2022, 11:34 PM
aheejin requested review of this revision.Feb 16 2022, 11:34 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 16 2022, 11:34 PM
aheejin edited the summary of this revision. (Show Details)Feb 16 2022, 11:39 PM
aheejin added inline comments.Feb 16 2022, 11:42 PM
llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
1823

Drive-by fix

llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll
13

I changed this i32 to [[PTR]] in D119800 by mistake; this variable is always i32.

Can you verify that the core2 and other emscripten test suites both pass with this change

llvm/lib/CodeGen/WasmEHPrepare.cpp
221–222

I was expecting to see LPadContextGV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel); here...

tlively accepted this revision.Feb 17 2022, 12:23 PM
tlively added inline comments.
llvm/lib/CodeGen/WasmEHPrepare.cpp
221–222

It's there on the next line!

llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
1073–1077

Could we combine these two loops into one to avoid the need for the lambda?

This revision is now accepted and ready to land.Feb 17 2022, 12:23 PM
aheejin updated this revision to Diff 409756.Feb 17 2022, 12:54 PM

Remove lambda

aheejin added inline comments.Feb 17 2022, 12:59 PM
llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
1073–1077

I tried that, but it errors out saying

error: deduced conflicting types ('llvm::GlobalVariable *' vs 'llvm::Function *') for initializer list element type

I tried

for (GlobalValue *V : { ... } ))

too. (GlobalValue is a superclass of GlobalVariable and Function) It errors out the same.

By the way even though we need two loops we may not need the lambda, given that it's only two lines. I made the lambda when I wasn't using a loop so I was doing same thing like 8 times, and I changed it to the loop, but forgot to remove the lambda.

Can you verify that the core2 and other emscripten test suites both pass with this change

test_source_map and test_source_map_minimal_runtime failed in core2, and test_system_include_paths failed in other, but looking at the errors they don't seem to be related to this. Why they error I'm not sure; maybe because of my local machine settings or something. Others all ran OK.

sbc100 accepted this revision.Feb 17 2022, 2:31 PM

Can you verify that the core2 and other emscripten test suites both pass with this change

test_source_map and test_source_map_minimal_runtime failed in core2, and test_system_include_paths failed in other, but looking at the errors they don't seem to be related to this. Why they error I'm not sure; maybe because of my local machine settings or something. Others all ran OK.

As long as you verify that those test also fail with llvm ToT then that could be fine. We might want to figure out what is going on with your setup but that sounds like a different issue.

Yes, all three also fail with LLVM ToT.

core2.test_source_map and core2.test_source_map_minimal_runtime crashes with:

/usr/local/google/home/aheejin/emscripten/tests/sourcemap2json.js:15
new SourceMapConsumer(fs.readFileSync(process.argv[2], 'utf-8')).then((consumer) => {
                                                                 ^

TypeError: (intermediate value).then is not a function
    at Object.<anonymous> (/usr/local/google/home/aheejin/emscripten/tests/sourcemap2json.js:15:66)
    at Module._compile (node:internal/modules/cjs/loader:1097:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1151:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47
Thrown at:
    at /usr/local/google/home/aheejin/emscripten/tests/sourcemap2json.js:15:66
    at Module._compile (node:internal/modules/cjs/loader:1097:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1151:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Module._load (node:internal/modules/cjs/loader:822:12)
    at executeUserEntryPoint (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.5.0
-- end program output --
FAIL

In case of other.test_system_include_paths, the output is different:

--- expected
+++ actual
@@ -1 +1 @@
-/usr/local/google/home/aheejin/emscripten/system
+/usr/local/google/home/aheejin/local/include

In case you have a clue off the top of your head I'd appreciate that. I'll land this then.

This revision was landed with ongoing or failed builds.Feb 17 2022, 4:04 PM
This revision was automatically updated to reflect the committed changes.

For the source map failure.. have you run npm install recently?

Oh that fixed my error. Thanks!