From c6cd4608c8c4a5356ae41ef05e67df3dc5d9500b Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 12 Apr 2024 14:10:07 -0700 Subject: [PATCH] IRVerifier: Allow GlobalValue as llvm.threadlocal.address operand (#88321) Loosen `llvm.threadlocal.address` verifier checks to allow any `GlobalValue` with `isThreadLocal()` set to true. --- llvm/docs/LangRef.rst | 3 ++- llvm/lib/IR/Verifier.cpp | 8 +++--- llvm/test/Verifier/threadlocal-pass.ll | 13 ++++++++++ llvm/test/Verifier/threadlocal.ll | 34 ++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 llvm/test/Verifier/threadlocal-pass.ll create mode 100644 llvm/test/Verifier/threadlocal.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index f6ada292b93b1..9592929d79feb 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -28130,7 +28130,8 @@ Syntax: Arguments: """""""""" -The first argument is a thread local :ref:`global variable `. +The `llvm.threadlocal.address` intrinsic requires a global value argument (a +:ref:`global variable ` or alias) that is thread local. Semantics: """""""""" diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 4092f0cb12ffe..25cb99f0f9bd8 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -6226,10 +6226,10 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { } case Intrinsic::threadlocal_address: { const Value &Arg0 = *Call.getArgOperand(0); - Check(isa(Arg0), - "llvm.threadlocal.address first argument must be a GlobalVariable"); - Check(cast(Arg0).isThreadLocal(), - "llvm.threadlocal.address operand isThreadLocal() must no be false"); + Check(isa(Arg0), + "llvm.threadlocal.address first argument must be a GlobalValue"); + Check(cast(Arg0).isThreadLocal(), + "llvm.threadlocal.address operand isThreadLocal() must be true"); break; } }; diff --git a/llvm/test/Verifier/threadlocal-pass.ll b/llvm/test/Verifier/threadlocal-pass.ll new file mode 100644 index 0000000000000..0cee4af824397 --- /dev/null +++ b/llvm/test/Verifier/threadlocal-pass.ll @@ -0,0 +1,13 @@ +; RUN: opt -passes=verify -S < %s | FileCheck %s + +@var = thread_local global i32 0 +@alias = thread_local alias i32, ptr @var + +; CHECK-LABEL: @should_pass +define void @should_pass() { + %p0 = call ptr @llvm.threadlocal.address(ptr @var) + store i32 42, ptr %p0, align 4 + %p1 = call ptr @llvm.threadlocal.address(ptr @alias) + store i32 13, ptr %p1, align 4 + ret void +} diff --git a/llvm/test/Verifier/threadlocal.ll b/llvm/test/Verifier/threadlocal.ll new file mode 100644 index 0000000000000..8af23c361cc4b --- /dev/null +++ b/llvm/test/Verifier/threadlocal.ll @@ -0,0 +1,34 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +@var = global i32 0 +@tlsvar = thread_local addrspace(1) global i32 0 + +define void @fail0(ptr %arg) { +; CHECK: llvm.threadlocal.address first argument must be a GlobalValue + %p0 = call ptr @llvm.threadlocal.address(ptr %arg) + store i32 42, ptr %p0, align 4 + ret void +} + +define void @fail1() { +; CHECK: llvm.threadlocal.address first argument must be a GlobalValue + %p0 = call ptr @llvm.threadlocal.address.p0(ptr addrspacecast (ptr addrspace(1) @tlsvar to ptr addrspace(0))) + store i32 42, ptr %p0, align 4 + ret void +} + + + +define void @fail2() { +; CHECK: llvm.threadlocal.address operand isThreadLocal() must be true + %p0 = call ptr @llvm.threadlocal.address(ptr @var) + store i32 42, ptr %p0, align 4 + ret void +} + +define void @fail3() { +; CHECK: llvm.threadlocal.address operand isThreadLocal() must be true + %p0 = call ptr @llvm.threadlocal.address(ptr @fail2) + store i32 42, ptr %p0, align 4 + ret void +}