[Mlir-commits] [mlir] [MLIR][SPIRV] Add conversion for spirv.SpecConstant and spirv.mlir.referenceof to LLVM (PR #188746)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Mar 26 06:41:27 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

<details>
<summary>Changes</summary>

`-convert-spirv-to-llvm` failed with "failed to legalize operation 'spirv.SpecConstant'" because no conversion pattern existed for `spirv.SpecConstant` or `spirv.mlir.referenceof`.

Add two new conversion patterns:
- `SpecConstantPattern`: converts `spirv.SpecConstant` to an `llvm.mlir.global` constant (private linkage) using the spec constant's default value as the initializer. Signed/unsigned integer types are converted to signless integers, consistent with `ConstantScalarAndVectorPattern`.
- `ReferenceOfPattern`: converts `spirv.mlir.referenceof` to an `llvm.mlir.addressof` + `llvm.load` pair, loading the value from the corresponding global constant.

Since LLVM IR has no notion of specialization constants, the default value is used unconditionally when lowering.

Fixes #<!-- -->159485

Assisted-by: Claude Code

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


2 Files Affected:

- (modified) mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp (+59-2) 
- (modified) mlir/test/Conversion/SPIRVToLLVM/constant-op-to-llvm.mlir (+28) 


``````````diff
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
index d9144d0c5e228..5908db3c04817 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
@@ -441,6 +441,63 @@ class ConstantScalarAndVectorPattern
   }
 };
 
+/// Converts `spirv.SpecConstant` to an `llvm.mlir.global` constant with a
+/// private linkage, using the spec constant's default value as the initializer.
+/// When lowering to LLVM there is no notion of specialization, so the default
+/// value is used unconditionally.
+class SpecConstantPattern
+    : public SPIRVToLLVMConversion<spirv::SpecConstantOp> {
+public:
+  using SPIRVToLLVMConversion<spirv::SpecConstantOp>::SPIRVToLLVMConversion;
+
+  LogicalResult
+  matchAndRewrite(spirv::SpecConstantOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto defaultValue = cast<TypedAttr>(op.getDefaultValue());
+    auto srcType = defaultValue.getType();
+    auto dstType = getTypeConverter()->convertType(srcType);
+    if (!dstType)
+      return rewriter.notifyMatchFailure(op, "type conversion failed");
+
+    // Handle signed/unsigned integers: strip the sign by converting to a
+    // signless integer type (analogous to ConstantScalarAndVectorPattern).
+    Attribute initializer = defaultValue;
+    if (isSignedIntegerOrVector(srcType) ||
+        isUnsignedIntegerOrVector(srcType)) {
+      auto signlessType = rewriter.getIntegerType(getBitWidth(srcType));
+      dstType = getTypeConverter()->convertType(signlessType);
+      initializer = rewriter.getIntegerAttr(
+          signlessType, cast<IntegerAttr>(defaultValue).getValue());
+    }
+
+    rewriter.replaceOpWithNewOp<LLVM::GlobalOp>(
+        op, dstType, /*isConstant=*/true, LLVM::Linkage::Private,
+        op.getSymName(), initializer);
+    return success();
+  }
+};
+
+/// Converts `spirv.mlir.referenceof` (referencing a `spirv.SpecConstant`) to a
+/// load from the corresponding `llvm.mlir.global`.
+class ReferenceOfPattern : public SPIRVToLLVMConversion<spirv::ReferenceOfOp> {
+public:
+  using SPIRVToLLVMConversion<spirv::ReferenceOfOp>::SPIRVToLLVMConversion;
+
+  LogicalResult
+  matchAndRewrite(spirv::ReferenceOfOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto dstType = getTypeConverter()->convertType(op.getType());
+    if (!dstType)
+      return rewriter.notifyMatchFailure(op, "type conversion failed");
+
+    auto ptrType = LLVM::LLVMPointerType::get(op.getContext());
+    Value addr = LLVM::AddressOfOp::create(rewriter, op.getLoc(), ptrType,
+                                           op.getSpecConst());
+    rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, dstType, addr);
+    return success();
+  }
+};
+
 class BitFieldSExtractPattern
     : public SPIRVToLLVMConversion<spirv::BitFieldSExtractOp> {
 public:
@@ -1850,8 +1907,8 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
       IComparePattern<spirv::ULessThanEqualOp, LLVM::ICmpPredicate::ule>,
       IComparePattern<spirv::ULessThanOp, LLVM::ICmpPredicate::ult>,
 
-      // Constant op
-      ConstantScalarAndVectorPattern,
+      // Constant ops
+      ConstantScalarAndVectorPattern, SpecConstantPattern, ReferenceOfPattern,
 
       // Control Flow ops
       BranchConversionPattern, BranchConditionalConversionPattern,
diff --git a/mlir/test/Conversion/SPIRVToLLVM/constant-op-to-llvm.mlir b/mlir/test/Conversion/SPIRVToLLVM/constant-op-to-llvm.mlir
index 2d74022b34406..7066b9fe1f388 100644
--- a/mlir/test/Conversion/SPIRVToLLVM/constant-op-to-llvm.mlir
+++ b/mlir/test/Conversion/SPIRVToLLVM/constant-op-to-llvm.mlir
@@ -59,3 +59,31 @@ spirv.func @float_constant_vector() "None" {
   %0 = spirv.Constant dense<[2.000000e+00, 3.000000e+00]> : vector<2xf32>
   spirv.Return
 }
+
+//===----------------------------------------------------------------------===//
+// spirv.SpecConstant and spirv.mlir.referenceof
+//===----------------------------------------------------------------------===//
+
+// CHECK: llvm.mlir.global private constant @sc_int(-5 : i32) {{.*}} : i32
+// CHECK: llvm.mlir.global private constant @sc_signed(-5 : i32) {{.*}} : i32
+// CHECK: llvm.mlir.global private constant @sc_unsigned(10 : i16) {{.*}} : i16
+// CHECK: llvm.mlir.global private constant @sc_float(3.140000e+00 : f32) {{.*}} : f32
+// CHECK: llvm.mlir.global private constant @sc_bool(true) {{.*}} : i1
+spirv.module Logical GLSL450 {
+  spirv.SpecConstant @sc_int = -5 : i32
+  spirv.SpecConstant @sc_signed = -5 : si32
+  spirv.SpecConstant @sc_unsigned = 10 : ui16
+  spirv.SpecConstant @sc_float = 3.14 : f32
+  spirv.SpecConstant @sc_bool = true
+}
+
+// CHECK-LABEL: @use_spec_consts
+spirv.module Logical GLSL450 {
+  spirv.SpecConstant @sc = 42 : i32
+  spirv.func @use_spec_consts() -> i32 "None" {
+    // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @sc : !llvm.ptr
+    // CHECK: llvm.load %[[ADDR]] : !llvm.ptr -> i32
+    %0 = spirv.mlir.referenceof @sc : i32
+    spirv.ReturnValue %0 : i32
+  }
+}

``````````

</details>


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


More information about the Mlir-commits mailing list