Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify threadlocal_address constraints #87841

Merged
merged 3 commits into from
Apr 9, 2024
Merged

Conversation

MatzeB
Copy link
Contributor

@MatzeB MatzeB commented Apr 5, 2024

Check invariants for llvm.threadlocal.address intrinsic in IR Verifier.

Check invariants for `llvm.threadlocal.address` intrinsic in IR
Verifier.
@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 5, 2024

@AlexVlx the test/Transforms/HipStdPar/unsupported-thread-local-indirect-use.ll does not conform to this verifier check as it uses @llvm.threadlocal.address.p0(addrspacecast ... @tls).

I'm not really sure whether this is a desirable pattern, if so then we should document this as an allowed use case for the threadlocal.address intrinsic or otherwise can we just remove the test here?

@llvmbot
Copy link
Collaborator

llvmbot commented Apr 6, 2024

@llvm/pr-subscribers-mlir-llvm
@llvm/pr-subscribers-mlir
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-ir

Author: Matthias Braun (MatzeB)

Changes

Check invariants for llvm.threadlocal.address intrinsic in IR Verifier.


Full diff: https://github.com/llvm/llvm-project/pull/87841.diff

1 Files Affected:

  • (modified) llvm/lib/IR/Verifier.cpp (+8)
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 64c59914cf2fc2..ac3d13f3d2b057 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -6223,6 +6223,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
           &Call);
     break;
   }
+  case Intrinsic::threadlocal_address: {
+    const Value &Arg0 = *Call.getArgOperand(0);
+    Check(isa<GlobalVariable>(Arg0),
+          "llvm.threadlocal.address first argument must be a GlobalVariable");
+    Check(cast<GlobalVariable>(Arg0).isThreadLocal(),
+          "llvm.threadlocal.address operand isThreadLocal() must no be false");
+    break;
+  }
   };
 
   // Verify that there aren't any unmediated control transfers between funclets.

@AlexVlx
Copy link
Contributor

AlexVlx commented Apr 6, 2024

Hmm, that is an interesting question; whilst I recall having excised this from an actual app, it does look somewhat contrived / bogus looking at it with today's eyes. I think it's fine to XFAIL it so as to not be blocked on it and I will rework it in a future PR, since what it tests is relevant. At a broader scope, LangRef says The first argument is a pointer, which refers to a thread local global., and it seems (to me) that the verifier check is a wee bit more strict, since otherwise a validly AS cast pointer would still meet the LangRef wording. It's unclear if that pattern could ever obtain naturally though, since the intrinsic is overloaded, so perhaps we just need to touch LangRef as well?

@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 6, 2024

It seems code like my #87844 is slightly simpler when it can rely on there only ever being a GlobalVariable. So I'll go and change the language ref.

That said: If this pattern is helpful to support then I can trivially add some loop to skip address space casts in #87844 instead, so this isn't really blocking anything. I was just wondering what the rules are...

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I am a bit concerned that we're going to violate these rules in some transforms (e.g. by creating threadlocal.address of a phi or select), though at least from some cursory testing we seem to already avoid converting intrinsics with constants args into non-constants. I guess we can try this and see whether anything falls out.

@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 8, 2024

LGTM. I am a bit concerned that we're going to violate these rules in some transforms (e.g. by creating threadlocal.address of a phi or select),

Me too, but that is all the more reason to have this verifier IMO

@MatzeB MatzeB merged commit 4a812b5 into llvm:main Apr 9, 2024
5 checks passed
@sbc100
Copy link
Collaborator

sbc100 commented Apr 9, 2024

This seems to have caused a regression when integrating into emscripten today: https://logs.chromium.org/logs/emscripten-releases/buildbucket/cr-buildbucket/8751138098141239841/+/u/Build_Emscripten/stdout

When I run locally I get this:

llvm.threadlocal.address operand isThreadLocal() must no be false
in function __clock
fatal error: error in backend: Broken function found, compilation aborted!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /usr/local/google/home/sbc/dev/wasm/llvm-build/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/usr/local/google/home/sbc/dev/wasm/emscripten/cache/sysroot -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -c -O2 -Wall -fno-unroll-loops -std=c99 -D_XOPEN_SOURCE=700 -Wno-unused-result -Os -fno-inline-functions -fno-builtin -Wno-ignored-attributes -Wno-macro-redefined -Wno-shift-op-parentheses -Wno-string-plus-int -Wno-missing-braces -Wno-logical-op-parentheses -Wno-bitwise-op-parentheses -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unused-label -Wno-pointer-sign -g3 -Werror -I/usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/libc/musl/src/internal -I/usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/libc/musl/src/include -I/usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/libc/musl/include -I/usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/libc -I/usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/pthread /usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/libc/emscripten_time.c -o /usr/local/google/home/sbc/dev/wasm/emscripten/cache/build/libc-debug-tmp/emscripten_time.o
1.	<eof> parser at end of file
2.	Code generation
3.	Running pass 'Function Pass Manager' on module '/usr/local/google/home/sbc/dev/wasm/emscripten/system/lib/libc/emscripten_time.c'.
4.	Running pass 'Module Verifier' on function '@__clock'
 #0 0x00007fc0c998a188 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0x18a188)
 #1 0x00007fc0c9987dfe llvm::sys::RunSignalHandlers() (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0x187dfe)
 #2 0x00007fc0c9989561 llvm::sys::CleanupOnSignal(unsigned long) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0x189561)
 #3 0x00007fc0c98c6557 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) CrashRecoveryContext.cpp:0:0
 #4 0x00007fc0c98c64ef llvm::CrashRecoveryContext::HandleExit(int) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0xc64ef)
 #5 0x00007fc0c9984ad7 llvm::sys::Process::Exit(int, bool) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0x184ad7)
 #6 0x00005571d7549a53 (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/clang+0x10a53)
 #7 0x00007fc0c98d87fc llvm::report_fatal_error(llvm::Twine const&, bool) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0xd87fc)
 #8 0x00007fc0c98d86e6 (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0xd86e6)
 #9 0x00007fc0c9f443f0 void llvm::VerifierSupport::WriteTs<llvm::Instruction*, llvm::MDNode const*>(llvm::Instruction* const&, llvm::MDNode const* const&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMCore.so.19.0git+0x3443f0)
#10 0x00007fc0c9e95a5a llvm::FPPassManager::runOnFunction(llvm::Function&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMCore.so.19.0git+0x295a5a)
#11 0x00007fc0c9e9de62 llvm::FPPassManager::runOnModule(llvm::Module&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMCore.so.19.0git+0x29de62)
#12 0x00007fc0c9e9654f llvm::legacy::PassManagerImpl::run(llvm::Module&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMCore.so.19.0git+0x29654f)
#13 0x00007fc0cdee6ad9 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::__2::unique_ptr<llvm::raw_pwrite_stream, std::__2::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangCodeGen.so.19.0git+0xe6ad9)
#14 0x00007fc0ce33a934 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangCodeGen.so.19.0git+0x53a934)
#15 0x00007fc0c78f3179 clang::ParseAST(clang::Sema&, bool, bool) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/../lib/libclangParse.so.19.0git+0x38179)
#16 0x00007fc0cc54620f clang::FrontendAction::Execute() (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangFrontend.so.19.0git+0x14620f)
#17 0x00007fc0cc4af7ad clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangFrontend.so.19.0git+0xaf7ad)
#18 0x00007fc0cf8776d0 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangFrontendTool.so.19.0git+0x46d0)
#19 0x00005571d7549648 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/clang+0x10648)
#20 0x00005571d754637b ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#21 0x00007fc0cc0d2349 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::__2::optional<llvm::StringRef>>, std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>>*, bool*) const::$_0>(long) Job.cpp:0:0
#22 0x00007fc0c98c6486 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0xc6486)
#23 0x00007fc0cc0d1992 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::__2::optional<llvm::StringRef>>, std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>>*, bool*) const (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangDriver.so.19.0git+0xd1992)
#24 0x00007fc0cc08992c clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangDriver.so.19.0git+0x8992c)
#25 0x00007fc0cc089c1e clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::__2::pair<int, clang::driver::Command const*>>&, bool) const (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangDriver.so.19.0git+0x89c1e)
#26 0x00007fc0cc0ad62f clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::__2::pair<int, clang::driver::Command const*>>&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/../lib/libclangDriver.so.19.0git+0xad62f)
#27 0x00005571d7545660 clang_main(int, char**, llvm::ToolContext const&) (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/clang+0xc660)
#28 0x00005571d75542f7 main (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/clang+0x1b2f7)
#29 0x00007fc0ca8456ca __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#30 0x00007fc0ca845785 call_init ./csu/../csu/libc-start.c:128:20
#31 0x00007fc0ca845785 __libc_start_main ./csu/../csu/libc-start.c:347:5
#32 0x00005571d7543b6a _start (/usr/local/google/home/sbc/dev/wasm/llvm-build/bin/clang+0xab6a)
clang: error: clang frontend command failed with exit code 70 (use -v to see invocation)
clang version 19.0.0git (https://github.com/sbc100/llvm-project 4a812b5912d3149592cae195c9007b05649d9b41)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /usr/local/google/home/sbc/dev/wasm/llvm-build/bin
Build config: +assertions
clang: note: diagnostic msg: 
********************

See:
The source being compiled is https://github.com/emscripten-core/emscripten/blob/main/system/lib/libc/emscripten_time.c

@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 9, 2024

Is this using an unmodified clang/llvm? Is there a way to reproduce on clang trunk (ideally without doing a full chromium build)?

@sbc100
Copy link
Collaborator

sbc100 commented Apr 9, 2024

Yes, this is unmodified llvm. No need to build chromium. This looks like a Wasm specific issue. It can be reproduced by simply compiling https://github.com/emscripten-core/emscripten/blob/main/system/lib/libc/emscripten_time.c with emscripten.

To simplify this I've attached the pre-processed version of that file which you can reproduce this crash with using just: clang -c -target wasm32-unknown-emscripten repro.c
repro.c.gz

@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 9, 2024

So this code clears the ThreadLocal bit and was probably written before the llvm.threadlocal_address intrinsic was introduced: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp#L295

It happens to work anyway by accident, but needs to adjust all users now... let's see how hard that is...

@Dinistro
Copy link
Contributor

Dinistro commented Apr 10, 2024

This seems to also break bitcode backwards compatibility for some of our files. I can currently not provide a reproducer but I might find some time later to do so.

NVM: This might be caused by some custom modifications on our end that lead to illegal intrinsics.

@MatzeB
Copy link
Contributor Author

MatzeB commented Apr 10, 2024

I just noticed that LLVM allows thread-local GlobalAliases so I submitted #88321 for a looser check.

MatzeB added a commit that referenced this pull request Apr 10, 2024
Remove `llvm.threadlocal.address` intrinsic usage when disabling TLS.
This fixes errors revealed by the stricter IR verification introduced in
PR #87841.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants