[llvm] [SPIRV] Fix crash when two functions share an alias scope (PR #225017)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 00:00:13 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Nikhita Hegde (Nikhita-P-Hegde)

<details>
<summary>Changes</summary>

When two functions referenced the same alias scope metadata, they were incorrectly sharing a virtual register. This caused either a crash or broken SPIR-V output with undefined references. The fix ensures each function creates its own virtual register for alias scope metadata

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


3 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp (+10-6) 
- (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h (+5-2) 
- (added) llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-scope-shared-across-functions.ll (+46) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 021bc1806d284..a0eab4a541550 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -2265,7 +2265,9 @@ MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
     MachineIRBuilder &MIRBuilder, const MDNode *AliasingListMD) {
   if (AliasingListMD->getNumOperands() == 0)
     return nullptr;
-  if (auto L = AliasInstMDMap.find(AliasingListMD); L != AliasInstMDMap.end())
+  const MachineFunction *MF = &MIRBuilder.getMF();
+  if (auto L = AliasInstMDMap.find({MF, AliasingListMD});
+      L != AliasInstMDMap.end())
     return L->second;
 
   SmallVector<MachineInstr *> ScopeList;
@@ -2278,7 +2280,7 @@ MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
       if (!DomainMD)
         return nullptr;
       auto *Domain = [&] {
-        auto D = AliasInstMDMap.find(DomainMD);
+        auto D = AliasInstMDMap.find({MF, DomainMD});
         if (D != AliasInstMDMap.end())
           return D->second;
         const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass);
@@ -2286,9 +2288,10 @@ MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
             MIRBuilder.buildInstr(SPIRV::OpAliasDomainDeclINTEL).addDef(Ret);
         return MIB.getInstr();
       }();
-      AliasInstMDMap.insert(std::make_pair(DomainMD, Domain));
+      AliasInstMDMap.insert(
+          std::make_pair(std::make_pair(MF, DomainMD), Domain));
       auto *Scope = [&] {
-        auto S = AliasInstMDMap.find(ScopeMD);
+        auto S = AliasInstMDMap.find({MF, ScopeMD});
         if (S != AliasInstMDMap.end())
           return S->second;
         const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass);
@@ -2297,7 +2300,7 @@ MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
                        .addUse(Domain->getOperand(0).getReg());
         return MIB.getInstr();
       }();
-      AliasInstMDMap.insert(std::make_pair(ScopeMD, Scope));
+      AliasInstMDMap.insert(std::make_pair(std::make_pair(MF, ScopeMD), Scope));
       ScopeList.push_back(Scope);
     }
   }
@@ -2308,7 +2311,8 @@ MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
   for (auto *Scope : ScopeList)
     MIB.addUse(Scope->getOperand(0).getReg());
   auto List = MIB.getInstr();
-  AliasInstMDMap.insert(std::make_pair(AliasingListMD, List));
+  AliasInstMDMap.insert(
+      std::make_pair(std::make_pair(MF, AliasingListMD), List));
   return List;
 }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index 37911c1bffd88..af2d3bf08207b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -97,8 +97,11 @@ class SPIRVGlobalRegistry : public SPIRVIRMapping {
   // Maps OpVariable and OpFunction-related v-regs to its LLVM IR definition.
   DenseMap<std::pair<const MachineFunction *, Register>, const Value *> Reg2GO;
 
-  // map of aliasing decorations to aliasing metadata
-  DenseMap<const MDNode *, MachineInstr *> AliasInstMDMap;
+  // map of aliasing decorations to aliasing metadata, keyed per
+  // MachineFunction: the cached instructions define virtual registers, which
+  // are only valid in the function that created them.
+  DenseMap<std::pair<const MachineFunction *, const MDNode *>, MachineInstr *>
+      AliasInstMDMap;
 
   // Add a new OpTypeXXX instruction without checking for duplicates.
   SPIRVTypeInst createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-scope-shared-across-functions.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-scope-shared-across-functions.ll
new file mode 100644
index 0000000000000..34349bdd4de3c
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-scope-shared-across-functions.ll
@@ -0,0 +1,46 @@
+; Check that an alias scope list referenced from two functions is declared in
+; each of them. The aliasing instructions are cached per MDNode, but the virtual
+; registers they define belong to one MachineFunction, so a cache shared across
+; functions makes the second function reference a register that does not exist
+; in it.
+
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown -verify-machineinstrs --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: OpCapability MemoryAccessAliasingINTEL
+; CHECK: OpExtension "SPV_INTEL_memory_access_aliasing"
+
+; Both functions use !1, so each declares its own domain, scope and list.
+; CHECK: %[[#Domain1:]] = OpAliasDomainDeclINTEL
+; CHECK: %[[#Domain2:]] = OpAliasDomainDeclINTEL
+; CHECK: %[[#Scope1:]] = OpAliasScopeDeclINTEL %[[#Domain1]]
+; CHECK: %[[#Scope2:]] = OpAliasScopeDeclINTEL %[[#Domain2]]
+; CHECK: %[[#List1:]] = OpAliasScopeListDeclINTEL %[[#Scope1]]
+; CHECK: %[[#List2:]] = OpAliasScopeListDeclINTEL %[[#Scope2]]
+
+; One load per function, each using a different one of the two lists. Which
+; function gets which id is not fixed, so match them in either order.
+; CHECK-DAG: OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List1]]
+; CHECK-DAG: OpLoad %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List2]]
+
+define spir_kernel void @foo(ptr addrspace(1) noalias %in, ptr addrspace(1) noalias %out) {
+entry:
+  %0 = addrspacecast ptr addrspace(1) %in to ptr addrspace(4)
+  %1 = addrspacecast ptr addrspace(1) %out to ptr addrspace(4)
+  %v = load i32, ptr addrspace(4) %0, align 4, !alias.scope !1
+  store i32 %v, ptr addrspace(4) %1, align 4
+  ret void
+}
+
+define spir_kernel void @bar(ptr addrspace(1) noalias %in, ptr addrspace(1) noalias %out) {
+entry:
+  %0 = addrspacecast ptr addrspace(1) %in to ptr addrspace(4)
+  %1 = addrspacecast ptr addrspace(1) %out to ptr addrspace(4)
+  %v = load i32, ptr addrspace(4) %0, align 4, !alias.scope !1
+  store i32 %v, ptr addrspace(4) %1, align 4
+  ret void
+}
+
+!1 = !{!2}
+!2 = distinct !{!2, !3, !"shared: %in"}
+!3 = distinct !{!3, !"shared"}

``````````

</details>


https://github.com/llvm/llvm-project/pull/225017


More information about the llvm-commits mailing list