Skip to content

Conversation

@Keenuts
Copy link
Contributor

@Keenuts Keenuts commented Nov 18, 2024

Adds a new address spaces: hlsl_private. Variables with such address space will be emitted with a Private storage class.
This is useful for variables global to a SPIR-V module, since up to now, they were still emitted with a Function storage class, which is wrong.

@llvmbot
Copy link
Member

llvmbot commented Nov 18, 2024

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-backend-amdgpu
@llvm/pr-subscribers-backend-systemz
@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-backend-spir-v

Author: Nathan Gauër (Keenuts)

Changes

A global private variable was emitted with a Function storage class. This should be Private.

This PR touches 2 other parts:

  • a test
  • SPIRVUtils.

The test for SPV_INTEL_function_pointers was testing the storage class of a pointer, and expected "Function". But from what I read, the value should be "CodeSectionINTEL". So since this test was already wrong, updated it to expect "Private", which is as wrong as "Function". Maybe this test should be removed or marked as X-FAIL?

SPIRVUtils: I needed to add AS->SC conversion for Private. Input was already present, but not Output, so added Output just before Private. Input/Output/Private were not used, so picked the next numbers.


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

6 Files Affected:

  • (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+13-10)
  • (modified) llvm/lib/Target/SPIRV/SPIRVUtils.cpp (+4)
  • (modified) llvm/lib/Target/SPIRV/SPIRVUtils.h (+4)
  • (modified) llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp_const.ll (+5-1)
  • (added) llvm/test/CodeGen/SPIRV/pointers/variables-storage-class-vk.ll (+15)
  • (modified) llvm/test/CodeGen/SPIRV/pointers/variables-storage-class.ll (+18-5)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 158314d23393ae..05a4bb12b54cba 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3264,9 +3264,15 @@ bool SPIRVInstructionSelector::selectGlobalValue(
     PointerBaseType = GR.getOrCreateSPIRVType(
         GVType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, false);
   }
-  SPIRVType *ResType = GR.getOrCreateSPIRVPointerType(
-      PointerBaseType, I, TII,
-      addressSpaceToStorageClass(GV->getAddressSpace(), STI));
+
+  const unsigned AddrSpace = GV->getAddressSpace();
+  SPIRV::StorageClass::StorageClass StorageClass =
+      addressSpaceToStorageClass(AddrSpace, STI);
+  if (StorageClass == SPIRV::StorageClass::Function)
+    StorageClass = SPIRV::StorageClass::Private;
+
+  SPIRVType *ResType =
+      GR.getOrCreateSPIRVPointerType(PointerBaseType, I, TII, StorageClass);
 
   std::string GlobalIdent;
   if (!GV->hasName()) {
@@ -3337,11 +3343,8 @@ bool SPIRVInstructionSelector::selectGlobalValue(
   if (HasInit && !Init)
     return true;
 
-  unsigned AddrSpace = GV->getAddressSpace();
-  SPIRV::StorageClass::StorageClass Storage =
-      addressSpaceToStorageClass(AddrSpace, STI);
   bool HasLnkTy = GV->getLinkage() != GlobalValue::InternalLinkage &&
-                  Storage != SPIRV::StorageClass::Function;
+                  StorageClass != SPIRV::StorageClass::Function;
   SPIRV::LinkageType::LinkageType LnkType =
       (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
           ? SPIRV::LinkageType::Import
@@ -3350,9 +3353,9 @@ bool SPIRVInstructionSelector::selectGlobalValue(
                  ? SPIRV::LinkageType::LinkOnceODR
                  : SPIRV::LinkageType::Export);
 
-  Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV,
-                                        Storage, Init, GlobalVar->isConstant(),
-                                        HasLnkTy, LnkType, MIRBuilder, true);
+  Register Reg = GR.buildGlobalVariable(
+      ResVReg, ResType, GlobalIdent, GV, StorageClass, Init,
+      GlobalVar->isConstant(), HasLnkTy, LnkType, MIRBuilder, true);
   return Reg.isValid();
 }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index aeb2c29f7b8618..bfa3f50b8f16d9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -205,6 +205,10 @@ addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) {
                : SPIRV::StorageClass::CrossWorkgroup;
   case 7:
     return SPIRV::StorageClass::Input;
+  case 8:
+    return SPIRV::StorageClass::Output;
+  case 9:
+    return SPIRV::StorageClass::Private;
   default:
     report_fatal_error("Unknown address space");
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 298b0b93b0e4d2..1a3c1399c5a02c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -166,6 +166,10 @@ storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
     return 6;
   case SPIRV::StorageClass::Input:
     return 7;
+  case SPIRV::StorageClass::Output:
+    return 8;
+  case SPIRV::StorageClass::Private:
+    return 9;
   default:
     report_fatal_error("Unable to get address space id");
   }
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp_const.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp_const.ll
index b4faba9a4eb8e3..a6b5e2fe3c2971 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp_const.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp_const.ll
@@ -11,7 +11,11 @@
 ; CHECK-DAG: %[[TyFun:.*]] = OpTypeFunction %[[TyInt64]] %[[TyInt64]]
 ; CHECK-DAG: %[[TyInt8:.*]] = OpTypeInt 8 0
 ; CHECK-DAG: %[[TyPtrFun:.*]] = OpTypePointer Function %[[TyFun]]
-; CHECK-DAG: %[[ConstFunFp:.*]] = OpConstantFunctionPointerINTEL %[[TyPtrFun]] %[[DefFunFp:.*]]
+
+; FIXME: OpConstantFunctionPointerINTEL requires a CodeSectionINTEL ptr.
+; CHECK-DAG: %[[TyPtrPriv:.*]] = OpTypePointer Private %[[TyFun]]
+; CHECK-DAG: %[[ConstFunFp:.*]] = OpConstantFunctionPointerINTEL %[[TyPtrPriv]] %[[DefFunFp:.*]]
+
 ; CHECK-DAG: %[[TyPtrPtrFun:.*]] = OpTypePointer Function %[[TyPtrFun]]
 ; CHECK-DAG: %[[TyPtrInt8:.*]] = OpTypePointer Function %[[TyInt8]]
 ; CHECK-DAG: %[[TyPtrPtrInt8:.*]] = OpTypePointer Function %[[TyPtrInt8]]
diff --git a/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class-vk.ll b/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class-vk.ll
new file mode 100644
index 00000000000000..f7dbef2d01f5fc
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class-vk.ll
@@ -0,0 +1,15 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#U32:]] = OpTypeInt 32 0
+
+; CHECK-DAG: %[[#VAL:]] = OpConstant %[[#U32]] 456
+; CHECK-DAG: %[[#VTYPE:]] = OpTypePointer Private %[[#U32]]
+; CHECK-DAG: %[[#VAR:]] = OpVariable %[[#VTYPE]] Private %[[#VAL]]
+; CHECK-NOT: OpDecorate %[[#VAR]] LinkageAttributes
+@PrivInternal = internal global i32 456
+
+define void @main() {
+  %l = load i32, ptr @PrivInternal
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class.ll b/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class.ll
index 2d4c805ac9df15..fdbe2750a0c159 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/variables-storage-class.ll
@@ -1,18 +1,31 @@
 ; 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-DAG: %[[#U8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#U32:]] = OpTypeInt 32 0
+
+; CHECK-DAG: %[[#TYPE:]] = OpTypePointer CrossWorkgroup %[[#U8]]
+; CHECK-DAG: %[[#VAL:]] = OpConstantNull %[[#TYPE]]
+; CHECK-DAG: %[[#VTYPE:]] = OpTypePointer CrossWorkgroup %[[#TYPE]]
+; CHECK-DAG: %[[#PTR:]] = OpVariable %[[#VTYPE]] CrossWorkgroup %[[#VAL]]
 @Ptr = addrspace(1) global ptr addrspace(1) null
-@Init = private addrspace(2) constant i32 123
 
-; CHECK-DAG: %[[#PTR:]] = OpVariable %[[#]] UniformConstant %[[#]]
-; CHECK-DAG: %[[#INIT:]] = OpVariable %[[#]] CrossWorkgroup %[[#]]
+; CHECK-DAG: %[[#VAL:]] = OpConstant %[[#U32]] 123
+; CHECK-DAG: %[[#VTYPE:]] = OpTypePointer UniformConstant %[[#U32]]
+; CHECK-DAG: %[[#INIT:]] = OpVariable %[[#VTYPE]] UniformConstant %[[#VAL]]
+@Init = private addrspace(2) constant i32 123
 
-; CHECK: %[[#]] = OpLoad %[[#]] %[[#INIT]] Aligned 8
-; CHECK: OpCopyMemorySized %[[#]] %[[#PTR]] %[[#]] Aligned 4
+; CHECK-DAG: %[[#VAL:]] = OpConstant %[[#U32]] 456
+; CHECK-DAG: %[[#VTYPE:]] = OpTypePointer Private %[[#U32]]
+; CHECK-DAG: %[[#]] = OpVariable %[[#VTYPE]] Private %[[#VAL]]
+@PrivInternal = internal global i32 456
 
 define spir_kernel void @Foo() {
+; CHECK: %[[#]] = OpLoad %[[#]] %[[#PTR]] Aligned 8
   %l = load ptr addrspace(1), ptr addrspace(1) @Ptr, align 8
+; CHECK: OpCopyMemorySized %[[#]] %[[#INIT]] %[[#]] Aligned 4
   call void @llvm.memcpy.p1.p2.i64(ptr addrspace(1) align 4 %l, ptr addrspace(2) align 1 @Init, i64 4, i1 false)
+
   ret void
 }
 

VyacheslavLevytskyy added a commit that referenced this pull request Nov 22, 2024
…CodeSectionINTEL (#117250)

This PR fixes generation of OpConstantFunctionPointerINTEL instruction
for the SPIR-V extension SPV_INTEL_function_pointers. Result type of
OpConstantFunctionPointerINTEL must be OpTypePointer with Storage Class
operand equal to CodeSectionINTEL.

See also #116636

CC: @MrSidims
In SPIR-V, private global variables have the `Private` storage class.
This PR adds a new address space which allows frontend to emit variable
with this storage class.

Before this change, global variable were emitted with the 'Function'
storage class, which was wrong.

Signed-off-by: Nathan Gauër <[email protected]>
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:AArch64 backend:AMDGPU backend:SystemZ backend:WebAssembly clang:frontend Language frontend issues, e.g. anything involving "Sema" backend:DirectX labels Nov 28, 2024
@Keenuts
Copy link
Contributor Author

Keenuts commented Nov 28, 2024

Hello all!
Changed the PR to use a new AS emitted by the FE. This way there are no more weird storage class switch.
However, this required to support a new addrspacecast operation from Function to Private and the other way around.

The FE change will be in another PR (can be merged later on)

@Keenuts Keenuts requested a review from llvm-beanz November 28, 2024 14:14
@Keenuts
Copy link
Contributor Author

Keenuts commented Nov 28, 2024

@llvm-beanz : FYI for the added address space.

@Keenuts Keenuts requested review from MrSidims and s-perron November 29, 2024 12:16
Copy link
Contributor

@s-perron s-perron left a comment

Choose a reason for hiding this comment

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

The implementation looks good to me. I just wonder about one of the tests. I'd like to know why we need to handle that case, and how prevalent the addrspacecasts will be.

Signed-off-by: Nathan Gauër <[email protected]>
Copy link
Contributor

@MrSidims MrSidims left a comment

Choose a reason for hiding this comment

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

LGTM
Guess the PR description should be updated removing CodeSectionINTEL mentioning

@Keenuts Keenuts merged commit aa7fe1c into llvm:main Dec 2, 2024
8 of 9 checks passed
@Keenuts Keenuts deleted the global-private branch December 2, 2024 15:17

// HLSL specific address spaces.
hlsl_groupshared,
hlsl_private,
Copy link
Contributor

Choose a reason for hiding this comment

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

There are no language / source tests making use of this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We hoped to split the PRs between back-end and FE, shall I land both at the same time?

Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't split though, the backend parts don't require any of these clang changes

Copy link
Contributor Author

@Keenuts Keenuts Dec 2, 2024

Choose a reason for hiding this comment

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

Oh didn't knew I could modify the target's AS maps without also modifying this.
I'll revert/re-land this PR (given the other test), and see if I can do that:
#118312

edit: seems like I don't even need to touch the maps until the FE changes emits this new address space. I'll re-land the PR without those bits then.

neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}}
correct<0x7FFFE9>();
tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}}
tooBig<8388651>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388651L>' requested here}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks unrelated

Keenuts added a commit to Keenuts/llvm-project that referenced this pull request Dec 2, 2024
Keenuts added a commit that referenced this pull request Dec 2, 2024
Keenuts added a commit to Keenuts/llvm-project that referenced this pull request Dec 2, 2024
Re-land of llvm#116636
Adds a new address spaces: hlsl_private. Variables with such address space
will be emitted with a Private storage class.
This is useful for variables global to a SPIR-V module, since up to now,
they were still emitted with a Function storage class, which is wrong.

Signed-off-by: Nathan Gauër <[email protected]>
Keenuts added a commit that referenced this pull request Dec 3, 2024
Re-land of #116636
Adds a new address spaces: hlsl_private. Variables with such address
space will be emitted with a Private storage class.
This is useful for variables global to a SPIR-V module, since up to now,
they were still emitted with a Function storage class, which is wrong.

---------

Signed-off-by: Nathan Gauër <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:AArch64 backend:AMDGPU backend:DirectX backend:SPIR-V backend:SystemZ backend:WebAssembly clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants