diff --git a/Brutus/Project.toml b/Brutus/Project.toml index 0419239..01db25d 100644 --- a/Brutus/Project.toml +++ b/Brutus/Project.toml @@ -4,8 +4,8 @@ authors = ["Valentin Churavy ", "Leon Shen " version = "0.1.0" [deps] -GPUCompiler = "61eb1bfa-7361-4325-ad38-22787b887f55" +MLIR = "bfde9dd4-8f40-4a1e-be09-1475335e1c92" +Preferences = "21216c6a-2e73-6563-6e65-726566657250" [compat] julia = "1.8" -GPUCompiler = "0.13" diff --git a/Brutus/src/Brutus.jl b/Brutus/src/Brutus.jl index 3469b81..1c9ac83 100644 --- a/Brutus/src/Brutus.jl +++ b/Brutus/src/Brutus.jl @@ -1,18 +1,57 @@ module Brutus -using GPUCompiler: GPUCompiler, CompilerJob -import GPUCompiler -import GPUCompiler: AbstractCompilerTarget, AbstractCompilerParams +using Preferences +using MLIR -##### -##### Exports -##### +const libbrutus = @load_preference("libbrutus") +const libbrutus_c = @load_preference("libbrutus_c") -export emit +module BrutusAPI + import ..Brutus: libbrutus, libbrutus_c + import MLIR.API: MlirDialectHandle + function mlirGetDialectHandle__jlir__() + @ccall libbrutus_c.mlirGetDialectHandle__jlir__()::MlirDialectHandle + end +end -include("init.jl") -include("codegen.jl") -include("reflection.jl") -include("interface.jl") +import MLIR: API, IR, Dialects +module BrutusDialects + include(joinpath("Dialects", string(Base.libllvm_version.major), "JuliaOps.jl")) +end + +function load_dialect(ctx) + dialect = IR.DialectHandle(BrutusAPI.mlirGetDialectHandle__jlir__()) + API.mlirDialectHandleRegisterDialect(dialect, ctx) + API.mlirDialectHandleLoadDialect(dialect, ctx) +end + +function code_mlir(f, types) + ctx = IR.context() + + src, rt = only(Base.code_ircode(f, types)) + + for dialect in ("func", "cf") + IR.get_or_load_dialect!(dialect) + end + load_dialect(ctx) + IR.get_or_load_dialect!(IR.DialectHandle(BrutusAPI.mlirGetDialectHandle__jlir__())) + + values = Vector{Value}(undef, length(ir.stmts)) +end + +# using GPUCompiler: GPUCompiler, CompilerJob +# import GPUCompiler +# import GPUCompiler: AbstractCompilerTarget, AbstractCompilerParams + +# ##### +# ##### Exports +# ##### + +# export emit + +# include("init.jl") +# include("codegen.jl") +# include("reflection.jl") +# include("interface.jl") end # module diff --git a/Brutus/src/Dialects/15/JuliaOps.jl b/Brutus/src/Dialects/15/JuliaOps.jl new file mode 100644 index 0000000..b5bf1db --- /dev/null +++ b/Brutus/src/Dialects/15/JuliaOps.jl @@ -0,0 +1,2172 @@ +module jlir + +import ...IR: NamedAttribute, MLIRType, Value, Location, Block, Region, Attribute, create_operation, context, IndexType +import ...Dialects: namedattribute, operandsegmentsizes +import ...API + + +""" +`arraytomemref` + +TODO +""" +function arraytomemref(a::Value; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[a, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.arraytomemref", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`call` + +TODO +""" +function call(callee::Value, arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[callee, arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.call", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`constant` + +TODO +""" +function constant(; result_0::MLIRType, value, location=Location()) + results = MLIRType[result_0, ] + operands = Value[] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[namedattribute("value", value), ] + + create_operation( + "jlir.constant", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`convertstd` + +""" +function convertstd(input::Value; output::MLIRType, location=Location()) + results = MLIRType[output, ] + operands = Value[input, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.convertstd", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`gotoifnot` + +TODO +""" +function gotoifnot(condition::Value, branchOperands::Vector{Value}, fallthroughOperands::Vector{Value}; branchDest::Block, fallthroughDest::Block, location=Location()) + results = MLIRType[] + operands = Value[condition, branchOperands..., fallthroughOperands..., ] + owned_regions = Region[] + successors = Block[branchDest, fallthroughDest, ] + attributes = NamedAttribute[] + push!(attributes, operandsegmentsizes([1, length(branchOperands), length(fallthroughOperands), ])) + + create_operation( + "jlir.gotoifnot", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`goto` + +TODO +""" +function goto(operands::Vector{Value}; dest::Block, location=Location()) + results = MLIRType[] + operands = Value[operands..., ] + owned_regions = Region[] + successors = Block[dest, ] + attributes = NamedAttribute[] + + create_operation( + "jlir.goto", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`invoke` + +TODO +""" +function invoke(callee::Value, arguments::Vector{Value}; result_0::MLIRType, methodInstance, location=Location()) + results = MLIRType[result_0, ] + operands = Value[callee, arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[namedattribute("methodInstance", methodInstance), ] + + create_operation( + "jlir.invoke", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`_apply` + +""" +function _apply(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir._apply", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`_apply_iterate` + +""" +function _apply_iterate(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir._apply_iterate", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`_apply_latest` + +""" +function _apply_latest(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir._apply_latest", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`_apply_pure` + +""" +function _apply_pure(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir._apply_pure", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`_expr` + +""" +function _expr(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir._expr", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`_typevar` + +""" +function _typevar(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir._typevar", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`applicable` + +""" +function applicable(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.applicable", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`apply_type` + +""" +function apply_type(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.apply_type", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`arrayref` + +""" +function arrayref(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.arrayref", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`arrayset` + +""" +function arrayset(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.arrayset", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`arraysize` + +""" +function arraysize(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.arraysize", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`const_arrayref` + +""" +function const_arrayref(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.const_arrayref", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fieldtype` + +""" +function fieldtype(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fieldtype", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`getfield` + +""" +function getfield(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.getfield", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ifelse` + +""" +function ifelse(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ifelse", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`===` + +""" +function ===(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.===", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`isa` + +""" +function isa(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.isa", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`isdefined` + +""" +function isdefined(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.isdefined", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`issubtype` + +""" +function issubtype(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.issubtype", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`nfields` + +""" +function nfields(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.nfields", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`setfield!` + +""" +function setfield!(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.setfield!", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`sizeof` + +""" +function sizeof(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.sizeof", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`svec` + +""" +function svec(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.svec", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`throw` + +""" +function throw(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.throw", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`tuple` + +""" +function tuple(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.tuple", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`typeassert` + +""" +function typeassert(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.typeassert", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`typeof` + +""" +function typeof(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.typeof", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`abs_float` + +""" +function abs_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.abs_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`add_float` + +""" +function add_float(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.add_float", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`add_int` + +""" +function add_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.add_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`add_ptr` + +""" +function add_ptr(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.add_ptr", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`and_int` + +""" +function and_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.and_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`arraylen` + +""" +function arraylen(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.arraylen", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ashr_int` + +""" +function ashr_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ashr_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`bitcast` + +""" +function bitcast(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.bitcast", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`bswap_int` + +""" +function bswap_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.bswap_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ceil_llvm` + +""" +function ceil_llvm(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ceil_llvm", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +# """ +# `cglobal` + +# """ +# function cglobal(arguments::Vector{Value}; result_0::MLIRType, location=Location()) +# results = MLIRType[result_0, ] +# operands = Value[arguments..., ] +# owned_regions = Region[] +# successors = Block[] +# attributes = NamedAttribute[] + +# create_operation( +# "jlir.cglobal", location; +# operands, owned_regions, successors, attributes, +# results=results, +# result_inference=false +# ) +# end + +""" +`checked_sadd_int` + +""" +function checked_sadd_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_sadd_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_sdiv_int` + +""" +function checked_sdiv_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_sdiv_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_smul_int` + +""" +function checked_smul_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_smul_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_srem_int` + +""" +function checked_srem_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_srem_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_ssub_int` + +""" +function checked_ssub_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_ssub_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_uadd_int` + +""" +function checked_uadd_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_uadd_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_udiv_int` + +""" +function checked_udiv_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_udiv_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_umul_int` + +""" +function checked_umul_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_umul_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_urem_int` + +""" +function checked_urem_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_urem_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`checked_usub_int` + +""" +function checked_usub_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.checked_usub_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`copysign_float` + +""" +function copysign_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.copysign_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ctlz_int` + +""" +function ctlz_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ctlz_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ctpop_int` + +""" +function ctpop_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ctpop_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`cttz_int` + +""" +function cttz_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.cttz_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`div_float` + +""" +function div_float(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.div_float", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`eq_float` + +""" +function eq_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.eq_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`eq_int` + +""" +function eq_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.eq_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`flipsign_int` + +""" +function flipsign_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.flipsign_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`floor_llvm` + +""" +function floor_llvm(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.floor_llvm", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fma_float` + +""" +function fma_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fma_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fpext` + +""" +function fpext(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fpext", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fpiseq` + +""" +function fpiseq(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fpiseq", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fpislt` + +""" +function fpislt(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fpislt", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fptosi` + +""" +function fptosi(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fptosi", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fptoui` + +""" +function fptoui(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fptoui", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`fptrunc` + +""" +function fptrunc(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.fptrunc", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`le_float` + +""" +function le_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.le_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`lshr_int` + +""" +function lshr_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.lshr_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`lt_float` + +""" +function lt_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.lt_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`mul_float` + +""" +function mul_float(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.mul_float", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`mul_int` + +""" +function mul_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.mul_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`muladd_float` + +""" +function muladd_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.muladd_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ne_float` + +""" +function ne_float(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ne_float", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ne_int` + +""" +function ne_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ne_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`neg_float` + +""" +function neg_float(arg::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[arg, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.neg_float", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`neg_int` + +""" +function neg_int(arg::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[arg, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.neg_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`not_int` + +""" +function not_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.not_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`or_int` + +""" +function or_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.or_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`pointerref` + +""" +function pointerref(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.pointerref", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`pointerset` + +""" +function pointerset(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.pointerset", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`rem_float` + +""" +function rem_float(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.rem_float", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`rint_llvm` + +""" +function rint_llvm(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.rint_llvm", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`sdiv_int` + +""" +function sdiv_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.sdiv_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`sext_int` + +""" +function sext_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.sext_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`shl_int` + +""" +function shl_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.shl_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`sitofp` + +""" +function sitofp(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.sitofp", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`sle_int` + +""" +function sle_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.sle_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`slt_int` + +""" +function slt_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.slt_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`sqrt_llvm` + +""" +function sqrt_llvm(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.sqrt_llvm", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`sqrt_llvm_fast` + +""" +function sqrt_llvm_fast(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.sqrt_llvm_fast", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`srem_int` + +""" +function srem_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.srem_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`sub_float` + +""" +function sub_float(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.sub_float", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`sub_int` + +""" +function sub_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.sub_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`sub_ptr` + +""" +function sub_ptr(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.sub_ptr", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`trunc_int` + +""" +function trunc_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.trunc_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`trunc_llvm` + +""" +function trunc_llvm(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.trunc_llvm", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`udiv_int` + +""" +function udiv_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.udiv_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`uitofp` + +""" +function uitofp(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.uitofp", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ule_int` + +""" +function ule_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ule_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`ult_int` + +""" +function ult_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.ult_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`urem_int` + +""" +function urem_int(rhs::Value, lhs::Value; result_0=nothing::Union{Nothing, MLIRType}, location=Location()) + results = MLIRType[] + operands = Value[rhs, lhs, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + (result_0 != nothing) && push!(results, result_0) + + create_operation( + "jlir.urem_int", location; + operands, owned_regions, successors, attributes, + results=(length(results) == 0 ? nothing : results), + result_inference=(length(results) == 0 ? true : false) + ) +end + +""" +`xor_int` + +""" +function xor_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.xor_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`zext_int` + +""" +function zext_int(arguments::Vector{Value}; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[arguments..., ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.zext_int", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`pi` + +TODO +""" +function pi(input::Value; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[input, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.pi", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`return_` + +The \"return\" operation represents a return operation within a function. +The operand type must match the signature of the function that contains +the operation. For example: + +```mlir +func @foo() -> i32 { + ... + jlir.return %0 : i32 +} +``` +""" +function return_(input::Value; location=Location()) + results = MLIRType[] + operands = Value[input, ] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.return", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`undef` + +TODO +""" +function undef(; result_0::MLIRType, location=Location()) + results = MLIRType[result_0, ] + operands = Value[] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.undef", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +""" +`unimplemented` + +unimplemented +""" +function unimplemented(; type::MLIRType, location=Location()) + results = MLIRType[type, ] + operands = Value[] + owned_regions = Region[] + successors = Block[] + attributes = NamedAttribute[] + + create_operation( + "jlir.unimplemented", location; + operands, owned_regions, successors, attributes, + results=results, + result_inference=false + ) +end + +end # jlir diff --git a/CMakeLists.txt b/CMakeLists.txt index c76bf1c..73cbc28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,10 @@ if(POLICY CMP0068) set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() + if(POLICY CMP0075) cmake_policy(SET CMP0075 NEW) endif() @@ -16,6 +20,7 @@ endif() project(brutus) set(BRUTUS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +find_package(LLVM REQUIRED CONFIG) find_package(MLIR REQUIRED CONFIG) message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") @@ -28,6 +33,7 @@ set(MLIR_BINARY_DIR ${CMAKE_BINARY_DIR}) list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") list(APPEND CMAKE_MODULE_PATH "${BRUTUS_SOURCE_DIR}/cmake/modules") + include(TableGen) include(AddLLVM) include(AddMLIR) @@ -51,16 +57,3 @@ add_subdirectory(include) add_subdirectory(lib) add_subdirectory(test) add_subdirectory(tools) - -set(JLRUN "${CMAKE_BINARY_DIR}/jl.sh") -file( WRITE ${JLRUN} "#!/bin/bash\n") -file( APPEND ${JLRUN} "export LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib\n") -file( APPEND ${JLRUN} "export JULIA_PROJECT=${BRUTUS_SOURCE_DIR}/Brutus\n") -file( APPEND ${JLRUN} "${Julia_EXECUTABLE}\n") -execute_process( COMMAND chmod +x ${JLRUN}) - - -set(FISHENV "${CMAKE_BINARY_DIR}/env.fish") -file( WRITE ${FISHENV} "set -x -g LD_LIBRARY_PATH ${CMAKE_BINARY_DIR}/lib\n") -file( APPEND ${FISHENV} "set -x -g JULIA_PROJECT ${BRUTUS_SOURCE_DIR}/Brutus\n") -file( APPEND ${FISHENV} "alias julia='${Julia_EXECUTABLE}'\n") diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..a5ea13e --- /dev/null +++ b/Project.toml @@ -0,0 +1,6 @@ +[deps] +CMake_jll = "3f4e10e2-61f2-5801-8945-23b9d642d0e6" +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +Preferences = "21216c6a-2e73-6563-6e65-726566657250" +Scratch = "6c6a2e73-6563-6170-7368-637461726353" diff --git a/build_local.jl b/build_local.jl new file mode 100644 index 0000000..20a6a87 --- /dev/null +++ b/build_local.jl @@ -0,0 +1,91 @@ +# build a local version of brutus +using Pkg +Pkg.activate(@__DIR__) +Pkg.instantiate() + +if haskey(ENV, "GITHUB_ACTIONS") + println("::warning ::Using a locally-built brutus; A bump of brutus_jll will be required before releasing Brutus.jl.") +end + +using Pkg, Scratch, Preferences, Libdl, CMake_jll + +Brutus = Base.UUID("44ccd279-0a44-4492-af09-0e34b2907bcc") + +# get scratch directories +scratch_dir = get_scratch!(Brutus, "build") +isdir(scratch_dir) && rm(scratch_dir; recursive=true) +source_dir = @__DIR__ + +# get build directory +build_dir = if isempty(ARGS) + mktempdir() +else + ARGS[1] +end +mkpath(build_dir) + +# download LLVM +Pkg.activate(; temp=true) +llvm_assertions = try + cglobal((:_ZN4llvm24DisableABIBreakingChecksE, Base.libllvm_path()), Cvoid) + false +catch + true +end +llvm_pkg_version = "$(Base.libllvm_version.major).$(Base.libllvm_version.minor)" +LLVM = if llvm_assertions + Pkg.add(name="LLVM_full_assert_jll", version=llvm_pkg_version) + using LLVM_full_assert_jll + LLVM_full_assert_jll +else + Pkg.add(name="LLVM_full_jll", version=llvm_pkg_version) + using LLVM_full_jll + LLVM_full_jll +end +Pkg.add(name="mlir_jl_tblgen_jll") + +LLVM_DIR = joinpath(LLVM.artifact_dir, "lib", "cmake", "llvm") +MLIR_DIR = joinpath(LLVM.artifact_dir, "lib", "cmake", "mlir") + +# build and install +julia = joinpath(Sys.BINDIR, Base.julia_exename()) +@info "Building" source_dir scratch_dir build_dir LLVM_DIR MLIR_DIR julia +cmake() do cmake_path + config_opts = `-DLLVM_ROOT=$(LLVM_DIR) -DMLIR_ROOT=$(MLIR_DIR) -DCMAKE_INSTALL_PREFIX=$(scratch_dir) -DJulia_EXECUTABLE=$julia` + if Sys.iswindows() + # prevent picking up MSVC + config_opts = `$config_opts -G "MSYS Makefiles"` + end + run(`$cmake_path $config_opts -B$(build_dir) -S$(source_dir)`) + run(`$cmake_path --build $(build_dir) --target install`) +end + +# discover built binaries +built_libs = filter(readdir(joinpath(scratch_dir, "lib"))) do file + endswith(file, "brutus.$(Libdl.dlext)") +end + +libbrutus_path = joinpath(scratch_dir, "lib", only(built_libs)) +isfile(libbrutus_path) || error("Could not find library $libbrutus_path in build directory") + +built_libs = filter(readdir(joinpath(scratch_dir, "lib"))) do file + endswith(file, "brutus-c.$(Libdl.dlext)") +end + +libbrutus_c_path = joinpath(scratch_dir, "lib", only(built_libs)) +isfile(libbrutus_c_path) || error("Could not find library $libbrutus_c_path in build directory") + +# tell Brutus.jl to load our library instead of the default artifact one +set_preferences!( + joinpath(@__DIR__, "Brutus", "LocalPreferences.toml"), + "Brutus", + "libbrutus" => libbrutus_path, + "libbrutus_c" => libbrutus_c_path; + force=true, +) + +include_dir = joinpath(LLVM.artifact_dir, "include") +output = joinpath(@__DIR__, "Brutus", "src", "Dialects", string(Base.libllvm_version.major), "JuliaOps.jl") +mkpath(dirname(output)) +using mlir_jl_tblgen_jll +run(`$(mlir_jl_tblgen()) --generator=jl-op-defs include/brutus/Dialect/Julia/JuliaOps.td -I $include_dir -o $output`) diff --git a/include/brutus-c/Dialects.h b/include/brutus-c/Dialects.h new file mode 100644 index 0000000..7553a5a --- /dev/null +++ b/include/brutus-c/Dialects.h @@ -0,0 +1,24 @@ +//===- Dialects.h - CAPI for dialects -----------------------------*- C -*-===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef BRUTUS_C_DIALECTS_H +#define BRUTUS_C_DIALECTS_H + +#include "mlir-c/IR.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(JLIR, jlir); + +#ifdef __cplusplus +} +#endif + +#endif // BRUTUS_C_DIALECTS_H \ No newline at end of file diff --git a/include/brutus/Conversion/JLIRToLLVM/JLIRToLLVM.h b/include/brutus/Conversion/JLIRToLLVM/JLIRToLLVM.h index 3f8c864..bbd016d 100644 --- a/include/brutus/Conversion/JLIRToLLVM/JLIRToLLVM.h +++ b/include/brutus/Conversion/JLIRToLLVM/JLIRToLLVM.h @@ -5,8 +5,8 @@ #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Conversion/LLVMCommon/TypeConverter.h" -#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" -#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h" +// #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" +// #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h" #include "mlir/Pass/Pass.h" namespace mlir { @@ -36,13 +36,13 @@ struct JLIRToLLVMTypeConverter : public LLVMTypeConverter { }; struct JLIRToLLVMLoweringPass - : public PassWrapper { + : public PassWrapper> { void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } - void runOnFunction() final; + void runOnOperation() final; }; /// Create a pass to convert JLIR operations to the LLVMIR dialect. diff --git a/include/brutus/Conversion/JLIRToStandard/JLIRToStandard.h b/include/brutus/Conversion/JLIRToStandard/JLIRToStandard.h index c18a47e..75fad62 100644 --- a/include/brutus/Conversion/JLIRToStandard/JLIRToStandard.h +++ b/include/brutus/Conversion/JLIRToStandard/JLIRToStandard.h @@ -21,7 +21,7 @@ struct JLIRToStandardTypeConverter : public TypeConverter { /// conversion patterns capture the LLVMTypeConverter and the LowerToLLVMOptions /// by reference meaning the references have to remain alive during the entire /// pattern lifetime. -void populateJLIRToStdConversionPatterns(OwningRewritePatternList &patterns, +void populateJLIRToStdConversionPatterns(RewritePatternSet &patterns, MLIRContext &context, JLIRToStandardTypeConverter &converter); diff --git a/include/brutus/Dialect/Julia/JuliaDialect.h b/include/brutus/Dialect/Julia/JuliaDialect.h new file mode 100644 index 0000000..69e1330 --- /dev/null +++ b/include/brutus/Dialect/Julia/JuliaDialect.h @@ -0,0 +1,8 @@ +#ifndef BRUTUS_JULIADIALECT_H +#define BRUTUS_JULIADIALECT_H + +#include "mlir/IR/Dialect.h" + +#include "brutus/Dialect/Julia/JuliaOpsDialect.h.inc" + +#endif // BRUTUS_JULIADIALECT_H diff --git a/include/brutus/Dialect/Julia/JuliaDialect.td b/include/brutus/Dialect/Julia/JuliaDialect.td new file mode 100644 index 0000000..df541ad --- /dev/null +++ b/include/brutus/Dialect/Julia/JuliaDialect.td @@ -0,0 +1,62 @@ +#ifndef JULIA_DIALECT +#define JULIA_DIALECT + +include "mlir/IR/OpBase.td" +include "mlir/Interfaces/InferTypeOpInterface.td" +include "mlir/Interfaces/SideEffectInterfaces.td" + +def JLIR_Dialect : Dialect { + let name = "jlir"; + let summary = ""; + let description = [{ + }]; + let cppNamespace = "::mlir::jlir"; + + let emitAccessorPrefix = kEmitAccessorPrefix_Prefixed; +} + +//===----------------------------------------------------------------------===// +// Dialect types // +//===----------------------------------------------------------------------===// + + +def JLIR_JuliaType : DialectType()">, "JLIR Julia type">; + +def JLIR_JuliaValueAttr : Attr()">, + "JLIR Julia Value attribute"> { + let storageType = [{ JuliaValueAttr }]; + let returnType = [{ jl_value_t * }]; +} + + +// Base class for JLIR dialect operations. This operation inherits from the base +// `Op` class in OpBase.td, and provides: +// * The parent dialect of the operation. +// * The mnemonic for the operation, or the name without the dialect prefix. +// * A list of traits for the operation. +class JLIR_Op traits = []> : + Op; + +// Base clase for JLIR intrinsics +class JLIR_IntrinsicBuiltinOp traits = []> : + JLIR_Op { + + let arguments = (ins Variadic:$arguments); + let results = (outs JLIR_JuliaType); +} + +class JLIR_ArithmeticOp traits = []>: + JLIR_IntrinsicBuiltinOp { + + let arguments = (ins JLIR_JuliaType:$rhs, JLIR_JuliaType:$lhs); + let results = (outs JLIR_JuliaType); +} + +class JLIR_UnaryArithmeticOp traits = []>: + JLIR_IntrinsicBuiltinOp { + + let arguments = (ins JLIR_JuliaType:$arg); + let results = (outs JLIR_JuliaType); +} + +#endif // STANDALONE_DIALECT diff --git a/include/brutus/Dialect/Julia/JuliaOps.h b/include/brutus/Dialect/Julia/JuliaOps.h index fa52ea1..2111f5e 100644 --- a/include/brutus/Dialect/Julia/JuliaOps.h +++ b/include/brutus/Dialect/Julia/JuliaOps.h @@ -5,41 +5,45 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/Interfaces/SideEffectInterfaces.h" +#include "mlir/Interfaces/InferTypeOpInterface.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" + #include "julia.h" #include "brutus/brutus_internal.h" +#include "brutus/Dialect/Julia/JuliaDialect.h" namespace mlir { namespace jlir { -/// This is the definition of the Julia dialect. A dialect inherits from -/// mlir::Dialect and registers custom attributes, operations, and types (in its -/// constructor). It can also override some general behavior exposed via virtual -/// methods. -class JLIRDialect : public mlir::Dialect { -public: - explicit JLIRDialect(mlir::MLIRContext *ctx); +// /// This is the definition of the Julia dialect. A dialect inherits from +// /// mlir::Dialect and registers custom attributes, operations, and types (in its +// /// constructor). It can also override some general behavior exposed via virtual +// /// methods. +// class JLIRDialect : public mlir::Dialect { +// public: +// explicit JLIRDialect(mlir::MLIRContext *ctx); - // /// A hook used to materialize constant values with the given type. - // Operation *materializeConstant(OpBuilder &builder, Attribute value, Type type, - // Location loc) override; +// // /// A hook used to materialize constant values with the given type. +// // Operation *materializeConstant(OpBuilder &builder, Attribute value, Type type, +// // Location loc) override; - // /// Parse an instance of a type registered to the toy dialect. - // mlir::Type parseType(mlir::DialectAsmParser &parser) const override; +// // /// Parse an instance of a type registered to the toy dialect. +// // mlir::Type parseType(mlir::DialectAsmParser &parser) const override; - /// Print an instance of a type registered to the toy dialect. - void printType(mlir::Type type, - mlir::DialectAsmPrinter &printer) const override; +// /// Print an instance of a type registered to the toy dialect. +// void printType(mlir::Type type, +// mlir::DialectAsmPrinter &printer) const override; - void printAttribute(mlir::Attribute attr, - mlir::DialectAsmPrinter &printer) const override; +// void printAttribute(mlir::Attribute attr, +// mlir::DialectAsmPrinter &printer) const override; - /// Provide a utility accessor to the dialect namespace. This is used by - /// several utilities for casting between dialects. - static llvm::StringRef getDialectNamespace() { return "jlir"; } +// /// Provide a utility accessor to the dialect namespace. This is used by +// /// several utilities for casting between dialects. +// static llvm::StringRef getDialectNamespace() { return "jlir"; } - static std::string showValue(jl_value_t *value); -}; +// static std::string showValue(jl_value_t *value); +// }; /// JLIR Types diff --git a/include/brutus/Dialect/Julia/JuliaOps.td b/include/brutus/Dialect/Julia/JuliaOps.td index b58bc54..1a1351a 100644 --- a/include/brutus/Dialect/Julia/JuliaOps.td +++ b/include/brutus/Dialect/Julia/JuliaOps.td @@ -7,61 +7,10 @@ #ifndef JULIA_MLIR_JLIR_TD #define JULIA_MLIR_JLIR_TD -include "mlir/IR/OpBase.td" -include "mlir/Interfaces/SideEffectInterfaces.td" - -// Provide a definition of the 'JLIR' dialect in the ODS framework so that we -// can define our operations. -def JLIR_Dialect : Dialect { - let name = "jlir"; - let cppNamespace = "::mlir::jlir"; -} - -//===----------------------------------------------------------------------===// -// Dialect types // -//===----------------------------------------------------------------------===// - - -def JLIR_JuliaType : DialectType()">, "JLIR Julia type">; - -def JLIR_JuliaValueAttr : Attr()">, - "JLIR Julia Value attribute"> { - let storageType = [{ JuliaValueAttr }]; - let returnType = [{ jl_value_t * }]; -} +include "brutus/Dialect/Julia/JuliaDialect.td" def JLIR_IsJLArrayTypePred : CPred<"jl_is_array_type($_self.cast().getDatatype())">; -// Base class for JLIR dialect operations. This operation inherits from the base -// `Op` class in OpBase.td, and provides: -// * The parent dialect of the operation. -// * The mnemonic for the operation, or the name without the dialect prefix. -// * A list of traits for the operation. -class JLIR_Op traits = []> : - Op; - -// Base clase for JLIR intrinsics -class JLIR_IntrinsicBuiltinOp traits = []> : - JLIR_Op { - - let arguments = (ins Variadic:$arguments); - let results = (outs JLIR_JuliaType); -} - -class JLIR_ArithmeticOp traits = []>: - JLIR_IntrinsicBuiltinOp { - - let arguments = (ins JLIR_JuliaType:$rhs, JLIR_JuliaType:$lhs); - let results = (outs JLIR_JuliaType); -} - -class JLIR_UnaryArithmeticOp traits = []>: - JLIR_IntrinsicBuiltinOp { - - let arguments = (ins JLIR_JuliaType:$arg); - let results = (outs JLIR_JuliaType); -} - //===----------------------------------------------------------------------===// // JLIR Operations //===----------------------------------------------------------------------===// @@ -140,11 +89,11 @@ def InvokeOp : JLIR_Op<"invoke"> { let arguments = (ins JLIR_JuliaValueAttr:$methodInstance, JLIR_JuliaType:$callee, Variadic:$arguments); - + let results = (outs JLIR_JuliaType); - + let builders = [ - OpBuilder<(ins "jl_method_instance_t *":$methodInstance, + OpBuilder<(ins "jl_method_instance_t *":$methodInstance, "Value":$callee, "ArrayRef":$arguments, "jl_datatype_t *":$type)> @@ -174,15 +123,15 @@ def GotoIfNotOp : JLIR_Op<"gotoifnot", [AttrSizedOperandSegments, Terminator]> { let arguments = (ins JLIR_JuliaType:$condition, Variadic:$branchOperands, Variadic:$fallthroughOperands); - - let successors = (successor AnySuccessor:$branchDest, + + let successors = (successor AnySuccessor:$branchDest, AnySuccessor:$fallthroughDest); let builders = [ OpBuilder<(ins "Value":$condition, - "Block *":$branchDest, + "Block *":$branchDest, "ValueRange":$branchOperands, - "Block *":$fallthroughDest, + "Block *":$fallthroughDest, "ValueRange":$fallthroughOperands), [{ build($_builder, $_state, condition, @@ -192,7 +141,7 @@ def GotoIfNotOp : JLIR_Op<"gotoifnot", [AttrSizedOperandSegments, Terminator]> { ]; } -def ReturnOp : JLIR_Op<"return", [Terminator, HasParent<"FuncOp">]> { +def ReturnOp : JLIR_Op<"return", [Terminator, HasParent<"func::FuncOp">]> { let summary = "return operation"; let description = [{ The "return" operation represents a return operation within a function. @@ -212,7 +161,7 @@ def ReturnOp : JLIR_Op<"return", [Terminator, HasParent<"FuncOp">]> { let arguments = (ins JLIR_JuliaType:$input); // Invoke a static verify method to verify this return operation. - let verifier = [{ return ::verify(*this); }]; + // let verifier = [{ return ::verify(*this); }]; } def PiOp : JLIR_Op<"pi", [NoSideEffect]> { diff --git a/include/brutus/brutus.h b/include/brutus/brutus.h index 2b45b00..3dbfbbf 100644 --- a/include/brutus/brutus.h +++ b/include/brutus/brutus.h @@ -17,7 +17,7 @@ #include "mlir/Pass/PassManager.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/Passes.h" -#include "mlir/Dialect/StandardOps/IR/Ops.h" +// #include "mlir/Dialect/StandardOps/IR/Ops.h" #ifdef __cplusplus extern "C" diff --git a/lib/CAPI/CMakeLists.txt b/lib/CAPI/CMakeLists.txt new file mode 100644 index 0000000..d65881f --- /dev/null +++ b/lib/CAPI/CMakeLists.txt @@ -0,0 +1,25 @@ +add_mlir_public_c_api_library(BRUTUSCAPI + Dialects.cpp + LINK_LIBS PUBLIC + MLIRJulia +) + +add_mlir_aggregate( + brutus-c + SHARED + EMBED_LIBS + BRUTUSCAPI + PUBLIC_LIBS + ${Julia_LIBRARY} + ${Julia_Internal_LIBRARY} +) + +install(TARGETS brutus-c DESTINATION lib) + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_options(brutus-c PRIVATE "-Wl,-exclude-libs,ALL") +else() + if(NOT CMAKE_C_VISIBILITY_PRESET STREQUAL "hidden" OR NOT CMAKE_CXX_VISIBILITY_PRESET STREQUAL "hidden") + message(STATUS "brutus-c on this platform exports all symbols. Recommend building with CMAKE_(C|CXX)_VISIBILITY_PRESET=hidden or implement filtering support.") + endif() +endif() diff --git a/lib/CAPI/Dialects.cpp b/lib/CAPI/Dialects.cpp new file mode 100644 index 0000000..c045e08 --- /dev/null +++ b/lib/CAPI/Dialects.cpp @@ -0,0 +1,16 @@ + +//===- Dialects.cpp - CAPI for dialects -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "brutus-c/Dialects.h" + +#include "brutus/Dialect/Julia/JuliaOps.h" +#include "mlir/CAPI/Registration.h" + +MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(JLIR, jlir, + mlir::jlir::JLIRDialect) \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 072ceb2..2b486b4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Codegen) -add_subdirectory(Conversion) +# add_subdirectory(Conversion) add_subdirectory(Dialect) +add_subdirectory(CAPI) diff --git a/lib/Codegen/Brutus.cpp b/lib/Codegen/Brutus.cpp index c1f92ad..1969105 100644 --- a/lib/Codegen/Brutus.cpp +++ b/lib/Codegen/Brutus.cpp @@ -1,6 +1,7 @@ #include "brutus/brutus.h" #include "brutus/brutus_internal.h" #include "brutus/Dialect/Julia/JuliaOps.h" +#include "brutus/Dialect/Julia/JuliaDialect.h" #include "mlir/InitAllDialects.h" diff --git a/lib/Codegen/CMakeLists.txt b/lib/Codegen/CMakeLists.txt index 9793ee3..0d14278 100644 --- a/lib/Codegen/CMakeLists.txt +++ b/lib/Codegen/CMakeLists.txt @@ -1,23 +1,25 @@ add_mlir_library( BRUTUSCodegen Brutus.cpp - Codegen.cpp ADDITIONAL_HEADER_DIRS ${BRUTUS_INCLUDE_DIR}/JuliaOps + DEPENDS + MLIRJuliaOpsIncGen + LINK_LIBS PUBLIC MLIR - MLIRCAPIDebug - MLIRCAPIIR - MLIRCAPIRegistration # TODO: See about dis-aggregating + # MLIRCAPIDebug + # MLIRCAPIIR + # MLIRCAPIRegistration # TODO: See about dis-aggregating # Dialects - MLIRCAPILinalg # TODO: Remove when above is removed. - MLIRCAPISparseTensor # TODO: Remove when above is removed. - MLIRCAPIStandard - MLIRExecutionEngine - MLIRTargetLLVMIRExport + # MLIRCAPILinalg # TODO: Remove when above is removed. + # MLIRCAPISparseTensor # TODO: Remove when above is removed. + # MLIRCAPIStandard + # MLIRExecutionEngine + # MLIRTargetLLVMIRExport ) llvm_update_compile_flags(BRUTUSCodegen) diff --git a/lib/Codegen/Codegen.cpp b/lib/Codegen/Codegen.cpp deleted file mode 100644 index f08f756..0000000 --- a/lib/Codegen/Codegen.cpp +++ /dev/null @@ -1,696 +0,0 @@ - -#include "brutus/brutus.h" -#include "brutus/brutus_internal.h" -#include "brutus/Dialect/Julia/JuliaOps.h" -#include "brutus/Conversion/JLIRToLLVM/JLIRToLLVM.h" -#include "brutus/Conversion/JLIRToStandard/JLIRToStandard.h" - -#include "julia.h" - -#include "mlir/IR/Verifier.h" -#include "mlir/ExecutionEngine/ExecutionEngine.h" -#include "mlir/ExecutionEngine/OptUtils.h" -#include "mlir/IR/Attributes.h" -#include "mlir/IR/Builders.h" -#include "mlir/IR/MLIRContext.h" -#include "mlir/Pass/PassManager.h" -#include "mlir/Pass/Pass.h" -#include "mlir/Transforms/Passes.h" -#include "mlir/Target/LLVMIR/Export.h" -#include "mlir-c/IR.h" -#include "mlir/CAPI/Wrap.h" -#include "mlir/CAPI/IR.h" - -#include "mlir/Dialect/StandardOps/IR/Ops.h" -#include "mlir/Dialect/Linalg/IR/LinalgOps.h" - -using namespace mlir; -using namespace mlir::jlir; - -class jl_mlirctx_t -{ - public: - OpBuilder builder; - MLIRContext *context; - std::vector values; - std::vector arguments; - - jl_mlirctx_t(MLIRContext *context) - : builder(context), context(context) {} -}; - -std::string mi_name(jl_method_instance_t *mi) -{ - ios_t str_; - ios_mem(&str_, 10000); - JL_STREAM *str = (JL_STREAM *)&str_; - - // jl_printf(str, "%s.", jl_symbol_name(mi->def.method->module->name)); - // // doesn't work well with call overloading - // jl_static_show_func_sig(str, mi->specTypes); - jl_static_show(str, mi->specTypes); - str_.buf[str_.size] = '\0'; - - std::string s(str_.buf); - ios_close(&str_); - - return s; -} - -mlir::Value maybe_widen_type(jl_mlirctx_t &ctx, mlir::Location loc, - mlir::Value value, jl_datatype_t *expected_type) -{ - // widen the type of the value with a PiOp if its type is a subtype of the - // expected type - jl_value_t *value_type = - (jl_value_t *)value.getType().cast().getDatatype(); - if (!jl_egal(value_type, (jl_value_t *)expected_type) && jl_subtype(value_type, (jl_value_t *)expected_type)) - { - auto op = ctx.builder.create(loc, value, expected_type); - return op.getResult(); - } - - // value was already of expected type, or its type is not a subtype of what - // was expected and cannot be widened (so detect this mismatch later) - return value; -} - -mlir::Value emit_value(jl_mlirctx_t &ctx, mlir::Location loc, - jl_value_t *value, jl_datatype_t *type = nullptr) -{ - // check if we have a const globalref - if (jl_is_globalref(value)) - { - jl_sym_t *s = jl_globalref_name(value); - jl_binding_t *b = jl_get_binding(jl_globalref_mod(value), s); - if (b && b->constp) - { - // if (b->deprecated) - // FIXME: Deprecation warning - value = b->value; - } - } - - // Not to be confused with a raw symbol... - // that would mean a global variable - if (jl_is_quotenode(value)) - { - value = jl_fieldref_noalloc(value, 0); - } - - if (type == nullptr) - type = (jl_datatype_t *)jl_typeof(value); - - if (jl_is_ssavalue(value)) - { - ssize_t idx = ((jl_ssavalue_t *)value)->id - 1; - assert(idx >= 0); - return ctx.values[idx]; - } - else if (jl_isa(value, argument_type)) - { - // FIXME: this is unsafe and stupid, but they do have the same layout - // first argument is function itself, can be needed with call overloading - // and closures - ssize_t idx = ((jl_ssavalue_t *)value)->id - 1; - assert(idx >= 0); - return (mlir::Value)ctx.arguments[idx]; - } - else if (jl_is_globalref(value)) - { - // FIXME: Non-const globalref - auto op = ctx.builder.create(loc, type); - return op.getResult(); - } - else - { - auto op = ctx.builder.create(loc, value, type); - return op.getResult(); - } -} - -mlir::Value emit_expr(jl_mlirctx_t &ctx, Location &loc, jl_expr_t *expr, jl_datatype_t *type) -{ - jl_sym_t *head = expr->head; - size_t nargs = jl_array_dim0(expr->args); - jl_value_t **args = (jl_value_t **)jl_array_data(expr->args); - - // from codegen.cpp: - // if (head == isdefined_sym) { - // } else if (head == throw_undef_if_not_sym) { - // } else if (head == invoke_sym) { - // } else if (head == call_sym) { - // } else if (head == foreigncall_sym) { - // } else if (head == cfunction_sym) { - // } else if (head == assign_sym) { - // } else if (head == static_parameter_sym) { - // } else if (head == method_sym) { - // } else if (head == const_sym) { - // } else if (head == new_sym) { - // } else if (head == splatnew_sym) { - // } else if (head == exc_sym) { - // } else if (head == copyast_sym) { - // } else if (head == loopinfo_sym) { - // } else if (head == goto_ifnot_sym || head == leave_sym || head == coverageeffect_sym - // || head == pop_exception_sym || head == enter_sym || head == inbounds_sym - // || head == aliasscope_sym || head == popaliasscope_sym) { - // } else if (head == boundscheck_sym) { - // } else if (head == gc_preserve_begin_sym) { - // } else if (head == gc_preserve_end_sym) { - // } - - if (head == invoke_sym) - { - // first argument is the `MethodInstance`, second argument is the function - assert(jl_is_method_instance(args[0])); - jl_method_instance_t *mi = (jl_method_instance_t *)args[0]; - mlir::Value callee = emit_value(ctx, loc, args[1]); - - // arguments to the `MethodInstance` start from the 3rd argument - std::vector arguments; - for (unsigned i = 2; i < nargs; ++i) - { - arguments.push_back(emit_value(ctx, loc, args[i])); - } - InvokeOp op = ctx.builder.create(loc, mi, callee, arguments, type); - return op.getResult(); - } - else if (head == call_sym) - { - mlir::Value callee = emit_value(ctx, loc, args[0]); - std::vector arguments; - for (unsigned i = 1; i < nargs; ++i) - { - arguments.push_back(emit_value(ctx, loc, args[i])); - } - auto op = ctx.builder.create(loc, callee, arguments, type); - return op.getResult(); - } - else - { - auto op = ctx.builder.create( - loc, type); - return op.getResult(); - } -} - -void handleLLVMError(llvm::Error error) -{ - llvm::handleAllErrors(std::move(error), - [](const llvm::ErrorInfoBase &info) { - llvm::errs() << "error: "; - info.log(llvm::errs()); - llvm::errs() << "\n"; - }); -} - -mlir::FunctionType emit_ftype(jl_mlirctx_t &ctx, - jl_value_t *ir_code, - jl_value_t *ret_type) -{ - - jl_array_t *argtypes = (jl_array_t *)jl_get_field(ir_code, "argtypes"); - size_t nargs = jl_array_dim0(argtypes); - // FIXME: Handle varargs - std::vector args; - // First argument is the function, can be needed with call overloading and closures - for (int i = 0; i < (int)nargs; i++) - { - // this assumes that we have `jl_datatype_t`s! - args.push_back( - JuliaType::get(ctx.context, (jl_datatype_t *)jl_arrayref(argtypes, i))); - } - mlir::Type ret = (mlir::Type)JuliaType::get(ctx.context, (jl_datatype_t *)ret_type); - return ctx.builder.getFunctionType(args, llvm::makeArrayRef(ret)); -} - -mlir::FuncOp emit_function(jl_mlirctx_t &ctx, - jl_value_t *ir_code, - mlir::FunctionType ftype, - mlir::Type ret, - jl_value_t *ret_type, - std::string name) -{ - jl_value_t *irstream = jl_get_field(ir_code, "stmts"); - - // 1. Setup debug-information - std::vector locations; - // `location_indices` is used to convert statement index to location index - jl_array_t *location_indices = (jl_array_t *)jl_get_field(irstream, "line"); - { - jl_array_t *linetable = (jl_array_t *)jl_get_field(ir_code, "linetable"); - size_t nlocs = jl_array_len(linetable); - for (size_t i = 0; i < nlocs; i++) - { - // LineInfoNode(mod::Module, method::Any, file::Symbol, line::Int, inlined_at::Int) - jl_value_t *locinfo = jl_array_ptr_ref(linetable, i); - assert(jl_typeis(locinfo, jl_lineinfonode_type)); - jl_value_t *method = jl_fieldref_noalloc(locinfo, 1); - jl_sym_t *filesym = (jl_sym_t *)jl_fieldref_noalloc(locinfo, 2); - size_t line = jl_unbox_long(jl_fieldref(locinfo, 3)); - size_t inlined_at = jl_unbox_long(jl_fieldref(locinfo, 4)); - - if (jl_is_method_instance(method)) - method = ((jl_method_instance_t *)method)->def.value; - llvm::StringRef file = jl_symbol_name(filesym); - - if (file.empty()) - file = ""; - llvm::StringRef fname; - if (jl_is_method(method)) - method = (jl_value_t *)((jl_method_t *)method)->name; - if (jl_is_symbol(method)) - fname = jl_symbol_name((jl_sym_t *)method); - if (fname.empty()) - fname = "macro expansion"; - assert(inlined_at <= i); - mlir::Location current = mlir::NameLoc::get(mlir::Identifier::get(fname, ctx.context), - mlir::FileLineColLoc::get(ctx.context, file, line, 0)); - - // codegen.cpp uses a better heuristic for now just live with this - if (inlined_at > 0) - { - current = mlir::CallSiteLoc::get(current, locations[inlined_at - 1]); - } - locations.push_back(current); - } - } - - // Create actual function - mlir::FuncOp function = mlir::FuncOp::create(locations[0], name, ftype); - mlir::SymbolTable::setSymbolVisibility(function, mlir::SymbolTable::Visibility::Nested); - - // In MLIR the entry block of the function is special: it must have the same - // argument list as the function itself. - auto *entryBlock = function.addEntryBlock(); - ctx.builder.setInsertionPointToStart(entryBlock); - - // 3. Get the number of blocks from the CFG and prepare the labels - jl_value_t *cfg = jl_get_field(ir_code, "cfg"); - jl_array_t *cfg_blocks = (jl_array_t *)jl_get_field(cfg, "blocks"); - int nblocks = (int)jl_array_len(cfg_blocks); - - // Blocks will be 1-index based and block 0 will be the entry block - std::vector bbs(nblocks + 1); - bbs[0] = entryBlock; - for (int i = 1; i <= nblocks; i++) - { - bbs[i] = function.addBlock(); - } - - // 4. Setup conversion - jl_array_t *stmts = (jl_array_t *)jl_get_field(irstream, "inst"); - jl_array_t *types = (jl_array_t *)jl_get_field(irstream, "type"); - size_t nstmts = jl_array_dim0(stmts); - ctx.values.resize(nstmts); - std::copy(entryBlock->args_begin(), entryBlock->args_end(), std::back_inserter(ctx.arguments)); - - // Helper function to emit SSAValue, Arguments, GlobalRefs and Constants - // Helper function to convert PhiNodes into block arguments - // current_block and target are 1-indexed - auto emit_branchargs = [&](int current_block, int target, mlir::Location loc) { - llvm::SmallVector v; - - jl_value_t *range = jl_get_field(jl_arrayref(cfg_blocks, target - 1), "stmts"); - int start = jl_unbox_long(jl_get_field(range, "start")) - 1; - int stop = jl_unbox_long(jl_get_field(range, "stop")) - 1; - for (int i = start; start <= stop; ++i) - { - jl_value_t *stmt = jl_arrayref(stmts, i); - jl_datatype_t *type = (jl_datatype_t *)jl_arrayref(types, i); - if (jl_is_phinode(stmt)) - { - jl_array_t *edges = (jl_array_t *)jl_fieldref_noalloc(stmt, 0); - jl_array_t *values = (jl_array_t *)jl_fieldref_noalloc(stmt, 1); - - int nedges = (int)jl_array_len(edges); - bool found = false; - for (int edge = 0; edge < nedges; ++edge) - { - int frombb = jl_unbox_long(jl_arrayref(edges, edge)); // frombb is 1-indexed - if (frombb == current_block) - { - mlir::Value value = - emit_value(ctx, loc, jl_arrayref(values, edge)); - // if type of block argument is a subtype of the expected - // block argument type, use PiOp to widen the value - v.push_back(maybe_widen_type(ctx, loc, value, type)); - found = true; - } - } - if (!found) - { - // Julia allows undef PhiNode references to be dropped need to represent them here - auto op = ctx.builder.create( - loc, JuliaType::get(ctx.context, type)); - v.push_back(op.getResult()); - } - } - else - { - // PhiNodes are required to be at the beginning of the basic-blocks - // so as soon as we find a non-PhiNode we can stop our search. - break; - } - } - return v; - }; - - // Insert a goto node from the entry block to Julia's first block - int current_block = 1; - ctx.builder.create(mlir::UnknownLoc::get(ctx.context), bbs[current_block], emit_branchargs(0, current_block, locations[0])); - ctx.builder.setInsertionPointToStart(bbs[current_block]); - - // Process stmts in order - for (int i = 0; i < (int)nstmts; i++) - { - assert(current_block <= nblocks); - // XXX: what is jl_array_ptr_ref - jl_value_t *stmt = jl_arrayref(stmts, i); - jl_datatype_t *type = (jl_datatype_t *)jl_arrayref(types, i); - int linetable_index = jl_unbox_int32(jl_arrayref(location_indices, i)); // linetable_index is 1-indexed - mlir::Location loc = (linetable_index == 0) ? mlir::UnknownLoc::get(ctx.context) : locations[linetable_index - 1]; - - bool is_terminator = false; - - if (jl_isa(stmt, return_node_type)) - { - jl_value_t *ret_val = jl_get_field(stmt, "val"); - Value value; - if (ret_val) - { - // if type of return value is a subtype of expected return type, - // use PiOp to widen the value - value = maybe_widen_type( - ctx, loc, - emit_value(ctx, loc, ret_val), - (jl_datatype_t *)ret_type); - } - else - { - // unreachable terminator, so return undef - value = ctx.builder.create(loc, ret); - } - ctx.builder.create(loc, value); - is_terminator = true; - } - else if (jl_is_gotonode(stmt)) - { - int label = jl_gotonode_label(stmt); - assert(label <= nblocks); - ctx.builder.create(loc, bbs[label], emit_branchargs(current_block, label, loc)); - is_terminator = true; - } - else if (jl_isa(stmt, gotoifnot_type)) - { - mlir::Value cond = emit_value(ctx, loc, jl_get_field(stmt, "cond")); - int dest = jl_unbox_long(jl_get_field(stmt, "dest")); - assert(dest <= nblocks); - assert(current_block + 1 <= nblocks); - ctx.builder.create( - loc, cond, - bbs[dest], emit_branchargs(current_block, dest, loc), - bbs[current_block + 1], emit_branchargs(current_block, current_block + 1, loc)); // Implicit fallthrough - is_terminator = true; - } - else if (jl_is_phinode(stmt)) - { - // add argument slot to current_block - auto arg = bbs[current_block]->addArgument((mlir::Type)JuliaType::get(ctx.context, type)); - // add argument reference to values - ctx.values[i] = arg; - } - else if (jl_is_pinode(stmt)) - { - jl_value_t *val = jl_get_field(stmt, "val"); - assert(type == (jl_datatype_t *)jl_get_field(stmt, "typ")); - auto op = ctx.builder.create(loc, emit_value(ctx, loc, val), type); - ctx.values[i] = op.getResult(); - } - else if (jl_is_nothing(stmt)) - { - // ignore dead code - } - else if (jl_is_expr(stmt)) - { - ctx.values[i] = emit_expr(ctx, loc, (jl_expr_t *)stmt, type); - } - else - { - ctx.values[i] = emit_value(ctx, loc, stmt, type); - } - - // handle implicit fallthrough - if (!is_terminator) - { - jl_value_t *range = jl_get_field( - jl_arrayref(cfg_blocks, current_block - 1), "stmts"); - int stop = jl_unbox_long(jl_get_field(range, "stop")) - 1; - if (i == stop) - { - assert(current_block + 1 <= nblocks); - ctx.builder.create( - loc, bbs[current_block + 1], - emit_branchargs(current_block, current_block + 1, loc)); - is_terminator = true; - } - } - - if (is_terminator) - { - current_block += 1; - if (current_block <= nblocks) - ctx.builder.setInsertionPointToStart(bbs[current_block]); - } - } - return function; -} - -extern "C" -{ - - enum DumpOption - { - // DUMP_IRCODE = 0, - DUMP_TRANSLATED = 1, - DUMP_CANONICALIZED = 2, - DUMP_LOWERED_TO_STD = 4, - DUMP_LOWERED_TO_LLVM = 8, - DUMP_TRANSLATE_TO_LLVM = 16, - }; - - // TODO: enum with ERROR codes for failures. - void brutus_codegen_jlir(MlirContext Context, - MlirModule Module, - jl_value_t *methods, - jl_method_instance_t *entry_mi, - char dump_flags) - { - mlir::MLIRContext *context = unwrap(Context); - mlir::ModuleOp module = unwrap(Module); - - jl_mlirctx_t ctx(context); - - context->getOrLoadDialect(); - context->getOrLoadDialect(); - context->getOrLoadDialect(); - - jl_value_t *entry = jl_call2(getindex_func, methods, (jl_value_t *)entry_mi); - jl_value_t *ir_code = jl_fieldref(entry, 0); - jl_value_t *ret_type = jl_fieldref(entry, 1); - - // 2. Function prototype - mlir::FunctionType ftype = emit_ftype(ctx, ir_code, ret_type); - // TODO: Fixup singular return - mlir::Type ret = ftype.getResult(0); - - // 3. Emit function - std::string name = mi_name(entry_mi); - mlir::FuncOp function = emit_function(ctx, ir_code, ftype, ret, ret_type, name); - module.push_back(function); - function->setAttr("llvm.emit_c_interface", UnitAttr::get(ctx.context)); - if (failed(mlir::verify(module))) - { - module->emitError("module verification failed"); - } - } - - // canonicalize - void brutus_canonicalize(MlirContext Context, - MlirModule Module, - char dump_flags) - { - mlir::MLIRContext *context = unwrap(Context); - mlir::ModuleOp module = unwrap(Module); - - mlir::PassManager canonicalizePM(context); - // Apply any generic pass manager command line options and run the - // pipeline. - // FIXME: The next line currently seqfaults - // applyPassManagerCLOptions(canonicalizePM); - mlir::OpPassManager &canonicalizeOpPM = canonicalizePM.nest(); - canonicalizeOpPM.addPass(mlir::createCanonicalizerPass()); - canonicalizeOpPM.addPass(mlir::createCSEPass()); - LogicalResult canonicalizeResult = canonicalizePM.run(module); - ; - - if (mlir::failed(canonicalizeResult)) - { - module->emitError("module canonicalization failed"); - } - } - - // lower to Standard dialect - void brutus_lower_to_standard(MlirContext Context, - MlirModule Module, - char dump_flags) - { - mlir::MLIRContext *context = unwrap(Context); - mlir::ModuleOp module = unwrap(Module); - - // llvm::DebugFlag = true; - mlir::PassManager loweringToStdPM(context); - loweringToStdPM.addPass(createJLIRToStandardLoweringPass()); - // canonicalize to remove redundant `ConvertStdOp`s - loweringToStdPM.addPass(mlir::createCanonicalizerPass()); - loweringToStdPM.addPass(mlir::createCSEPass()); - LogicalResult loweringToStdResult = loweringToStdPM.run(module); - if (mlir::failed(loweringToStdResult)) - { - module->emitError("lowering to Standard dialect failed"); - } - } - - // lower to LLVM dialect - void brutus_lower_to_llvm(MlirContext Context, - MlirModule Module, - char dump_flags) - { - mlir::MLIRContext *context = unwrap(Context); - mlir::ModuleOp module = unwrap(Module); - - mlir::PassManager loweringToLLVMPM(context); - mlir::OpPassManager &funcop_pm = loweringToLLVMPM.nest(); - funcop_pm.addPass(createJLIRToLLVMLoweringPass()); - loweringToLLVMPM.addPass(mlir::createCanonicalizerPass()); - loweringToLLVMPM.addPass(mlir::createCSEPass()); - LogicalResult loweringToLLVMResult = loweringToLLVMPM.run(module); - LogicalResult verifyResult = verify(module); - if (mlir::failed(loweringToLLVMResult)) - { - module->emitError("lowering to LLVM dialect failed"); - } - if (mlir::failed(verifyResult)) - { - module->emitError("module verification failed"); - } - } - - ExecutionEngineFPtrResult brutus_create_execution_engine(MlirContext Context, - MlirModule Module, - std::string name) - { - mlir::ModuleOp module = unwrap(Module); - - Optional jitCodeGenOptLevel = - llvm::CodeGenOpt::Aggressive; - - auto tmBuilderOrError = llvm::orc::JITTargetMachineBuilder::detectHost(); - if (!tmBuilderOrError) - { - llvm::errs() << "failed to create a JITTargetMachineBuilder for the host\n"; - return nullptr; - } - auto tmOrError = tmBuilderOrError->createTargetMachine(); - if (!tmOrError) - { - llvm::errs() << "failed to create a TargetMachine for the host\n"; - return nullptr; - } - - auto transformer = makeLLVMPassesTransformer(None, 3, tmOrError->get()); - auto expectedEngine = ExecutionEngine::create(module, nullptr, transformer, jitCodeGenOptLevel); - - if (!expectedEngine) - { - handleLLVMError(expectedEngine.takeError()); - return nullptr; - } - - std::string cabi_name = "ciface_" + name; - ExecutionEngine *engine = expectedEngine.get().release(); - auto expectedFPtr = engine->lookup(cabi_name); - if (!expectedFPtr) - { - handleLLVMError(expectedFPtr.takeError()); - return nullptr; - } - - return expectedFPtr.get(); - } - - ExecutionEngineFPtrResult brutus_codegen(jl_value_t *methods, jl_method_instance_t *entry_mi, char emit_fptr, char dump_flags) - { - MlirContext Context = mlirContextCreate(); - MlirModule Module = mlirModuleCreateEmpty(mlirLocationUnknownGet(Context)); - - brutus_codegen_jlir(Context, Module, methods, entry_mi, dump_flags); - if (dump_flags && DUMP_TRANSLATED) - { - mlir::ModuleOp module = unwrap(Module); - llvm::dbgs() << "after translating to MLIR in JLIR dialect:\n"; - module.dump(); - llvm::dbgs() << "\n\n"; - } - - brutus_canonicalize(Context, Module, dump_flags); - if (dump_flags & DUMP_CANONICALIZED) - { - mlir::ModuleOp module = unwrap(Module); - llvm::dbgs() << "after canonicalizing:\n"; - module.dump(); - llvm::dbgs() << "\n\n"; - } - - brutus_lower_to_standard(Context, Module, dump_flags); - if (dump_flags & DUMP_LOWERED_TO_STD) - { - mlir::ModuleOp module = unwrap(Module); - llvm::dbgs() << "after lowering to Standard dialect:\n"; - module.dump(); - llvm::dbgs() << "\n\n"; - } - - brutus_lower_to_llvm(Context, Module, dump_flags); - if (dump_flags & DUMP_LOWERED_TO_LLVM) - { - mlir::ModuleOp module = unwrap(Module); - llvm::dbgs() << "after lowering to LLVM dialect:\n"; - module.dump(); - llvm::dbgs() << "\n\n"; - } - if (dump_flags & DUMP_TRANSLATE_TO_LLVM) - { - mlir::ModuleOp module = unwrap(Module); - llvm::LLVMContext llvmContext; - auto Mod = mlir::translateModuleToLLVMIR(module, llvmContext, "JuliaModule"); - llvm::dbgs() << "after lowering to LLVM IR:\n"; - Mod->print(llvm::dbgs(), nullptr); - llvm::dbgs() << "\n\n"; - return nullptr; - } - - if (!emit_fptr) - { - return nullptr; - } - - std::string name = mi_name(entry_mi); - auto engine_ptr = brutus_create_execution_engine(Context, Module, name); - - mlirModuleDestroy(Module); - mlirContextDestroy(Context); - - return engine_ptr; - } -} diff --git a/lib/Conversion/JLIRToLLVM/JLIRToLLVM.cpp b/lib/Conversion/JLIRToLLVM/JLIRToLLVM.cpp index 4e0bbe4..ad0cd9f 100644 --- a/lib/Conversion/JLIRToLLVM/JLIRToLLVM.cpp +++ b/lib/Conversion/JLIRToLLVM/JLIRToLLVM.cpp @@ -152,6 +152,7 @@ namespace template struct OpAndTypeConversionPattern : OpConversionPattern { + using OpConversionPattern::OpConversionPattern; JLIRToLLVMTypeConverter &lowering; OpAndTypeConversionPattern(MLIRContext *ctx, @@ -261,16 +262,17 @@ namespace struct ToLLVMOpPattern : public OpAndTypeConversionPattern { using OpAndTypeConversionPattern::OpAndTypeConversionPattern; + using OpAdaptor = typename SourceOp::Adaptor; LogicalResult matchAndRewrite(SourceOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { static_assert( std::is_base_of, SourceOp>::value, "expected single result op"); rewriter.replaceOpWithNewOp( - op, this->lowering.convertType(op.getType()), operands); + op, this->lowering.convertType(op.getType()), adaptor.getOperands()); return success(); } }; @@ -279,14 +281,16 @@ namespace struct ToUnaryLLVMOpPattern : public OpAndTypeConversionPattern { using OpAndTypeConversionPattern::OpAndTypeConversionPattern; + using OpAdaptor = typename SourceOp::Adaptor; LogicalResult matchAndRewrite(SourceOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { static_assert( std::is_base_of, SourceOp>::value, "expected single result op"); + auto operands = adaptor.getOperands(); assert(operands.size() == 1 && "expected unary operation"); rewriter.replaceOpWithNewOp( op, this->lowering.convertType(op.getType()), operands.front()); @@ -298,14 +302,16 @@ namespace struct ToTernaryLLVMOpPattern : public OpAndTypeConversionPattern { using OpAndTypeConversionPattern::OpAndTypeConversionPattern; + using OpAdaptor = typename SourceOp::Adaptor; LogicalResult matchAndRewrite(SourceOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { static_assert( std::is_base_of, SourceOp>::value, "expected single result op"); + auto operands = adaptor.getOperands(); assert(operands.size() == 3 && "expected ternary operation"); rewriter.replaceOpWithNewOp( op, this->lowering.convertType(op.getType()), @@ -320,9 +326,10 @@ namespace struct ToUndefOpPattern : public OpAndTypeConversionPattern { using OpAndTypeConversionPattern::OpAndTypeConversionPattern; + using OpAdaptor = typename SourceOp::Adaptor; LogicalResult matchAndRewrite(SourceOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { static_assert( @@ -340,9 +347,10 @@ namespace LogicalResult matchAndRewrite(ConvertStdOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); // TODO: check that this conversion is valid rewriter.replaceOp(op, operands.front()); return success(); @@ -354,7 +362,7 @@ namespace using OpAndTypeConversionPattern::OpAndTypeConversionPattern; LogicalResult matchAndRewrite(ConstantOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { jl_value_t *value = op.value(); @@ -427,9 +435,10 @@ namespace using OpAndTypeConversionPattern::OpAndTypeConversionPattern; LogicalResult matchAndRewrite(GotoIfNotOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); assert(operands.size() >= 1); rewriter.replaceOpWithNewOp( op, operands, op.getSuccessors(), op->getAttrs()); @@ -442,9 +451,10 @@ namespace using OpAndTypeConversionPattern::OpAndTypeConversionPattern; LogicalResult matchAndRewrite(GotoOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); rewriter.replaceOpWithNewOp( op, operands, op.getSuccessor(), op->getAttrs()); return success(); @@ -456,9 +466,10 @@ namespace using OpAndTypeConversionPattern::OpAndTypeConversionPattern; LogicalResult matchAndRewrite(ReturnOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); rewriter.replaceOpWithNewOp(op, operands); return success(); } @@ -469,9 +480,10 @@ namespace using OpAndTypeConversionPattern::OpAndTypeConversionPattern; LogicalResult matchAndRewrite(Intrinsic_not_int op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); jl_datatype_t *operand_type = op.getOperand(0).getType().dyn_cast().getDatatype(); bool is_bool = operand_type == jl_bool_type; @@ -499,9 +511,10 @@ namespace using OpAndTypeConversionPattern::OpAndTypeConversionPattern; LogicalResult matchAndRewrite(Builtin_is op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); assert(operands.size() == 2); jl_value_t *jt1 = (jl_value_t *)op.getOperand(0).getType().cast().getDatatype(); jl_value_t *jt2 = (jl_value_t *)op.getOperand(1).getType().cast().getDatatype(); @@ -545,7 +558,7 @@ namespace // // f(x::Bool) = x ? nothing : 100 -void JLIRToLLVMLoweringPass::runOnFunction() +void JLIRToLLVMLoweringPass::runOnOperation() { RewritePatternSet patterns(&getContext()); @@ -679,11 +692,11 @@ void JLIRToLLVMLoweringPass::runOnFunction() // invoke_kwsorter? >(&getContext(), converter); - populateStdToLLVMConversionPatterns(converter, patterns); + // populateStdToLLVMConversionPatterns(converter, patterns); LLVMConversionTarget target(getContext()); if (failed(applyPartialConversion( - getFunction(), target, std::move(patterns)))) + getOperation(), target, std::move(patterns)))) signalPassFailure(); } diff --git a/lib/Conversion/JLIRToStandard/JLIRToStandard.cpp b/lib/Conversion/JLIRToStandard/JLIRToStandard.cpp index 756fda8..f4ca0b4 100644 --- a/lib/Conversion/JLIRToStandard/JLIRToStandard.cpp +++ b/lib/Conversion/JLIRToStandard/JLIRToStandard.cpp @@ -1,12 +1,13 @@ #include "brutus/Conversion/JLIRToStandard/JLIRToStandard.h" -#include "mlir/Dialect/StandardOps/IR/Ops.h" +// #include "mlir/Dialect/StandardOps/IR/Ops.h" +#include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" #include "mlir/Dialect/Math/IR/Math.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" #include "mlir/IR/AffineMap.h" #include "mlir/IR/Types.h" -#include "mlir/Dialect/StandardOps/Transforms/FuncConversions.h" +#include "mlir/Transforms/DialectConversion.h" #include "llvm/Support/FormatVariadic.h" @@ -120,8 +121,7 @@ struct JLIRToStdConversionPattern : OpConversionPattern { JLIRToStandardTypeConverter &lowering) : OpConversionPattern(lowering, ctx){} - Value - convertValue(ConversionPatternRewriter &rewriter, + Value convertValue(ConversionPatternRewriter &rewriter, Location location, Value value) const { @@ -156,7 +156,7 @@ struct JLIRToStdConversionPattern : OpConversionPattern { // an index, unlike most other uses, which involve a Julia type ConvertStdOp convertedIndex = rewriter.create( location, rewriter.getIndexType(), index); - SubIOp subOp = rewriter.create( + arith::SubIOp subOp = rewriter.create( location, rewriter.getIndexType(), convertedIndex.getResult(), @@ -168,10 +168,12 @@ struct JLIRToStdConversionPattern : OpConversionPattern { template struct ToStdOpPattern : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; + using OpAdaptor = typename SourceOp::Adaptor; LogicalResult matchAndRewrite(SourceOp op, - ArrayRef operands, - ConversionPatternRewriter &rewriter) const override { + OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); auto result = this->typeConverter->convertType(op.getType()); if (!result) return failure(); @@ -185,37 +187,38 @@ struct ToStdOpPattern : public JLIRToStdConversionPattern { template struct ToCmpOpPattern : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; + using OpAdaptor = typename SourceOp::Adaptor; LogicalResult matchAndRewrite(SourceOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { - - + auto operands = adaptor.getOperands(); rewriter.replaceOpWithNewOp(op, predicate, operands[0], operands[1]); return success(); } }; -template -struct ToCmpIOpPattern : public ToCmpOpPattern { - using ToCmpOpPattern::ToCmpOpPattern; +template +struct ToCmpIOpPattern : public ToCmpOpPattern { + using ToCmpOpPattern::ToCmpOpPattern; }; -template -struct ToCmpFOpPattern : public ToCmpOpPattern { - using ToCmpOpPattern::ToCmpOpPattern; +template +struct ToCmpFOpPattern : public ToCmpOpPattern { + using ToCmpOpPattern::ToCmpOpPattern; }; struct ConstantOpLowering : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; + LogicalResult matchAndRewrite(jlir::ConstantOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { JuliaType type = op.getType().cast(); jl_datatype_t *julia_type = type.getDatatype(); @@ -251,11 +254,11 @@ struct GotoOpLowering : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(GotoOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { - + rewriter.replaceOpWithNewOp( - op, op.getSuccessor(), operands); + op, op.getSuccessor(), adaptor.getOperands()); return success(); } }; @@ -264,15 +267,16 @@ struct GotoIfNotOpLowering : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(GotoIfNotOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); unsigned nBranchOperands = op.branchOperands().size(); unsigned nFallthroughOperands = op.fallthroughOperands().size(); assert(operands.size() == nBranchOperands + nFallthroughOperands + 1); Value cond = this->convertValue(rewriter, op.getLoc(), operands.front()); // TODO: Go from i8 to i1 - ValueRange branchOperands = operands.slice(1, nBranchOperands); + ValueRange branchOperands = operands.slice(1, nBranchOperands); ValueRange fallthroughOperands = operands.slice(1 + nBranchOperands, nFallthroughOperands); rewriter.replaceOpWithNewOp(op, cond, @@ -286,10 +290,10 @@ struct ReturnOpLowering : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(jlir::ReturnOp op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { - rewriter.replaceOpWithNewOp(op, operands); + rewriter.replaceOpWithNewOp(op, adaptor.getOperands()); return success(); } }; @@ -298,9 +302,10 @@ struct NotIntOpLowering : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(Intrinsic_not_int op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { - + + auto operands = adaptor.getOperands(); IntegerType type = operands.front().getType().cast(); mlir::ConstantOp maskConstantOp = @@ -311,7 +316,7 @@ struct NotIntOpLowering : public JLIRToStdConversionPattern { APInt(type.getWidth(), -1, /*isSigned=*/true))); - rewriter.replaceOpWithNewOp( + rewriter.replaceOpWithNewOp( op, type, operands.front(), maskConstantOp.getResult()); return success(); } @@ -321,8 +326,9 @@ struct IsOpLowering : public JLIRToStdConversionPattern { using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(Builtin_is op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); IntegerAttr falseAttr = rewriter.getIntegerAttr(rewriter.getI1Type(), 0); @@ -356,10 +362,11 @@ struct ArrayrefOpLowering : public JLIRToStdConversionPattern using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(Builtin_arrayref op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + auto operands = adaptor.getOperands(); Value memref = operands[1]; - + if (auto memrefType = memref.getType().dyn_cast()) { // indices are reversed because Julia is column-major, but MLIR is // row-major @@ -391,11 +398,13 @@ struct ArraysetOpLowering : public JLIRToStdConversionPattern using JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(Builtin_arrayset op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + + auto operands = adaptor.getOperands(); // arrayset(i1, Array, val, indices...) Value memref = operands[1]; - + if (auto memrefType = memref.getType().dyn_cast()) { // indices are reversed because Julia is column-major, but MLIR is // row-major @@ -427,13 +436,14 @@ struct ArraysizeOpLowering : public JLIRToStdConversionPattern::JLIRToStdConversionPattern; LogicalResult matchAndRewrite(Builtin_arraysize op, - ArrayRef operands, + OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { // TODO: Boundschecking // arraysize(array, ndim) + auto operands = adaptor.getOperands(); Value memref = operands[0]; - - if (auto memrefType = memref.getType().dyn_cast()) { + + if (auto memrefType = memref.getType().dyn_cast()) { // indices are reversed because Julia is column-major, but MLIR is // row-major auto rank = getIndexConstant(rewriter, op.getLoc(), memrefType.getRank()); @@ -441,7 +451,7 @@ struct ArraysizeOpLowering : public JLIRToStdConversionPattern(op.getLoc(), indexType, operands[1]); - SubIOp subOp = rewriter.create(op.getLoc(), indexType, rank, index); + arith::SubIOp subOp = rewriter.create(op.getLoc(), indexType, rank, index); rewriter.replaceOpWithNewOp(op, memref, subOp.getResult()); return success(); @@ -452,10 +462,10 @@ struct ArraysizeOpLowering : public JLIRToStdConversionPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, // Intrinsic_add_ptr // Intrinsic_sub_ptr - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, // Intrinsic_fma_float (JLIRToLLVM) // Intrinsic_muladd_float // Intrinsic_neg_float_fast @@ -491,38 +501,38 @@ void mlir::jlir::populateJLIRToStdConversionPatterns(RewritePatternSet &patterns // Intrinsic_mul_float_fast // Intrinsic_div_float_fast // Intrinsic_rem_float_fast - ToCmpIOpPattern, - ToCmpIOpPattern, - ToCmpIOpPattern, - ToCmpIOpPattern, - ToCmpIOpPattern, - ToCmpIOpPattern, - ToCmpFOpPattern, - ToCmpFOpPattern, - ToCmpFOpPattern, - ToCmpFOpPattern, + ToCmpIOpPattern, + ToCmpIOpPattern, + ToCmpIOpPattern, + ToCmpIOpPattern, + ToCmpIOpPattern, + ToCmpIOpPattern, + ToCmpFOpPattern, + ToCmpFOpPattern, + ToCmpFOpPattern, + ToCmpFOpPattern, // Intrinsic_fpiseq // Intrinsic_fpislt - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, NotIntOpLowering, // Intrinsic_not_int - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, // Intrinsic_bswap_int // Intrinsic_ctpop_int // Intrinsic_ctlz_int // Intrinsic_cttz_int - ToStdOpPattern, // TODO: args don't match - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, // TODO: args don't match + ToStdOpPattern, + ToStdOpPattern, // Intrinsic_fptoui // Intrinsic_fptosi // Intrinsic_uitofp - ToStdOpPattern, - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, // Intrinsic_checked_sadd_int // Intrinsic_checked_uadd_int // Intrinsic_checked_ssub_int @@ -533,10 +543,10 @@ void mlir::jlir::populateJLIRToStdConversionPatterns(RewritePatternSet &patterns // Intrinsic_checked_udiv_int // Intrinsic_checked_srem_int // Intrinsic_checked_urem_int - ToStdOpPattern, - ToStdOpPattern, + ToStdOpPattern, + ToStdOpPattern, // Intrinsic_flipsign_int - ToStdOpPattern, + ToStdOpPattern, // Intrinsic_floor_llvm // Intrinsic_trunc_llvm (JLIRToLLVM, but maybe could be here?) // Intrinsic_rint_llvm @@ -625,7 +635,7 @@ void JLIRToStandardLoweringPass::runOnOperation() { target.addDynamicallyLegalOp([&converter](FuncOp op) { return isFuncOpLegal(op, converter); }); - populateFuncOpTypeConversionPattern(patterns, converter); + mlir::populateFunctionOpInterfaceTypeConversionPattern(patterns, converter); if (failed(applyPartialConversion( module, target, std::move(patterns)))) diff --git a/lib/Dialect/Julia/CMakeLists.txt b/lib/Dialect/Julia/CMakeLists.txt index b939e82..31b0256 100644 --- a/lib/Dialect/Julia/CMakeLists.txt +++ b/lib/Dialect/Julia/CMakeLists.txt @@ -1,10 +1,8 @@ add_mlir_dialect_library( MLIRJulia + Dialect.cpp Ops.cpp CanonicalizationPatterns.cpp - ADDITIONAL_HEADER_DIRS - StandaloneDialect.cpp - StandaloneOps.cpp ADDITIONAL_HEADER_DIRS ${PROJECT_SOURCE_DIR}/include/Brutus/JuliaOps @@ -12,6 +10,7 @@ add_mlir_dialect_library( DEPENDS MLIRJuliaOpsIncGen MLIRSideEffectInterfaces + MLIRInferTypeOpInterface LINK_LIBS PUBLIC MLIR diff --git a/lib/Dialect/Julia/CanonicalizationPatterns.cpp b/lib/Dialect/Julia/CanonicalizationPatterns.cpp index 02a09b1..a46ecee 100644 --- a/lib/Dialect/Julia/CanonicalizationPatterns.cpp +++ b/lib/Dialect/Julia/CanonicalizationPatterns.cpp @@ -22,35 +22,35 @@ struct LowerIntrinsicCallPattern : public OpRewritePattern { using OpRewritePattern::OpRewritePattern; LogicalResult match(CallOp op) const override { - Value callee = op.callee(); - Operation *definingOp = callee.getDefiningOp(); - if (!definingOp) { - // Value is block-argument. - return failure(); - } - if (ConstantOp constant = dyn_cast(definingOp)) { - jl_value_t* value = constant.value(); - if (jl_typeis(value, jl_intrinsic_type)) { - return success(); - } - } + // Value callee = op.callee(); + // Operation *definingOp = callee.getDefiningOp(); + // if (!definingOp) { + // // Value is block-argument. + // return failure(); + // } + // if (ConstantOp constant = dyn_cast(definingOp)) { + // jl_value_t* value = constant.value(); + // if (jl_typeis(value, jl_intrinsic_type)) { + // return success(); + // } + // } return failure(); } void rewrite(CallOp op, PatternRewriter &rewriter) const override { - ConstantOp defining = dyn_cast(op.callee().getDefiningOp()); - JL_I::intrinsic f = (JL_I::intrinsic)*(uint32_t*)jl_data_ptr(defining.value()); - assert(f < JL_I::num_intrinsics); - StringRef name = "jlir." + std::string(jl_intrinsic_name(f)); - - // The IntrinsicOps are defined by their name, so we can lookup the name - // from Julia and construct a generic Operation based on an OperationState - OperationState state = OperationState(op.getLoc(), name); - state.addOperands(op.arguments()); - state.addTypes(op.getType()); - Operation *newOp = rewriter.createOperation(state); - // Replace the value of the old Op with the Result of the new op - rewriter.replaceOp(op, newOp->getResult(0)); + // ConstantOp defining = dyn_cast(op.callee().getDefiningOp()); + // JL_I::intrinsic f = (JL_I::intrinsic)*(uint32_t*)jl_data_ptr(defining.value()); + // assert(f < JL_I::num_intrinsics); + // StringRef name = "jlir." + std::string(jl_intrinsic_name(f)); + + // // The IntrinsicOps are defined by their name, so we can lookup the name + // // from Julia and construct a generic Operation based on an OperationState + // OperationState state = OperationState(op.getLoc(), name); + // state.addOperands(op.arguments()); + // state.addTypes(op.getType()); + // Operation *newOp = rewriter.create(state); + // // Replace the value of the old Op with the Result of the new op + // rewriter.replaceOp(op, newOp->getResult(0)); } }; @@ -60,34 +60,34 @@ struct LowerBuiltinCallPattern : public OpRewritePattern { using OpRewritePattern::OpRewritePattern; LogicalResult match(CallOp op) const override { - Value callee = op.callee(); - Operation *definingOp = callee.getDefiningOp(); - if (!definingOp) { - // Value is block-argument. - return failure(); - } - if (ConstantOp constant = dyn_cast(definingOp)) { - jl_value_t* value = constant.value(); - if (jl_isa(value, (jl_value_t*)jl_builtin_type)) { - return success(); - } - } + // Value callee = op.callee(); + // Operation *definingOp = callee.getDefiningOp(); + // if (!definingOp) { + // // Value is block-argument. + // return failure(); + // } + // if (ConstantOp constant = dyn_cast(definingOp)) { + // jl_value_t* value = constant.value(); + // if (jl_isa(value, (jl_value_t*)jl_builtin_type)) { + // return success(); + // } + // } return failure(); } void rewrite(CallOp op, PatternRewriter &rewriter) const override { - ConstantOp defining = dyn_cast(op.callee().getDefiningOp()); - assert(jl_isa(defining.value(), (jl_value_t*)jl_builtin_type)); - jl_datatype_t* typeof_builtin = (jl_datatype_t*)jl_typeof(defining.value()); - StringRef name = "jlir." + std::string(jl_symbol_name(typeof_builtin->name->mt->name)); - - // TODO: factor out - OperationState state = OperationState(op.getLoc(), name); - state.addOperands(op.arguments()); - state.addTypes(op.getType()); - Operation *newOp = rewriter.createOperation(state); - // Replace the value of the old Op with the Result of the new op - rewriter.replaceOp(op, newOp->getResult(0)); + // ConstantOp defining = dyn_cast(op.callee().getDefiningOp()); + // assert(jl_isa(defining.value(), (jl_value_t*)jl_builtin_type)); + // jl_datatype_t* typeof_builtin = (jl_datatype_t*)jl_typeof(defining.value()); + // StringRef name = "jlir." + std::string(jl_symbol_name(typeof_builtin->name->mt->name)); + + // // TODO: factor out + // OperationState state = OperationState(op.getLoc(), name); + // state.addOperands(op.arguments()); + // state.addTypes(op.getType()); + // Operation *newOp = rewriter.create(state); + // // Replace the value of the old Op with the Result of the new op + // rewriter.replaceOp(op, newOp->getResult(0)); } }; @@ -95,10 +95,10 @@ struct LowerBuiltinCallPattern : public OpRewritePattern { /// Register our patterns as "canonicalization" patterns on the CallOp so /// that they can be picked up by the Canonicalization framework. -void CallOp::getCanonicalizationPatterns(OwningRewritePatternList &results, +void CallOp::getCanonicalizationPatterns(RewritePatternSet &results, MLIRContext *context) { - results.insert(context); - results.insert(context); + results.add(context); + results.add(context); } namespace { @@ -115,7 +115,7 @@ struct SimplifyRedundantConvertStdOps : public OpRewritePattern { rewriter.replaceOp(op, {op.getOperand()}); return success(); } - + // 2. Check if we have a chain of convert ops ConvertStdOp inputOp = dyn_cast_or_null( op.getOperand().getDefiningOp()); @@ -131,13 +131,13 @@ struct SimplifyRedundantConvertStdOps : public OpRewritePattern { // 3. Shortcut the input op. rewriter.replaceOpWithNewOp(op, resultType, inputOp.getOperand()); - return success(); + return success(); } }; } // namespace -void ConvertStdOp::getCanonicalizationPatterns(OwningRewritePatternList &results, +void ConvertStdOp::getCanonicalizationPatterns(RewritePatternSet &results, MLIRContext *context) { results.insert(context); } diff --git a/lib/Dialect/Julia/Dialect.cpp b/lib/Dialect/Julia/Dialect.cpp new file mode 100644 index 0000000..35a6b36 --- /dev/null +++ b/lib/Dialect/Julia/Dialect.cpp @@ -0,0 +1,50 @@ + +#include "brutus/Dialect/Julia/JuliaDialect.h" +#include "brutus/Dialect/Julia/JuliaOps.h" + +using namespace mlir; +using namespace mlir::jlir; + +#include "brutus/Dialect/Julia/JuliaOpsDialect.cpp.inc" + +//===----------------------------------------------------------------------===// +// Standalone dialect. +//===----------------------------------------------------------------------===// + +/// Dialect creation, the instance will be owned by the context. This is the +/// point of registration of custom types and operations for the dialect. +void JLIRDialect::initialize() { + addOperations< +#define GET_OP_LIST +#include "brutus/Dialect/Julia/JuliaOps.cpp.inc" + >(); + addTypes(); + addAttributes< + JuliaValueAttr + >(); +} + +// void JLIRDialect::printType(mlir::Type type, +// mlir::DialectAsmPrinter &printer) const { +// assert(type.isa()); +// printer << showValue((jl_value_t*)type.cast().getDatatype()); +// } + +// void JLIRDialect::printAttribute(mlir::Attribute attr, +// mlir::DialectAsmPrinter &printer) const { +// // NOTE: printing values may use illegal characters (such as quotes?) +// assert(attr.isa()); +// printer << showValue(attr.cast().getValue()); +// } + +// std::string JLIRDialect::showValue(jl_value_t *value) { +// ios_t str_; +// ios_mem(&str_, 10); +// JL_STREAM *str = (JL_STREAM*)&str_; +// jl_static_show(str, value); +// str_.buf[str_.size] = '\0'; +// std::string s = str_.buf; +// ios_close(&str_); +// return s; +// } + diff --git a/lib/Dialect/Julia/Ops.cpp b/lib/Dialect/Julia/Ops.cpp index d05bdd8..415aa7b 100644 --- a/lib/Dialect/Julia/Ops.cpp +++ b/lib/Dialect/Julia/Ops.cpp @@ -9,41 +9,6 @@ using namespace mlir; using namespace mlir::jlir; -/// Dialect creation, the instance will be owned by the context. This is the -/// point of registration of custom types and operations for the dialect. -JLIRDialect::JLIRDialect(mlir::MLIRContext *ctx) : mlir::Dialect("jlir", ctx, TypeID::get()) { - addOperations< -#define GET_OP_LIST -#include "brutus/Dialect/Julia/JuliaOps.cpp.inc" - >(); - addTypes(); - addAttributes(); -} - -void JLIRDialect::printType(mlir::Type type, - mlir::DialectAsmPrinter &printer) const { - assert(type.isa()); - printer << showValue((jl_value_t*)type.cast().getDatatype()); -} - -void JLIRDialect::printAttribute(mlir::Attribute attr, - mlir::DialectAsmPrinter &printer) const { - // NOTE: printing values may use illegal characters (such as quotes?) - assert(attr.isa()); - printer << showValue(attr.cast().getValue()); -} - -std::string JLIRDialect::showValue(jl_value_t *value) { - ios_t str_; - ios_mem(&str_, 10); - JL_STREAM *str = (JL_STREAM*)&str_; - jl_static_show(str, value); - str_.buf[str_.size] = '\0'; - std::string s = str_.buf; - ios_close(&str_); - return s; -} - void UnimplementedOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, jl_datatype_t *type) { state.addTypes(JuliaType::get(builder.getContext(), type)); } @@ -58,7 +23,7 @@ void ConstantOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, jl } mlir::OpFoldResult ConstantOp::fold(llvm::ArrayRef operands) { - return valueAttr(); + return getValueAttr(); } void PiOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, @@ -96,18 +61,18 @@ void InvokeOp::build(mlir::OpBuilder &builder, mlir::OperationState &state, static mlir::LogicalResult verify(ReturnOp op) { // We know that the parent operation is a function, because of the 'HasParent' // trait attached to the operation definition. - auto function = cast(op->getParentOp()); - - const auto &results = function.getType().getResults(); - if (results.size() != 1) - return function.emitOpError() << "does not return exactly one value"; - - // check that result type of function matches the operand type - if (results.front() != op.getOperand().getType()) - return op.emitError() << "type of return operand (" - << op.getOperand().getType() - << ") doesn't match function result type (" - << results.front() << ")"; + auto function = cast(op->getParentOp()); + + // const auto &results = function.getType().getResults(); + // if (results.size() != 1) + // return function.emitOpError() << "does not return exactly one value"; + + // // check that result type of function matches the operand type + // if (results.front() != op.getOperand().getType()) + // return op.emitError() << "type of return operand (" + // << op.getOperand().getType() + // << ") doesn't match function result type (" + // << results.front() << ")"; return success(); } diff --git a/tools/brutus-shlib/CMakeLists.txt b/tools/brutus-shlib/CMakeLists.txt index 6bac7dc..9b14ee0 100644 --- a/tools/brutus-shlib/CMakeLists.txt +++ b/tools/brutus-shlib/CMakeLists.txt @@ -17,7 +17,7 @@ llvm_add_library( SHARED empty.cpp ${_OBJECTS} - LINK_LIBS PRIVATE + LINK_LIBS ${_DEPS} LLVM MLIR @@ -29,4 +29,5 @@ llvm_update_compile_flags(brutus) message("Libraries included in libBrutus.so: ${brutus_libs}") # message("LLVM Components included in libMLIR.so: ${mlir_llvm_link_components}") -mlir_check_all_link_libraries(MLIR) \ No newline at end of file +mlir_check_all_link_libraries(MLIR) +install(TARGETS brutus DESTINATION lib) \ No newline at end of file