[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