Skip to content

daneelsan/MLIRToyOutOfTree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MLIR: Toy Tutorial Out-of-Tree

This tutorial runs through the implementation of a basic toy language on top of MLIR. The difference with the tutorial done in the official MLIR page is that this dialect is setup to be an out-of-tree dialect.

NOTE: The tutorial is up-to-date until Ch2 of the Toy Tutorial.

Build

Build MLIR

$LLVM_SRC_DIR stores the directory of the llvm-project repository:

$ echo $LLVM_SRC_DIR
/Users/daniels/git/llvm-project

Clone the LLVM git project (I chose to put it in ~/git):

$ cd ~/git && git clone https://github.com/llvm/llvm-project.git && cd llvm-project

Create a directory to store the MLIR build:

$ mkdir build-mlir && cd build-mlir

Configure the build using cmake (see https://mlir.llvm.org/getting_started/):

$ cmake -G Ninja ../llvm \
   -DLLVM_ENABLE_LLD=ON -DMLIR_INCLUDE_INTEGRATION_TESTS=ON \
   -DLLVM_ENABLE_PROJECTS=mlir \
   -DLLVM_BUILD_EXAMPLES=ON \
   -DLLVM_TARGETS_TO_BUILD=host \
   -DCMAKE_BUILD_TYPE=Release \
   -DLLVM_ENABLE_ASSERTIONS=ON

$ cmake --build . --target check-mlir

$MLIR_BUILD_DIR stores the directory where MLIR was build:

$ echo $MLIR_BUILD_DIR
/Users/daniels/git/llvm-project/build-mlir

Build the Toy Dialect (Out-of-Tree)

Now that MLIR is built we proceed to build this project:

$ rm -rf build

$ cmake -S . -B build -DMLIR_DIR=$MLIR_BUILD_DIR/lib/cmake/mlir

$ cmake --build build
[ 11%] Building Ops.h.inc...
[ 22%] Building Ops.cpp.inc...
[ 33%] Building Dialect.h.inc...
[ 44%] Building Dialect.cpp.inc...
[ 44%] Built target ToyOpsIncGen
[ 55%] Building CXX object toyc/CMakeFiles/toyc.dir/toyc.cpp.o
[ 66%] Building CXX object toyc/CMakeFiles/toyc.dir/parser/AST.cpp.o
[ 77%] Building CXX object toyc/CMakeFiles/toyc.dir/mlir/Dialect.cpp.o
[ 88%] Building CXX object toyc/CMakeFiles/toyc.dir/mlir/MLIRGen.cpp.o
[100%] Linking CXX executable ../bin/toyc
[100%] Built target toyc

The executables built are stored in:

$ ls ./build/bin
toyc

Examples

-emit=ast

Let's convert the following toy code:

$ cat test/Ch2/codegen.toy
# User defined generic function that operates on unknown shaped arguments.
def multiply_transpose(a, b) {
  return transpose(a) * transpose(b);
}

def main() {
  var a<2, 3> = [[1, 2, 3], [4, 5, 6]];
  var b<2, 3> = [1, 2, 3, 4, 5, 6];
  var c = multiply_transpose(a, b);
  var d = multiply_transpose(b, a);
  print(d);

To its AST representation:

$ ./build/bin/toyc -emit=ast test/Ch2/codegen.toy
Module:
    Function
      Proto 'multiply_transpose' @test/Ch2/codegen.toy:2:1
      Params: [a, b]
      Block {
        Return
          BinOp: * @test/Ch2/codegen.toy:3:25
            Call 'transpose' [ @test/Ch2/codegen.toy:3:10
              var: a @test/Ch2/codegen.toy:3:20
            ]
            Call 'transpose' [ @test/Ch2/codegen.toy:3:25
              var: b @test/Ch2/codegen.toy:3:35
            ]
      } // Block
    Function
      Proto 'main' @test/Ch2/codegen.toy:6:1
      Params: []
      Block {
        VarDecl a<2, 3> @test/Ch2/codegen.toy:7:3
          Literal: <2, 3>[ <3>[ 1.000000e+00, 2.000000e+00, 3.000000e+00], <3>[ 4.000000e+00, 5.000000e+00, 6.000000e+00]] @test/Ch2/codegen.toy:7:17
        VarDecl b<2, 3> @test/Ch2/codegen.toy:8:3
          Literal: <6>[ 1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00] @test/Ch2/codegen.toy:8:17
        VarDecl c<> @test/Ch2/codegen.toy:9:3
          Call 'multiply_transpose' [ @test/Ch2/codegen.toy:9:11
            var: a @test/Ch2/codegen.toy:9:30
            var: b @test/Ch2/codegen.toy:9:33
          ]
        VarDecl d<> @test/Ch2/codegen.toy:10:3
          Call 'multiply_transpose' [ @test/Ch2/codegen.toy:10:11
            var: b @test/Ch2/codegen.toy:10:30
            var: a @test/Ch2/codegen.toy:10:33
          ]
        Print [ @test/Ch2/codegen.toy:11:3
          var: d @test/Ch2/codegen.toy:11:9
        ]
      } // Block

-emit=mlir

Let's convert the following toy code:

$ cat test/Ch2/codegen.toy
# User defined generic function that operates on unknown shaped arguments.
def multiply_transpose(a, b) {
  return transpose(a) * transpose(b);
}

def main() {
  var a<2, 3> = [[1, 2, 3], [4, 5, 6]];
  var b<2, 3> = [1, 2, 3, 4, 5, 6];
  var c = multiply_transpose(a, b);
  var d = multiply_transpose(b, a);
  print(d);

To MLIR using the toyc executable and the -emit=mlir flag:

$ ./build/bin/toyc -emit=mlir test/Ch2/codegen.toy -emit=mlir test/Ch2/codegen.toy
module {
  toy.func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> {
    %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64>
    %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64>
    %2 = toy.mul %0, %1 : tensor<*xf64>
    toy.return %2 : tensor<*xf64>
  }
  toy.func @main() {
    %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>
    %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64>
    %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>
    %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64>
    %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64>
    %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64>
    toy.print %5 : tensor<*xf64>
    toy.return
  }
}

Print additional debugging information:

$ ./build/bin/toyc -emit=mlir -mlir-print-debuginfo test/Ch2/codegen.toy
module {
  toy.func @multiply_transpose(%arg0: tensor<*xf64> loc("test/Ch2/codegen.toy":2:1), %arg1: tensor<*xf64> loc("test/Ch2/codegen.toy":2:1)) -> tensor<*xf64> {
    %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> loc("test/Ch2/codegen.toy":3:10)
    %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> loc("test/Ch2/codegen.toy":3:25)
    %2 = toy.mul %0, %1 : tensor<*xf64> loc("test/Ch2/codegen.toy":3:25)
    toy.return %2 : tensor<*xf64> loc("test/Ch2/codegen.toy":3:3)
  } loc("test/Ch2/codegen.toy":2:1)
  toy.func @main() {
    %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> loc("test/Ch2/codegen.toy":7:17)
    %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> loc("test/Ch2/codegen.toy":7:3)
    %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> loc("test/Ch2/codegen.toy":8:17)
    %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> loc("test/Ch2/codegen.toy":8:3)
    %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("test/Ch2/codegen.toy":9:11)
    %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("test/Ch2/codegen.toy":10:11)
    toy.print %5 : tensor<*xf64> loc("test/Ch2/codegen.toy":11:3)
    toy.return loc("test/Ch2/codegen.toy":6:1)
  } loc("test/Ch2/codegen.toy":6:1)
} loc(unknown)

Other Useful Examples

Generate C++ code using mlir-tblgen

Call mlir-tblgen on Ops.td to generate dialect declarations:

$ ${MLIR_BUILD_DIR}/bin/mlir-tblgen -gen-dialect-decls include/toy/Ops.td -I ${LLVM_SRC_DIR}/mlir/include/
/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
|*                                                                            *|
|* Dialect Declarations                                                       *|
|*                                                                            *|
|* Automatically generated file, do not edit!                                 *|
|* From: Ops.td                                                               *|
|*                                                                            *|
\*===----------------------------------------------------------------------===*/

namespace toy {

/// A high-level dialect for analyzing and optimizing the Toy language.
/// The Toy language is a tensor-based language that allows you to define
///     functions, perform some math computation, and print results. This dialect
///     provides a representation of the language that is amenable to analysis and
///     optimization.
class ToyDialect : public ::mlir::Dialect {
  explicit ToyDialect(::mlir::MLIRContext *context);

  void initialize();
  friend class ::mlir::MLIRContext;
public:
  ~ToyDialect() override;
  static constexpr ::llvm::StringLiteral getDialectNamespace() {
    return ::llvm::StringLiteral("toy");
  }
};
} // namespace toy
MLIR_DECLARE_EXPLICIT_TYPE_ID(toy::ToyDialect)

Call mlir-tblgen on Ops.td to generate operation declarations:

$ ${MLIR_BUILD_DIR}/bin/mlir-tblgen -gen-op-decls include/toy/Ops.td -I ${LLVM_SRC_DIR}/mlir/include/
/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
|*                                                                            *|
|* Op Declarations                                                            *|
|*                                                                            *|
|* Automatically generated file, do not edit!                                 *|
|* From: Ops.td                                                               *|
|*                                                                            *|
\*===----------------------------------------------------------------------===*/

namespace toy {
/// constant
/// Constant operation turns a literal into an SSA value. The data is attached
///     to the operation as an attribute. For example:
///
///     ```mlir
///       %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]>
///                         : tensor<2x3xf64>
///     ```
class ConstantOp;
} // namespace toy
...

Alternatively, use -gen-op-defs to generate the class C++ implementation.

Links

About

Out-of-tree implementation of the MLIR Toy dialect

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors