[llvm] [SPIRV] Print split 64-bit OpSwitch operands as a single operand for text output (PR #164886)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 24 10:47:58 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Nick Sarnie (sarnex)

<details>
<summary>Changes</summary>

In binary form, 64-bit values are split into two 32-bit values as per the spec. Naturally this works fine with all tools.

However, the text format does not have a formal specification but SPIR-V-Tools, which we already rely on in the SPIRV workflow (clang calls `spirv-as` for example), expects the full 64 bit value, but today we print the two 32-bit values. causing the tool to error and report that the format is invalid.

The SPIR-V Translator also prints a single 64-bit value for text format.

This case is already handled specifically for `OpConstant`, but `OpSwitch` was missed. The SPIR-V translator also has special code in `OpSwitch` handling for this case.

Recombine the two 32-bit operands into a single 64-bit value to print in `AsmPrinter`. The actual ASM (aka binary form) emission is unchanged.

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


6 Files Affected:

- (modified) llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h (+4-1) 
- (modified) llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp (+29) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstrInfo.h (+3-1) 
- (modified) llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp (+2) 
- (modified) llvm/lib/Target/SPIRV/SPIRVUtils.cpp (+2) 
- (modified) llvm/test/CodeGen/SPIRV/branching/OpSwitch64.ll (+5-1) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
index d76180ce97e9e..ea41716bf204e 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
@@ -245,7 +245,10 @@ struct ExtendedBuiltin {
 
 enum InstFlags {
   // It is a half type
-  INST_PRINTER_WIDTH16 = 1
+  INST_PRINTER_WIDTH16 = 1,
+  // It is a 64-bit type
+  INST_PRINTER_WIDTH64 = INST_PRINTER_WIDTH16 << 1,
+
 };
 } // namespace SPIRV
 
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index 35a2ee16b2309..6a0f5b70e5d67 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -167,6 +167,35 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
               MI, FirstVariableIndex, OS);
           printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
           break;
+        case SPIRV::OpSwitch:
+          if (MI->getFlags() & SPIRV::INST_PRINTER_WIDTH64) {
+            // In binary format 64-bit types are split into two 32-bit operands,
+            // but in text format combine these into a single 64-bit value as
+            // this is what tools such as spirv-as require.
+            const unsigned NumOps = MI->getNumOperands();
+            for (unsigned OpIdx = NumFixedOps; OpIdx < NumOps;) {
+              if (OpIdx + 1 >= NumOps || !MI->getOperand(OpIdx).isImm() ||
+                  !MI->getOperand(OpIdx + 1).isImm()) {
+                continue;
+              }
+              OS << ' ';
+              uint64_t LowBits = MI->getOperand(OpIdx).getImm();
+              uint64_t HighBits = MI->getOperand(OpIdx + 1).getImm();
+              uint64_t CombinedValue = (HighBits << 32) | LowBits;
+              OS << formatImm(CombinedValue);
+              OpIdx += 2;
+
+              // Next should be the label
+              if (OpIdx < NumOps) {
+                OS << ' ';
+                printOperand(MI, OpIdx, OS);
+                OpIdx++;
+              }
+            }
+          } else {
+            printRemainingVariableOps(MI, NumFixedOps, OS);
+          }
+          break;
         case SPIRV::OpImageSampleImplicitLod:
         case SPIRV::OpImageSampleDrefImplicitLod:
         case SPIRV::OpImageSampleProjImplicitLod:
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
index 4de9d6a936abd..4c5b81fdd359a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
@@ -62,7 +62,9 @@ class SPIRVInstrInfo : public SPIRVGenInstrInfo {
 namespace SPIRV {
 enum AsmComments {
   // It is a half type
-  ASM_PRINTER_WIDTH16 = MachineInstr::TAsmComments
+  ASM_PRINTER_WIDTH16 = MachineInstr::TAsmComments,
+  // It is a 64 bit type
+  ASM_PRINTER_WIDTH64 = ASM_PRINTER_WIDTH16 << 1,
 };
 } // namespace SPIRV
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp b/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp
index e39666c5bc345..9aa07b52b4081 100644
--- a/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp
@@ -25,6 +25,8 @@ void SPIRVMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI,
   // Propagate previously set flags
   if (MI->getAsmPrinterFlags() & SPIRV::ASM_PRINTER_WIDTH16)
     OutMI.setFlags(SPIRV::INST_PRINTER_WIDTH16);
+  if (MI->getAsmPrinterFlags() & SPIRV::ASM_PRINTER_WIDTH64)
+    OutMI.setFlags(SPIRV::INST_PRINTER_WIDTH64);
   const MachineFunction *MF = MI->getMF();
   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
     const MachineOperand &MO = MI->getOperand(i);
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 4e2cc882ed6ba..8f2fc01da476f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -105,6 +105,8 @@ void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) {
     uint32_t LowBits = FullImm & 0xffffffff;
     uint32_t HighBits = (FullImm >> 32) & 0xffffffff;
     MIB.addImm(LowBits).addImm(HighBits);
+    // Asm Printer needs this info to print 64-bit operands correctly
+    MIB.getInstr()->setAsmPrinterFlag(SPIRV::ASM_PRINTER_WIDTH64);
     return;
   }
   report_fatal_error("Unsupported constant bitwidth");
diff --git a/llvm/test/CodeGen/SPIRV/branching/OpSwitch64.ll b/llvm/test/CodeGen/SPIRV/branching/OpSwitch64.ll
index 5e4f1f14f8f91..8fc986fe41b44 100644
--- a/llvm/test/CodeGen/SPIRV/branching/OpSwitch64.ll
+++ b/llvm/test/CodeGen/SPIRV/branching/OpSwitch64.ll
@@ -19,7 +19,11 @@
 
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
 
-; CHECK-SPIRV: OpSwitch %[[#]] %[[#]] 0 0 %[[#]] 1 0 %[[#]] 1 5 %[[#]]
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=asm | spirv-as - -o /dev/null %}
+
+; CHECK-SPIRV: OpSwitch %[[#]] %[[#]] 0 %[[#]] 1 %[[#]] 21474836481 %[[#]]
 
 define spir_kernel void @test_64(i32 addrspace(1)* %res) {
 entry:

``````````

</details>


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


More information about the llvm-commits mailing list