[llvm] [SPIRV] Fix crash when two functions share an alias scope (PR #225017)
Nikhita Hegde via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 24 00:15:21 PDT 2026
https://github.com/Nikhita-P-Hegde updated https://github.com/llvm/llvm-project/pull/225017
>From 213995a4516caca23da09a2cf3a1837544a33434 Mon Sep 17 00:00:00 2001
From: nikhitah <nikhita.hegde at intel.com>
Date: Thu, 17 Sep 2026 07:57:27 +0000
Subject: [PATCH 1/2] [SPIRV] Fix crash when two functions share an alias scope
AliasInstMDMap caches the MachineInstr created for an alias scope MDNode,
but those instructions define virtual registers that are only valid in the
function that created them. If two functions reference the same alias scope
metadata, the second reuses the first function's register and we either
index MachineRegisterInfo out of bounds or emit SPIR-V referencing an
undefined id.
Key the map on {MachineFunction, MDNode} so each function gets its own
declarations
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 16 ++++---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h | 7 ++-
.../alias-scope-shared-across-functions.ll | 46 +++++++++++++++++++
3 files changed, 61 insertions(+), 8 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-scope-shared-across-functions.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 021bc1806d284c..a0eab4a541550f 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 37911c1bffd884..af2d3bf08207b1 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 00000000000000..34349bdd4de3c8
--- /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"}
>From 98f18b345de4e8d2173486fe13f3a33e2d905f8d Mon Sep 17 00:00:00 2001
From: nikhitah <nikhita.hegde at intel.com>
Date: Thu, 24 Sep 2026 07:13:35 +0000
Subject: [PATCH 2/2] Name the virtual registers in the alias scope test
---
.../alias-scope-shared-across-functions.ll | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
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
index 34349bdd4de3c8..19d4d4e302e3b0 100644
--- 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
@@ -25,19 +25,19 @@
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
+ %src = addrspacecast ptr addrspace(1) %in to ptr addrspace(4)
+ %dst = addrspacecast ptr addrspace(1) %out to ptr addrspace(4)
+ %val = load i32, ptr addrspace(4) %src, align 4, !alias.scope !1
+ store i32 %val, ptr addrspace(4) %dst, 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
+ %src = addrspacecast ptr addrspace(1) %in to ptr addrspace(4)
+ %dst = addrspacecast ptr addrspace(1) %out to ptr addrspace(4)
+ %val = load i32, ptr addrspace(4) %src, align 4, !alias.scope !1
+ store i32 %val, ptr addrspace(4) %dst, align 4
ret void
}
More information about the llvm-commits
mailing list