Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mlir][spirv] Add a generic convert-to-spirv pass #95942

Merged
merged 1 commit into from
Jun 21, 2024

Conversation

angelz913
Copy link
Contributor

This PR implements a MVP version of an MLIR lowering pipeline to SPIR-V. The goal of adding this pipeline is to have a better test coverage of SPIR-V compilation upstream, and enable writing simple kernels by hand. The dialects supported in this version include arith, vector (only 1-D vectors with size 2,3,4,8 or 16), scf, ub, index, func and math. New test cases for the pass are also included in this PR.

Relevant links

Future plans

  • Add conversion patterns for other dialects, e.g. gpu, tensor, etc.
  • Include vector transformation to unroll vectors to 1-D, and handle those with unsupported sizes.
  • Implement multiple-return. SPIR-V does not support multiple return values since a spirv.func can only return zero or one values. It might be possible to wrap the return values in a spirv.struct.
  • Add a conversion for scf.parallel.

@llvmbot
Copy link
Member

llvmbot commented Jun 18, 2024

@llvm/pr-subscribers-mlir-spirv

@llvm/pr-subscribers-mlir

Author: Angel Zhang (angelz913)

Changes

This PR implements a MVP version of an MLIR lowering pipeline to SPIR-V. The goal of adding this pipeline is to have a better test coverage of SPIR-V compilation upstream, and enable writing simple kernels by hand. The dialects supported in this version include arith, vector (only 1-D vectors with size 2,3,4,8 or 16), scf, ub, index, func and math. New test cases for the pass are also included in this PR.

Relevant links

Future plans

  • Add conversion patterns for other dialects, e.g. gpu, tensor, etc.
  • Include vector transformation to unroll vectors to 1-D, and handle those with unsupported sizes.
  • Implement multiple-return. SPIR-V does not support multiple return values since a spirv.func can only return zero or one values. It might be possible to wrap the return values in a spirv.struct.
  • Add a conversion for scf.parallel.

Patch is 43.88 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/95942.diff

13 Files Affected:

  • (added) mlir/include/mlir/Conversion/ConvertToSPIRV/ConvertToSPIRV.h (+26)
  • (modified) mlir/include/mlir/Conversion/Passes.h (+1)
  • (modified) mlir/include/mlir/Conversion/Passes.td (+14-1)
  • (modified) mlir/lib/Conversion/CMakeLists.txt (+1)
  • (added) mlir/lib/Conversion/ConvertToSPIRV/CMakeLists.txt (+22)
  • (added) mlir/lib/Conversion/ConvertToSPIRV/ConvertToSPIRVPass.cpp (+86)
  • (added) mlir/test/Conversion/ConvertToSPIRV/arith.mlir (+276)
  • (added) mlir/test/Conversion/ConvertToSPIRV/combined.mlir (+47)
  • (added) mlir/test/Conversion/ConvertToSPIRV/index.mlir (+104)
  • (added) mlir/test/Conversion/ConvertToSPIRV/scf.mlir (+47)
  • (added) mlir/test/Conversion/ConvertToSPIRV/simple.mlir (+15)
  • (added) mlir/test/Conversion/ConvertToSPIRV/ub.mlir (+9)
  • (added) mlir/test/Conversion/ConvertToSPIRV/vector.mlir (+439)
diff --git a/mlir/include/mlir/Conversion/ConvertToSPIRV/ConvertToSPIRV.h b/mlir/include/mlir/Conversion/ConvertToSPIRV/ConvertToSPIRV.h
new file mode 100644
index 0000000000000..b539f5059b871
--- /dev/null
+++ b/mlir/include/mlir/Conversion/ConvertToSPIRV/ConvertToSPIRV.h
@@ -0,0 +1,26 @@
+//===- ConvertToSPIRV.h - Conversion to SPIR-V pass ---*- C++ -*-===================//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CONVERSION_CONVERTTOSPIRV_CONVERTTOSPIRV_H
+#define MLIR_CONVERSION_CONVERTTOSPIRV_CONVERTTOSPIRV_H
+
+#include <memory>
+
+#include "mlir/Pass/Pass.h"
+
+#define GEN_PASS_DECL_CONVERTTOSPIRVPASS
+#include "mlir/Conversion/Passes.h.inc"
+
+namespace mlir {
+
+/// Create a pass that performs dialect conversion to SPIR-V for all dialects
+std::unique_ptr<OperationPass<>> createConvertToSPIRVPass();
+
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_CONVERTTOSPIRV_CONVERTTOSPIRV_H
diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h
index 7700299b3a4f3..81daec6fd0138 100644
--- a/mlir/include/mlir/Conversion/Passes.h
+++ b/mlir/include/mlir/Conversion/Passes.h
@@ -30,6 +30,7 @@
 #include "mlir/Conversion/ControlFlowToSPIRV/ControlFlowToSPIRV.h"
 #include "mlir/Conversion/ControlFlowToSPIRV/ControlFlowToSPIRVPass.h"
 #include "mlir/Conversion/ConvertToLLVM/ToLLVMPass.h"
+#include "mlir/Conversion/ConvertToSPIRV/ConvertToSPIRV.h"
 #include "mlir/Conversion/FuncToEmitC/FuncToEmitCPass.h"
 #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h"
 #include "mlir/Conversion/FuncToSPIRV/FuncToSPIRVPass.h"
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index db67d6a5ff128..5747b8d38001d 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -11,7 +11,6 @@
 
 include "mlir/Pass/PassBase.td"
 
-
 //===----------------------------------------------------------------------===//
 // ToLLVM
 //===----------------------------------------------------------------------===//
@@ -31,6 +30,20 @@ def ConvertToLLVMPass : Pass<"convert-to-llvm"> {
   ];
 }
 
+//===----------------------------------------------------------------------===//
+// ToSPIRV
+//===----------------------------------------------------------------------===//
+
+def ConvertToSPIRVPass : Pass<"convert-to-spirv"> {
+  let summary = "Convert to SPIR-V";
+  let description = [{
+    This is a generic pass to convert to SPIR-V.
+  }];
+
+  let constructor = "mlir::createConvertToSPIRVPass()";
+  let options = [];
+}
+
 //===----------------------------------------------------------------------===//
 // AffineToStandard
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index 0a03a2e133db1..e107738a4c50c 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -19,6 +19,7 @@ add_subdirectory(ControlFlowToLLVM)
 add_subdirectory(ControlFlowToSCF)
 add_subdirectory(ControlFlowToSPIRV)
 add_subdirectory(ConvertToLLVM)
+add_subdirectory(ConvertToSPIRV)
 add_subdirectory(FuncToEmitC)
 add_subdirectory(FuncToLLVM)
 add_subdirectory(FuncToSPIRV)
diff --git a/mlir/lib/Conversion/ConvertToSPIRV/CMakeLists.txt b/mlir/lib/Conversion/ConvertToSPIRV/CMakeLists.txt
new file mode 100644
index 0000000000000..9a93301f09b48
--- /dev/null
+++ b/mlir/lib/Conversion/ConvertToSPIRV/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(LLVM_OPTIONAL_SOURCES
+  ConvertToSPIRVPass.cpp
+)
+
+add_mlir_conversion_library(MLIRConvertToSPIRVPass
+  ConvertToSPIRVPass.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/ConvertToSPIRV
+
+  DEPENDS
+  MLIRConversionPassIncGen
+
+  LINK_LIBS PUBLIC
+  MLIRIR
+  MLIRPass
+  MLIRRewrite
+  MLIRSPIRVConversion
+  MLIRSPIRVDialect
+  MLIRSupport
+  MLIRTransformUtils
+  )
diff --git a/mlir/lib/Conversion/ConvertToSPIRV/ConvertToSPIRVPass.cpp b/mlir/lib/Conversion/ConvertToSPIRV/ConvertToSPIRVPass.cpp
new file mode 100644
index 0000000000000..b755e7d7ffe13
--- /dev/null
+++ b/mlir/lib/Conversion/ConvertToSPIRV/ConvertToSPIRVPass.cpp
@@ -0,0 +1,86 @@
+//===- ConvertToSPIRVPass.cpp - MLIR SPIR-V Conversion
+//--------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Conversion/ArithToSPIRV/ArithToSPIRV.h"
+#include "mlir/Conversion/ConvertToSPIRV/ConvertToSPIRV.h"
+#include "mlir/Conversion/FuncToSPIRV/FuncToSPIRV.h"
+#include "mlir/Conversion/IndexToSPIRV/IndexToSPIRV.h"
+#include "mlir/Conversion/SCFToSPIRV/SCFToSPIRV.h"
+#include "mlir/Conversion/UBToSPIRV/UBToSPIRV.h"
+#include "mlir/Conversion/VectorToSPIRV/VectorToSPIRV.h"
+#include "mlir/Dialect/Arith/Transforms/Passes.h"
+#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
+#include "mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h"
+#include "mlir/Dialect/Vector/Transforms/VectorRewritePatterns.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Rewrite/FrozenRewritePatternSet.h"
+#include "mlir/Transforms/DialectConversion.h"
+#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
+#include <memory>
+
+#define DEBUG_TYPE "convert-to-spirv"
+
+namespace mlir {
+#define GEN_PASS_DEF_CONVERTTOSPIRVPASS
+#include "mlir/Conversion/Passes.h.inc"
+} // namespace mlir
+
+using namespace mlir;
+
+namespace {
+
+/// A pass to perform the SPIR-V conversion.
+class ConvertToSPIRVPass
+    : public impl::ConvertToSPIRVPassBase<ConvertToSPIRVPass> {
+
+public:
+  using impl::ConvertToSPIRVPassBase<
+      ConvertToSPIRVPass>::ConvertToSPIRVPassBase;
+
+  // Register dependent dialects for the current pass
+  void getDependentDialects(DialectRegistry &registry) const override {
+    registry.insert<spirv::SPIRVDialect>();
+  }
+
+  void runOnOperation() final {
+    MLIRContext *context = &getContext();
+    Operation *op = getOperation();
+
+    auto targetAttr = spirv::lookupTargetEnvOrDefault(op);
+    SPIRVTypeConverter typeConverter(targetAttr);
+
+    RewritePatternSet patterns(context);
+    ScfToSPIRVContext scfToSPIRVContext;
+
+    // Populate patterns.
+    arith::populateCeilFloorDivExpandOpsPatterns(patterns);
+    arith::populateArithToSPIRVPatterns(typeConverter, patterns);
+    populateBuiltinFuncToSPIRVPatterns(typeConverter, patterns);
+    populateFuncToSPIRVPatterns(typeConverter, patterns);
+    index::populateIndexToSPIRVPatterns(typeConverter, patterns);
+    populateVectorToSPIRVPatterns(typeConverter, patterns);
+    populateSCFToSPIRVPatterns(typeConverter, scfToSPIRVContext, patterns);
+    ub::populateUBToSPIRVConversionPatterns(typeConverter, patterns);
+
+    std::unique_ptr<ConversionTarget> target =
+        SPIRVConversionTarget::get(targetAttr);
+
+    FrozenRewritePatternSet frozenPatterns(std::move(patterns));
+    if (failed(applyPartialConversion(op, *target, frozenPatterns))) {
+      return signalPassFailure();
+    }
+  }
+};
+
+} // namespace
+
+std::unique_ptr<OperationPass<>> mlir::createConvertToSPIRVPass() {
+  return std::make_unique<ConvertToSPIRVPass>();
+}
diff --git a/mlir/test/Conversion/ConvertToSPIRV/arith.mlir b/mlir/test/Conversion/ConvertToSPIRV/arith.mlir
new file mode 100644
index 0000000000000..823e9b4a6c3ab
--- /dev/null
+++ b/mlir/test/Conversion/ConvertToSPIRV/arith.mlir
@@ -0,0 +1,276 @@
+// RUN: mlir-opt -convert-to-spirv -split-input-file %s | FileCheck %s
+
+//===----------------------------------------------------------------------===//
+// arithmetic ops
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @int32_scalar
+func.func @int32_scalar(%lhs: i32, %rhs: i32) {
+  // CHECK: spirv.IAdd %{{.*}}, %{{.*}}: i32
+  %0 = arith.addi %lhs, %rhs: i32
+  // CHECK: spirv.ISub %{{.*}}, %{{.*}}: i32
+  %1 = arith.subi %lhs, %rhs: i32
+  // CHECK: spirv.IMul %{{.*}}, %{{.*}}: i32
+  %2 = arith.muli %lhs, %rhs: i32
+  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: i32
+  %3 = arith.divsi %lhs, %rhs: i32
+  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: i32
+  %4 = arith.divui %lhs, %rhs: i32
+  // CHECK: spirv.UMod %{{.*}}, %{{.*}}: i32
+  %5 = arith.remui %lhs, %rhs: i32
+  return
+}
+
+// CHECK-LABEL: @int32_scalar_srem
+// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
+func.func @int32_scalar_srem(%lhs: i32, %rhs: i32) {
+  // CHECK: %[[LABS:.+]] = spirv.GL.SAbs %[[LHS]] : i32
+  // CHECK: %[[RABS:.+]] = spirv.GL.SAbs %[[RHS]] : i32
+  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : i32
+  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : i32
+  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : i32
+  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
+  %0 = arith.remsi %lhs, %rhs: i32
+  return
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// std bit ops
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @bitwise_scalar
+func.func @bitwise_scalar(%arg0 : i32, %arg1 : i32) {
+  // CHECK: spirv.BitwiseAnd
+  %0 = arith.andi %arg0, %arg1 : i32
+  // CHECK: spirv.BitwiseOr
+  %1 = arith.ori %arg0, %arg1 : i32
+  // CHECK: spirv.BitwiseXor
+  %2 = arith.xori %arg0, %arg1 : i32
+  return
+}
+
+// CHECK-LABEL: @bitwise_vector
+func.func @bitwise_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
+  // CHECK: spirv.BitwiseAnd
+  %0 = arith.andi %arg0, %arg1 : vector<4xi32>
+  // CHECK: spirv.BitwiseOr
+  %1 = arith.ori %arg0, %arg1 : vector<4xi32>
+  // CHECK: spirv.BitwiseXor
+  %2 = arith.xori %arg0, %arg1 : vector<4xi32>
+  return
+}
+
+// CHECK-LABEL: @logical_scalar
+func.func @logical_scalar(%arg0 : i1, %arg1 : i1) {
+  // CHECK: spirv.LogicalAnd
+  %0 = arith.andi %arg0, %arg1 : i1
+  // CHECK: spirv.LogicalOr
+  %1 = arith.ori %arg0, %arg1 : i1
+  // CHECK: spirv.LogicalNotEqual
+  %2 = arith.xori %arg0, %arg1 : i1
+  return
+}
+
+// CHECK-LABEL: @logical_vector
+func.func @logical_vector(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
+  // CHECK: spirv.LogicalAnd
+  %0 = arith.andi %arg0, %arg1 : vector<4xi1>
+  // CHECK: spirv.LogicalOr
+  %1 = arith.ori %arg0, %arg1 : vector<4xi1>
+  // CHECK: spirv.LogicalNotEqual
+  %2 = arith.xori %arg0, %arg1 : vector<4xi1>
+  return
+}
+
+// CHECK-LABEL: @shift_scalar
+func.func @shift_scalar(%arg0 : i32, %arg1 : i32) {
+  // CHECK: spirv.ShiftLeftLogical
+  %0 = arith.shli %arg0, %arg1 : i32
+  // CHECK: spirv.ShiftRightArithmetic
+  %1 = arith.shrsi %arg0, %arg1 : i32
+  // CHECK: spirv.ShiftRightLogical
+  %2 = arith.shrui %arg0, %arg1 : i32
+  return
+}
+
+// CHECK-LABEL: @shift_vector
+func.func @shift_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
+  // CHECK: spirv.ShiftLeftLogical
+  %0 = arith.shli %arg0, %arg1 : vector<4xi32>
+  // CHECK: spirv.ShiftRightArithmetic
+  %1 = arith.shrsi %arg0, %arg1 : vector<4xi32>
+  // CHECK: spirv.ShiftRightLogical
+  %2 = arith.shrui %arg0, %arg1 : vector<4xi32>
+  return
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// arith.cmpf
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @cmpf
+func.func @cmpf(%arg0 : f32, %arg1 : f32) {
+  // CHECK: spirv.FOrdEqual
+  %1 = arith.cmpf oeq, %arg0, %arg1 : f32
+  // CHECK: spirv.FOrdGreaterThan
+  %2 = arith.cmpf ogt, %arg0, %arg1 : f32
+  // CHECK: spirv.FOrdGreaterThanEqual
+  %3 = arith.cmpf oge, %arg0, %arg1 : f32
+  // CHECK: spirv.FOrdLessThan
+  %4 = arith.cmpf olt, %arg0, %arg1 : f32
+  // CHECK: spirv.FOrdLessThanEqual
+  %5 = arith.cmpf ole, %arg0, %arg1 : f32
+  // CHECK: spirv.FOrdNotEqual
+  %6 = arith.cmpf one, %arg0, %arg1 : f32
+  // CHECK: spirv.FUnordEqual
+  %7 = arith.cmpf ueq, %arg0, %arg1 : f32
+  // CHECK: spirv.FUnordGreaterThan
+  %8 = arith.cmpf ugt, %arg0, %arg1 : f32
+  // CHECK: spirv.FUnordGreaterThanEqual
+  %9 = arith.cmpf uge, %arg0, %arg1 : f32
+  // CHECK: spirv.FUnordLessThan
+  %10 = arith.cmpf ult, %arg0, %arg1 : f32
+  // CHECK: FUnordLessThanEqual
+  %11 = arith.cmpf ule, %arg0, %arg1 : f32
+  // CHECK: spirv.FUnordNotEqual
+  %12 = arith.cmpf une, %arg0, %arg1 : f32
+  return
+}
+
+// CHECK-LABEL: @vec1cmpf
+func.func @vec1cmpf(%arg0 : vector<1xf32>, %arg1 : vector<1xf32>) {
+  // CHECK: spirv.FOrdGreaterThan
+  %0 = arith.cmpf ogt, %arg0, %arg1 : vector<1xf32>
+  // CHECK: spirv.FUnordLessThan
+  %1 = arith.cmpf ult, %arg0, %arg1 : vector<1xf32>
+  return
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// arith.cmpi
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @cmpi
+func.func @cmpi(%arg0 : i32, %arg1 : i32) {
+  // CHECK: spirv.IEqual
+  %0 = arith.cmpi eq, %arg0, %arg1 : i32
+  // CHECK: spirv.INotEqual
+  %1 = arith.cmpi ne, %arg0, %arg1 : i32
+  // CHECK: spirv.SLessThan
+  %2 = arith.cmpi slt, %arg0, %arg1 : i32
+  // CHECK: spirv.SLessThanEqual
+  %3 = arith.cmpi sle, %arg0, %arg1 : i32
+  // CHECK: spirv.SGreaterThan
+  %4 = arith.cmpi sgt, %arg0, %arg1 : i32
+  // CHECK: spirv.SGreaterThanEqual
+  %5 = arith.cmpi sge, %arg0, %arg1 : i32
+  // CHECK: spirv.ULessThan
+  %6 = arith.cmpi ult, %arg0, %arg1 : i32
+  // CHECK: spirv.ULessThanEqual
+  %7 = arith.cmpi ule, %arg0, %arg1 : i32
+  // CHECK: spirv.UGreaterThan
+  %8 = arith.cmpi ugt, %arg0, %arg1 : i32
+  // CHECK: spirv.UGreaterThanEqual
+  %9 = arith.cmpi uge, %arg0, %arg1 : i32
+  return
+}
+
+// CHECK-LABEL: @indexcmpi
+func.func @indexcmpi(%arg0 : index, %arg1 : index) {
+  // CHECK: spirv.IEqual
+  %0 = arith.cmpi eq, %arg0, %arg1 : index
+  // CHECK: spirv.INotEqual
+  %1 = arith.cmpi ne, %arg0, %arg1 : index
+  // CHECK: spirv.SLessThan
+  %2 = arith.cmpi slt, %arg0, %arg1 : index
+  // CHECK: spirv.SLessThanEqual
+  %3 = arith.cmpi sle, %arg0, %arg1 : index
+  // CHECK: spirv.SGreaterThan
+  %4 = arith.cmpi sgt, %arg0, %arg1 : index
+  // CHECK: spirv.SGreaterThanEqual
+  %5 = arith.cmpi sge, %arg0, %arg1 : index
+  // CHECK: spirv.ULessThan
+  %6 = arith.cmpi ult, %arg0, %arg1 : index
+  // CHECK: spirv.ULessThanEqual
+  %7 = arith.cmpi ule, %arg0, %arg1 : index
+  // CHECK: spirv.UGreaterThan
+  %8 = arith.cmpi ugt, %arg0, %arg1 : index
+  // CHECK: spirv.UGreaterThanEqual
+  %9 = arith.cmpi uge, %arg0, %arg1 : index
+  return
+}
+
+// CHECK-LABEL: @vec1cmpi
+func.func @vec1cmpi(%arg0 : vector<1xi32>, %arg1 : vector<1xi32>) {
+  // CHECK: spirv.ULessThan
+  %0 = arith.cmpi ult, %arg0, %arg1 : vector<1xi32>
+  // CHECK: spirv.SGreaterThan
+  %1 = arith.cmpi sgt, %arg0, %arg1 : vector<1xi32>
+  return
+}
+
+// CHECK-LABEL: @boolcmpi_equality
+func.func @boolcmpi_equality(%arg0 : i1, %arg1 : i1) {
+  // CHECK: spirv.LogicalEqual
+  %0 = arith.cmpi eq, %arg0, %arg1 : i1
+  // CHECK: spirv.LogicalNotEqual
+  %1 = arith.cmpi ne, %arg0, %arg1 : i1
+  return
+}
+
+// CHECK-LABEL: @boolcmpi_unsigned
+func.func @boolcmpi_unsigned(%arg0 : i1, %arg1 : i1) {
+  // CHECK-COUNT-2: spirv.Select
+  // CHECK: spirv.UGreaterThanEqual
+  %0 = arith.cmpi uge, %arg0, %arg1 : i1
+  // CHECK-COUNT-2: spirv.Select
+  // CHECK: spirv.ULessThan
+  %1 = arith.cmpi ult, %arg0, %arg1 : i1
+  return
+}
+
+// CHECK-LABEL: @vec1boolcmpi_equality
+func.func @vec1boolcmpi_equality(%arg0 : vector<1xi1>, %arg1 : vector<1xi1>) {
+  // CHECK: spirv.LogicalEqual
+  %0 = arith.cmpi eq, %arg0, %arg1 : vector<1xi1>
+  // CHECK: spirv.LogicalNotEqual
+  %1 = arith.cmpi ne, %arg0, %arg1 : vector<1xi1>
+  return
+}
+
+// CHECK-LABEL: @vec1boolcmpi_unsigned
+func.func @vec1boolcmpi_unsigned(%arg0 : vector<1xi1>, %arg1 : vector<1xi1>) {
+  // CHECK-COUNT-2: spirv.Select
+  // CHECK: spirv.UGreaterThanEqual
+  %0 = arith.cmpi uge, %arg0, %arg1 : vector<1xi1>
+  // CHECK-COUNT-2: spirv.Select
+  // CHECK: spirv.ULessThan
+  %1 = arith.cmpi ult, %arg0, %arg1 : vector<1xi1>
+  return
+}
+
+// CHECK-LABEL: @vecboolcmpi_equality
+func.func @vecboolcmpi_equality(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
+  // CHECK: spirv.LogicalEqual
+  %0 = arith.cmpi eq, %arg0, %arg1 : vector<4xi1>
+  // CHECK: spirv.LogicalNotEqual
+  %1 = arith.cmpi ne, %arg0, %arg1 : vector<4xi1>
+  return
+}
+
+// CHECK-LABEL: @vecboolcmpi_unsigned
+func.func @vecboolcmpi_unsigned(%arg0 : vector<3xi1>, %arg1 : vector<3xi1>) {
+  // CHECK-COUNT-2: spirv.Select
+  // CHECK: spirv.UGreaterThanEqual
+  %0 = arith.cmpi uge, %arg0, %arg1 : vector<3xi1>
+  // CHECK-COUNT-2: spirv.Select
+  // CHECK: spirv.ULessThan
+  %1 = arith.cmpi ult, %arg0, %arg1 : vector<3xi1>
+  return
+}
diff --git a/mlir/test/Conversion/ConvertToSPIRV/combined.mlir b/mlir/test/Conversion/ConvertToSPIRV/combined.mlir
new file mode 100644
index 0000000000000..9e908465cb142
--- /dev/null
+++ b/mlir/test/Conversion/ConvertToSPIRV/combined.mlir
@@ -0,0 +1,47 @@
+// RUN: mlir-opt -convert-to-spirv %s | FileCheck %s
+
+// CHECK-LABEL: @combined
+// CHECK: %[[C0_F32:.*]] = spirv.Constant 0.000000e+00 : f32
+// CHECK: %[[C1_F32:.*]]  = spirv.Constant 1.000000e+00 : f32
+// CHECK: %[[C0_I32:.*]] = spirv.Constant 0 : i32
+// CHECK: %[[C4_I32:.*]] = spirv.Constant 4 : i32
+// CHECK: %[[C0_I32_0:.*]] = spirv.Constant 0 : i32
+// CHECK: %[[C4_I32_0:.*]] = spirv.Constant 4 : i32
+// CHECK: %[[C1_I32:.*]] = spirv.Constant 1 : i32
+// CHECK: %[[VEC:.*]] = spirv.Constant dense<1.000000e+00> : vector<4xf32>
+// CHECK: %[[VARIABLE:.*]] = spirv.Variable : !spirv.ptr<f32, Function>
+// CHECK: spirv.mlir.loop {
+// CHECK:    spirv.Branch ^[[HEADER:.*]](%[[C0_I32_0]], %[[C0_F32]] : i32, f32)
+// CHECK:  ^[[HEADER]](%[[INDVAR_0:.*]]: i32, %[[INDVAR_1:.*]]: f32):
+// CHECK:    %[[SLESSTHAN:.*]] = spirv.SLessThan %[[INDVAR_0]], %[[C4_I32_0]] : i32
+// CHECK:    spirv.BranchConditional %[[SLESSTHAN]], ^[[BODY:.*]], ^[[MERGE:.*]]
+// CHECK:  ^[[BODY]]:
+// CHECK:    %[[FADD:.*]] = spirv.FAdd %[[INDVAR_1]], %[[C1_F32]]  : f32
+// CHECK:    %[[INSERT:.*]] = spirv.CompositeInsert %[[FADD]], %[[VEC]][0 : i32] : f32 into vector<4xf32>
+// CHECK:    spirv.Store "Function" %[[VARIABLE]], %[[FADD]] : f32
+// CHECK:    %[[IADD:.*]] = spirv.IAdd %[[INDVAR_0]], %[[C1_I32]] : i32
+// CHECK:    spirv.Branch ^[[HEADER]](%[[IADD]], %[[FADD]] : i32, f32)
+// CHECK:  ^[[MERGE]]:
+// CHECK:    spirv.mlir.merge
+// CHECK:  }
+// CHECK:  %[[LOAD:.*]] = spirv.Load "Function" %[[VARIABLE]] : f32
+// CHECK:  %[[UNDEF:.*]] = spirv.Undef : f32
+// CHECK:  spirv.ReturnValue %[[UNDEF]] : f32
+func.func @combined() -> f32 {
+  %c0_f32 = arith.constant 0.0 : f32
+  %c1_f32 = arith.constant 1.0 : f32
+  %c0_i32 = arith.constant 0 : i32
+  %c4_i32 = arith.constant 4 : i32
+  %lb = index.casts %c0_i32 : i32 to index
+  %ub = index.casts %c4_i32 : i32 to index
+  %step = arith.constant 1 : index
+  %buf = vector.broadcast %c1_f32 : f32 to vector<4xf32>
+  scf.for %iv = %lb to %ub step %step iter_args(%sum_iter = %c0_f32) -> f32 {
+    %t = vector.extract %buf[0] : f32 from vector<4xf32>
+    %sum_next = arith.addf %sum_iter, %t : f32
+    vector.insert %sum_next, %buf[0] : f32 into vector<4xf32>
+    scf.yield %sum_next : f32
+  }
+  %ret = ub.poison : f32
+  return %ret : f32
+}
diff --git a/mlir/test/Conversion/ConvertToSPIRV/index.mlir b/mlir/test/Conversion/ConvertToSPIRV/index.mlir
new file mode 100644
index 0000000000000..5ad2217add0d4
--- /dev/null
+++ b/mlir/test/Conversion/ConvertToSPIRV/index.mlir
@@ -0,0 +1,104 @@
+// RUN: mlir-opt %s -convert-to-spirv | FileCheck %s
+
+// CHECK-LABEL: @basic
+func.func @basic(%a: index, %b: index) {
+  // CHECK: spirv.IAdd
+  %0 = index.add %a, %b
+  // CHECK: spirv.ISub
+  %1 = index.sub %a, %b
+  // CHECK: spirv.IMul
+  %2 = index.mul %a, %b
+  // CHECK: spirv.SDiv
+  %3 = index.divs %a, %b
+  // CHECK: spirv.UDiv
+  %4 = index.divu %a, %b
+  // CHECK: spirv.SRem
+  %5 = index.rems %a, %b
+  // CHECK: spirv.UMod
+  %6 = index.remu %a, %b
+  // CHECK: spirv.GL.SMax
+  %7 = index.maxs %a, %b
+  // CHECK: spirv.GL.UMax
+  %8 = index.maxu...
[truncated]

@angelz913 angelz913 changed the title [mlir][spirv] Add a generic "convert-to-spirv" pass [mlir][spirv] Add a generic convert-to-spirv pass Jun 18, 2024
@angelz913 angelz913 force-pushed the mlir-to-spirv-pipeline branch 3 times, most recently from 464e201 to 6c19ecd Compare June 18, 2024 19:47
@angelz913 angelz913 force-pushed the mlir-to-spirv-pipeline branch 3 times, most recently from 6d104c2 to cc9eb3a Compare June 19, 2024 13:06
@angelz913 angelz913 force-pushed the mlir-to-spirv-pipeline branch from cc9eb3a to 2b57c1b Compare June 19, 2024 18:07
Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but please wait for at least one more approval before merging.

@kuhar kuhar requested a review from Hardcode84 June 19, 2024 18:21
This commit implements a MVP version of an MLIR lowering pipeline to SPIR-V.
The goal is to have a better test coverage of SPIR-V compilation upstream,
and enable writing simple kernels by hand. The dialects supported in this
version include arith, vector (only 1-D vectors with size 2,3,4,8 or 16),
scf, ub, index, func and math.
@angelz913 angelz913 force-pushed the mlir-to-spirv-pipeline branch from 2b57c1b to d34055f Compare June 19, 2024 18:39
@kuhar kuhar merged commit 6a69cfb into llvm:main Jun 21, 2024
7 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 21, 2024

LLVM Buildbot has detected a new failure on builder flang-aarch64-libcxx running on linaro-flang-aarch64-libcxx while building mlir at step 5 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/89/builds/547

Here is the relevant piece of the build log for the reference:

Step 5 (build-unified-tree) failure: build (failure)
...
162.859 [1965/35/5069] Linking CXX shared library lib/libMLIRFuncTransformOps.so.19.0git
162.864 [1959/40/5070] Creating library symlink lib/libMLIROpenMPToLLVM.so
162.868 [1959/39/5071] Creating library symlink lib/libMLIRFuncTransformOps.so
162.868 [1959/38/5072] Creating library symlink lib/libMLIRBufferizationDialect.so
162.871 [1955/41/5073] Creating library symlink lib/libMLIRAMDGPUTransforms.so
162.872 [1955/40/5074] Creating library symlink lib/libMLIRSCFDialect.so
162.876 [1955/39/5075] Creating library symlink lib/libMLIRShapeDialect.so
162.880 [1955/38/5076] Creating library symlink lib/libMLIRSPIRVUtils.so
162.988 [1955/37/5077] Linking CXX shared library lib/libMLIRFuncToSPIRV.so.19.0git
162.998 [1955/36/5078] Linking CXX shared library lib/libMLIRConvertToSPIRVPass.so.19.0git
FAILED: lib/libMLIRConvertToSPIRVPass.so.19.0git 
: && /usr/local/bin/c++ -fPIC -stdlib=libc++ -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -Wundef -Werror=mismatched-tags -Werror=global-constructors -O3 -DNDEBUG  -stdlib=libc++ -Wl,-z,defs -Wl,-z,nodelete   -Wl,-rpath-link,/home/tcwg-buildbot/worker/flang-aarch64-libcxx/build/./lib  -Wl,--gc-sections -shared -Wl,-soname,libMLIRConvertToSPIRVPass.so.19.0git -o lib/libMLIRConvertToSPIRVPass.so.19.0git tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o  -Wl,-rpath,"\$ORIGIN/../lib:/home/tcwg-buildbot/worker/flang-aarch64-libcxx/build/lib:"  lib/libMLIRSPIRVConversion.so.19.0git  lib/libMLIRSPIRVDialect.so.19.0git  lib/libMLIRParser.so.19.0git  lib/libMLIRBytecodeReader.so.19.0git  lib/libMLIRAsmParser.so.19.0git  lib/libMLIRTransforms.so.19.0git  lib/libMLIRCopyOpInterface.so.19.0git  lib/libMLIRMemorySlotInterfaces.so.19.0git  lib/libMLIRRuntimeVerifiableOpInterface.so.19.0git  lib/libMLIRUBDialect.so.19.0git  lib/libMLIRTransformUtils.so.19.0git  lib/libMLIRRewrite.so.19.0git  lib/libMLIRRewritePDL.so.19.0git  lib/libMLIRPDLToPDLInterp.so.19.0git  lib/libMLIRPass.so.19.0git  lib/libMLIRPDLInterpDialect.so.19.0git  lib/libMLIRPDLDialect.so.19.0git  lib/libMLIRSubsetOpInterface.so.19.0git  lib/libMLIRValueBoundsOpInterface.so.19.0git  lib/libMLIRAnalysis.so.19.0git  lib/libMLIRLoopLikeInterface.so.19.0git  lib/libMLIRDataLayoutInterfaces.so.19.0git  lib/libMLIRInferIntRangeInterface.so.19.0git  lib/libMLIRPresburger.so.19.0git  lib/libMLIRViewLikeInterface.so.19.0git  lib/libMLIRDestinationStyleOpInterface.so.19.0git  lib/libMLIRFuncDialect.so.19.0git  lib/libMLIRSideEffectInterfaces.so.19.0git  lib/libMLIRControlFlowInterfaces.so.19.0git  lib/libMLIRFunctionInterfaces.so.19.0git  lib/libMLIRCallInterfaces.so.19.0git  lib/libMLIRInferTypeOpInterface.so.19.0git  lib/libMLIRIR.so.19.0git  lib/libMLIRSupport.so.19.0git  -lpthread  lib/libLLVMSupport.so.19.0git  -Wl,-rpath-link,/home/tcwg-buildbot/worker/flang-aarch64-libcxx/build/lib && :
/usr/bin/ld: tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o: in function `(anonymous namespace)::ConvertToSPIRVPass::runOnOperation()':
ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0xbc): undefined reference to `mlir::ScfToSPIRVContext::ScfToSPIRVContext()'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0xc4): undefined reference to `mlir::arith::populateCeilFloorDivExpandOpsPatterns(mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0xd0): undefined reference to `mlir::arith::populateArithToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0xe8): undefined reference to `mlir::populateFuncToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0xf4): undefined reference to `mlir::index::populateIndexToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0x100): undefined reference to `mlir::populateVectorToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0x110): undefined reference to `mlir::populateSCFToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::ScfToSPIRVContext&, mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0x11c): undefined reference to `mlir::ub::populateUBToSPIRVConversionPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)'
/usr/bin/ld: ConvertToSPIRVPass.cpp:(.text._ZN12_GLOBAL__N_118ConvertToSPIRVPass14runOnOperationEv+0x1a4): undefined reference to `mlir::ScfToSPIRVContext::~ScfToSPIRVContext()'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
163.000 [1955/35/5079] Linking CXX shared library lib/libMLIRControlFlowToSPIRV.so.19.0git
163.019 [1955/34/5080] Linking CXX shared library lib/libMLIRUBToSPIRV.so.19.0git
163.023 [1955/33/5081] Linking CXX shared library lib/libMLIRIndexToSPIRV.so.19.0git
163.026 [1955/32/5082] Linking CXX shared library lib/libMLIRTensorInferTypeOpInterfaceImpl.so.19.0git
163.031 [1955/31/5083] Linking CXX shared library lib/libMLIRMathToSPIRV.so.19.0git
163.036 [1955/30/5084] Linking CXX shared library lib/libMLIRComplexToSPIRV.so.19.0git
163.047 [1955/29/5085] Linking CXX shared library lib/libMLIRMLProgramTransforms.so.19.0git
163.061 [1955/28/5086] Linking CXX shared library lib/libMLIRMemRefToSPIRV.so.19.0git
163.353 [1955/27/5087] Building CXX object tools/mlir/test/lib/Dialect/ArmSME/CMakeFiles/MLIRArmSMETestPasses.dir/TestLowerToArmSME.cpp.o
163.403 [1955/26/5088] Building CXX object tools/mlir/lib/Dialect/Linalg/Transforms/CMakeFiles/obj.MLIRLinalgTransforms.dir/SwapExtractSliceWithFillPatterns.cpp.o
165.339 [1955/25/5089] Building CXX object tools/mlir/lib/Dialect/NVGPU/TransformOps/CMakeFiles/obj.MLIRNVGPUTransformOps.dir/NVGPUTransformOps.cpp.o
165.659 [1955/24/5090] Building CXX object tools/mlir/test/lib/Dialect/ControlFlow/CMakeFiles/MLIRControlFlowTestPasses.dir/TestAssert.cpp.o
165.788 [1955/23/5091] Building CXX object tools/mlir/lib/Conversion/NVGPUToNVVM/CMakeFiles/obj.MLIRNVGPUToNVVM.dir/NVGPUToNVVM.cpp.o
168.628 [1955/22/5092] Building CXX object tools/mlir/test/lib/Dialect/Linalg/CMakeFiles/MLIRLinalgTestPasses.dir/TestDataLayoutPropagation.cpp.o
168.737 [1955/21/5093] Building CXX object tools/mlir/test/lib/Dialect/Linalg/CMakeFiles/MLIRLinalgTestPasses.dir/TestLinalgDropUnitDims.cpp.o
168.922 [1955/20/5094] Building CXX object tools/mlir/lib/CAPI/Dialect/CMakeFiles/obj.MLIRCAPILinalg.dir/LinalgPasses.cpp.o
169.093 [1955/19/5095] Building CXX object tools/mlir/lib/Dialect/Linalg/TransformOps/CMakeFiles/obj.MLIRLinalgTransformOps.dir/LinalgTransformOps.cpp.o
169.291 [1955/18/5096] Building CXX object tools/mlir/test/lib/Dialect/Linalg/CMakeFiles/MLIRLinalgTestPasses.dir/TestLinalgDecomposeOps.cpp.o
170.902 [1955/17/5097] Building CXX object tools/mlir/test/lib/Dialect/Linalg/CMakeFiles/MLIRLinalgTestPasses.dir/TestLinalgFusionTransforms.cpp.o
172.922 [1955/16/5098] Building CXX object tools/mlir/lib/Dialect/SparseTensor/Transforms/CMakeFiles/obj.MLIRSparseTensorTransforms.dir/SparseTensorPasses.cpp.o
173.414 [1955/15/5099] Building CXX object tools/mlir/lib/Conversion/GPUToNVVM/CMakeFiles/obj.MLIRGPUToNVVMTransforms.dir/LowerGpuOpsToNVVMOps.cpp.o
173.559 [1955/14/5100] Building CXX object tools/mlir/test/lib/Dialect/Linalg/CMakeFiles/MLIRLinalgTestPasses.dir/TestPadFusion.cpp.o
174.508 [1955/13/5101] Building CXX object tools/mlir/lib/Conversion/VectorToGPU/CMakeFiles/obj.MLIRVectorToGPU.dir/VectorToGPU.cpp.o
174.672 [1955/12/5102] Building CXX object tools/mlir/lib/Dialect/Vector/TransformOps/CMakeFiles/obj.MLIRVectorTransformOps.dir/VectorTransformOps.cpp.o
175.433 [1955/11/5103] Building CXX object tools/mlir/lib/Conversion/GPUCommon/CMakeFiles/obj.MLIRGPUToGPURuntimeTransforms.dir/GPUToLLVMConversion.cpp.o
175.807 [1955/10/5104] Building CXX object tools/mlir/test/lib/Dialect/Linalg/CMakeFiles/MLIRLinalgTestPasses.dir/TestLinalgTransforms.cpp.o

@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 21, 2024

LLVM Buildbot has detected a new failure on builder mlir-nvidia running on mlir-nvidia while building mlir at step 5 "build-check-mlir-build-only".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/138/builds/309

Here is the relevant piece of the build log for the reference:

Step 5 (build-check-mlir-build-only) failure: build (failure)
...
138.760 [780/16/3990] Creating library symlink lib/libMLIRSPIRVConversion.so
138.761 [779/16/3991] Creating library symlink lib/libMLIRSPIRVUtils.so
138.767 [778/16/3992] Creating library symlink lib/libMLIRVectorTransforms.so
138.771 [777/16/3993] Linking CXX shared library lib/libMLIRGPUToLLVMSPV.so.19.0git
138.846 [776/16/3994] Linking CXX shared library lib/libMLIRTransformDialectTransforms.so.19.0git
138.847 [775/16/3995] Linking CXX shared library lib/libMLIRUBToSPIRV.so.19.0git
138.856 [774/16/3996] Linking CXX shared library lib/libMLIRTransformPDLExtension.so.19.0git
138.857 [773/16/3997] Creating library symlink lib/libMLIRGPUToLLVMSPV.so
138.857 [772/16/3998] Linking CXX shared library lib/libMLIRControlFlowToSPIRV.so.19.0git
138.865 [771/16/3999] Linking CXX shared library lib/libMLIRConvertToSPIRVPass.so.19.0git
FAILED: lib/libMLIRConvertToSPIRVPass.so.19.0git 
: && /usr/bin/clang++ -fPIC -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -Wundef -Werror=mismatched-tags -Werror=global-constructors -O3 -DNDEBUG  -Wl,-z,defs -Wl,-z,nodelete -fuse-ld=lld -Wl,--color-diagnostics   -Wl,--gc-sections -shared -Wl,-soname,libMLIRConvertToSPIRVPass.so.19.0git -o lib/libMLIRConvertToSPIRVPass.so.19.0git tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o  -Wl,-rpath,"\$ORIGIN/../lib:/vol/worker/mlir-nvidia/mlir-nvidia/llvm.obj/lib:"  lib/libMLIRSPIRVConversion.so.19.0git  lib/libMLIRSPIRVDialect.so.19.0git  lib/libMLIRParser.so.19.0git  lib/libMLIRBytecodeReader.so.19.0git  lib/libMLIRAsmParser.so.19.0git  lib/libMLIRTransforms.so.19.0git  lib/libMLIRCopyOpInterface.so.19.0git  lib/libMLIRMemorySlotInterfaces.so.19.0git  lib/libMLIRRuntimeVerifiableOpInterface.so.19.0git  lib/libMLIRUBDialect.so.19.0git  lib/libMLIRTransformUtils.so.19.0git  lib/libMLIRRewrite.so.19.0git  lib/libMLIRRewritePDL.so.19.0git  lib/libMLIRPDLToPDLInterp.so.19.0git  lib/libMLIRPass.so.19.0git  lib/libMLIRPDLInterpDialect.so.19.0git  lib/libMLIRPDLDialect.so.19.0git  lib/libMLIRSubsetOpInterface.so.19.0git  lib/libMLIRValueBoundsOpInterface.so.19.0git  lib/libMLIRAnalysis.so.19.0git  lib/libMLIRLoopLikeInterface.so.19.0git  lib/libMLIRDataLayoutInterfaces.so.19.0git  lib/libMLIRInferIntRangeInterface.so.19.0git  lib/libMLIRPresburger.so.19.0git  lib/libMLIRViewLikeInterface.so.19.0git  lib/libMLIRDestinationStyleOpInterface.so.19.0git  lib/libMLIRFuncDialect.so.19.0git  lib/libMLIRSideEffectInterfaces.so.19.0git  lib/libMLIRControlFlowInterfaces.so.19.0git  lib/libMLIRFunctionInterfaces.so.19.0git  lib/libMLIRCallInterfaces.so.19.0git  lib/libMLIRInferTypeOpInterface.so.19.0git  lib/libMLIRIR.so.19.0git  lib/libMLIRSupport.so.19.0git  -lpthread  lib/libLLVMSupport.so.19.0git  -Wl,-rpath-link,/vol/worker/mlir-nvidia/mlir-nvidia/llvm.obj/lib && :
ld.lld: error: undefined symbol: mlir::ScfToSPIRVContext::ScfToSPIRVContext()
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::arith::populateCeilFloorDivExpandOpsPatterns(mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::arith::populateArithToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::populateFuncToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::index::populateIndexToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::populateVectorToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::populateSCFToSPIRVPatterns(mlir::SPIRVTypeConverter&, mlir::ScfToSPIRVContext&, mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::ub::populateUBToSPIRVConversionPatterns(mlir::SPIRVTypeConverter&, mlir::RewritePatternSet&)
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())

ld.lld: error: undefined symbol: mlir::ScfToSPIRVContext::~ScfToSPIRVContext()
>>> referenced by ConvertToSPIRVPass.cpp
>>>               tools/mlir/lib/Conversion/ConvertToSPIRV/CMakeFiles/obj.MLIRConvertToSPIRVPass.dir/ConvertToSPIRVPass.cpp.o:((anonymous namespace)::ConvertToSPIRVPass::runOnOperation())
clang: error: linker command failed with exit code 1 (use -v to see invocation)
138.869 [771/15/4000] Creating library symlink lib/libMLIRControlFlowToSPIRV.so

angelz913 added a commit to angelz913/llvm-project that referenced this pull request Jun 21, 2024
keith added a commit that referenced this pull request Jun 21, 2024
keith added a commit that referenced this pull request Jun 21, 2024
Original change was reverted

Reverts #96334
angelz913 added a commit to angelz913/llvm-project that referenced this pull request Jun 21, 2024
This PR implements a MVP version of an MLIR lowering pipeline to SPIR-V.
The goal of adding this pipeline is to have a better test coverage of
SPIR-V compilation upstream, and enable writing simple kernels by hand.
The dialects supported in this version include `arith`, `vector` (only
1-D vectors with size 2,3,4,8 or 16), `scf`, `ub`, `index`, `func` and
`math`. New test cases for the pass are also included in this PR.

**Relevant links**

- [Open MLIR Meeting - YouTube
Video](https://www.youtube.com/watch?v=csWPOQfgLMo)
- [Discussion on LLVM
Forum](https://discourse.llvm.org/t/open-mlir-meeting-12-14-2023-discussion-on-improving-handling-of-unit-dimensions-in-the-vector-dialect/75683)

**Future plans**

- Add conversion patterns for other dialects, e.g. `gpu`, `tensor`, etc.
- Include vector transformation to unroll vectors to 1-D, and handle
those with unsupported sizes.
- Implement multiple-return. SPIR-V does not support multiple return
values since a `spirv.func` can only return zero or one values. It might
be possible to wrap the return values in a `spirv.struct`.
- Add a conversion for `scf.parallel`.
angelz913 pushed a commit to angelz913/llvm-project that referenced this pull request Jun 21, 2024
kuhar pushed a commit that referenced this pull request Jun 24, 2024
This PR relands #95942, which was reverted in #96332 due to link
failures. It fixes the issue by updating CMake dependencies. The bazel
support, originally introduced in #96334, is also included in this PR.

---------

Co-authored-by: Keith Smiley <keithbsmiley@gmail.com>
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
This PR implements a MVP version of an MLIR lowering pipeline to SPIR-V.
The goal of adding this pipeline is to have a better test coverage of
SPIR-V compilation upstream, and enable writing simple kernels by hand.
The dialects supported in this version include `arith`, `vector` (only
1-D vectors with size 2,3,4,8 or 16), `scf`, `ub`, `index`, `func` and
`math`. New test cases for the pass are also included in this PR.

**Relevant links**

- [Open MLIR Meeting - YouTube
Video](https://www.youtube.com/watch?v=csWPOQfgLMo)
- [Discussion on LLVM
Forum](https://discourse.llvm.org/t/open-mlir-meeting-12-14-2023-discussion-on-improving-handling-of-unit-dimensions-in-the-vector-dialect/75683)

**Future plans**

- Add conversion patterns for other dialects, e.g. `gpu`, `tensor`, etc.
- Include vector transformation to unroll vectors to 1-D, and handle
those with unsupported sizes.
- Implement multiple-return. SPIR-V does not support multiple return
values since a `spirv.func` can only return zero or one values. It might
be possible to wrap the return values in a `spirv.struct`.
- Add a conversion for `scf.parallel`.
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
Original change was reverted

Reverts llvm#96334
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
This PR relands llvm#95942, which was reverted in llvm#96332 due to link
failures. It fixes the issue by updating CMake dependencies. The bazel
support, originally introduced in llvm#96334, is also included in this PR.

---------

Co-authored-by: Keith Smiley <keithbsmiley@gmail.com>
kuhar added a commit that referenced this pull request Aug 9, 2024
This PR adds conversion patterns for MemRef to the `convert-to-spirv`
pass, introduced in #95942. Conversions from MemRef memory space to
SPIR-V storage class were also included, and would run before the final
dialect conversion phase.

**Future Plans**
- Add tests for ops other than `memref.load` and `memref.store`

---------

Co-authored-by: Jakub Kuderski <kubakuderski@gmail.com>
kuhar pushed a commit that referenced this pull request Aug 12, 2024
…spirv` pass (#102528)

This PR adds lit tests that check for `scf.while` and `scf.for`
conversions for the `convert-to-spirv` pass, introduced in #95942.
kuhar pushed a commit that referenced this pull request Aug 20, 2024
This PR adds conversion patterns for GPU to the `convert-to-spirv` pass,
introduced in #95942. Now the pass is able to convert each `gpu.module`
and its ops within a `builtin.module` into a `spirv.module`.

**Future Plans**
- Use `gpu.launch_func` to invoke kernel from host functions
- Potentially integrate into the `mlir-vulkan-runner` for e2e testing
def ConvertToSPIRVPass : Pass<"convert-to-spirv"> {
let summary = "Convert to SPIR-V";
let description = [{
This is a generic pass to convert to SPIR-V.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This claims to be a "generic" pass but it seems to me instead to be a "monolithic" pass.

Why didn't we align this on the convert-to-llvm pass design instead?

Copy link
Member

@kuhar kuhar Aug 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@angelz913 talked about this in https://youtu.be/-qoMMrlYvGs?t=436 (starts around the 7m 15s mark). The TL;DR is we didn't know what interfaces to have, and decided to start with a monolithic multi-stage v0 implementation, with the plan to add make it interface-based when gain confidence in this design.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TL;DR is we didn't know what interfaces to have

I don't quite understand? Why isn't it just copy the convert-to-llvm one and rename it?

I have strong concerns with in-tree monolithic passes like this: what is the timeline to remove this and migrate to a pluggable one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that in-tree monolithic passes arent great, but the change to use interfaces and go to more LLVM based approach is more involved (I dont think it is as simple as "copy the convert-to-llvm and rename it". Angel and Jakub can fill in more details here). I think timeline will depend on how much community involvement we get here. Jakub and Angel are trying to get upstream support flushed out more. So this is a strict improvement anyway. Its probably better to iterate on this in a bit.

FWIW, for conversion to LLVM in IREE we just throw all the conversion patterns into one pass and run them together. I personally find the split of conversion from each dialect to LLVM kind of artificial. Everything needs to be translated to LLVM. Running multiple passes that walk the IR multiple times seems like a waste. But that is a downstream decision and not having monoliths in upstream MLIR is useful.

Copy link
Collaborator

@joker-eph joker-eph Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think timeline will depend on how much community involvement we get here.

In this case I would want to see this pass moved to the test folder: I'm not comfortable with monolithic passes alongside the rest of the transformations right now.

FWIW, for conversion to LLVM in IREE we just throw all the conversion patterns into one pass and run them together. I personally find the split of conversion from each dialect to LLVM kind of artificial

I suspect you missed the intent of upstream design: these individual passes are all made that way upstream for testing, the intention has always been that downstream projects create a monolithic pass for their own purpose and don't use the upstream passes as-is (which is why the populatePatterns method are exposed): that's exactly "work as intended".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the dependency on the spirv conversion code will have to move over there in some form.

Why would it have to be moved to the runner? The current pattern is that the transformations are made with mlir-opt ahead of invoking the runner (hence why we ended up with a "pure" mlir-cpu-runner).

So we can drop the runner, but it will just make the situation worse).

I think we're talking about different things maybe?
You seem to argue about the need for running some of these tests, while I'm just describing the system architecture of the project, which does not impact in any way which tests we're running.

That is, from a very high-level, the specific runner tool goes away and you do instead something like mlir-opt -pass-pipeline="builtin.module(convert-to-spirv)" %s | mlir-cpu-runner --shared-libs=mlir_vulkan_runtime.so.
(this is a transition we made for the mlir-cuda-runner ~3 years ago, and the Vulkan runner has been a TODO ever since IIUC)

Note that in this model, the test pass is available for the opt tool, the runner does not need to know about the test passes (or any pass).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification, Mehdi.

You seem to argue about the need for running some of these tests, while I'm just describing the system architecture of the project, which does not impact in any way which tests we're running.

Right, that's a good way to put it. From my point of view, what I mostly care about is that we do keep these tests (as in, both the implementation of convert-to-spirv and the e2e .mlir tests) while the cleanup in this area (both gpu-to-spirv and the runner implementation). I think we all aggrege on the end state, so I just want to make sure that we can find a path that allows us to make incremental improvements to get there.

From your perspective, would it be an option to make this a test pass and temporarily have it registered it in the vulkan runner (similar to how they are manually listed in mlir-opt.cpp)? Maybe that's a middle ground, although I'm not sure of how much difference to a pass being a test or not there practically is for other users of mlir.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From your perspective, would it be an option to make this a test pass and temporarily have it registered it in the vulkan runner (similar to how they are manually listed in mlir-opt.cpp)?

The problem is that we optionally compile the test passes I think? (With -DMLIR_INCLUDE_TESTS=ON).

It may be easier to just keep the pass as-is until we migrate tests from mlir-vulkan-runner to mlir-cpu-runner?

The only thing that makes be nervous is that unless there is a timeline with people making progress on it, we'll still be adding mlir-vulkan-runner based tests multiple years from now. What I'm trying to see is some sort of a "gradient" on the progression of all this (and some timeline), rather than a quick immediate solution.

Copy link
Member

@kuhar kuhar Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let me check internally if we can commit to something more concrete along this axis. Overall, I think we did make a lot of recent progress on the spirv conversion test coverage and general cleanup in this area, but I understand why you'd want to prioritize the runner cleanup next.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joker-eph I checked and we will have @andfau-amd work on the mlir runner migration, starting from ~next week.

kuhar pushed a commit that referenced this pull request Aug 28, 2024
#106426)

This PR adds an integration test for an argmax kernel with
`mlir-vulkan-runner`. This test exercises the `convert-to-spirv` pass
(landed in #95942) and demonstrates that we can use SPIR-V ops as
"intrinsics" among higher-level dialects.

The support for `index` dialect in `mlir-vulkan-runner` is also added.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants