From bbfe9a6bc2a34aa2f81530e4bb97c042df156f5c Mon Sep 17 00:00:00 2001 From: Arseniy Obolenskiy 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(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( - 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(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( - 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 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 }> +@src2 = external dso_local addrspace(1) global %struct.T, align 4 +@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 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(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 }> +@src = external dso_local addrspace(1) global %struct.T, align 4 +@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 }> -@src2 = external dso_local addrspace(1) global %struct.T, align 4 -@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"} -