[Mlir-commits] [mlir] 2d6beb4 - [mlir][SPIR-V] Add SPIRVToLLVM conversions for SMulExtended and UMulExtended (#228052)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Oct 14 01:56:59 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-10-14T10:56:53+02:00
New Revision: 2d6beb4c424a146d42db00acae57f3f4d77bc05c

URL: https://github.com/llvm/llvm-project/commit/2d6beb4c424a146d42db00acae57f3f4d77bc05c
DIFF: https://github.com/llvm/llvm-project/commit/2d6beb4c424a146d42db00acae57f3f4d77bc05c.diff

LOG: [mlir][SPIR-V] Add SPIRVToLLVM conversions for SMulExtended and UMulExtended (#228052)

Added: 
    

Modified: 
    mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
    mlir/test/Conversion/SPIRVToLLVM/arithmetic-ops-to-llvm.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
index 4e733ff45360d..8cb50dbd07102 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
@@ -741,6 +741,51 @@ class ArithmeticWithOverflowPattern : public SPIRVToLLVMConversion<SPIRVOp> {
   }
 };
 
+/// Converts `spirv.SMulExtended` and `spirv.UMulExtended` by multiplying
+/// operands extended to twice the width and packing the low and high halves
+/// into the SPIR-V result struct.
+template <typename SPIRVOp, typename LLVMExtOp>
+class MulExtendedPattern : public SPIRVToLLVMConversion<SPIRVOp> {
+public:
+  using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
+
+  LogicalResult
+  matchAndRewrite(SPIRVOp op, typename SPIRVOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    Type dstType = this->getTypeConverter()->convertType(op.getType());
+    if (!dstType)
+      return rewriter.notifyMatchFailure(op, "type conversion failed");
+
+    Location loc = op.getLoc();
+    Type operandType = adaptor.getOperand1().getType();
+    unsigned bitwidth = getLLVMTypeBitWidth(operandType);
+    IntegerType wideElemType = rewriter.getIntegerType(bitwidth * 2);
+    Type wideType = wideElemType;
+    if (auto vecType = dyn_cast<VectorType>(operandType))
+      wideType = VectorType::get(vecType.getShape(), wideElemType);
+
+    Value lhs =
+        LLVMExtOp::create(rewriter, loc, wideType, adaptor.getOperand1());
+    Value rhs =
+        LLVMExtOp::create(rewriter, loc, wideType, adaptor.getOperand2());
+    Value mul = LLVM::MulOp::create(rewriter, loc, wideType, lhs, rhs);
+    Value low = LLVM::TruncOp::create(rewriter, loc, operandType, mul);
+    Value shift =
+        createIntegerConstant(loc, wideType, wideType, rewriter,
+                              rewriter.getIntegerAttr(wideElemType, bitwidth));
+    Value high = LLVM::LShrOp::create(rewriter, loc, mul, shift);
+    high = LLVM::TruncOp::create(rewriter, loc, operandType, high);
+
+    Value result = LLVM::PoisonOp::create(rewriter, loc, dstType);
+    result = LLVM::InsertValueOp::create(rewriter, loc, result, low,
+                                         ArrayRef<int64_t>{0});
+    result = LLVM::InsertValueOp::create(rewriter, loc, result, high,
+                                         ArrayRef<int64_t>{1});
+    rewriter.replaceOp(op, result);
+    return success();
+  }
+};
+
 /// Converts `spirv.ExecutionMode` into a global struct constant that holds
 /// execution mode information.
 class ExecutionModePattern
@@ -2206,6 +2251,8 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
                                     LLVM::UAddWithOverflowOp>,
       ArithmeticWithOverflowPattern<spirv::ISubBorrowOp,
                                     LLVM::USubWithOverflowOp>,
+      MulExtendedPattern<spirv::SMulExtendedOp, LLVM::SExtOp>,
+      MulExtendedPattern<spirv::UMulExtendedOp, LLVM::ZExtOp>,
 
       // Bitwise ops
       BitFieldInsertPattern, BitFieldUExtractPattern, BitFieldSExtractPattern,

diff  --git a/mlir/test/Conversion/SPIRVToLLVM/arithmetic-ops-to-llvm.mlir b/mlir/test/Conversion/SPIRVToLLVM/arithmetic-ops-to-llvm.mlir
index 14ddfd64fefa9..0eed482fe0243 100644
--- a/mlir/test/Conversion/SPIRVToLLVM/arithmetic-ops-to-llvm.mlir
+++ b/mlir/test/Conversion/SPIRVToLLVM/arithmetic-ops-to-llvm.mlir
@@ -114,6 +114,78 @@ spirv.func @imul_vector(%arg0: vector<3xi32>, %arg1: vector<3xi32>) "None" {
   spirv.Return
 }
 
+//===----------------------------------------------------------------------===//
+// spirv.SMulExtended
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @smulextended_scalar
+spirv.func @smulextended_scalar(%arg0: i32, %arg1: i32) "None" {
+  // CHECK: %[[LHS:.*]] = llvm.sext %{{.*}} : i32 to i64
+  // CHECK: %[[RHS:.*]] = llvm.sext %{{.*}} : i32 to i64
+  // CHECK: %[[MUL:.*]] = llvm.mul %[[LHS]], %[[RHS]] : i64
+  // CHECK: %[[LOW:.*]] = llvm.trunc %[[MUL]] : i64 to i32
+  // CHECK: %[[C32:.*]] = llvm.mlir.constant(32 : i64) : i64
+  // CHECK: %[[SHR:.*]] = llvm.lshr %[[MUL]], %[[C32]] : i64
+  // CHECK: %[[HIGH:.*]] = llvm.trunc %[[SHR]] : i64 to i32
+  // CHECK: %[[UNDEF:.*]] = llvm.mlir.poison : !llvm.struct<packed (i32, i32)>
+  // CHECK: %[[R0:.*]] = llvm.insertvalue %[[LOW]], %[[UNDEF]][0] : !llvm.struct<packed (i32, i32)>
+  // CHECK: llvm.insertvalue %[[HIGH]], %[[R0]][1] : !llvm.struct<packed (i32, i32)>
+  %0 = spirv.SMulExtended %arg0, %arg1 : !spirv.struct<(i32, i32)>
+  spirv.Return
+}
+
+// CHECK-LABEL: @smulextended_vector
+spirv.func @smulextended_vector(%arg0: vector<2xi16>, %arg1: vector<2xi16>) "None" {
+  // CHECK: %[[LHS:.*]] = llvm.sext %{{.*}} : vector<2xi16> to vector<2xi32>
+  // CHECK: %[[RHS:.*]] = llvm.sext %{{.*}} : vector<2xi16> to vector<2xi32>
+  // CHECK: %[[MUL:.*]] = llvm.mul %[[LHS]], %[[RHS]] : vector<2xi32>
+  // CHECK: %[[LOW:.*]] = llvm.trunc %[[MUL]] : vector<2xi32> to vector<2xi16>
+  // CHECK: %[[C16:.*]] = llvm.mlir.constant(dense<16> : vector<2xi32>) : vector<2xi32>
+  // CHECK: %[[SHR:.*]] = llvm.lshr %[[MUL]], %[[C16]] : vector<2xi32>
+  // CHECK: %[[HIGH:.*]] = llvm.trunc %[[SHR]] : vector<2xi32> to vector<2xi16>
+  // CHECK: %[[UNDEF:.*]] = llvm.mlir.poison : !llvm.struct<packed (vector<2xi16>, vector<2xi16>)>
+  // CHECK: %[[R0:.*]] = llvm.insertvalue %[[LOW]], %[[UNDEF]][0] : !llvm.struct<packed (vector<2xi16>, vector<2xi16>)>
+  // CHECK: llvm.insertvalue %[[HIGH]], %[[R0]][1] : !llvm.struct<packed (vector<2xi16>, vector<2xi16>)>
+  %0 = spirv.SMulExtended %arg0, %arg1 : !spirv.struct<(vector<2xi16>, vector<2xi16>)>
+  spirv.Return
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.UMulExtended
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @umulextended_scalar
+spirv.func @umulextended_scalar(%arg0: i32, %arg1: i32) "None" {
+  // CHECK: %[[LHS:.*]] = llvm.zext %{{.*}} : i32 to i64
+  // CHECK: %[[RHS:.*]] = llvm.zext %{{.*}} : i32 to i64
+  // CHECK: %[[MUL:.*]] = llvm.mul %[[LHS]], %[[RHS]] : i64
+  // CHECK: %[[LOW:.*]] = llvm.trunc %[[MUL]] : i64 to i32
+  // CHECK: %[[C32:.*]] = llvm.mlir.constant(32 : i64) : i64
+  // CHECK: %[[SHR:.*]] = llvm.lshr %[[MUL]], %[[C32]] : i64
+  // CHECK: %[[HIGH:.*]] = llvm.trunc %[[SHR]] : i64 to i32
+  // CHECK: %[[UNDEF:.*]] = llvm.mlir.poison : !llvm.struct<packed (i32, i32)>
+  // CHECK: %[[R0:.*]] = llvm.insertvalue %[[LOW]], %[[UNDEF]][0] : !llvm.struct<packed (i32, i32)>
+  // CHECK: llvm.insertvalue %[[HIGH]], %[[R0]][1] : !llvm.struct<packed (i32, i32)>
+  %0 = spirv.UMulExtended %arg0, %arg1 : !spirv.struct<(i32, i32)>
+  spirv.Return
+}
+
+// CHECK-LABEL: @umulextended_vector
+spirv.func @umulextended_vector(%arg0: vector<2xi32>, %arg1: vector<2xi32>) "None" {
+  // CHECK: %[[LHS:.*]] = llvm.zext %{{.*}} : vector<2xi32> to vector<2xi64>
+  // CHECK: %[[RHS:.*]] = llvm.zext %{{.*}} : vector<2xi32> to vector<2xi64>
+  // CHECK: %[[MUL:.*]] = llvm.mul %[[LHS]], %[[RHS]] : vector<2xi64>
+  // CHECK: %[[LOW:.*]] = llvm.trunc %[[MUL]] : vector<2xi64> to vector<2xi32>
+  // CHECK: %[[C32:.*]] = llvm.mlir.constant(dense<32> : vector<2xi64>) : vector<2xi64>
+  // CHECK: %[[SHR:.*]] = llvm.lshr %[[MUL]], %[[C32]] : vector<2xi64>
+  // CHECK: %[[HIGH:.*]] = llvm.trunc %[[SHR]] : vector<2xi64> to vector<2xi32>
+  // CHECK: %[[UNDEF:.*]] = llvm.mlir.poison : !llvm.struct<packed (vector<2xi32>, vector<2xi32>)>
+  // CHECK: %[[R0:.*]] = llvm.insertvalue %[[LOW]], %[[UNDEF]][0] : !llvm.struct<packed (vector<2xi32>, vector<2xi32>)>
+  // CHECK: llvm.insertvalue %[[HIGH]], %[[R0]][1] : !llvm.struct<packed (vector<2xi32>, vector<2xi32>)>
+  %0 = spirv.UMulExtended %arg0, %arg1 : !spirv.struct<(vector<2xi32>, vector<2xi32>)>
+  spirv.Return
+}
+
 //===----------------------------------------------------------------------===//
 // spirv.FAdd
 //===----------------------------------------------------------------------===//


        


More information about the Mlir-commits mailing list