-
Notifications
You must be signed in to change notification settings - Fork 74
IO Example through LLVM stdlib
Emilien Bauer edited this page Apr 18, 2023
·
5 revisions
Here is a basic example of using LLVM and stdlin to get basic IO in MLIR IR.
This is a toy program, reading a line from stdin up to 1024 bytes, and just printing it out. It uses terrible practices, and is just meant as a minimal example on how to use stdlib's IO routines from an MLIR IR, nothing more. Please choose your routines and error checking accordingly to your use-case!
module{
// Declare external puts/gets functions.
func.func private @puts(!llvm.ptr<i8>) -> i32
func.func private @gets(!llvm.ptr<i8>) -> !llvm.ptr<i8>
// MLIR's func dialect doesn't handle variadics at this point.
// To use e.g. printf, one have to use the llvm dialect at the time of writing.
// It can then be called with llvm.call, which has the same syntax as func.call!
llvm.func @printf(!llvm.ptr<i8>) -> i32
// Declare your main function
func.func @main() -> (i32){
// Allocate some buffer for your data
%N = arith.constant 1024 : i64
%buffer = llvm.alloca %N x i8 : (i64) -> !llvm.ptr<i8>
// Just call gets on this buffer
%ptr = func.call @gets(%buffer) : (!llvm.ptr<i8>) -> !llvm.ptr<i8>
// Call puts on its returned pointer
%puts = func.call @puts(%ptr) : (!llvm.ptr<i8>) -> i32
// Return puts's returned value, just for fun
return %puts : i32
}
}
In generic syntax:
"builtin.module"() ({
// Declare external puts/gets functions.
"func.func"() ({
}) {function_type = (!llvm.ptr<i8>) -> i32, sym_name = "puts", sym_visibility = "private"} : () -> ()
"func.func"() ({
}) {function_type = (!llvm.ptr<i8>) -> !llvm.ptr<i8>, sym_name = "gets", sym_visibility = "private"} : () -> ()
// MLIR's func dialect doesn't handle variadics at this point.
// To use e.g. printf, one have to use the llvm dialect at the time of writing.
// It can then be called with llvm.call, which has the same syntax as func.call!
"llvm.func"() ({
}) {CConv = #llvm.cconv<ccc>, function_type = !llvm.func<i32 (ptr<i8>)>, linkage = #llvm.linkage<external>, sym_name = "printf"} : () -> ()
// Declare your main function
"func.func"() ({
// Allocate some buffer for your data
%0 = "arith.constant"() {value = 1024 : i64} : () -> i64
%1 = "llvm.alloca"(%0) : (i64) -> !llvm.ptr<i8>
// Just call gets on this buffer
%2 = "func.call"(%1) {callee = @gets} : (!llvm.ptr<i8>) -> !llvm.ptr<i8>
// Call puts on its returned pointer
%3 = "func.call"(%2) {callee = @puts} : (!llvm.ptr<i8>) -> i32
// Return puts's returned value, just for fun
"func.return"(%3) : (i32) -> ()
}) {function_type = () -> i32, sym_name = "main"} : () -> ()
}) : () -> ()
You should be able to compile it to a reader
executable with mlir-opt io.mlir --pass-pipeline="builtin.module(convert-func-to-llvm)" | mlir-translate --mlir-to-llvmir | clang -x ir - -o reader
Here is en exemple execution:
myterminalprompt:~$ ./reader
Hey reader, please print this, cheers.
Hey reader, please print this, cheers.