Parsing support for Range, View and Slice operations
authorNicolas Vasilache <ntv@google.com>
Mon, 29 Apr 2019 19:11:58 +0000 (12:11 -0700)
committerMehdi Amini <joker.eph@gmail.com>
Mon, 6 May 2019 15:20:55 +0000 (08:20 -0700)
    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

26 files changed:
mlir/examples/Linalg/CMakeLists.txt
mlir/examples/Linalg/Linalg1/CMakeLists.txt
mlir/examples/Linalg/Linalg1/Conversion.cpp [deleted file]
mlir/examples/Linalg/Linalg1/Example.cpp [deleted file]
mlir/examples/Linalg/Linalg1/include/linalg1/Passes.h [new file with mode: 0644]
mlir/examples/Linalg/Linalg1/lib/CMakeLists.txt
mlir/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp
mlir/examples/Linalg/Linalg1/lib/Dialect.cpp
mlir/examples/Linalg/Linalg1/lib/DialectRegistration.cpp [new file with mode: 0644]
mlir/examples/Linalg/Linalg1/lib/RangeOp.cpp
mlir/examples/Linalg/Linalg1/lib/SliceOp.cpp
mlir/examples/Linalg/Linalg1/lib/ViewOp.cpp
mlir/examples/Linalg/Linalg2/CMakeLists.txt
mlir/examples/Linalg/Linalg2/Example.cpp
mlir/examples/Linalg/Linalg2/lib/CMakeLists.txt
mlir/examples/Linalg/Linalg3/CMakeLists.txt
mlir/examples/Linalg/Linalg3/Example.cpp
mlir/examples/Linalg/Linalg3/lib/CMakeLists.txt
mlir/examples/Linalg/Linalg4/CMakeLists.txt
mlir/examples/Linalg/Linalg4/Example.cpp
mlir/examples/Linalg/Linalg4/lib/CMakeLists.txt
mlir/g3doc/Tutorials/Linalg/Ch-1.md
mlir/lib/Transforms/CMakeLists.txt
mlir/test/CMakeLists.txt
mlir/test/Examples/Linalg/Linalg1.mlir [new file with mode: 0644]
mlir/tools/mlir-opt/CMakeLists.txt

index c4a2610..8e955d9 100644 (file)
@@ -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
index 8556c6f..3ea7a41 100644 (file)
@@ -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 (file)
index a1c9d4e..0000000
+++ /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<?x?xf32>, !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<RangeType>(), builder.getType<RangeType>()},
-      {});
-  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<?x?xf32>, !linalg.range, index) -> ()
-  // define it, and add it to the module.
-  FunctionType funcType = builder.getFunctionType(
-      {builder.getMemRefType({-1, -1}, builder.getF32Type(), {}, 0),
-       builder.getType<RangeType>(), 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<?x?xf32>, !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<RangeType>(), builder.getType<RangeType>(),
-       builder.getType<RangeType>()},
-      {});
-  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<?x?xf32>, !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<RangeType>(), builder.getType<RangeType>(),
-       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<linalg::LinalgDialect>();
-  RUN_TESTS();
-  return 0;
-}
diff --git a/mlir/examples/Linalg/Linalg1/Example.cpp b/mlir/examples/Linalg/Linalg1/Example.cpp
deleted file mode 100644 (file)
index 3ab54d0..0000000
+++ /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<OperationHandle> 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<f32>
-  //  CHECK-NEXT:  {{.*}} = linalg.view {{.*}}[%[[R]]] : !linalg.view<?xf32>
-  //  CHECK-NEXT:  {{.*}} = linalg.view {{.*}}[%[[R]], %[[R]]] : !linalg.view<?x?xf32>
-  // 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<OperationHandle> 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<?x?xf32>
-  //  CHECK-NEXT: %[[M:.*]] = dim %0, 0 : memref<?x?xf32>
-  //  CHECK-NEXT: %[[N:.*]] = dim %0, 1 : memref<?x?xf32>
-  //  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<?x?xf32>
-  //  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<?xf32>
-  //  CHECK-NEXT:     "some_consumer"(%[[S1]]) : (!linalg.view<?xf32>) -> ()
-  //  CHECK-NEXT:     %[[S2:.*]] = linalg.slice %[[V]][%i1, *]  : !linalg.view<?xf32>
-  //  CHECK-NEXT:     %[[S3:.*]] = linalg.slice %[[S2]][%i0]  : !linalg.view<f32>
-  //  CHECK-NEXT:     "some_consumer"(%[[S3]]) : (!linalg.view<f32>) -> ()
-  // clang-format on
-
-  cleanupAndPrintFunction(f);
-}
-
-int main() {
-  mlir::registerDialect<linalg::LinalgDialect>();
-  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 (file)
index 0000000..d87fa3b
--- /dev/null
@@ -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 <functional>
+#include <limits>
+
+namespace mlir {
+class ModulePassBase;
+} // namespace mlir
+
+namespace linalg {
+
+mlir::ModulePassBase *createLowerLinalgToLLVMPass();
+
+} // namespace linalg
+
+#endif // LINALG1_PASSES_H
index 3722701..d9daf60 100644 (file)
@@ -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)
index 0aca4c0..c00413c 100644 (file)
@@ -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<LowerLinalgToLLVMPass> {
+  void runOnModule() { linalg::convertToLLVM(getModule()); }
+};
+} // namespace
+
+ModulePassBase *linalg::createLowerLinalgToLLVMPass() {
+  return new LowerLinalgToLLVMPass();
+}
+
+static PassRegistration<LowerLinalgToLLVMPass>
+    pass("lower-linalg-to-llvm",
+         "Lower the operations from the linalg dialect into the LLVM dialect");
index 7b1dca4..5152df3 100644 (file)
 #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 (file)
index 0000000..e657bc3
--- /dev/null
@@ -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<LinalgDialect> LinalgOps;
index 56b9c02..6899ed6 100644 (file)
 #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<OpAsmParser::OperandType, 3> 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();
 }
index b7337a1..56a4aed 100644 (file)
@@ -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<OpAsmParser::OperandType, 1> indexingInfo;
+  SmallVector<Type, 8> 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<ViewType>();
+  if (!viewType)
+    return parser->emitError(parser->getNameLoc(),
+                             "view type expected as first type");
+
+  IndexType indexType = types.back().dyn_cast<IndexType>();
+  RangeType rangeType = types.back().dyn_cast<RangeType>();
+  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<?xf32>
+//   linalg.slice %0[%i0] {dim: 0} : !linalg.view<?xf32>, index
 // ```
 //
 // Where %0 is an ssa-value holding a `view<?x?xf32>`, %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<RangeOp>(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<ViewType>(); }
index 42be75a..6cd0f27 100644 (file)
@@ -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<MemRefType>();
-  unsigned memrefRank = memrefType.getRank();
-  if (!memrefType)
+  auto memRefType = getOperand(0)->getType().dyn_cast<MemRefType>();
+  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<OpAsmParser::OperandType, 8> indexingsInfo;
+  SmallVector<Type, 8> 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<MemRefType>();
+  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<ViewType>();
+  if (!viewType)
+    return parser->emitError(parser->getNameLoc(), "view type expected");
+
+  ArrayRef<Type> indexingTypes = ArrayRef<Type>(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<?x?xf32>
+//   linalg.view %0[%1, %2] :
+//     memref-type, [indexing-types], !linalg.view<?x?xf32>
 // ```
 //
 // 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<MemRefType>();
+  for (auto indexing : getIndexings()) {
+    *p << ", " << indexing->getType();
+  }
+  *p << ", " << getType();
 }
 
 Type linalg::ViewOp::getElementType() { return getViewType().getElementType(); }
index b6c2043..a965eeb 100644 (file)
@@ -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
   )
index 901fbe7..a8f9e9a 100644 (file)
@@ -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<?xf32>
-  //  CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[*, {{.*}}] : !linalg.view<?xf32>
-  //  CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}, *] : !linalg.view<?xf32>
-  //  CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}]  : !linalg.view<f32>
+  //       CHECK: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 1} : !linalg.view<?x?xf32>, index
+  //  CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 1} : !linalg.view<?x?xf32>, index
+  //  CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 0} : !linalg.view<?x?xf32>, index
+  //  CHECK-NEXT: {{.*}} = linalg.slice {{.*}}[{{.*}}] {dim: 0} : !linalg.view<?xf32>, index
   //       CHECK: linalg.matmul({{.*}}, {{.*}}, {{.*}}) : !linalg.view<?x?xf32>
   //  CHECK-NEXT: linalg.matvec({{.*}}, {{.*}}, {{.*}}) : !linalg.view<?xf32>
   //  CHECK-NEXT: linalg.dot({{.*}}, {{.*}}, {{.*}}) : !linalg.view<f32>
index 79546a8..76ca2b1 100644 (file)
@@ -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
index 4c6da82..c20483d 100644 (file)
@@ -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
     )
index 69a430b..32b5c9e 100644 (file)
@@ -69,10 +69,10 @@ TEST_FUNC(matmul_as_matvec) {
   // clang-format off
   // CHECK-LABEL: func @matmul_as_matvec(%arg0: memref<?x?xf32>, %arg1: memref<?x?xf32>, %arg2: memref<?x?xf32>) {
   //       CHECK: %[[N:.*]] = dim %arg2, 1 : memref<?x?xf32>
-  //       CHECK: %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>
+  //       CHECK: %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //       CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[N]]) {
-  //       CHECK:   %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : !linalg.view<?xf32>
-  //       CHECK:   %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : !linalg.view<?xf32>
+  //       CHECK:   %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
+  //       CHECK:   %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
   //       CHECK:   linalg.matvec(%[[vA]], %[[vB]], %[[vC]]) : !linalg.view<?xf32>
   // clang-format on
   cleanupAndPrintFunction(f);
@@ -90,10 +90,10 @@ TEST_FUNC(matmul_as_dot) {
   //       CHECK: %[[M:.*]] = dim %arg0, 0 : memref<?x?xf32>
   //       CHECK: %[[N:.*]] = dim %arg2, 1 : memref<?x?xf32>
   //       CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[N]]) {
-  //       CHECK:   %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : !linalg.view<?xf32>
+  //       CHECK:   %[[vB:.*]] = linalg.view %arg1[%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
   //  CHECK-NEXT:   affine.for %i1 = 0 to (d0) -> (d0)(%[[M]]) {
-  //       CHECK:     %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : !linalg.view<?xf32>
-  //  CHECK-NEXT:     %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : !linalg.view<f32>
+  //       CHECK:     %[[vA:.*]] = linalg.view %arg0[%{{.*}}, %{{.*}}] : memref<?x?xf32>, index, !linalg.range, !linalg.view<?xf32>
+  //  CHECK-NEXT:     %[[vC:.*]] = linalg.view %arg2[%{{.*}}, %{{.*}}] : memref<?x?xf32>, index, index, !linalg.view<f32>
   //  CHECK-NEXT:     linalg.dot(%[[vA]], %[[vB]], %[[vC]]) : !linalg.view<f32>
   // 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<?x?xf32>
-  //       CHECK: %[[vB:.*]] = linalg.view %arg1[%[[rK]], %[[rN]]] : !linalg.view<?x?xf32>
-  //       CHECK: %[[vC:.*]] = linalg.view %arg2[%[[rM]], %[[rN]]] : !linalg.view<?x?xf32>
+  //       CHECK: %[[vA:.*]] = linalg.view %arg0[%[[rM]], %[[rK]]] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  //       CHECK: %[[vB:.*]] = linalg.view %arg1[%[[rK]], %[[rN]]] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  //       CHECK: %[[vC:.*]] = linalg.view %arg2[%[[rM]], %[[rN]]] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //       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<?x?xf32>
   //       CHECK: %[[N:.*]] = dim %arg2, 1 : memref<?x?xf32>
   //       CHECK: %[[K:.*]] = dim %arg0, 1 : memref<?x?xf32>
-  //       CHECK: %[[vA:.*]] = linalg.view %arg0[{{.*}}, {{.*}}] : !linalg.view<?x?xf32>
+  //       CHECK: %[[vA:.*]] = linalg.view %arg0[{{.*}}, {{.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //       CHECK: affine.for %i0 = 0 to (d0) -> (d0)(%[[N]]) {
-  //       CHECK:   %[[vB:.*]] = linalg.view %arg1[{{.*}}, {{.*}}] : !linalg.view<?xf32>
-  //       CHECK:   %[[vC:.*]] = linalg.view %arg2[{{.*}}, {{.*}}] : !linalg.view<?xf32>
+  //       CHECK:   %[[vB:.*]] = linalg.view %arg1[{{.*}}, {{.*}}] : memref<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
+  //       CHECK:   %[[vC:.*]] = linalg.view %arg2[{{.*}}, {{.*}}] : memref<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
   //       CHECK:   affine.for %i1 = 0 to (d0) -> (d0)(%[[M]]) {
   //       CHECK:     affine.for %i2 = 0 to (d0) -> (d0)(%[[K]]) {
   //       CHECK:        %{{.*}} = cmpi "eq", %i2, %{{.*}} : index
index f87cbca..a8f00df 100644 (file)
@@ -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
index 61bc287..00afa32 100644 (file)
@@ -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
   )
 
index 00da459..cdd87d7 100644 (file)
@@ -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<?x?xf32>
+  //       CHECK:     %[[vA:.*]] = linalg.view %arg0[%[[ri0]], %[[rK]]] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //       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<?x?xf32>
-  //  CHECK-NEXT:     %[[vC:.*]]  = linalg.view %arg2[%5, %13] : !linalg.view<?x?xf32>
+  //  CHECK-NEXT:     %[[vB:.*]]  = linalg.view %arg1[%10, %13] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  //  CHECK-NEXT:     %[[vC:.*]]  = linalg.view %arg2[%5, %13] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //  CHECK-NEXT:     linalg.matmul(%[[vA]], %[[vB]], %[[vC]]) : !linalg.view<?x?xf32>
   // 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<?x?xf32>
+  //       CHECK:     %[[vA:.*]] = linalg.view %arg0[%[[ri0]], %[[rK]]] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //       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<?x?xf32>
-  //  CHECK-NEXT:     %[[vC:.*]]  = linalg.view %arg2[%5, %13] : !linalg.view<?x?xf32>
+  //  CHECK-NEXT:     %[[vB:.*]]  = linalg.view %arg1[%10, %13] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  //  CHECK-NEXT:     %[[vC:.*]]  = linalg.view %arg2[%5, %13] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
   //  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]]) {
index 523050f..ee0fb3b 100644 (file)
@@ -12,4 +12,5 @@ target_link_libraries(Linalg4
     MLIRParser
     MLIRPass
     MLIRTransforms
+    Linalg3
     )
index 86fbc43..5b3627c 100644 (file)
@@ -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.
index 9e7083f..c6b58d8 100644 (file)
@@ -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
+  )
index 39fa952..4a775a6 100644 (file)
@@ -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 (file)
index 0000000..7606ffa
--- /dev/null
@@ -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<f32>, %arg1: memref<?xf32>, %arg2: memref<?x?xf32>) {
+  %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<f32>, !linalg.view<f32>
+  %5 = linalg.view %arg1[%3] : memref<?xf32>, !linalg.range, !linalg.view<?xf32>
+  %6 = linalg.view %arg2[%3, %3] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  "some_consumer"(%4, %5, %6) : (!linalg.view<f32>, !linalg.view<?xf32>, !linalg.view<?x?xf32>) -> ()
+  return
+}
+// CHECK-LABEL: func @view_op(%arg0: memref<f32>, %arg1: memref<?xf32>, %arg2: memref<?x?xf32>) {
+//       CHECK:  %0 = linalg.range {{.*}} : !linalg.range
+//       CHECK:  {{.*}} = linalg.view %arg0[] : memref<f32>, !linalg.view<f32>
+//       CHECK:  {{.*}} = linalg.view %arg1[%0] : memref<?xf32>, !linalg.range, !linalg.view<?xf32>
+//       CHECK:  {{.*}} = linalg.view %arg2[%0, %0] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+
+func @slice_op(%arg0: memref<?x?xf32>) {
+  %c0 = constant 0 : index
+  %c1 = constant 1 : index
+  %1 = dim %arg0, 0 : memref<?x?xf32>
+  %2 = dim %arg0, 1 : memref<?x?xf32>
+  %3 = linalg.range %c0:%1:%c1 : !linalg.range
+  %4 = linalg.range %c0:%2:%c1 : !linalg.range
+  %5 = linalg.view %arg0[%3, %4] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  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<?x?xf32>, index
+      "some_consumer"(%6) : (!linalg.view<?xf32>) -> ()
+      %7 = linalg.slice %5[%i1] {dim: 0} : !linalg.view<?x?xf32>, index
+      %8 = linalg.slice %7[%i0] {dim: 0} : !linalg.view<?xf32>, index
+    }
+  }
+  return
+}
+// CHECK-LABEL: func @slice_op(%arg0: memref<?x?xf32>) {
+//       CHECK:  %[[M:.*]] = dim %arg0, 0 : memref<?x?xf32>
+//       CHECK:  %[[N:.*]] = dim %arg0, 1 : memref<?x?xf32>
+//       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<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+//       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<?x?xf32>, index
+//       CHECK:      %[[V2:.*]] = linalg.slice %[[V]][%i1] {dim: 0} : !linalg.view<?x?xf32>, index
+//       CHECK:      {{.*}} = linalg.slice %[[V2]][%i0] {dim: 0} : !linalg.view<?xf32>, 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<?x?xf32>, %arg1: !linalg.range, %arg2: !linalg.range) {
+  %0 = linalg.view %arg0[%arg1, %arg2] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  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<?x?xf32>, %arg1: !linalg.range, %arg2: index) {
+  %0 = linalg.view %arg0[%arg1, %arg2] : memref<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
+  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<?x?xf32>, %arg1: !linalg.range, %arg2: !linalg.range, %arg3: !linalg.range) {
+  %0 = linalg.view %arg0[%arg1, %arg2] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  %1 = linalg.slice %0[%arg3] {dim: 0} : !linalg.view<?x?xf32>, !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<?x?xf32>, %arg1: !linalg.range, %arg2: !linalg.range, %arg3: index) {
+  %0 = linalg.view %arg0[%arg1, %arg2] : memref<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+  %1 = linalg.slice %0[%arg3] {dim: 0} : !linalg.view<?x?xf32>, 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] }">
index f6e9ac7..a0ce32c 100644 (file)
@@ -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)