[llvm] [SPIR-V] Fix lowering of declarations with hidden visibility (PR #185029)

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 10 15:03:37 PDT 2026


https://github.com/MrSidims updated https://github.com/llvm/llvm-project/pull/185029

>From 90f9140ebdf715a0476e64fb00de4b83905236c3 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 6 Mar 2026 16:36:38 +0100
Subject: [PATCH 1/8] [SPIR-V] Fix lowering of declarations with hidden
 visibility

They should be translated to SPIR-V and have Import linkage (unless
they are Interface variables).

Also add a test for protected visibility.
---
 .../SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp     |  3 ++
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          | 16 ++++++++--
 .../SPIRV/linkage/hidden-interface-vars.ll    | 25 +++++++++++++++
 .../SPIRV/linkage/hidden-visibility.ll        | 32 +++++++++++++++++++
 .../SPIRV/linkage/protected-visibility.ll     | 26 +++++++++++++++
 5 files changed, 100 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll

diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp
index 800bf2297fa7b..3f0a4c2eb5c76 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp
@@ -27,6 +27,9 @@ SPIRVMCAsmInfo::SPIRVMCAsmInfo(const Triple &TT,
   CodePointerSize = 4;
   CommentString = ";";
   HasFunctionAlignment = false;
+
+  HiddenDeclarationVisibilityAttr = HiddenVisibilityAttr = MCSA_Invalid;
+  ProtectedVisibilityAttr = MCSA_Invalid;
 }
 
 bool SPIRVMCAsmInfo::shouldOmitSectionDirective(StringRef SectionName) const {
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 7858f7f932a46..4a49bbd1164bf 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -1197,11 +1197,23 @@ Type *reconstitutePeeledArrayType(Type *Ty) {
 
 std::optional<SPIRV::LinkageType::LinkageType>
 getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) {
-  if (GV.hasLocalLinkage() || GV.hasHiddenVisibility())
+  if (GV.hasLocalLinkage())
     return std::nullopt;
 
-  if (GV.isDeclarationForLinker())
+  if (GV.isDeclarationForLinker()) {
+    // Interface variables mustn't not get Import linkage.
+    if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
+      auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST);
+      if (SC == SPIRV::StorageClass::Input ||
+          SC == SPIRV::StorageClass::Output ||
+          SC == SPIRV::StorageClass::PushConstant)
+        return std::nullopt;
+    }
     return SPIRV::LinkageType::Import;
+  }
+
+  if (GV.hasHiddenVisibility())
+    return std::nullopt;
 
   if (GV.hasLinkOnceODRLinkage() &&
       ST.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr))
diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
new file mode 100644
index 0000000000000..29fa5cdf41ac1
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
@@ -0,0 +1,25 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-pixel %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-pixel %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
+; Check that interface variables (Input, Output, PushConstant) do not get
+; Import linkage even when declared as external hidden.
+
+; CHECK-NOT: OpCapability Linkage
+; CHECK-NOT: LinkageAttributes
+
+ at input_var = external hidden addrspace(7) global <4 x float>
+ at output_var = external hidden addrspace(8) global <4 x float>
+
+; CHECK-DAG: %[[#INPUT_TYPE:]] = OpTypePointer Input %[[#FLOAT4:]]
+; CHECK-DAG: %[[#OUTPUT_TYPE:]] = OpTypePointer Output %[[#FLOAT4]]
+; CHECK-DAG: %[[#INPUT_VAR:]] = OpVariable %[[#INPUT_TYPE]] Input
+; CHECK-DAG: %[[#OUTPUT_VAR:]] = OpVariable %[[#OUTPUT_TYPE]] Output
+
+define void @main() #0 {
+entry:
+  %val = load <4 x float>, ptr addrspace(7) @input_var
+  store <4 x float> %val, ptr addrspace(8) @output_var
+  ret void
+}
+
+attributes #0 = { "hlsl.shader"="pixel" }
diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
new file mode 100644
index 0000000000000..de3ef5dc3277f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
@@ -0,0 +1,32 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Check that hidden visibility does not cause a crash and that hidden
+; declarations get Import linkage while hidden definitions do not.
+
+; CHECK-DAG: OpName %[[#HIDDEN_HELPER:]] "hidden_helper"
+; CHECK-DAG: OpName %[[#HIDDEN_DEF:]] "hidden_def"
+; CHECK-DAG: OpName %[[#HIDDEN_VAR:]] "hidden_leaf_var"
+; CHECK-DAG: OpName %[[#KERN:]] "test_kernel"
+
+; CHECK-DAG: OpDecorate %[[#HIDDEN_HELPER]] LinkageAttributes "hidden_helper" Import
+; CHECK-DAG: OpDecorate %[[#HIDDEN_VAR]] LinkageAttributes "hidden_leaf_var" Import
+; CHECK-NOT: OpDecorate %[[#HIDDEN_DEF]] LinkageAttributes
+
+ at hidden_leaf_var = external hidden addrspace(1) global i32
+
+declare hidden spir_func void @hidden_helper(ptr addrspace(1))
+
+define hidden spir_func void @hidden_def(ptr addrspace(1) %x) {
+entry:
+  ret void
+}
+
+define spir_kernel void @test_kernel(ptr addrspace(1) %data) {
+entry:
+  %val = load i32, ptr addrspace(1) @hidden_leaf_var
+  store i32 %val, ptr addrspace(1) %data
+  call spir_func void @hidden_helper(ptr addrspace(1) %data)
+  call spir_func void @hidden_def(ptr addrspace(1) %data)
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
new file mode 100644
index 0000000000000..41e973ed269d6
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
@@ -0,0 +1,26 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Check that protected visibility does not cause a crash, that protected
+; declarations get Import linkage, and protected definitions get Export.
+
+; CHECK-DAG: OpName %[[#PROTECTED_DECL:]] "protected_decl"
+; CHECK-DAG: OpName %[[#PROTECTED_DEF:]] "protected_def"
+; CHECK-DAG: OpName %[[#KERN:]] "test_kernel"
+
+; CHECK-DAG: OpDecorate %[[#PROTECTED_DECL]] LinkageAttributes "protected_decl" Import
+; CHECK-DAG: OpDecorate %[[#PROTECTED_DEF]] LinkageAttributes "protected_def" Export
+
+declare protected spir_func void @protected_decl(ptr addrspace(1))
+
+define protected spir_func void @protected_def(ptr addrspace(1) %x) {
+entry:
+  ret void
+}
+
+define spir_kernel void @test_kernel(ptr addrspace(1) %data) {
+entry:
+  call spir_func void @protected_decl(ptr addrspace(1) %data)
+  call spir_func void @protected_def(ptr addrspace(1) %data)
+  ret void
+}

>From 5e7f0f2f6397e962d8d8c96c9ab1a38809f76892 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 6 Mar 2026 18:01:59 +0100
Subject: [PATCH 2/8] add decorations to make validator happy

---
 llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
index 29fa5cdf41ac1..bb3f7c3c4ec65 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
@@ -7,8 +7,8 @@
 ; CHECK-NOT: OpCapability Linkage
 ; CHECK-NOT: LinkageAttributes
 
- at input_var = external hidden addrspace(7) global <4 x float>
- at output_var = external hidden addrspace(8) global <4 x float>
+ at input_var = external hidden addrspace(7) global <4 x float>, !spirv.Decorations !0
+ at output_var = external hidden addrspace(8) global <4 x float>, !spirv.Decorations !2
 
 ; CHECK-DAG: %[[#INPUT_TYPE:]] = OpTypePointer Input %[[#FLOAT4:]]
 ; CHECK-DAG: %[[#OUTPUT_TYPE:]] = OpTypePointer Output %[[#FLOAT4]]
@@ -23,3 +23,8 @@ entry:
 }
 
 attributes #0 = { "hlsl.shader"="pixel" }
+
+!0 = !{!1}
+!1 = !{i32 30, i32 0}   ; Location 0
+!2 = !{!3}
+!3 = !{i32 30, i32 1}   ; Location 1

>From c737e6282bd7c88f6b49022e8b42d4ae5748cfe5 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Mon, 9 Mar 2026 20:50:16 +0100
Subject: [PATCH 3/8] add vulkan tests

---
 .../SPIRV/linkage/hidden-interface-vars.ll    |  8 ++++-
 .../SPIRV/linkage/hidden-visibility.ll        | 32 +++++++++++++++----
 .../SPIRV/linkage/protected-visibility.ll     | 30 ++++++++++++++---
 3 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
index bb3f7c3c4ec65..4b156bf5cbda9 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-interface-vars.ll
@@ -7,18 +7,24 @@
 ; CHECK-NOT: OpCapability Linkage
 ; CHECK-NOT: LinkageAttributes
 
+%struct.PC = type <{ float }>
+
 @input_var = external hidden addrspace(7) global <4 x float>, !spirv.Decorations !0
 @output_var = external hidden addrspace(8) global <4 x float>, !spirv.Decorations !2
+ at push_const = external hidden addrspace(13) externally_initialized global %struct.PC, align 1
 
 ; CHECK-DAG: %[[#INPUT_TYPE:]] = OpTypePointer Input %[[#FLOAT4:]]
 ; CHECK-DAG: %[[#OUTPUT_TYPE:]] = OpTypePointer Output %[[#FLOAT4]]
 ; CHECK-DAG: %[[#INPUT_VAR:]] = OpVariable %[[#INPUT_TYPE]] Input
 ; CHECK-DAG: %[[#OUTPUT_VAR:]] = OpVariable %[[#OUTPUT_TYPE]] Output
+; CHECK-DAG: %[[#PC_VAR:]] = OpVariable %[[#]] PushConstant
 
 define void @main() #0 {
 entry:
   %val = load <4 x float>, ptr addrspace(7) @input_var
-  store <4 x float> %val, ptr addrspace(8) @output_var
+  %pc = load float, ptr addrspace(13) @push_const
+  %ins = insertelement <4 x float> %val, float %pc, i32 0
+  store <4 x float> %ins, ptr addrspace(8) @output_var
   ret void
 }
 
diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
index de3ef5dc3277f..69116df9062b9 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
@@ -1,18 +1,21 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-
 ; Check that hidden visibility does not cause a crash and that hidden
 ; declarations get Import linkage while hidden definitions do not.
 
+; RUN: split-file %s %t
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - -filetype=obj | spirv-val %}
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
 ; CHECK-DAG: OpName %[[#HIDDEN_HELPER:]] "hidden_helper"
 ; CHECK-DAG: OpName %[[#HIDDEN_DEF:]] "hidden_def"
-; CHECK-DAG: OpName %[[#HIDDEN_VAR:]] "hidden_leaf_var"
-; CHECK-DAG: OpName %[[#KERN:]] "test_kernel"
 
 ; CHECK-DAG: OpDecorate %[[#HIDDEN_HELPER]] LinkageAttributes "hidden_helper" Import
-; CHECK-DAG: OpDecorate %[[#HIDDEN_VAR]] LinkageAttributes "hidden_leaf_var" Import
 ; CHECK-NOT: OpDecorate %[[#HIDDEN_DEF]] LinkageAttributes
 
+;--- opencl.ll
 @hidden_leaf_var = external hidden addrspace(1) global i32
 
 declare hidden spir_func void @hidden_helper(ptr addrspace(1))
@@ -30,3 +33,20 @@ entry:
   call spir_func void @hidden_def(ptr addrspace(1) %data)
   ret void
 }
+
+;--- vulkan.ll
+declare hidden void @hidden_helper()
+
+define hidden void @hidden_def() {
+entry:
+  ret void
+}
+
+define void @main() #0 {
+entry:
+  call void @hidden_helper()
+  call void @hidden_def()
+  ret void
+}
+
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
index 41e973ed269d6..28575ce2c3fdb 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
@@ -1,16 +1,21 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-
 ; Check that protected visibility does not cause a crash, that protected
 ; declarations get Import linkage, and protected definitions get Export.
 
+; RUN: split-file %s %t
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - -filetype=obj | spirv-val %}
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
 ; CHECK-DAG: OpName %[[#PROTECTED_DECL:]] "protected_decl"
 ; CHECK-DAG: OpName %[[#PROTECTED_DEF:]] "protected_def"
-; CHECK-DAG: OpName %[[#KERN:]] "test_kernel"
 
 ; CHECK-DAG: OpDecorate %[[#PROTECTED_DECL]] LinkageAttributes "protected_decl" Import
 ; CHECK-DAG: OpDecorate %[[#PROTECTED_DEF]] LinkageAttributes "protected_def" Export
 
+;--- opencl.ll
 declare protected spir_func void @protected_decl(ptr addrspace(1))
 
 define protected spir_func void @protected_def(ptr addrspace(1) %x) {
@@ -24,3 +29,20 @@ entry:
   call spir_func void @protected_def(ptr addrspace(1) %data)
   ret void
 }
+
+;--- vulkan.ll
+declare protected void @protected_decl()
+
+define protected void @protected_def() {
+entry:
+  ret void
+}
+
+define void @main() #0 {
+entry:
+  call void @protected_decl()
+  call void @protected_def()
+  ret void
+}
+
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }

>From 5576d5660bae202d56bd01d204e97f6b83d437b9 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Mon, 9 Mar 2026 20:51:45 +0100
Subject: [PATCH 4/8] fix typo

---
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 4a49bbd1164bf..4a25886614098 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -1201,7 +1201,7 @@ getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) {
     return std::nullopt;
 
   if (GV.isDeclarationForLinker()) {
-    // Interface variables mustn't not get Import linkage.
+    // Interface variables must not get Import linkage.
     if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
       auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST);
       if (SC == SPIRV::StorageClass::Input ||

>From adba0a74a1c5c5a9c6ea606e6f93cc5f975ccb42 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Tue, 10 Mar 2026 00:42:18 +0100
Subject: [PATCH 5/8] fix linkage on no-lib vulkan

---
 llvm/lib/Target/SPIRV/SPIRVSubtarget.h        |  5 +++
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  5 +++
 .../SPIRV/linkage/hidden-visibility.ll        | 32 +++++++++++++++----
 .../SPIRV/linkage/protected-visibility.ll     | 30 ++++++++++++++---
 4 files changed, 61 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
index 1b14a89695f59..a884e9783b67c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
@@ -86,6 +86,11 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
   SPIRVEnvType getEnv() const { return Env; }
   bool isKernel() const { return getEnv() == Kernel; }
   bool isShader() const { return getEnv() == Shader; }
+  // Returns true if this is a shader library module.
+  bool isShaderLibrary() const {
+    return isShader() && (!TargetTriple.isShaderStageEnvironment() ||
+                          TargetTriple.getEnvironment() == Triple::Library);
+  }
   bool isLogicalSPIRV() const {
     return TargetTriple.getArch() == Triple::spirv;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 4a25886614098..7e2fd911b1774 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -1200,6 +1200,11 @@ getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) {
   if (GV.hasLocalLinkage())
     return std::nullopt;
 
+  // Shader targets do not support the Linkage capability unless the module
+  // is a shader library.
+  if (ST.isShader() && !ST.isShaderLibrary())
+    return std::nullopt;
+
   if (GV.isDeclarationForLinker()) {
     // Interface variables must not get Import linkage.
     if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
index 69116df9062b9..f7763c2aa291a 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
@@ -1,20 +1,28 @@
 ; Check that hidden visibility does not cause a crash and that hidden
-; declarations get Import linkage while hidden definitions do not.
+; declarations get Import linkage while hidden definitions do not for
+; environments that have Linkage capability. For environments without Linkage
+; support - no LinkageAttributes is expected.
 
 ; RUN: split-file %s %t
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s --check-prefix=CHECK
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s --check-prefix=VULKAN
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
 
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - | FileCheck %s --check-prefix=CHECK
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - -filetype=obj | spirv-val %}
+
 ; CHECK-DAG: OpName %[[#HIDDEN_HELPER:]] "hidden_helper"
 ; CHECK-DAG: OpName %[[#HIDDEN_DEF:]] "hidden_def"
 
 ; CHECK-DAG: OpDecorate %[[#HIDDEN_HELPER]] LinkageAttributes "hidden_helper" Import
 ; CHECK-NOT: OpDecorate %[[#HIDDEN_DEF]] LinkageAttributes
 
+; VULKAN-NOT: OpCapability Linkage
+; VULKAN-NOT: LinkageAttributes
+
 ;--- opencl.ll
 @hidden_leaf_var = external hidden addrspace(1) global i32
 
@@ -35,8 +43,6 @@ entry:
 }
 
 ;--- vulkan.ll
-declare hidden void @hidden_helper()
-
 define hidden void @hidden_def() {
 entry:
   ret void
@@ -44,9 +50,23 @@ entry:
 
 define void @main() #0 {
 entry:
-  call void @hidden_helper()
   call void @hidden_def()
   ret void
 }
 
 attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+
+;--- vulkan-lib.ll
+declare hidden void @hidden_helper()
+
+define hidden void @hidden_def() {
+entry:
+  ret void
+}
+
+define void @caller() {
+entry:
+  call void @hidden_helper()
+  call void @hidden_def()
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
index 28575ce2c3fdb..6ceba05567e8e 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
@@ -1,20 +1,28 @@
 ; Check that protected visibility does not cause a crash, that protected
 ; declarations get Import linkage, and protected definitions get Export.
+; If environment doesn't support Linkage capability - ensure, that no
+; LinkageAttributes is emitted.
 
 ; RUN: split-file %s %t
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s --check-prefix=CHECK
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s --check-prefix=VULKAN
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
 
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - | FileCheck %s --check-prefix=CHECK
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - -filetype=obj | spirv-val %}
+
 ; CHECK-DAG: OpName %[[#PROTECTED_DECL:]] "protected_decl"
 ; CHECK-DAG: OpName %[[#PROTECTED_DEF:]] "protected_def"
 
 ; CHECK-DAG: OpDecorate %[[#PROTECTED_DECL]] LinkageAttributes "protected_decl" Import
 ; CHECK-DAG: OpDecorate %[[#PROTECTED_DEF]] LinkageAttributes "protected_def" Export
 
+; VULKAN-NOT: OpCapability Linkage
+; VULKAN-NOT: LinkageAttributes
+
 ;--- opencl.ll
 declare protected spir_func void @protected_decl(ptr addrspace(1))
 
@@ -31,8 +39,6 @@ entry:
 }
 
 ;--- vulkan.ll
-declare protected void @protected_decl()
-
 define protected void @protected_def() {
 entry:
   ret void
@@ -40,9 +46,23 @@ entry:
 
 define void @main() #0 {
 entry:
-  call void @protected_decl()
   call void @protected_def()
   ret void
 }
 
 attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+
+;--- vulkan-lib.ll
+declare protected void @protected_decl()
+
+define protected void @protected_def() {
+entry:
+  ret void
+}
+
+define void @caller() {
+entry:
+  call void @protected_decl()
+  call void @protected_def()
+  ret void
+}

>From 43e2fbf627504a78839ff444ee7a3ef40faff169 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Tue, 10 Mar 2026 22:05:35 +0100
Subject: [PATCH 6/8] remove is shader lib check

---
 llvm/lib/Target/SPIRV/SPIRVSubtarget.h        |  5 -----
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  5 -----
 .../SPIRV/linkage/hidden-visibility.ll        | 19 +++++++++----------
 .../SPIRV/linkage/protected-visibility.ll     | 17 ++++++++---------
 4 files changed, 17 insertions(+), 29 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
index a884e9783b67c..1b14a89695f59 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
@@ -86,11 +86,6 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
   SPIRVEnvType getEnv() const { return Env; }
   bool isKernel() const { return getEnv() == Kernel; }
   bool isShader() const { return getEnv() == Shader; }
-  // Returns true if this is a shader library module.
-  bool isShaderLibrary() const {
-    return isShader() && (!TargetTriple.isShaderStageEnvironment() ||
-                          TargetTriple.getEnvironment() == Triple::Library);
-  }
   bool isLogicalSPIRV() const {
     return TargetTriple.getArch() == Triple::spirv;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 7e2fd911b1774..4a25886614098 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -1200,11 +1200,6 @@ getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) {
   if (GV.hasLocalLinkage())
     return std::nullopt;
 
-  // Shader targets do not support the Linkage capability unless the module
-  // is a shader library.
-  if (ST.isShader() && !ST.isShaderLibrary())
-    return std::nullopt;
-
   if (GV.isDeclarationForLinker()) {
     // Interface variables must not get Import linkage.
     if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
index f7763c2aa291a..ef0e214544970 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
@@ -1,17 +1,16 @@
 ; Check that hidden visibility does not cause a crash and that hidden
-; declarations get Import linkage while hidden definitions do not for
-; environments that have Linkage capability. For environments without Linkage
-; support - no LinkageAttributes is expected.
+; declarations get Import linkage while hidden definitions do not.
 
 ; RUN: split-file %s %t
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s --check-prefix=CHECK
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s --check-prefix=VULKAN
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s
+; FIXME: re-enable validator check when spirv-val allows Linkage in vulkan env.
+; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - | FileCheck %s --check-prefix=CHECK
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - | FileCheck %s
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - -filetype=obj | spirv-val %}
 
 ; CHECK-DAG: OpName %[[#HIDDEN_HELPER:]] "hidden_helper"
@@ -20,9 +19,6 @@
 ; CHECK-DAG: OpDecorate %[[#HIDDEN_HELPER]] LinkageAttributes "hidden_helper" Import
 ; CHECK-NOT: OpDecorate %[[#HIDDEN_DEF]] LinkageAttributes
 
-; VULKAN-NOT: OpCapability Linkage
-; VULKAN-NOT: LinkageAttributes
-
 ;--- opencl.ll
 @hidden_leaf_var = external hidden addrspace(1) global i32
 
@@ -43,6 +39,8 @@ entry:
 }
 
 ;--- vulkan.ll
+declare hidden void @hidden_helper()
+
 define hidden void @hidden_def() {
 entry:
   ret void
@@ -50,6 +48,7 @@ entry:
 
 define void @main() #0 {
 entry:
+  call void @hidden_helper()
   call void @hidden_def()
   ret void
 }
diff --git a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
index 6ceba05567e8e..31bf63e6f3e53 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/protected-visibility.ll
@@ -1,17 +1,16 @@
 ; Check that protected visibility does not cause a crash, that protected
 ; declarations get Import linkage, and protected definitions get Export.
-; If environment doesn't support Linkage capability - ensure, that no
-; LinkageAttributes is emitted.
 
 ; RUN: split-file %s %t
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s --check-prefix=CHECK
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - | FileCheck %s
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %t/opencl.ll -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s --check-prefix=VULKAN
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - | FileCheck %s
+; FIXME: re-enable validator check when spirv-val allows Linkage in vulkan env.
+; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %t/vulkan.ll -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - | FileCheck %s --check-prefix=CHECK
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - | FileCheck %s
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %t/vulkan-lib.ll -o - -filetype=obj | spirv-val %}
 
 ; CHECK-DAG: OpName %[[#PROTECTED_DECL:]] "protected_decl"
@@ -20,9 +19,6 @@
 ; CHECK-DAG: OpDecorate %[[#PROTECTED_DECL]] LinkageAttributes "protected_decl" Import
 ; CHECK-DAG: OpDecorate %[[#PROTECTED_DEF]] LinkageAttributes "protected_def" Export
 
-; VULKAN-NOT: OpCapability Linkage
-; VULKAN-NOT: LinkageAttributes
-
 ;--- opencl.ll
 declare protected spir_func void @protected_decl(ptr addrspace(1))
 
@@ -39,6 +35,8 @@ entry:
 }
 
 ;--- vulkan.ll
+declare protected void @protected_decl()
+
 define protected void @protected_def() {
 entry:
   ret void
@@ -46,6 +44,7 @@ entry:
 
 define void @main() #0 {
 entry:
+  call void @protected_decl()
   call void @protected_def()
   ret void
 }

>From 0ee78b9eb79cfacb73ce500d264eab0b94108172 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Tue, 10 Mar 2026 22:14:44 +0100
Subject: [PATCH 7/8] align tests for opencl and vulkan

---
 .../SPIRV/linkage/hidden-visibility.ll        | 28 ++++++++++++-------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
index ef0e214544970..85d3b2980cede 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
@@ -39,33 +39,41 @@ entry:
 }
 
 ;--- vulkan.ll
-declare hidden void @hidden_helper()
+ at hidden_leaf_var = external hidden addrspace(1) global i32
+
+declare hidden void @hidden_helper(ptr addrspace(1))
 
-define hidden void @hidden_def() {
+define hidden void @hidden_def(ptr addrspace(1) %x) {
 entry:
   ret void
 }
 
-define void @main() #0 {
+define void @main(ptr addrspace(1) %data) #0 {
 entry:
-  call void @hidden_helper()
-  call void @hidden_def()
+  %val = load i32, ptr addrspace(1) @hidden_leaf_var
+  store i32 %val, ptr addrspace(1) %data
+  call void @hidden_helper(ptr addrspace(1) %data)
+  call void @hidden_def(ptr addrspace(1) %data)
   ret void
 }
 
 attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
 
 ;--- vulkan-lib.ll
-declare hidden void @hidden_helper()
+ at hidden_leaf_var = external hidden addrspace(1) global i32
+
+declare hidden void @hidden_helper(ptr addrspace(1))
 
-define hidden void @hidden_def() {
+define hidden void @hidden_def(ptr addrspace(1) %x) {
 entry:
   ret void
 }
 
-define void @caller() {
+define void @caller(ptr addrspace(1) %data) {
 entry:
-  call void @hidden_helper()
-  call void @hidden_def()
+  %val = load i32, ptr addrspace(1) @hidden_leaf_var
+  store i32 %val, ptr addrspace(1) %data
+  call void @hidden_helper(ptr addrspace(1) %data)
+  call void @hidden_def(ptr addrspace(1) %data)
   ret void
 }

>From 53a55dd6b622cf908d50abc55606da0db77e3274 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Tue, 10 Mar 2026 23:03:17 +0100
Subject: [PATCH 8/8] Revert "align tests for opencl and vulkan"

This reverts commit 0ee78b9eb79cfacb73ce500d264eab0b94108172.
---
 .../SPIRV/linkage/hidden-visibility.ll        | 28 +++++++------------
 1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
index 85d3b2980cede..ef0e214544970 100644
--- a/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
+++ b/llvm/test/CodeGen/SPIRV/linkage/hidden-visibility.ll
@@ -39,41 +39,33 @@ entry:
 }
 
 ;--- vulkan.ll
- at hidden_leaf_var = external hidden addrspace(1) global i32
-
-declare hidden void @hidden_helper(ptr addrspace(1))
+declare hidden void @hidden_helper()
 
-define hidden void @hidden_def(ptr addrspace(1) %x) {
+define hidden void @hidden_def() {
 entry:
   ret void
 }
 
-define void @main(ptr addrspace(1) %data) #0 {
+define void @main() #0 {
 entry:
-  %val = load i32, ptr addrspace(1) @hidden_leaf_var
-  store i32 %val, ptr addrspace(1) %data
-  call void @hidden_helper(ptr addrspace(1) %data)
-  call void @hidden_def(ptr addrspace(1) %data)
+  call void @hidden_helper()
+  call void @hidden_def()
   ret void
 }
 
 attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
 
 ;--- vulkan-lib.ll
- at hidden_leaf_var = external hidden addrspace(1) global i32
-
-declare hidden void @hidden_helper(ptr addrspace(1))
+declare hidden void @hidden_helper()
 
-define hidden void @hidden_def(ptr addrspace(1) %x) {
+define hidden void @hidden_def() {
 entry:
   ret void
 }
 
-define void @caller(ptr addrspace(1) %data) {
+define void @caller() {
 entry:
-  %val = load i32, ptr addrspace(1) @hidden_leaf_var
-  store i32 %val, ptr addrspace(1) %data
-  call void @hidden_helper(ptr addrspace(1) %data)
-  call void @hidden_def(ptr addrspace(1) %data)
+  call void @hidden_helper()
+  call void @hidden_def()
   ret void
 }



More information about the llvm-commits mailing list