My initial intension was to add a printf
op which lowers to LLVM dialect for CPU and it now ends up adding a new dialect. There were some discussions on the PR for this op.
Overview
This RFC for a new dialect is to enable an easy-to-use way of calling some of the “handy and small functions” in MLIR, which are implemented by the C standard runtime and other runtime functions. This implies that the ops in this dialect are lowered to function calls on CPU.
The scope of the dialect should be limited to the operations that are useful for common developers of MLIR, and are
- already implemented in existing libc runtime. e.g.
printf
,abort
- easy to implement in C/C++/other languages. e.g.
timer
,expect_close
,print
- simple control flow wrappers on functions above, like
assert
,scoped_timer
,bench_loop
The ops are useful for developers, to debug, benchmark and test their MLIR program. There exists some direct call to runtime functions in CRunnerUtils
in current FileCheck testing. The function calls may be replaced by printf
ops, for example.
The naming of this new dialect is not finalized. Maybe util
, c_runner_util
or dev
?
Note: The ideas of the checking operations and timers operations are originated from TPP project’s check, perf
Proposed ops
This is not a finalized list of the operations. Again, I am currently be most interested in printf
op. This section is to facilitate discussions on what can be added to this dialect.
printf
C-style printf. Similar Op definitions of gpu.printf
, except that it is for cpu.
runtime.printf "Hello world %f %d %lld\n" %t, %t2, %t3 : f32, i32, i64
abort
Calling abort()
of libc
assert
Accepts a predicate of i1
, and an optional StringAttr
for the failure message.
runtime.assert %0, "should be true!"
Can be lowered to SCF like:
scf.if(%0) {
} else {
runtime.printf "Error at XXX.mlir, Line123. should be true!"
runtime.abort
}
The source location in the error message can be extracted by the Location
of the assert
op.
We can have an option at the lowering pass, to remove the assertions for performance.
Will assert
be useful to improve the safety of the generated code? Memref dialect can use assert
to make sure the user-passed memref in func args have the claimed rank and dimensions at the function entry. Another useful feature based on assert
is the boundary checking on memory accesses on memref. I am not sure if these features are already in MLIR or not.
Generic print
It is possible to provide a generic print Op for generic types. This print
op can overload for various types like memref
and tensor
, to print the result of them. The op can be lowered to a function call in the existing printing primitives
Timer and benchmark ops
The operations exposes the access to timing APIs implemented in C. Based on that, we can introduce %t = bench_loop: i64 {...}
op which wraps around a Block
, runs it for several times and returns the execution time of the block. A working implementation at downstream
Arithmetic checking ops
expect_true
, expect_almost_same
, expect_sane
for memref
and tensor
. A working implementation here
Implementation of the runtime in C++
There are already some runtime functions in ExecutionEngine/CRunnerUtils
. We can put the new runtime C++ functions there.