[llvm] [SPIR-V] Parse parameterized Memory Access operands with a shared helper (PR #209262)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 06:22:08 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/209262

>From bbfe9a6bc2a34aa2f81530e4bb97c042df156f5c Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 13 Jul 2026 20:16:17 +0200
Subject: [PATCH 1/2] [SPIR-V] Parse parameterized Memory Access operands with
 a shared helper

Copy printing only special cased Aligned, so alias list and scope IDs were then misread as additional masks
---
 .../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp   | 63 ++++++++++++-------
 .../SPIRV/MCTargetDesc/SPIRVInstPrinter.h     |  1 +
 .../SPIRV/llvm-intrinsics/logical-memcpy.ll   | 28 ++++++++-
 3 files changed, 68 insertions(+), 24 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index b7dcd10bac809..4454921753da7 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -113,6 +113,42 @@ void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
   O << Imm;
 }
 
+unsigned SPIRVInstPrinter::printMemoryOperand(const MCInst *MI, unsigned OpNo,
+                                              raw_ostream &O) {
+  O << ' ';
+  if (OpNo >= MI->getNumOperands())
+    return OpNo;
+  const uint64_t Mask = MI->getOperand(OpNo).getImm();
+  printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, OpNo, O);
+  unsigned NextOp = OpNo + 1;
+  if (Mask & SPIRV::MemoryOperand::Aligned) {
+    O << ' ';
+    printOperand(MI, NextOp, O);
+    ++NextOp;
+  }
+  if (Mask & SPIRV::MemoryOperand::MakePointerAvailableKHR) {
+    O << ' ';
+    printOperand(MI, NextOp, O);
+    ++NextOp;
+  }
+  if (Mask & SPIRV::MemoryOperand::MakePointerVisibleKHR) {
+    O << ' ';
+    printOperand(MI, NextOp, O);
+    ++NextOp;
+  }
+  if (Mask & SPIRV::MemoryOperand::AliasScopeINTELMask) {
+    O << ' ';
+    printOperand(MI, NextOp, O);
+    ++NextOp;
+  }
+  if (Mask & SPIRV::MemoryOperand::NoAliasINTELMask) {
+    O << ' ';
+    printOperand(MI, NextOp, O);
+    ++NextOp;
+  }
+  return NextOp;
+}
+
 void SPIRVInstPrinter::recordIntType(const MCInst *MI) {
   MCRegister IntTypeReg = MI->getOperand(0).getReg();
   unsigned Bitwidth = MI->getOperand(1).getImm();
@@ -192,10 +228,7 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
         switch (OpCode) {
         case SPIRV::OpLoad:
         case SPIRV::OpStore:
-          OS << ' ';
-          printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
-              MI, FirstVariableIndex, OS);
-          printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
+          printMemoryOperand(MI, FirstVariableIndex, OS);
           break;
         case SPIRV::OpSwitch:
           if (MI->getFlags() & SPIRV::INST_PRINTER_WIDTH64) {
@@ -253,17 +286,8 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
         case SPIRV::OpCopyMemory:
         case SPIRV::OpCopyMemorySized: {
           const unsigned NumOps = MI->getNumOperands();
-          for (unsigned i = NumFixedOps; i < NumOps; ++i) {
-            OS << ' ';
-            printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, i,
-                                                                        OS);
-            if (MI->getOperand(i).getImm() & MemoryOperand::Aligned) {
-              assert(i + 1 < NumOps && "Missing alignment operand");
-              OS << ' ';
-              printOperand(MI, i + 1, OS);
-              i += 1;
-            }
-          }
+          for (unsigned i = NumFixedOps; i < NumOps;)
+            i = printMemoryOperand(MI, i, OS);
           break;
         }
         case SPIRV::OpConstantI:
@@ -346,13 +370,8 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
         }
         case SPIRV::OpPredicatedLoadINTEL:
         case SPIRV::OpPredicatedStoreINTEL: {
-          const unsigned NumOps = MI->getNumOperands();
-          if (NumOps > NumFixedOps) {
-            OS << ' ';
-            printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
-                MI, NumOps - 1, OS);
-            break;
-          }
+          if (MI->getNumOperands() > NumFixedOps)
+            printMemoryOperand(MI, NumFixedOps, OS);
           break;
         }
         default:
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
index b195c3de1801d..4d9450376a0a4 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
@@ -43,6 +43,7 @@ class SPIRVInstPrinter : public MCInstPrinter {
                                  bool SkipImmediates = false);
   void printOpConstantVarOps(const MCInst *MI, unsigned StartIndex,
                              raw_ostream &O);
+  unsigned printMemoryOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
 
   void printExtension(const MCInst *MI, unsigned OpNo, raw_ostream &O);
   template <SPIRV::OperandCategory::OperandCategory category>
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll
index b8fe49a1ee481..007a32e244ac3 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll
@@ -1,9 +1,11 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK: OpName %[[dst_var:[0-9]+]] "dst"
 ; CHECK: OpName %[[src_var:[0-9]+]] "src"
 
+; CHECK: %[[#List:]] = OpAliasScopeListDeclINTEL
+
 ; CHECK: %[[f32:[0-9]+]] = OpTypeFloat 32
 ; CHECK: %[[structS:[0-9]+]] = OpTypeStruct %[[f32]] %[[f32]] %[[f32]] %[[f32]] %[[f32]]
 ; CHECK: %[[ptr_crosswkgrp_structS:[0-9]+]] = OpTypePointer CrossWorkgroup %[[structS]]
@@ -27,6 +29,28 @@ entry:
 ; CHECK: OpFunctionEnd
 }
 
+; Aliasing metadata on an OpCopyMemory pointer adds parameterized operands (an
+; alignment literal plus an alias-list ID) after the memory access mask; the
+; printer must consume exactly those operands rather than the fixed one it
+; previously special-cased for Aligned only.
+%struct.T = type <{ float, float, float, float, float }>
+ at src2 = external dso_local addrspace(1) global %struct.T, align 4
+ at dst2 = external dso_local addrspace(1) global %struct.T, align 4
+
+; CHECK: %[[#]] = OpFunction
+define void @copy_aliased() {
+entry:
+; CHECK: OpCopyMemory %[[#]] %[[#]] AliasScopeINTELMask %[[#List]]
+  call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) align 4 @dst2, ptr addrspace(1) align 4 @src2, i64 20, i1 false), !alias.scope !1
+  ret void
+}
+
+declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1), ptr addrspace(1), i64, i1)
+
 attributes #0 = { "hlsl.numthreads"="8,1,1" "hlsl.shader"="compute" }
 
+!1 = !{!2}
+!2 = distinct !{!2, !3, !"copy_aliased: %this"}
+!3 = distinct !{!3, !"copy_aliased"}
+
 

>From 535199afbb79e4f6e2c79197d7bc0b0f6dc52a16 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 14 Jul 2026 15:21:57 +0200
Subject: [PATCH 2/2] Address comments

---
 .../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp   | 31 ++++++-------------
 .../alias-copy-memory.ll                      | 25 +++++++++++++++
 .../SPIRV/llvm-intrinsics/logical-memcpy.ll   | 28 ++---------------
 3 files changed, 37 insertions(+), 47 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-copy-memory.ll

diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index 4454921753da7..1a05aea432bee 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -121,27 +121,16 @@ unsigned SPIRVInstPrinter::printMemoryOperand(const MCInst *MI, unsigned OpNo,
   const uint64_t Mask = MI->getOperand(OpNo).getImm();
   printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, OpNo, O);
   unsigned NextOp = OpNo + 1;
-  if (Mask & SPIRV::MemoryOperand::Aligned) {
-    O << ' ';
-    printOperand(MI, NextOp, O);
-    ++NextOp;
-  }
-  if (Mask & SPIRV::MemoryOperand::MakePointerAvailableKHR) {
-    O << ' ';
-    printOperand(MI, NextOp, O);
-    ++NextOp;
-  }
-  if (Mask & SPIRV::MemoryOperand::MakePointerVisibleKHR) {
-    O << ' ';
-    printOperand(MI, NextOp, O);
-    ++NextOp;
-  }
-  if (Mask & SPIRV::MemoryOperand::AliasScopeINTELMask) {
-    O << ' ';
-    printOperand(MI, NextOp, O);
-    ++NextOp;
-  }
-  if (Mask & SPIRV::MemoryOperand::NoAliasINTELMask) {
+  static constexpr uint64_t ParameterizedMasks[] = {
+      SPIRV::MemoryOperand::Aligned,
+      SPIRV::MemoryOperand::MakePointerAvailableKHR,
+      SPIRV::MemoryOperand::MakePointerVisibleKHR,
+      SPIRV::MemoryOperand::AliasScopeINTELMask,
+      SPIRV::MemoryOperand::NoAliasINTELMask,
+  };
+  for (uint64_t ParamMask : ParameterizedMasks) {
+    if (!(Mask & ParamMask))
+      continue;
     O << ' ';
     printOperand(MI, NextOp, O);
     ++NextOp;
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-copy-memory.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-copy-memory.ll
new file mode 100644
index 0000000000000..89bdfbc2bd96d
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_memory_access_aliasing/alias-copy-memory.ll
@@ -0,0 +1,25 @@
+; Aliasing metadata on OpCopyMemory adds an alignment literal and an
+; alias-list ID after the memory access mask.
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: %[[#List:]] = OpAliasScopeListDeclINTEL
+
+; CHECK: %[[#]] = OpFunction
+define void @copy_aliased() {
+entry:
+; CHECK: OpCopyMemory %[[#]] %[[#]] Aligned|AliasScopeINTELMask 4 %[[#List]]
+  call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) align 4 @dst, ptr addrspace(1) align 4 @src, i64 20, i1 false), !alias.scope !1
+  ret void
+}
+
+%struct.T = type <{ float, float, float, float, float }>
+ at src = external dso_local addrspace(1) global %struct.T, align 4
+ at dst = external dso_local addrspace(1) global %struct.T, align 4
+
+declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1), ptr addrspace(1), i64, i1)
+
+!1 = !{!2}
+!2 = distinct !{!2, !3, !"copy_aliased: %this"}
+!3 = distinct !{!3, !"copy_aliased"}
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll
index 007a32e244ac3..b8fe49a1ee481 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/logical-memcpy.ll
@@ -1,11 +1,9 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown --spirv-ext=+SPV_INTEL_memory_access_aliasing %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK: OpName %[[dst_var:[0-9]+]] "dst"
 ; CHECK: OpName %[[src_var:[0-9]+]] "src"
 
-; CHECK: %[[#List:]] = OpAliasScopeListDeclINTEL
-
 ; CHECK: %[[f32:[0-9]+]] = OpTypeFloat 32
 ; CHECK: %[[structS:[0-9]+]] = OpTypeStruct %[[f32]] %[[f32]] %[[f32]] %[[f32]] %[[f32]]
 ; CHECK: %[[ptr_crosswkgrp_structS:[0-9]+]] = OpTypePointer CrossWorkgroup %[[structS]]
@@ -29,28 +27,6 @@ entry:
 ; CHECK: OpFunctionEnd
 }
 
-; Aliasing metadata on an OpCopyMemory pointer adds parameterized operands (an
-; alignment literal plus an alias-list ID) after the memory access mask; the
-; printer must consume exactly those operands rather than the fixed one it
-; previously special-cased for Aligned only.
-%struct.T = type <{ float, float, float, float, float }>
- at src2 = external dso_local addrspace(1) global %struct.T, align 4
- at dst2 = external dso_local addrspace(1) global %struct.T, align 4
-
-; CHECK: %[[#]] = OpFunction
-define void @copy_aliased() {
-entry:
-; CHECK: OpCopyMemory %[[#]] %[[#]] AliasScopeINTELMask %[[#List]]
-  call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) align 4 @dst2, ptr addrspace(1) align 4 @src2, i64 20, i1 false), !alias.scope !1
-  ret void
-}
-
-declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1), ptr addrspace(1), i64, i1)
-
 attributes #0 = { "hlsl.numthreads"="8,1,1" "hlsl.shader"="compute" }
 
-!1 = !{!2}
-!2 = distinct !{!2, !3, !"copy_aliased: %this"}
-!3 = distinct !{!3, !"copy_aliased"}
-
 



More information about the llvm-commits mailing list