From: Nicolas Vasilache Date: Mon, 29 Apr 2019 19:11:58 +0000 (-0700) Subject: Parsing support for Range, View and Slice operations X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=56c7a957bfc5cbcb97e92286bd3b1dae3a06659a;p=platform%2Fupstream%2Fllvm.git Parsing support for Range, View and Slice operations This CL implements the previously unsupported parsing for Range, View and Slice operations. A pass is introduced to lower to the LLVM. Tests are moved out of C++ land and into mlir/test/Examples. This allows better fitting within standard developer workflows. -- PiperOrigin-RevId: 245796600 --- diff --git a/mlir/examples/Linalg/CMakeLists.txt b/mlir/examples/Linalg/CMakeLists.txt index c4a2610..8e955d9 100644 --- a/mlir/examples/Linalg/CMakeLists.txt +++ b/mlir/examples/Linalg/CMakeLists.txt @@ -7,9 +7,7 @@ include_directories(Linalg4/include/) add_custom_target(Linalg) set_target_properties(Linalg PROPERTIES FOLDER Examples) add_dependencies(Linalg - linalg-conversion-1 linalg-conversion-3 - linalg-example-1 linalg-example-2 linalg-example-3 linalg-example-4 diff --git a/mlir/examples/Linalg/Linalg1/CMakeLists.txt b/mlir/examples/Linalg/Linalg1/CMakeLists.txt index 8556c6f..3ea7a41 100644 --- a/mlir/examples/Linalg/Linalg1/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg1/CMakeLists.txt @@ -1,36 +1 @@ add_subdirectory(lib) - -set(LLVM_LINK_COMPONENTS - Core - Support - ) - -set(LLVM_OPTIONAL_SOURCES Conversion.cpp Example.cpp) - -add_llvm_example(linalg-conversion-1 - Conversion.cpp - ) - -add_llvm_example(linalg-example-1 - Example.cpp - ) - -target_link_libraries(linalg-example-1 - PRIVATE - Linalg1DialectConstruction - Linalg1 - ) - -whole_archive_link(linalg-example-1 - MLIRStandardOps - ) - -target_link_libraries(linalg-conversion-1 - PRIVATE - Linalg1DialectConstruction - Linalg1 - ) - -whole_archive_link(linalg-conversion-1 - MLIRStandardOps - ) diff --git a/mlir/examples/Linalg/Linalg1/Conversion.cpp b/mlir/examples/Linalg/Linalg1/Conversion.cpp deleted file mode 100644 index a1c9d4e..0000000 --- a/mlir/examples/Linalg/Linalg1/Conversion.cpp +++ /dev/null @@ -1,309 +0,0 @@ -//===- Conversion.cpp - Linalg to LLVM conversion driver ------------------===// -// -// Copyright 2019 The MLIR Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ============================================================================= - -// RUN: %p/conversion | FileCheck %s - -#include "TestHarness.h" - -#include "linalg1/Common.h" -#include "linalg1/ConvertToLLVMDialect.h" -#include "linalg1/Dialect.h" -#include "linalg1/Intrinsics.h" -#include "linalg1/Ops.h" -#include "linalg1/Types.h" -#include "mlir/EDSC/Builders.h" -#include "mlir/EDSC/Intrinsics.h" -#include "mlir/IR/Function.h" - -using namespace linalg; -using namespace linalg::common; -using namespace linalg::intrinsics; -using namespace mlir; -using namespace mlir::edsc; -using namespace mlir::edsc::intrinsics; - -TEST_FUNC(rangeConversion) { - // Define the MLIR context, create a Module in this context, and a Builder to - // facilitate type construction. - MLIRContext context; - Module module(&context); - Builder builder(&module); - - // Declare a function called "rangeConversion" with type: - // (index, index, index) -> () - // define it, and add it to the module. - FunctionType funcType = builder.getFunctionType( - {builder.getIndexType(), builder.getIndexType(), builder.getIndexType()}, - {}); - Function *f = - new Function(builder.getUnknownLoc(), "rangeConversion", funcType); - f->addEntryBlock(); - module.getFunctions().push_back(f); - - // Construct a linalg::RangeOp taking function arguments as operands. - ScopedContext scope(f); - ValueHandle arg0(f->getArgument(0)), arg1(f->getArgument(1)), - arg2(f->getArgument(2)); - { - range(arg0, arg1, arg2); - ret(); - } - - // clang-format off - // CHECK-LABEL: @rangeConversion - // CHECK-NEXT: %0 = llvm.undef : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %1 = llvm.insertvalue %arg0, %0[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %2 = llvm.insertvalue %arg1, %1[1] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %3 = llvm.insertvalue %arg2, %2[2] : !llvm<"{ i64, i64, i64 }"> - // clang-format on - convertToLLVM(module); - module.print(llvm::outs()); -} - -TEST_FUNC(viewRangeConversion) { - // Define the MLIR context, create a Module in this context, and a Builder to - // facilitate type construction. - MLIRContext context; - Module module(&context); - Builder builder(&module); - - // Declare a function called "viewRangeConversion" with type: - // (memref, !linalg.range, !linalg.range) -> () - // define it, and add it to the module. - FunctionType funcType = builder.getFunctionType( - {builder.getMemRefType({-1, -1}, builder.getF32Type(), {}, 0), - builder.getType(), builder.getType()}, - {}); - Function *f = - new Function(builder.getUnknownLoc(), "viewRangeConversion", funcType); - f->addEntryBlock(); - module.getFunctions().push_back(f); - - // Construct a linalg::ViewOp taking function arguments as operands. - ScopedContext scope(f); - ValueHandle memref(f->getArgument(0)), range1(f->getArgument(1)), - range2(f->getArgument(2)); - { - view(memref, {range1, range2}); - ret(); - } - - // clang-format off - // CHECK-LABEL: @viewRangeConversion - // CHECK-NEXT: %0 = llvm.undef : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }"> - // CHECK-NEXT: %2 = llvm.insertvalue %1, %0[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }"> - // CHECK-NEXT: %4 = llvm.constant(1 : index) : !llvm.i64 - // CHECK-NEXT: %5 = llvm.mul %4, %3 : !llvm.i64 - // CHECK-NEXT: %6 = llvm.constant(0 : index) : !llvm.i64 - // CHECK-NEXT: %7 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %8 = llvm.mul %7, %5 : !llvm.i64 - // CHECK-NEXT: %9 = llvm.add %6, %8 : !llvm.i64 - // CHECK-NEXT: %10 = llvm.extractvalue %arg2[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %11 = llvm.mul %10, %4 : !llvm.i64 - // CHECK-NEXT: %12 = llvm.add %9, %11 : !llvm.i64 - // CHECK-NEXT: %13 = llvm.insertvalue %12, %2[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %14 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %15 = llvm.extractvalue %arg1[1] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %16 = llvm.sub %15, %14 : !llvm.i64 - // CHECK-NEXT: %17 = llvm.insertvalue %16, %13[2, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %18 = llvm.extractvalue %arg2[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %19 = llvm.extractvalue %arg2[1] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %20 = llvm.sub %19, %18 : !llvm.i64 - // CHECK-NEXT: %21 = llvm.insertvalue %20, %17[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %22 = llvm.extractvalue %arg1[2] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %23 = llvm.mul %5, %22 : !llvm.i64 - // CHECK-NEXT: %24 = llvm.insertvalue %23, %21[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %25 = llvm.extractvalue %arg2[2] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %26 = llvm.mul %4, %25 : !llvm.i64 - // CHECK-NEXT: %27 = llvm.insertvalue %26, %24[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // clang-format on - convertToLLVM(module); - module.print(llvm::outs()); -} - -TEST_FUNC(viewNonRangeConversion) { - // Define the MLIR context, create a Module in this context, and a Builder to - // facilitate type construction. - MLIRContext context; - Module module(&context); - Builder builder(&module); - - // Declare a function called "viewNonRangeConversion" with type: - // (memref, !linalg.range, index) -> () - // define it, and add it to the module. - FunctionType funcType = builder.getFunctionType( - {builder.getMemRefType({-1, -1}, builder.getF32Type(), {}, 0), - builder.getType(), builder.getIndexType()}, - {}); - Function *f = - new Function(builder.getUnknownLoc(), "viewNonRangeConversion", funcType); - f->addEntryBlock(); - module.getFunctions().push_back(f); - - // Construct a linalg::ViewOp taking function arguments as operands. - ScopedContext scope(f); - ValueHandle memref(f->getArgument(0)), range(f->getArgument(1)), - index(f->getArgument(2)); - { - view(memref, {range, index}); - ret(); - } - - // clang-format off - // CHECK-LABEL: @viewNonRangeConversion - // CHECK-NEXT: %0 = llvm.undef : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> - // CHECK-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }"> - // CHECK-NEXT: %2 = llvm.insertvalue %1, %0[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> - // CHECK-NEXT: %3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }"> - // CHECK-NEXT: %4 = llvm.constant(1 : index) : !llvm.i64 - // CHECK-NEXT: %5 = llvm.mul %4, %3 : !llvm.i64 - // CHECK-NEXT: %6 = llvm.constant(0 : index) : !llvm.i64 - // CHECK-NEXT: %7 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %8 = llvm.mul %7, %5 : !llvm.i64 - // CHECK-NEXT: %9 = llvm.add %6, %8 : !llvm.i64 - // CHECK-NEXT: %10 = llvm.mul %arg2, %4 : !llvm.i64 - // CHECK-NEXT: %11 = llvm.add %9, %10 : !llvm.i64 - // CHECK-NEXT: %12 = llvm.insertvalue %11, %2[1] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> - // CHECK-NEXT: %13 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %14 = llvm.extractvalue %arg1[1] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %15 = llvm.sub %14, %13 : !llvm.i64 - // CHECK-NEXT: %16 = llvm.insertvalue %15, %12[2, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> - // CHECK-NEXT: %17 = llvm.extractvalue %arg1[2] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %18 = llvm.mul %5, %17 : !llvm.i64 - // CHECK-NEXT: %19 = llvm.insertvalue %18, %16[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> - // clang-format on - convertToLLVM(module); - module.print(llvm::outs()); -} - -TEST_FUNC(sliceRangeConversion) { - // Define the MLIR context, create a Module in this context, and a Builder to - // facilitate type construction. - MLIRContext context; - Module module(&context); - Builder builder(&module); - - // Declare a function called "sliceRangeConversion" with type: - // (memref, !linalg.range, !linalg.range, !linalg.range) -> () - // define it, and add it to the module. - FunctionType funcType = builder.getFunctionType( - {builder.getMemRefType({-1, -1}, builder.getF32Type(), {}, 0), - builder.getType(), builder.getType(), - builder.getType()}, - {}); - Function *f = - new Function(builder.getUnknownLoc(), "sliceRangeConversion", funcType); - f->addEntryBlock(); - module.getFunctions().push_back(f); - - // Construct a linalg::SliceOp based on the result of a linalg::ViewOp. - // Note: SliceOp builder does not support ViewOps that are not defined by - // a dominating ViewOp. - ScopedContext scope(f); - ValueHandle memref(f->getArgument(0)), range1(f->getArgument(1)), - range2(f->getArgument(2)), range3(f->getArgument(3)); - { - slice(view(memref, {range1, range2}), range3, 0); - ret(); - } - - // clang-format off - // CHECK-LABEL: @sliceRangeConversion - // CHECK: %28 = llvm.undef : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %29 = llvm.extractvalue %27[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %30 = llvm.insertvalue %29, %28[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %31 = llvm.extractvalue %27[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %32 = llvm.extractvalue %arg3[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %33 = llvm.extractvalue %27[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %34 = llvm.mul %32, %33 : !llvm.i64 - // CHECK-NEXT: %35 = llvm.add %31, %34 : !llvm.i64 - // CHECK-NEXT: %36 = llvm.insertvalue %35, %30[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %37 = llvm.extractvalue %arg3[1] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %38 = llvm.extractvalue %arg3[0] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %39 = llvm.sub %37, %38 : !llvm.i64 - // CHECK-NEXT: %40 = llvm.extractvalue %27[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %41 = llvm.extractvalue %arg3[2] : !llvm<"{ i64, i64, i64 }"> - // CHECK-NEXT: %42 = llvm.mul %40, %41 : !llvm.i64 - // CHECK-NEXT: %43 = llvm.insertvalue %39, %36[2, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %44 = llvm.insertvalue %42, %43[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %45 = llvm.extractvalue %27[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %46 = llvm.extractvalue %27[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %47 = llvm.insertvalue %45, %44[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %48 = llvm.insertvalue %46, %47[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // clang-format on - convertToLLVM(module); - module.print(llvm::outs()); -} - -TEST_FUNC(sliceNonRangeConversion) { - // Define the MLIR context, create a Module in this context, and a Builder to - // facilitate type construction. - MLIRContext context; - Module module(&context); - Builder builder(&module); - - // Declare a function called "sliceNonRangeConversion" with type: - // (memref, !linalg.range, !linalg.range, !linalg.range) -> () - // define it, and add it to the module. - FunctionType funcType = builder.getFunctionType( - {builder.getMemRefType({-1, -1}, builder.getF32Type(), {}, 0), - builder.getType(), builder.getType(), - builder.getIndexType()}, - {}); - Function *f = new Function(builder.getUnknownLoc(), "sliceNonRangeConversion", - funcType); - f->addEntryBlock(); - module.getFunctions().push_back(f); - - // Construct a linalg::SliceOp based on the result of a linalg::ViewOp. - // Note: SliceOp builder does not support ViewOps that are not defined by - // a dominating ViewOp. - ScopedContext scope(f); - ValueHandle memref(f->getArgument(0)), range1(f->getArgument(1)), - range2(f->getArgument(2)), index(f->getArgument(3)); - { - slice(view(memref, {range1, range2}), index, 0); - ret(); - } - - // CHECK-LABEL: @sliceNonRangeConversion - // CHECK: %28 = llvm.undef : !llvm<"{ float*, i64, [1 x i64], [1 x i64] - // }"> CHECK-NEXT: %29 = llvm.extractvalue %27[0] : !llvm<"{ float*, i64, [2 x - // i64], [2 x i64] }"> CHECK-NEXT: %30 = llvm.insertvalue %29, %28[0] : - // !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> CHECK-NEXT: %31 = - // llvm.extractvalue %27[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> - // CHECK-NEXT: %32 = llvm.extractvalue %27[3, 0] : !llvm<"{ float*, i64, [2 x - // i64], [2 x i64] }"> CHECK-NEXT: %33 = llvm.mul %arg3, %32 : !llvm.i64 - // CHECK-NEXT: %34 = llvm.add %31, %33 : !llvm.i64 - // CHECK-NEXT: %35 = llvm.insertvalue %34, %30[1] : !llvm<"{ float*, i64, [1 x - // i64], [1 x i64] }"> CHECK-NEXT: %36 = llvm.extractvalue %27[2, 1] : - // !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> CHECK-NEXT: %37 = - // llvm.extractvalue %27[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] - // }"> CHECK-NEXT: %38 = llvm.insertvalue %36, %35[2, 0] : !llvm<"{ float*, - // i64, [1 x i64], [1 x i64] }"> CHECK-NEXT: %39 = llvm.insertvalue %37, - // %38[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> - convertToLLVM(module); - module.print(llvm::outs()); -} - -int main() { - mlir::registerDialect(); - RUN_TESTS(); - return 0; -} diff --git a/mlir/examples/Linalg/Linalg1/Example.cpp b/mlir/examples/Linalg/Linalg1/Example.cpp deleted file mode 100644 index 3ab54d0..0000000 --- a/mlir/examples/Linalg/Linalg1/Example.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//===- Example.cpp - Our running example ----------------------------------===// -// -// Copyright 2019 The MLIR Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ============================================================================= - -// RUN: %p/test | FileCheck %s - -#include "TestHarness.h" - -#include "linalg1/Common.h" -#include "linalg1/Dialect.h" -#include "linalg1/Intrinsics.h" -#include "linalg1/Ops.h" -#include "linalg1/Types.h" -#include "linalg1/Utils.h" -#include "mlir/IR/Function.h" - -using namespace linalg; -using namespace linalg::common; -using namespace linalg::intrinsics; -using namespace mlir; -using namespace mlir::edsc; -using namespace mlir::edsc::intrinsics; - -TEST_FUNC(view_op) { - MLIRContext context; - Module module(&context); - auto indexType = mlir::IndexType::get(&context); - Function *f = - makeFunction(module, "view_op", {indexType, indexType, indexType}, {}); - - ScopedContext scope(f); - - // Let's be lazy and define some custom ops that prevent DCE. - CustomOperation some_consumer("some_consumer"); - - // clang-format off - ValueHandle M(f->getArgument(0)), N(f->getArgument(1)), - A0 = alloc(floatMemRefType<0>(&context)), - A1 = alloc(floatMemRefType<1>(&context), {M}), - A2 = alloc(floatMemRefType<2>(&context), {M, N}), - r0 = range(constant_index(3), constant_index(17), constant_index(1)), - v0 = view(A0, {}), - v1 = view(A1, {r0}), - v2 = view(A2, {r0, r0}); - some_consumer({v0, v1, v2}); - ret(); - // CHECK-LABEL: func @view_op - // CHECK: %[[R:.*]] = linalg.range %{{.*}}:%{{.*}}:%{{.*}} : !linalg.range - // CHECK-NEXT: {{.*}} = linalg.view {{.*}}[] : !linalg.view - // CHECK-NEXT: {{.*}} = linalg.view {{.*}}[%[[R]]] : !linalg.view - // CHECK-NEXT: {{.*}} = linalg.view {{.*}}[%[[R]], %[[R]]] : !linalg.view - // clang-format on - - cleanupAndPrintFunction(f); -} - -TEST_FUNC(slice_op) { - MLIRContext context; - Module module(&context); - auto indexType = mlir::IndexType::get(&context); - Function *f = - makeFunction(module, "slice_op", {indexType, indexType, indexType}, {}); - - ScopedContext scope(f); - - // Let's be lazy and define some custom op that prevents DCE. - CustomOperation some_consumer("some_consumer"); - - // clang-format off - ValueHandle M(f->getArgument(0)), N(f->getArgument(1)), - A = alloc(floatMemRefType<2>(&context), {M, N}); - ViewOp vA = emitAndReturnViewOpFromMemRef(A); - IndexHandle i, j; - LoopNestRangeBuilder({&i, &j}, vA.getRanges())({ - some_consumer(slice(vA, i, 1)), - some_consumer(slice(slice(vA, j, 0), i, 0)), - }); - ret(); - // CHECK-LABEL: func @slice_op(%arg0: index, %arg1: index, %arg2: index) { - // CHECK: %[[ALLOC:.*]] = alloc(%arg0, %arg1) : memref - // CHECK-NEXT: %[[M:.*]] = dim %0, 0 : memref - // CHECK-NEXT: %[[N:.*]] = dim %0, 1 : memref - // CHECK-NEXT: %[[R1:.*]] = linalg.range {{.*}}:%[[M]]:{{.*}} : !linalg.range - // CHECK-NEXT: %[[R2:.*]] = linalg.range {{.*}}:%[[N]]:{{.*}} : !linalg.range - // CHECK-NEXT: %[[V:.*]] = linalg.view %0[%[[R1]], %[[R2]]] : !linalg.view - // CHECK-NEXT: for %i0 = 0 to (d0) -> (d0)(%[[M]]) { - // CHECK-NEXT: for %i1 = 0 to (d0) -> (d0)(%[[N]]) { - // CHECK-NEXT: %[[S1:.*]] = linalg.slice %[[V]][*, %i0] : !linalg.view - // CHECK-NEXT: "some_consumer"(%[[S1]]) : (!linalg.view) -> () - // CHECK-NEXT: %[[S2:.*]] = linalg.slice %[[V]][%i1, *] : !linalg.view - // CHECK-NEXT: %[[S3:.*]] = linalg.slice %[[S2]][%i0] : !linalg.view - // CHECK-NEXT: "some_consumer"(%[[S3]]) : (!linalg.view) -> () - // clang-format on - - cleanupAndPrintFunction(f); -} - -int main() { - mlir::registerDialect(); - RUN_TESTS(); - return 0; -} diff --git a/mlir/examples/Linalg/Linalg1/include/linalg1/Passes.h b/mlir/examples/Linalg/Linalg1/include/linalg1/Passes.h new file mode 100644 index 0000000..d87fa3b --- /dev/null +++ b/mlir/examples/Linalg/Linalg1/include/linalg1/Passes.h @@ -0,0 +1,39 @@ +//===- Passes.h - Pass Entrypoints ------------------------------*- C++ -*-===// +// +// Copyright 2019 The MLIR Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ============================================================================= +// +// This header file defines prototypes that expose pass constructors. +// +//===----------------------------------------------------------------------===// + +#ifndef LINALG1_PASSES_H +#define LINALG1_PASSES_H + +#include "mlir/Support/LLVM.h" +#include +#include + +namespace mlir { +class ModulePassBase; +} // namespace mlir + +namespace linalg { + +mlir::ModulePassBase *createLowerLinalgToLLVMPass(); + +} // namespace linalg + +#endif // LINALG1_PASSES_H diff --git a/mlir/examples/Linalg/Linalg1/lib/CMakeLists.txt b/mlir/examples/Linalg/Linalg1/lib/CMakeLists.txt index 3722701..d9daf60 100644 --- a/mlir/examples/Linalg/Linalg1/lib/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg1/lib/CMakeLists.txt @@ -9,8 +9,21 @@ set(LLVM_OPTIONAL_SOURCES Utils.cpp ViewType.cpp DialectConstruction.cpp + DialectRegistration.cpp ) +set(LIBS + MLIRAffineOps + MLIRAnalysis + MLIREDSC + MLIRLLVMIR + MLIRParser + MLIRPass + MLIRStandardOps + MLIRSupport + MLIRTransforms +) + add_llvm_library(Linalg1 Analysis.cpp ConvertToLLVMDialect.cpp @@ -22,22 +35,33 @@ add_llvm_library(Linalg1 Utils.cpp ViewType.cpp ) - target_link_libraries(Linalg1 PUBLIC - MLIRAnalysis - MLIRDialect - MLIREDSC - MLIRIR - MLIRLLVMIR - MLIRParser - MLIRPass - MLIRTransforms - ) + ${LIBS} + ) + +add_llvm_library(Linalg1LLVMConversion + ConvertToLLVMDialect.cpp + ) add_llvm_library(Linalg1DialectConstruction DialectConstruction.cpp ) +target_link_libraries(Linalg1DialectConstruction PUBLIC Linalg1) -target_link_libraries(Linalg1DialectConstruction - PUBLIC Linalg1) +add_executable(linalg1-opt + DialectRegistration.cpp + ) +llvm_update_compile_flags(linalg1-opt) +whole_archive_link(linalg1-opt + Linalg1LLVMConversion + Linalg1DialectConstruction + ${LIBS} + ) +target_link_libraries(linalg1-opt + Linalg1 + Linalg1LLVMConversion + Linalg1DialectConstruction + MLIRMlirOptLib + ${LIBS} + LLVMSupport) diff --git a/mlir/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp b/mlir/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp index 0aca4c0..c00413c 100644 --- a/mlir/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp +++ b/mlir/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp @@ -42,6 +42,7 @@ #include "linalg1/ConvertToLLVMDialect.h" #include "linalg1/LLVMIntrinsics.h" #include "linalg1/Ops.h" +#include "linalg1/Passes.h" using namespace mlir; @@ -513,3 +514,17 @@ void linalg::convertToLLVM(mlir::Module &module) { (void)r; assert(succeeded(r) && "second conversion failed"); } + +namespace { +struct LowerLinalgToLLVMPass : public ModulePass { + void runOnModule() { linalg::convertToLLVM(getModule()); } +}; +} // namespace + +ModulePassBase *linalg::createLowerLinalgToLLVMPass() { + return new LowerLinalgToLLVMPass(); +} + +static PassRegistration + pass("lower-linalg-to-llvm", + "Lower the operations from the linalg dialect into the LLVM dialect"); diff --git a/mlir/examples/Linalg/Linalg1/lib/Dialect.cpp b/mlir/examples/Linalg/Linalg1/lib/Dialect.cpp index 7b1dca4..5152df3 100644 --- a/mlir/examples/Linalg/Linalg1/lib/Dialect.cpp +++ b/mlir/examples/Linalg/Linalg1/lib/Dialect.cpp @@ -24,18 +24,37 @@ #include "linalg1/Ops.h" #include "linalg1/Types.h" #include "mlir/IR/Dialect.h" +#include "mlir/IR/OpImplementation.h" +#include "mlir/IR/StandardTypes.h" #include "llvm/Support/raw_ostream.h" using llvm::raw_ostream; using llvm::StringRef; -using mlir::Location; -using mlir::Type; +using namespace mlir; using namespace linalg; Type LinalgDialect::parseType(StringRef spec, Location loc) const { - llvm_unreachable("Unhandled linalg dialect parsing"); - return Type(); + MLIRContext *context = getContext(); + if (spec == "range") + return RangeType::get(getContext()); + + StringRef str = spec; + if (str.consume_front("view<")) { + // Just count the number of ? to get the rank, the type must be f32 for now. + unsigned rank = 0; + while (str.consume_front("?x")) + ++rank; + if (str.consume_front("bf16>")) + return ViewType::get(context, FloatType::getBF16(context), rank); + if (str.consume_front("f16>")) + return ViewType::get(context, FloatType::getF16(context), rank); + if (str.consume_front("f32>")) + return ViewType::get(context, FloatType::getF32(context), rank); + if (str.consume_front("f64>")) + return ViewType::get(context, FloatType::getF64(context), rank); + } + return (context->emitError(loc, "unknown Linalg type: " + spec), nullptr); } /// RangeType prints as just "range". diff --git a/mlir/examples/Linalg/Linalg1/lib/DialectRegistration.cpp b/mlir/examples/Linalg/Linalg1/lib/DialectRegistration.cpp new file mode 100644 index 0000000..e657bc3 --- /dev/null +++ b/mlir/examples/Linalg/Linalg1/lib/DialectRegistration.cpp @@ -0,0 +1,31 @@ +//===- DialectRegistration.cpp - Registration of the Linalg dialect -------===// +// +// Copyright 2019 The MLIR Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ============================================================================= +// +// This file implements a registration for the Linalg Dialect globally. +// This can just be linked in as a dependence into any binary to enable the +// Linalg dialect. Note that the binary it is linked into must not already +// register Linalg or double registration will occur. +// +//===----------------------------------------------------------------------===// + +#include "linalg1/Dialect.h" + +using namespace linalg; + +// Dialect registration triggers the creation of a `LinalgDialect` object which +// adds the proper types and operations to the dialect. +static mlir::DialectRegistration LinalgOps; diff --git a/mlir/examples/Linalg/Linalg1/lib/RangeOp.cpp b/mlir/examples/Linalg/Linalg1/lib/RangeOp.cpp index 56b9c02..6899ed6 100644 --- a/mlir/examples/Linalg/Linalg1/lib/RangeOp.cpp +++ b/mlir/examples/Linalg/Linalg1/lib/RangeOp.cpp @@ -26,18 +26,15 @@ #include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" -using mlir::Builder; -using mlir::IndexType; -using mlir::OpAsmParser; -using mlir::OpAsmPrinter; -using mlir::OperationState; -using mlir::Value; +using llvm::SmallVector; +using namespace mlir; +using namespace linalg; // Minimal example for a new RangeOp operating on RangeType. void linalg::RangeOp::build(Builder *b, OperationState *result, Value *min, Value *max, Value *step) { result->addOperands({min, max, step}); - result->addTypes({linalg::RangeType::get(b->getContext())}); + result->addTypes({RangeType::get(b->getContext())}); } // Verification is simply that a RangeOp takes 3 index ssa-value. @@ -51,9 +48,15 @@ mlir::LogicalResult linalg::RangeOp::verify() { return mlir::success(); } -// Parsing of the linalg dialect is not supported in this tutorial. bool linalg::RangeOp::parse(OpAsmParser *parser, OperationState *result) { - llvm_unreachable("Parsing linalg dialect is not supported in this tutorial"); + SmallVector rangeInfo(3); + RangeType type; + auto indexTy = parser->getBuilder().getIndexType(); + return parser->parseOperand(rangeInfo[0]) || parser->parseColon() || + parser->parseOperand(rangeInfo[1]) || parser->parseColon() || + parser->parseOperand(rangeInfo[2]) || parser->parseColonType(type) || + parser->resolveOperands(rangeInfo, indexTy, result->operands) || + parser->addTypeToList(type, result->types); } // A RangeOp prints as: @@ -63,5 +66,7 @@ bool linalg::RangeOp::parse(OpAsmParser *parser, OperationState *result) { // ``` void linalg::RangeOp::print(OpAsmPrinter *p) { *p << getOperationName() << " " << *getMin() << ":" << *getMax() << ":" - << *getStep() << " : " << getType(); + << *getStep(); + p->printOptionalAttrDict(getAttrs()); + *p << " : " << getType(); } diff --git a/mlir/examples/Linalg/Linalg1/lib/SliceOp.cpp b/mlir/examples/Linalg/Linalg1/lib/SliceOp.cpp index b7337a1..56a4aed 100644 --- a/mlir/examples/Linalg/Linalg1/lib/SliceOp.cpp +++ b/mlir/examples/Linalg/Linalg1/lib/SliceOp.cpp @@ -58,6 +58,8 @@ void linalg::SliceOp::build(Builder *b, OperationState *result, Value *view, } mlir::LogicalResult linalg::SliceOp::verify() { + if (!getAttr(getSlicingDimAttrName())) + return emitOpError("slice op expects a dim attribute"); unsigned dim = getSlicingDim(); if (dim >= getParentRank()) return emitOpError("slicing dim must be in the [0 .. parent_rank) range"); @@ -72,36 +74,61 @@ mlir::LogicalResult linalg::SliceOp::verify() { return mlir::success(); } -// Parsing of the linalg dialect is not supported in this tutorial. bool linalg::SliceOp::parse(OpAsmParser *parser, OperationState *result) { - llvm_unreachable("Parsing linalg dialect is not supported in this tutorial"); + OpAsmParser::OperandType viewInfo; + SmallVector indexingInfo; + SmallVector types; + if (parser->parseOperand(viewInfo) || + parser->parseOperandList(indexingInfo, 1, + OpAsmParser::Delimiter::Square) || + parser->parseOptionalAttributeDict(result->attributes) || + parser->parseColonTypeList(types)) + return true; + + if (indexingInfo.size() != 1) + return parser->emitError(parser->getNameLoc(), "expected 1 indexing type"); + + ViewType viewType = types.front().dyn_cast(); + if (!viewType) + return parser->emitError(parser->getNameLoc(), + "view type expected as first type"); + + IndexType indexType = types.back().dyn_cast(); + RangeType rangeType = types.back().dyn_cast(); + if (!indexType && !rangeType) { + llvm::errs() << types.back(); + return parser->emitError(parser->getNameLoc(), + "indexing must be of range or index type"); + } + + unsigned rank = viewType.getRank(); + if (indexType) + --rank; + ViewType resultViewType = + ViewType::get(viewType.getContext(), viewType.getElementType(), rank); + + return parser->resolveOperand(viewInfo, viewType, result->operands) || + parser->resolveOperands(indexingInfo[0], types.back(), + result->operands) || + parser->addTypeToList(resultViewType, result->types); } // A SliceOp prints as: // // ```{.mlir} -// linalg.slice %0[*, %i0] : !linalg.view +// linalg.slice %0[%i0] {dim: 0} : !linalg.view, index // ``` // // Where %0 is an ssa-value holding a `view`, %i0 is an ssa-value // holding an index. void linalg::SliceOp::print(OpAsmPrinter *p) { - unsigned dim = getSlicingDim(); - *p << getOperationName() << " " << *getParentView() << "["; - for (unsigned idx = 0, rank = getParentRank(); idx < rank; ++idx) { - if (idx != dim) { - *p << "*"; - } else { - auto *v = getIndexing(); - if (isa_and_nonnull(v->getDefiningOp())) { - *p << *v << ".."; - } else { - *p << *v; - } - } - *p << ((idx == rank - 1) ? "" : ", "); - } - *p << "] : " << getViewType(); + *p << getOperationName() << " " << *getParentView() << "[" << *getIndexing() + << "]"; + *p << " {dim: "; + p->printAttribute(getAttr("dim")); + *p << "}"; + p->printOptionalAttrDict(getAttrs(), {"dim"}); + *p << " : " << getParentViewType() << ", " << getIndexing()->getType(); } ViewType linalg::SliceOp::getViewType() { return getType().cast(); } diff --git a/mlir/examples/Linalg/Linalg1/lib/ViewOp.cpp b/mlir/examples/Linalg/Linalg1/lib/ViewOp.cpp index 42be75a..6cd0f27 100644 --- a/mlir/examples/Linalg/Linalg1/lib/ViewOp.cpp +++ b/mlir/examples/Linalg/Linalg1/lib/ViewOp.cpp @@ -58,9 +58,9 @@ LogicalResult linalg::ViewOp::verify() { if (llvm::empty(getOperands())) return emitOpError( "requires at least a memref operand followed by 'rank' indices"); - auto memrefType = getOperand(0)->getType().dyn_cast(); - unsigned memrefRank = memrefType.getRank(); - if (!memrefType) + auto memRefType = getOperand(0)->getType().dyn_cast(); + unsigned memrefRank = memRefType.getRank(); + if (!memRefType) return emitOpError("first operand must be of MemRefType"); unsigned index = 0; for (auto indexing : getIndexings()) { @@ -89,15 +89,50 @@ LogicalResult linalg::ViewOp::verify() { return success(); } -// Parsing of the linalg dialect is not supported in this tutorial. bool linalg::ViewOp::parse(OpAsmParser *parser, OperationState *result) { - llvm_unreachable("Parsing linalg dialect is not supported in this tutorial"); + OpAsmParser::OperandType memRefInfo; + SmallVector indexingsInfo; + SmallVector types; + if (parser->parseOperand(memRefInfo) || + parser->parseOperandList(indexingsInfo, -1, + OpAsmParser::Delimiter::Square) || + parser->parseOptionalAttributeDict(result->attributes) || + parser->parseColonTypeList(types)) + return true; + + if (types.size() != 2 + indexingsInfo.size()) + return parser->emitError(parser->getNameLoc(), + "unexpected number of types "); + MemRefType memRefType = types[0].dyn_cast(); + if (!memRefType) + return parser->emitError(parser->getNameLoc(), + "memRef type expected for first type"); + if (indexingsInfo.size() != memRefType.getRank()) + return parser->emitError(parser->getNameLoc(), + "expected " + Twine(memRefType.getRank()) + + " indexings"); + ViewType viewType = types.back().dyn_cast(); + if (!viewType) + return parser->emitError(parser->getNameLoc(), "view type expected"); + + ArrayRef indexingTypes = ArrayRef(types).drop_front().drop_back(); + if (indexingTypes.size() != memRefType.getRank()) + return parser->emitError(parser->getNameLoc(), + "expected " + Twine(memRefType.getRank()) + + " indexing types"); + return parser->resolveOperand(memRefInfo, memRefType, result->operands) || + (!indexingsInfo.empty() && + parser->resolveOperands(indexingsInfo, indexingTypes, + indexingsInfo.front().location, + result->operands)) || + parser->addTypeToList(viewType, result->types); } // A ViewOp prints as: // // ```{.mlir} -// linalg.view %0[%1, %2] : !linalg.view +// linalg.view %0[%1, %2] : +// memref-type, [indexing-types], !linalg.view // ``` // // Where %0 is an ssa-value holding a MemRef, %1 and %2 are ssa-value each @@ -109,7 +144,12 @@ void linalg::ViewOp::print(OpAsmPrinter *p) { for (auto indexing : getIndexings()) { *p << *indexing << ((index++ == numRanges - 1) ? "" : ", "); } - *p << "] : " << getType(); + p->printOptionalAttrDict(getAttrs()); + *p << "] : " << getSupportingMemRef()->getType().cast(); + for (auto indexing : getIndexings()) { + *p << ", " << indexing->getType(); + } + *p << ", " << getType(); } Type linalg::ViewOp::getElementType() { return getViewType().getElementType(); } diff --git a/mlir/examples/Linalg/Linalg2/CMakeLists.txt b/mlir/examples/Linalg/Linalg2/CMakeLists.txt index b6c2043..a965eeb 100644 --- a/mlir/examples/Linalg/Linalg2/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg2/CMakeLists.txt @@ -13,11 +13,11 @@ add_llvm_example(linalg-example-2 target_link_libraries(linalg-example-2 PRIVATE - Linalg1 Linalg2 Linalg2DialectConstruction ) whole_archive_link(linalg-example-2 + MLIRAffineOps MLIRStandardOps ) diff --git a/mlir/examples/Linalg/Linalg2/Example.cpp b/mlir/examples/Linalg/Linalg2/Example.cpp index 901fbe7..a8f9e9a 100644 --- a/mlir/examples/Linalg/Linalg2/Example.cpp +++ b/mlir/examples/Linalg/Linalg2/Example.cpp @@ -58,10 +58,10 @@ TEST_FUNC(linalg_ops) { dot(sA, sB, ssC); ret(); // CHECK-LABEL: func @linalg_ops(%arg0: index, %arg1: index, %arg2: index) { - // CHECK: {{.*}} = linalg.slice {{.*}}[*, {{.*}}] : !linalg.view - // CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[*, {{.*}}] : !linalg.view - // CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}, *] : !linalg.view - // CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] : !linalg.view + // CHECK: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 1} : !linalg.view, index + // CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 1} : !linalg.view, index + // CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 0} : !linalg.view, index + // CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 0} : !linalg.view, index // CHECK: linalg.matmul({{.*}}, {{.*}}, {{.*}}) : !linalg.view // CHECK-NEXT: linalg.matvec({{.*}}, {{.*}}, {{.*}}) : !linalg.view // CHECK-NEXT: linalg.dot({{.*}}, {{.*}}, {{.*}}) : !linalg.view diff --git a/mlir/examples/Linalg/Linalg2/lib/CMakeLists.txt b/mlir/examples/Linalg/Linalg2/lib/CMakeLists.txt index 79546a8..76ca2b18 100644 --- a/mlir/examples/Linalg/Linalg2/lib/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg2/lib/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_library(Linalg2 target_link_libraries(Linalg2 PUBLIC + MLIRAffineOps MLIRAnalysis MLIRDialect MLIREDSC @@ -19,6 +20,7 @@ target_link_libraries(Linalg2 MLIRParser MLIRPass MLIRTransforms + Linalg1 ) add_llvm_library(Linalg2DialectConstruction diff --git a/mlir/examples/Linalg/Linalg3/CMakeLists.txt b/mlir/examples/Linalg/Linalg3/CMakeLists.txt index 4c6da82..c20483d 100644 --- a/mlir/examples/Linalg/Linalg3/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg3/CMakeLists.txt @@ -29,20 +29,17 @@ add_llvm_example(linalg-execution-3 target_link_libraries(linalg-example-3 PRIVATE - Linalg1 - Linalg2 Linalg3 Linalg3DialectConstruction ) whole_archive_link(linalg-example-3 + MLIRAffineOps MLIRStandardOps ) target_link_libraries(linalg-conversion-3 PRIVATE - Linalg1 - Linalg2 Linalg3 Linalg3DialectConstruction ) @@ -54,8 +51,6 @@ whole_archive_link(linalg-conversion-3 target_link_libraries(linalg-execution-3 PRIVATE MLIRExecutionEngine - Linalg1 - Linalg2 Linalg3 Linalg3DialectConstruction ) diff --git a/mlir/examples/Linalg/Linalg3/Example.cpp b/mlir/examples/Linalg/Linalg3/Example.cpp index 69a430b..32b5c9e 100644 --- a/mlir/examples/Linalg/Linalg3/Example.cpp +++ b/mlir/examples/Linalg/Linalg3/Example.cpp @@ -69,10 +69,10 @@ TEST_FUNC(matmul_as_matvec) { // clang-format off // CHECK-LABEL: func @matmul_as_matvec(%arg0: memref, %arg1: memref, %arg2: memref) { // CHECK: %[[N:.*]] = dim %arg2, 1 : memref - // CHECK: %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : !linalg.view + // CHECK: %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[N]]) { - // CHECK: %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : !linalg.view - // CHECK: %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : !linalg.view + // CHECK: %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : memref, !linalg.range, index, !linalg.view + // CHECK: %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : memref, !linalg.range, index, !linalg.view // CHECK: linalg.matvec(%[[vA]], %[[vB]], %[[vC]]) : !linalg.view // clang-format on cleanupAndPrintFunction(f); @@ -90,10 +90,10 @@ TEST_FUNC(matmul_as_dot) { // CHECK: %[[M:.*]] = dim %arg0, 0 : memref // CHECK: %[[N:.*]] = dim %arg2, 1 : memref // CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[N]]) { - // CHECK: %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : !linalg.view + // CHECK: %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : memref, !linalg.range, index, !linalg.view // CHECK-NEXT: affine.for %i1 = 0 to (d0) -> (d0)(%[[M]]) { - // CHECK: %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : !linalg.view - // CHECK-NEXT: %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : !linalg.view + // CHECK: %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : memref, index, !linalg.range, !linalg.view + // CHECK-NEXT: %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : memref, index, index, !linalg.view // CHECK-NEXT: linalg.dot(%[[vA]], %[[vB]], %[[vC]]) : !linalg.view // clang-format on cleanupAndPrintFunction(f); @@ -113,9 +113,9 @@ TEST_FUNC(matmul_as_loops) { // CHECK: %[[rM:.*]] = linalg.range %c0:%[[M]]:%c1 : !linalg.range // CHECK: %[[rN:.*]] = linalg.range %c0:%[[N]]:%c1 : !linalg.range // CHECK: %[[rK:.*]] = linalg.range %c0:%[[K]]:%c1 : !linalg.range - // CHECK: %[[vA:.*]] = linalg.view %arg0[%[[rM]], %[[rK]]] : !linalg.view - // CHECK: %[[vB:.*]] = linalg.view %arg1[%[[rK]], %[[rN]]] : !linalg.view - // CHECK: %[[vC:.*]] = linalg.view %arg2[%[[rM]], %[[rN]]] : !linalg.view + // CHECK: %[[vA:.*]] = linalg.view %arg0[%[[rM]], %[[rK]]] : memref, !linalg.range, !linalg.range, !linalg.view + // CHECK: %[[vB:.*]] = linalg.view %arg1[%[[rK]], %[[rN]]] : memref, !linalg.range, !linalg.range, !linalg.view + // CHECK: %[[vC:.*]] = linalg.view %arg2[%[[rM]], %[[rN]]] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[M]]) { // CHECK: affine.for %i1 = 0 to (d0) -> (d0)(%[[N]]) { // CHECK: affine.for %i2 = 0 to (d0) -> (d0)(%[[K]]) { @@ -144,10 +144,10 @@ TEST_FUNC(matmul_as_matvec_as_loops) { // CHECK: %[[M:.*]] = dim %arg0, 0 : memref // CHECK: %[[N:.*]] = dim %arg2, 1 : memref // CHECK: %[[K:.*]] = dim %arg0, 1 : memref - // CHECK: %[[vA:.*]] = linalg.view %arg0[{{.*}}, {{.*}}] : !linalg.view + // CHECK: %[[vA:.*]] = linalg.view %arg0[{{.*}}, {{.*}}] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[N]]) { - // CHECK: %[[vB:.*]] = linalg.view %arg1[{{.*}}, {{.*}}] : !linalg.view - // CHECK: %[[vC:.*]] = linalg.view %arg2[{{.*}}, {{.*}}] : !linalg.view + // CHECK: %[[vB:.*]] = linalg.view %arg1[{{.*}}, {{.*}}] : memref, !linalg.range, index, !linalg.view + // CHECK: %[[vC:.*]] = linalg.view %arg2[{{.*}}, {{.*}}] : memref, !linalg.range, index, !linalg.view // CHECK: affine.for %i1 = 0 to (d0) -> (d0)(%[[M]]) { // CHECK: affine.for %i2 = 0 to (d0) -> (d0)(%[[K]]) { // CHECK: %{{.*}} = cmpi "eq", %i2, %{{.*}} : index diff --git a/mlir/examples/Linalg/Linalg3/lib/CMakeLists.txt b/mlir/examples/Linalg/Linalg3/lib/CMakeLists.txt index f87cbca..a8f00df 100644 --- a/mlir/examples/Linalg/Linalg3/lib/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg3/lib/CMakeLists.txt @@ -17,6 +17,7 @@ add_llvm_library(Linalg3 target_link_libraries(Linalg3 PUBLIC + MLIRAffineOps MLIRAnalysis MLIRDialect MLIREDSC @@ -25,6 +26,7 @@ target_link_libraries(Linalg3 MLIRParser MLIRPass MLIRTransforms + Linalg2 ) add_llvm_library(Linalg3DialectConstruction diff --git a/mlir/examples/Linalg/Linalg4/CMakeLists.txt b/mlir/examples/Linalg/Linalg4/CMakeLists.txt index 61bc287..00afa32 100644 --- a/mlir/examples/Linalg/Linalg4/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg4/CMakeLists.txt @@ -13,6 +13,7 @@ add_llvm_example(linalg-example-4 target_link_libraries(linalg-example-4 PRIVATE + MLIRAffineOps MLIRAnalysis MLIRDialect MLIREDSC @@ -21,14 +22,12 @@ target_link_libraries(linalg-example-4 MLIRParser MLIRPass MLIRTransforms - Linalg1 - Linalg2 - Linalg3 Linalg4 Linalg3DialectConstruction ) whole_archive_link(linalg-example-4 + MLIRAffineOps MLIRStandardOps ) diff --git a/mlir/examples/Linalg/Linalg4/Example.cpp b/mlir/examples/Linalg/Linalg4/Example.cpp index 00da459..cdd87d7 100644 --- a/mlir/examples/Linalg/Linalg4/Example.cpp +++ b/mlir/examples/Linalg/Linalg4/Example.cpp @@ -114,12 +114,12 @@ TEST_FUNC(matmul_tiled_views) { // CHECK-NEXT: %[[i0max:.*]] = affine.apply (d0) -> (d0 + 8)(%i0) // CHECK-NEXT: %[[ri0:.*]] = linalg.range %[[i0min]]:%[[i0max]]:{{.*}} : !linalg.range // CHECK: %[[rK:.*]] = linalg.range %{{.*}}:%{{.*}}:%{{.*}} : !linalg.range - // CHECK: %[[vA:.*]] = linalg.view %arg0[%[[ri0]], %[[rK]]] : !linalg.view + // CHECK: %[[vA:.*]] = linalg.view %arg0[%[[ri0]], %[[rK]]] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK: %[[i1min:.*]] = affine.apply (d0) -> (d0)(%i1) // CHECK-NEXT: %[[i1max:.*]] = affine.apply (d0) -> (d0 + 9)(%i1) // CHECK-NEXT: %[[ri1:.*]] = linalg.range %[[i1min]]:%[[i1max]]:%{{.*}} : !linalg.range - // CHECK-NEXT: %[[vB:.*]] = linalg.view %arg1[%10, %13] : !linalg.view - // CHECK-NEXT: %[[vC:.*]] = linalg.view %arg2[%5, %13] : !linalg.view + // CHECK-NEXT: %[[vB:.*]] = linalg.view %arg1[%10, %13] : memref, !linalg.range, !linalg.range, !linalg.view + // CHECK-NEXT: %[[vC:.*]] = linalg.view %arg2[%5, %13] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK-NEXT: linalg.matmul(%[[vA]], %[[vB]], %[[vC]]) : !linalg.view // clang-format on cleanupAndPrintFunction(f); @@ -150,12 +150,12 @@ TEST_FUNC(matmul_tiled_views_as_loops) { // CHECK-NEXT: %[[i0max:.*]] = affine.apply (d0) -> (d0 + 8)(%i0) // CHECK-NEXT: %[[ri0:.*]] = linalg.range %[[i0min]]:%[[i0max]]:{{.*}} : !linalg.range // CHECK: %[[rK:.*]] = linalg.range %{{.*}}:%{{.*}}:%{{.*}} : !linalg.range - // CHECK: %[[vA:.*]] = linalg.view %arg0[%[[ri0]], %[[rK]]] : !linalg.view + // CHECK: %[[vA:.*]] = linalg.view %arg0[%[[ri0]], %[[rK]]] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK: %[[i1min:.*]] = affine.apply (d0) -> (d0)(%i1) // CHECK-NEXT: %[[i1max:.*]] = affine.apply (d0) -> (d0 + 9)(%i1) // CHECK-NEXT: %[[ri1:.*]] = linalg.range %[[i1min]]:%[[i1max]]:%{{.*}} : !linalg.range - // CHECK-NEXT: %[[vB:.*]] = linalg.view %arg1[%10, %13] : !linalg.view - // CHECK-NEXT: %[[vC:.*]] = linalg.view %arg2[%5, %13] : !linalg.view + // CHECK-NEXT: %[[vB:.*]] = linalg.view %arg1[%10, %13] : memref, !linalg.range, !linalg.range, !linalg.view + // CHECK-NEXT: %[[vC:.*]] = linalg.view %arg2[%5, %13] : memref, !linalg.range, !linalg.range, !linalg.view // CHECK-NEXT: affine.for %i2 = (d0) -> (d0)(%i0) to (d0) -> (d0)(%[[i0max]]) { // CHECK-NEXT: affine.for %i3 = (d0) -> (d0)(%i1) to (d0) -> (d0)(%[[i1max]]) { // CHECK-NEXT: affine.for %i4 = 0 to (d0) -> (d0)(%[[K]]) { diff --git a/mlir/examples/Linalg/Linalg4/lib/CMakeLists.txt b/mlir/examples/Linalg/Linalg4/lib/CMakeLists.txt index 523050f..ee0fb3b 100644 --- a/mlir/examples/Linalg/Linalg4/lib/CMakeLists.txt +++ b/mlir/examples/Linalg/Linalg4/lib/CMakeLists.txt @@ -12,4 +12,5 @@ target_link_libraries(Linalg4 MLIRParser MLIRPass MLIRTransforms + Linalg3 ) diff --git a/mlir/g3doc/Tutorials/Linalg/Ch-1.md b/mlir/g3doc/Tutorials/Linalg/Ch-1.md index 86fbc43..5b3627c 100644 --- a/mlir/g3doc/Tutorials/Linalg/Ch-1.md +++ b/mlir/g3doc/Tutorials/Linalg/Ch-1.md @@ -229,7 +229,7 @@ enables constant folding and dead code elimination in the `canonicalizerPass`. Similarly to Toy, the dialect must be registered so that the pretty-printer and verifier can be enabled. Without registration, only the custom op form can be -printed. Beware of ops printed in custom op form, when a short-hand form exists, +printed. Beware of ops printed in custom op form, when a shorthand form exists, because there is a high chance the IR verification is not enabled. To register the Linalg dialect, call @@ -248,8 +248,13 @@ have been declared so far. ## Putting it all together -The -[example](https://github.com/tensorflow/mlir/blob/master/examples/Linalg/Linalg1/Example.cpp) -demonstrates how to construct some simple IR snippets that pass through the -verifier checks. We introduce a custom op called `some_consumer` to ensure that -dead-code elimination does not optimize these simple examples out of existence. +We create a `linalg1-opt` executable which links together `Linalg1` and the core +`MlirOptLib` library to add traditional compiler support for file handling, +parsing, command-line interface etc. The FileCheck'd test +[example](https://github.com/tensorflow/mlir/blob/master/test/Examples/Linalg/Linalg1.mlir) +demonstrates parsing, verification, pretty printing of the IR we have +constructed so far. We introduce a custom op called `some_consumer` to ensure +that dead-code elimination does not optimize these simple examples out of +existence, in the case an extra -canonicalize option is passed to `linalg1-opt`. +When called with `lower-linalg-to-llvm`, the test uses the +[LLVM conversion](LLVMConversion.md) mechanisms. diff --git a/mlir/lib/Transforms/CMakeLists.txt b/mlir/lib/Transforms/CMakeLists.txt index 9e7083f..c6b58d8 100644 --- a/mlir/lib/Transforms/CMakeLists.txt +++ b/mlir/lib/Transforms/CMakeLists.txt @@ -30,4 +30,9 @@ add_llvm_library(MLIRTransforms ${MLIR_MAIN_INCLUDE_DIR}/mlir/Transforms ) add_dependencies(MLIRTransforms MLIRStandardOpsIncGen) -target_link_libraries(MLIRTransforms MLIRVectorOps) +target_link_libraries(MLIRTransforms + MLIRAffineOps + MLIRAnalysis + MLIRPass + MLIRVectorOps + ) diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt index 39fa952..4a775a6 100644 --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -28,6 +28,7 @@ set(MLIR_TEST_DEPENDS if(LLVM_BUILD_EXAMPLES) list(APPEND MLIR_TEST_DEPENDS + linalg1-opt toyc-ch1 toyc-ch2 toyc-ch3 diff --git a/mlir/test/Examples/Linalg/Linalg1.mlir b/mlir/test/Examples/Linalg/Linalg1.mlir new file mode 100644 index 0000000..7606ffa --- /dev/null +++ b/mlir/test/Examples/Linalg/Linalg1.mlir @@ -0,0 +1,166 @@ +// RUN: linalg1-opt %s -verify | FileCheck %s +// RUN: linalg1-opt %s -lower-linalg-to-llvm -verify | FileCheck %s -check-prefix=LLVM + +func @view_op(%arg0: memref, %arg1: memref, %arg2: memref) { + %c3 = constant 3 : index + %c17 = constant 17 : index + %c1 = constant 1 : index + %3 = linalg.range %c3:%c17:%c1 : !linalg.range + %4 = linalg.view %arg0[] : memref, !linalg.view + %5 = linalg.view %arg1[%3] : memref, !linalg.range, !linalg.view + %6 = linalg.view %arg2[%3, %3] : memref, !linalg.range, !linalg.range, !linalg.view + "some_consumer"(%4, %5, %6) : (!linalg.view, !linalg.view, !linalg.view) -> () + return +} +// CHECK-LABEL: func @view_op(%arg0: memref, %arg1: memref, %arg2: memref) { +// CHECK: %0 = linalg.range {{.*}} : !linalg.range +// CHECK: {{.*}} = linalg.view %arg0[] : memref, !linalg.view +// CHECK: {{.*}} = linalg.view %arg1[%0] : memref, !linalg.range, !linalg.view +// CHECK: {{.*}} = linalg.view %arg2[%0, %0] : memref, !linalg.range, !linalg.range, !linalg.view + +func @slice_op(%arg0: memref) { + %c0 = constant 0 : index + %c1 = constant 1 : index + %1 = dim %arg0, 0 : memref + %2 = dim %arg0, 1 : memref + %3 = linalg.range %c0:%1:%c1 : !linalg.range + %4 = linalg.range %c0:%2:%c1 : !linalg.range + %5 = linalg.view %arg0[%3, %4] : memref, !linalg.range, !linalg.range, !linalg.view + affine.for %i0 = 0 to (d0) -> (d0)(%1) { + affine.for %i1 = 0 to (d0) -> (d0)(%2) { + %6 = linalg.slice %5[%i0] {dim: 1} : !linalg.view, index + "some_consumer"(%6) : (!linalg.view) -> () + %7 = linalg.slice %5[%i1] {dim: 0} : !linalg.view, index + %8 = linalg.slice %7[%i0] {dim: 0} : !linalg.view, index + } + } + return +} +// CHECK-LABEL: func @slice_op(%arg0: memref) { +// CHECK: %[[M:.*]] = dim %arg0, 0 : memref +// CHECK: %[[N:.*]] = dim %arg0, 1 : memref +// CHECK: %[[r1:.*]] = linalg.range %c0:%[[M]]:%c1 : !linalg.range +// CHECK: %[[r2:.*]] = linalg.range %c0:%[[N]]:%c1 : !linalg.range +// CHECK: %[[V:.*]] = linalg.view %arg0[%[[r1]], %[[r2]]] : memref, !linalg.range, !linalg.range, !linalg.view +// CHECK: affine.for %i0 = 0 to #map1(%0) { +// CHECK: affine.for %i1 = 0 to #map1(%1) { +// CHECK: {{.*}} = linalg.slice %[[V]][%i0] {dim: 1} : !linalg.view, index +// CHECK: %[[V2:.*]] = linalg.slice %[[V]][%i1] {dim: 0} : !linalg.view, index +// CHECK: {{.*}} = linalg.slice %[[V2]][%i0] {dim: 0} : !linalg.view, index + +func @rangeConversion(%arg0: index, %arg1: index, %arg2: index) { + %0 = linalg.range %arg0:%arg1:%arg2 : !linalg.range + return +} +// LLVM-LABEL: @rangeConversion +// LLVM-NEXT: %0 = llvm.undef : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %1 = llvm.insertvalue %arg0, %0[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %2 = llvm.insertvalue %arg1, %1[1] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %3 = llvm.insertvalue %arg2, %2[2] : !llvm<"{ i64, i64, i64 }"> + +func @viewRangeConversion(%arg0: memref, %arg1: !linalg.range, %arg2: !linalg.range) { + %0 = linalg.view %arg0[%arg1, %arg2] : memref, !linalg.range, !linalg.range, !linalg.view + return +} +// LLVM-LABEL: @viewRangeConversion +// LLVM-NEXT: %0 = llvm.undef : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }"> +// LLVM-NEXT: %2 = llvm.insertvalue %1, %0[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }"> +// LLVM-NEXT: %4 = llvm.constant(1 : index) : !llvm.i64 +// LLVM-NEXT: %5 = llvm.mul %4, %3 : !llvm.i64 +// LLVM-NEXT: %6 = llvm.constant(0 : index) : !llvm.i64 +// LLVM-NEXT: %7 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %8 = llvm.mul %7, %5 : !llvm.i64 +// LLVM-NEXT: %9 = llvm.add %6, %8 : !llvm.i64 +// LLVM-NEXT: %10 = llvm.extractvalue %arg2[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %11 = llvm.mul %10, %4 : !llvm.i64 +// LLVM-NEXT: %12 = llvm.add %9, %11 : !llvm.i64 +// LLVM-NEXT: %13 = llvm.insertvalue %12, %2[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %14 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %15 = llvm.extractvalue %arg1[1] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %16 = llvm.sub %15, %14 : !llvm.i64 +// LLVM-NEXT: %17 = llvm.insertvalue %16, %13[2, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %18 = llvm.extractvalue %arg2[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %19 = llvm.extractvalue %arg2[1] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %20 = llvm.sub %19, %18 : !llvm.i64 +// LLVM-NEXT: %21 = llvm.insertvalue %20, %17[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %22 = llvm.extractvalue %arg1[2] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %23 = llvm.mul %5, %22 : !llvm.i64 +// LLVM-NEXT: %24 = llvm.insertvalue %23, %21[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %25 = llvm.extractvalue %arg2[2] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %26 = llvm.mul %4, %25 : !llvm.i64 +// LLVM-NEXT: %27 = llvm.insertvalue %26, %24[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> + +func @viewNonRangeConversion(%arg0: memref, %arg1: !linalg.range, %arg2: index) { + %0 = linalg.view %arg0[%arg1, %arg2] : memref, !linalg.range, index, !linalg.view + return +} +// LLVM-LABEL: @viewNonRangeConversion +// LLVM-NEXT: %0 = llvm.undef : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }"> +// LLVM-NEXT: %2 = llvm.insertvalue %1, %0[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }"> +// LLVM-NEXT: %4 = llvm.constant(1 : index) : !llvm.i64 +// LLVM-NEXT: %5 = llvm.mul %4, %3 : !llvm.i64 +// LLVM-NEXT: %6 = llvm.constant(0 : index) : !llvm.i64 +// LLVM-NEXT: %7 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %8 = llvm.mul %7, %5 : !llvm.i64 +// LLVM-NEXT: %9 = llvm.add %6, %8 : !llvm.i64 +// LLVM-NEXT: %10 = llvm.mul %arg2, %4 : !llvm.i64 +// LLVM-NEXT: %11 = llvm.add %9, %10 : !llvm.i64 +// LLVM-NEXT: %12 = llvm.insertvalue %11, %2[1] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %13 = llvm.extractvalue %arg1[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %14 = llvm.extractvalue %arg1[1] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %15 = llvm.sub %14, %13 : !llvm.i64 +// LLVM-NEXT: %16 = llvm.insertvalue %15, %12[2, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %17 = llvm.extractvalue %arg1[2] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %18 = llvm.mul %5, %17 : !llvm.i64 +// LLVM-NEXT: %19 = llvm.insertvalue %18, %16[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> + +func @sliceRangeConversion(%arg0: memref, %arg1: !linalg.range, %arg2: !linalg.range, %arg3: !linalg.range) { + %0 = linalg.view %arg0[%arg1, %arg2] : memref, !linalg.range, !linalg.range, !linalg.view + %1 = linalg.slice %0[%arg3] {dim: 0} : !linalg.view, !linalg.range + return +} +// LLVM-LABEL: @sliceRangeConversion +// LLVM: %28 = llvm.undef : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %29 = llvm.extractvalue %27[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %30 = llvm.insertvalue %29, %28[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %31 = llvm.extractvalue %27[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %32 = llvm.extractvalue %arg3[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %33 = llvm.extractvalue %27[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %34 = llvm.mul %32, %33 : !llvm.i64 +// LLVM-NEXT: %35 = llvm.add %31, %34 : !llvm.i64 +// LLVM-NEXT: %36 = llvm.insertvalue %35, %30[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %37 = llvm.extractvalue %arg3[1] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %38 = llvm.extractvalue %arg3[0] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %39 = llvm.sub %37, %38 : !llvm.i64 +// LLVM-NEXT: %40 = llvm.extractvalue %27[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %41 = llvm.extractvalue %arg3[2] : !llvm<"{ i64, i64, i64 }"> +// LLVM-NEXT: %42 = llvm.mul %40, %41 : !llvm.i64 +// LLVM-NEXT: %43 = llvm.insertvalue %39, %36[2, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %44 = llvm.insertvalue %42, %43[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %45 = llvm.extractvalue %27[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %46 = llvm.extractvalue %27[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %47 = llvm.insertvalue %45, %44[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %48 = llvm.insertvalue %46, %47[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> + +func @sliceNonRangeConversion2(%arg0: memref, %arg1: !linalg.range, %arg2: !linalg.range, %arg3: index) { + %0 = linalg.view %arg0[%arg1, %arg2] : memref, !linalg.range, !linalg.range, !linalg.view + %1 = linalg.slice %0[%arg3] {dim: 0} : !linalg.view, index + return +} +// LLVM-LABEL: @sliceNonRangeConversion2 +// LLVM: %28 = llvm.undef : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %29 = llvm.extractvalue %27[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %30 = llvm.insertvalue %29, %28[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %31 = llvm.extractvalue %27[1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %32 = llvm.extractvalue %27[3, 0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %33 = llvm.mul %arg3, %32 : !llvm.i64 +// LLVM-NEXT: %34 = llvm.add %31, %33 : !llvm.i64 +// LLVM-NEXT: %35 = llvm.insertvalue %34, %30[1] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %36 = llvm.extractvalue %27[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %37 = llvm.extractvalue %27[3, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }"> +// LLVM-NEXT: %38 = llvm.insertvalue %36, %35[2, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> +// LLVM-NEXT: %39 = llvm.insertvalue %37, %38[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }"> diff --git a/mlir/tools/mlir-opt/CMakeLists.txt b/mlir/tools/mlir-opt/CMakeLists.txt index f6e9ac7..a0ce32c 100644 --- a/mlir/tools/mlir-opt/CMakeLists.txt +++ b/mlir/tools/mlir-opt/CMakeLists.txt @@ -1,3 +1,20 @@ +set(LLVM_OPTIONAL_SOURCES + null.cpp +) + +set(LIB_LIBS + MLIRAnalysis + MLIRLLVMIR + MLIRParser + MLIRPass + MLIRTransforms + MLIRSupport +) +add_llvm_library(MLIRMlirOptLib + mlir-opt.cpp +) +target_link_libraries(MLIRMlirOptLib ${LIB_LIBS}) + set(LIBS MLIRAffineOps MLIRAnalysis @@ -14,8 +31,8 @@ set(LIBS MLIRVectorOps ) add_executable(mlir-opt - mlir-opt.cpp + mlir-opt.cpp ) llvm_update_compile_flags(mlir-opt) whole_archive_link(mlir-opt ${LIBS}) -target_link_libraries(mlir-opt MLIRIR ${LIBS} LLVMSupport) +target_link_libraries(mlir-opt MLIRIR MLIRMlirOptLib ${LIBS} LLVMSupport)