Print in MLIR

I am writing MLIR code for tensor multiplication .But How can I write print operation in MLIR to print multiplication result.


The short answer is that it’s not something that MLIR provides out of the box. Personally, I think this is a significant barrier to entry for people, but I haven’t found the time to propose something. There is an example in the toy tutorial that does exactly this, for one type of lowering.

see: Chapter 6: Lowering to LLVM and CodeGeneration - MLIR

I have output in memref type.I am not able to print this using toy.print as it takes tensor type.Is there any ways to convert memref to tensor in MLIR or How can I print memref type variable.


These things are significantly better handled in C++ than in MLIR.

See which links a separately built .so that implements printing.

In a longer term future we just want to use any off-the-shelf library (e.g. numpy).
For now we just have a simple ABI and conventions to allow calling C / C++ from MLIR.

Although not directly applicable to your request, please note that the Vector dialect added some rudimentary built-in support for printing, something we use heavily during debugging and testing, as well as in our integration tests.

Something like

  vector.print %1 : vector<128xf32>

is lowered by unrolling this into a series of simple calls into a very small runtime support library. This approach does not scale very well, but it has the advantage that clients only need to provide a few methods for this runtime support library when targeting a new platform.

The implementation below is used for CPU. Linking these in (either when running JIT or AOT) makes it so much easier to test new features in the vector dialect (or anything that lowers to it).

extern "C" void print_i32(int32_t i) { fprintf(stdout, "%" PRId32, i); }
extern "C" void print_i64(int64_t l) { fprintf(stdout, "%" PRId64, l); }
extern "C" void print_f32(float f)   { fprintf(stdout, "%g", f); }
extern "C" void print_f64(double d)  { fprintf(stdout, "%lg", d); }
extern "C" void print_open()         { fputs("( ", stdout); }
extern "C" void print_close()        { fputs(" )", stdout); }
extern "C" void print_comma()        { fputs(", ", stdout); }
extern "C" void print_newline()      { fputc('\n', stdout); }

Please see examples with print_memref in test/mlir-cpu-runner/.

when I run the code utils.mlir I am getting error like this:
Fail to create MemoryBuffer for: %linalg_test_lib_dir/libmlir_runner_utils%shlibext
JIT session error: Symbols not found: [ _mlir_ciface_print_memref_f32, _mlir_ciface_print_memref_vector_4x4xf32 ]
Error: Failed to materialize symbols: { (main, { _mlir_print_memref_f32, _mlir_print_3d, _mlir_print_memref_vector_4x4xf32, print_0d, print_3d, vector_splat_2d, _mlir_vector_splat_2d, print_memref_f32, _mlir_print_0d, print_memref_vector_4x4xf32, _mlir_print_1d, print_1d }) }

Thank You

From the error message, it looks like you literally typed the option


but that is of course not going to work (the %vars are substituted for the right values by the test runner script). You will need to provide the full path. Something like the following, where the fullpathtolib depends on your build setup.

mlir-cpu-runner ....  \

And then it will work!

Thank You .I want to convert this mlir to llvm and I want to execute this in x86.When I tried this it gave segmentation fault because of the print_memref_f32.This is my MLIR code:

func @main() {
  %f = constant 2.00000e+00 : f32
  %A = alloc() : memref<16xf32>
  %B = memref_cast %A: memref<16xf32> to memref<?xf32>
  linalg.fill(%B, %f) : memref<?xf32>, f32
  %U = memref_cast %B :  memref<?xf32> to memref<*xf32>
  call @print_memref_f32(%U): (memref<*xf32>) -> ()
  dealloc %A : memref<16xf32>
func @print_memref_f32(memref<*xf32>)

How can I solve this?
Thank You

Please do always mention how exactly you ran it (the entire command) and the output/crash trace you obtained.

1.To lower the code to LLVM dialect: mlir-opt ex.mlir -convert-linalg-to-loops -convert-linalg-to-llvm -convert-std-to-llvm >exllvm.mlir
2. To get LLVMIR : mlir-translate -mlir-to-llvmir ex1.mlir >exllvmir.ll
3.llvm-as exllvmir.ll -o test.bc
4. To run the code : lli test.bc
When I run lli I got error as :
Stack dump:
0. Program arguments: lli test.bc
#0 0x00007f8eba6234ff llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/lib/x86_64-linux-gnu/
#1 0x00007f8eba6217b0 llvm::sys::RunSignalHandlers() (/lib/x86_64-linux-gnu/
#2 0x00007f8eba623ac5 (/lib/x86_64-linux-gnu/
#3 0x00007f8eb9c943c0 __restore_rt (/lib/x86_64-linux-gnu/
Segmentation fault (core dumped)
Thank You

A few remarks:

  • You don’t need to invoke llvm-as as most LLVM tools accept .ll files as input.
  • instead of lli you could use clang to build your code as a binary I believe.
  • your code depends on the print_memref_f32 function: mlir-cpu-runner examples above are including to get it. This is the reason lli is crashing.

For example clang exllvmir.ll <path_to_build_dir>/lib/ -o main followed by LD_LIBRARY_PATH=<path_to_build_dir>/lib ./main is working for me.

Its working for me now .Thank you

When I followed the same method for the following code :
func @main()
%c1= constant 0.500:f32
%A = alloc() : memref<1xf32>
%b = exp %c1 : f32 %b, %A[0] : memref<1xf32>

%U = memref_cast %A: memref<1xf32> to memref<*xf32>
call @print_memref_f32(%U): (memref<*xf32>) → ()
func @print_memref_f32(memref<*xf32>)
I lower these code to LLVM dialect using :mlir-opt --lower-affine --convert-scf-to-std -convert-std-to-llvm
then I lowered to LLVM IR using mlir-translate -mlir-to-llvmir

When I run the .ll file using
clang exllvmir.ll <path_to_build_dir>/lib/ -o main

I am getting error like this:
/usr/bin/ld: /tmp/n3-b2760a.o: undefined reference to symbol ‘expf@@GLIBC_2.27
/usr/bin/ld: /lib/x86_64-linux-gnu/ error adding symbols: DSO missing from command line
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Thank You

ld kind of tell you about the issue: /usr/bin/ld: /lib/x86_64-linux-gnu/ error adding symbols: DSO missing from command line

The expf symbols is provided by libm, try adding -lm on the clang invocation?

Hi all,
Is it possible to print a memref<vector<>> with print_memref_f32? I tried this codes and it works on vector.print but got a segment fault in call @print_memref_f32(%A) : (memref<vector<16xf32>>) → ().

func @broadcast16(%arg0: f32, %arg1: memref<vector<16xf32>>) {
  %v = vector.broadcast %arg0 : f32 to vector<16xf32> %v, %arg1[] : memref<vector<16xf32>>, vector<16xf32>

func @main() {
  %c1 = constant 1.00000e+00 : f32
  %z  = constant 0.00000e+00 : f32
  %i0 = constant 0 : index
  %i1 = constant 1 : index
  %A = memref.alloc() : memref<vector<16xf32>>
  %v = vector.broadcast %c1 : f32 to vector<16xf32> %v, %A[] : memref<vector<16xf32>>, vector<16xf32>
  vector.print %v : vector<16xf32>
  %v2 = vector.load %A[] : memref<vector<16xf32>>, vector<16xf32> 
  vector.print %v2 : vector<16xf32>

  call @print_memref_f32(%A) : (memref<vector<16xf32>>) -> ()
func private @print_memref_f32(memref<vector<16xf32>>)
func private @print_flops(f64)
func private @rtclock() -> f64

Unranked Memref base@ = 0 rank = 56769392 offset = 55801376 sizes = [0, 55801424, 0, 55801568, 1335734829056, 55801616, 0, 55728304, 0, 0, 0, 144, 3089, 139877812282000, …
Stack dump:

  1.  Program arguments: /data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner -O3 -e main -entry-point-result=void -shared-libs=/data/xxxxx/mlir/llvm-project/build/lib/ -shared-libs=/data/xxxxx/mlir/llvm-project/build/lib/ --dump-object-file --object-filename=bin.o

#0 0x00000000011164a3 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x11164a3)
#1 0x000000000111428e llvm::sys::RunSignalHandlers() (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x111428e)
#2 0x0000000001116d66 SignalHandler(int) (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x1116d66)
#3 0x00007f68e4659980 __restore_rt (/lib/x86_64-linux-gnu/
#4 0x00007f68e4a86860 void printMemRefMetaData<float, std::ostream>(std::ostream&, DynamicMemRefType const&) (/data/xxxxx/mlir/llvm-project/build/lib/
#5 0x00007f68e4a88c0e void impl::printMemRef(DynamicMemRefType const&) (/data/xxxxx/mlir/llvm-project/build/lib/
#6 0x00007f68e4a86ede print_memref_f32 (/data/xxxxx/mlir/llvm-project/build/lib/
#7 0x00000000015f1a86 compileAndExecute((anonymous namespace)::Options&, mlir::ModuleOp, llvm::StringRef, (anonymous namespace)::CompileAndExecuteConfig, void**) (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x15f1a86)
#8 0x00000000015eff39 compileAndExecuteVoidFunction((anonymous namespace)::Options&, mlir::ModuleOp, llvm::StringRef, (anonymous namespace)::CompileAndExecuteConfig) (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x15eff39)
#9 0x00000000015ee8e5 mlir::JitRunnerMain(int, char**, mlir::DialectRegistry const&, mlir::JitRunnerConfig) (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x15ee8e5)
#10 0x00000000010a7222 main (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x10a7222)
#11 0x00007f68e30e5bf7 __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/…/csu/libc-start.c:344:0
#12 0x00000000010a702a _start (/data/xxxxx/mlir/llvm-project/build/bin/mlir-cpu-runner+0x10a702a)



@print_memref_f32 is a function implemented in C and there is no equivalent of vector<???> types in C, so you can’t even represent the function signature correctly.

You can do something like

linalg.generic %memref ... {
^bb(%arg0: vector<???>):
  vector.print %arg0 : vector<???>

and have that lowered to loops, then cfg, then LLVM.

With vector.print, I find that the documentation for the operation was not self-explanatory, and thus I found it unclear as to how to get it working.

It says that it will work “when linked with a small runtime support library”. From looking at this discussion, I was finally able to see from the integration tests that is the required library.

Thus, if I have a bit of code such as:

func.func @print_vector() {
  %c1 = arith.constant 1.000000e+00 : f32

  %A = memref.alloc() : memref<vector<2xf32>>
  %v = vector.broadcast %c1 : f32 to vector<2xf32>

  vector.print %v : vector<2xf32>


Then passing it through:

mlir-opt \
      --convert-scf-to-cf \
      --convert-vector-to-llvm \
      --convert-func-to-llvm \

Then I can use the mlir-cpu-runner with the library, e.g.

mlir-cpu-runner \
    -shared-libs=${US_LLVM}/lib/ \
    -entry-point-result=void -e print_vector

It took me quite a while to figure this out, and I hope having this in the discussion forums makes it easier for other folk.

1 Like