diff --git a/mlir/include/mlir-c/IR.h b/mlir/include/mlir-c/IR.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir-c/IR.h @@ -0,0 +1,182 @@ +//===- IR.h - C Interface for Core MLIR APIs ----------------------*- C -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_C_IR_H +#define MLIR_C_IR_H + +#ifdef __cplusplus +extern "C" { +#endif + +//============================================================================// +// Opaque type declarations. +// +// Types are exposed to C bindings as structs containing opaque pointers. They +// are not supposed to be inspected from C. This allows the underlying +// representaiton to change without affecting the API users. The use of structs +// instead of typedefs enables some type safety as structs are not implicitly +// convertible to each other. +// +// Most types are non-owning and only point to a fragment of the IR owned by +// somebody else. Owning types are prefixed with `_owning`, except for +// `mlirContext`, which is always owning. The result of any creation function +// is an owning struct, which can be deleted. Owning structs are not accepted +// by any "inspection" function. Instead, the caller is expected to get the +// non-owning couterpart and use it for further inspection. It is impossible +// to create an owning struct from its non-owning counterpart, which provides +// some guarantee against accidental deletion. Owning structs are expected to +// be explicitly deleted when they are no longer necessary. + +#define DEFINE_C_API_STRUCT(name, storage) \ + struct name { \ + storage *ptr; \ + }; \ + typedef struct name name; + +DEFINE_C_API_STRUCT(mlirContext, void); +DEFINE_C_API_STRUCT(mlirOperation, void); +DEFINE_C_API_STRUCT(mlirBlock, void); +DEFINE_C_API_STRUCT(mlirRegion, void); + +DEFINE_C_API_STRUCT(mlirValue, const void); +DEFINE_C_API_STRUCT(mlirAttribute, const void); +DEFINE_C_API_STRUCT(mlirType, const void); +DEFINE_C_API_STRUCT(mlirLocation, const void); + +DEFINE_C_API_STRUCT(mlirOwningModule, void) +DEFINE_C_API_STRUCT(mlirOwningRegion, void); +DEFINE_C_API_STRUCT(mlirOwningBlock, void); +DEFINE_C_API_STRUCT(mlirOwningOperation, void); + +#undef DEFINE_C_API_STRUCT + +struct mlirNamedAttribute { + const char *name; + mlirAttribute attribute; +}; +typedef struct mlirNamedAttribute mlirNamedAttribute; + +//----------------------------------------------------------------------------// +// Context + +/// Creates or destroys the context. Transfers ownership. +mlirContext mlirContextCreate(); +void mlirContextDestroy(mlirContext context); + +//============================================================================// +// Location + +/// Creates a location in the context. +mlirLocation mlirLocationCreateFileLineCol(mlirContext context, + const char *filename, unsigned line, + unsigned col); +mlirLocation mlirLocationCreateUnknown(mlirContext context); + +//============================================================================// +// Module + +/// Creates a new, empty module. +mlirOwningModule mlirModuleCreate(mlirLocation location); +/// Parses a module from string. +mlirOwningModule mlirModuleParse(mlirContext context, const char *module); +/// Deletes a module. +void mlirModuleDestroy(mlirOwningModule module); + +/// Views the module as a generic operation. +mlirOperation mlirModuleGetOperation(mlirOwningModule module); + +//============================================================================// +// Operation + +//----------------------------------------------------------------------------// +// Creation and Deletion. + +/// Creates an operation. +mlirOwningOperation +mlirOperationCreate(const char *name, mlirLocation location, unsigned nResults, + mlirType *results, unsigned nOperands, mlirValue *operands, + unsigned nAttributes, mlirNamedAttribute *attributes, + unsigned nRegions, mlirOwningRegion *regions, + unsigned nSuccessors, mlirBlock *successors); + +/// Gets an inspectable operation. +mlirOperation mlirOperationGet(mlirOwningOperation op); + +/// Deletes an operation. +void mlirOperationDestroy(mlirOwningOperation op); + +//----------------------------------------------------------------------------// +// Inspection. + +int mlirOperationIsNull(mlirOperation op); +unsigned mlirOperationGetNumRegions(mlirOperation op); +mlirRegion mlirOperationGetRegion(mlirOperation op, unsigned pos); +mlirOperation mlirOperationGetNextInBlock(mlirOperation op); +unsigned mlirOperationGetNumOperands(mlirOperation op); +mlirValue mlirOperationGetOperand(mlirOperation op, unsigned pos); +unsigned mlirOperationGetNumResults(mlirOperation op); +mlirValue mlirOperationGetResult(mlirOperation op, unsigned pos); +unsigned mlirOperationGetNumSuccessors(mlirOperation op); +mlirBlock mlirOperationGetSuccessor(mlirOperation op, unsigned pos); +unsigned mlirOperationGetNumAttributes(mlirOperation op); +mlirNamedAttribute mlirOperationGetAttribute(mlirOperation op, unsigned pos); +mlirAttribute mlirOperationGetAttributeByName(mlirOperation op, + const char *name); +void mlirOperationDump(mlirOperation op); + +//============================================================================// +// Region + +mlirOwningRegion mlirRegionCreate(); +mlirRegion mlirRegionGet(mlirOwningRegion region); +mlirBlock mlirRegionGetFirstBlock(mlirRegion region); +void mlirRegionAppendBlock(mlirRegion region, mlirOwningBlock block); +void mlirRegionInsertBlock(mlirRegion region, unsigned pos, + mlirOwningBlock block); +void mlirRegionDestroy(mlirOwningRegion region); +int mlirRegionIsNull(mlirRegion region); + +//============================================================================// +// Block + +mlirOwningBlock mlirBlockCreate(unsigned nArgs, mlirType *args); +mlirBlock mlirBlockGet(mlirOwningBlock block); +mlirBlock mlirBlockGetNextInRegion(mlirBlock block); +mlirOperation mlirBlockGetFirstOperation(mlirBlock block); +void mlirBlockAppendOperation(mlirBlock block, mlirOwningOperation operation); +void mlirBlockInsertOperation(mlirBlock block, unsigned pos, + mlirOwningOperation operation); +void mlirBlockDestroy(mlirOwningBlock block); +int mlirBlockIsNull(mlirBlock block); +unsigned mlirBlockGetNumArguments(mlirBlock block); +mlirValue mlirBlockGetArgument(mlirBlock block, unsigned pos); + +//============================================================================// +// Value + +mlirType mlirValueGetType(mlirValue value); + +//============================================================================// +// Type + +mlirType mlirTypeParse(mlirContext context, const char *type); +void mlirTypeDump(mlirType type); + +//============================================================================// +// Attribute + +mlirAttribute mlirAttributeParse(mlirContext context, const char *attr); +void mlirAttributeDump(mlirAttribute attr); +mlirNamedAttribute mlirNamedAttributeCreate(const char *name, + mlirAttribute attr); + +#ifdef __cplusplus +} +#endif + +#endif // MLIR_C_IR_H diff --git a/mlir/lib/CAPI/CMakeLists.txt b/mlir/lib/CAPI/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/mlir/lib/CAPI/CMakeLists.txt @@ -0,0 +1,28 @@ +add_mlir_library(MLIRCAPI + IR.cpp + + EXCLUDE_FROM_LIBMLIR + + ADDITIONAL_HEADER_DIRS + ${MLIR_MAIN_INCLUDE_DIR}/mlir-c + + LINK_LIBS PUBLIC + MLIRIR + MLIRParser + MLIRSupport + ) + +set(LLVM_LINK_COMPONENTS + Core + Parser + Support + ) +add_llvm_executable(mlir-capi-test + test.c +) +llvm_update_compile_flags(mlir-capi-test) + +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) +target_link_libraries(mlir-capi-test + PRIVATE + ${dialect_libs}) diff --git a/mlir/lib/CAPI/IR.cpp b/mlir/lib/CAPI/IR.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/CAPI/IR.cpp @@ -0,0 +1,344 @@ +//===- IR.cpp - C Interface for Core MLIR APIs ----------------------------===// +// +// 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 "mlir-c/IR.h" + +#include "mlir/IR/Attributes.h" +#include "mlir/IR/Module.h" +#include "mlir/IR/Operation.h" +#include "mlir/IR/Types.h" +#include "mlir/InitAllDialects.h" +#include "mlir/Parser.h" + +using namespace mlir; + +/* ========================================================================== */ +/* Definitions of methods for non-owning structures used in C API. */ +/* ========================================================================== */ + +#define DEFINE_C_API_PTR_METHODS(name, cpptype) \ + static name wrap(cpptype *cpp) { return name{cpp}; } \ + static cpptype *unwrap(name c) { return static_cast(c.ptr); } + +DEFINE_C_API_PTR_METHODS(mlirContext, MLIRContext) +DEFINE_C_API_PTR_METHODS(mlirOperation, Operation) +DEFINE_C_API_PTR_METHODS(mlirBlock, Block) +DEFINE_C_API_PTR_METHODS(mlirRegion, Region) + +#define DEFINE_C_API_METHODS(name, cpptype) \ + static name wrap(cpptype cpp) { return name{cpp.getAsOpaquePointer()}; } \ + static cpptype unwrap(name c) { return cpptype::getFromOpaquePointer(c.ptr); } + +DEFINE_C_API_METHODS(mlirAttribute, Attribute) +DEFINE_C_API_METHODS(mlirLocation, Location); +DEFINE_C_API_METHODS(mlirType, Type) +DEFINE_C_API_METHODS(mlirValue, Value) + +template +ArrayRef unwrapList(unsigned size, CTy *first, + SmallVectorImpl &storage) { + static_assert(std::is_same_v())), CppTy>, + "incompatible C and C++ types"); + + if (size == 0) + return ArrayRef(); + + assert(first); + assert(storage.empty()); + storage.reserve(size); + for (unsigned i = 0; i < size; ++i) + storage.push_back(unwrap(*(first + i))); + return storage; +} + +/* ========================================================================== */ +/* Definitions of methods for owning structures used in C API. */ +/* ========================================================================== */ + +#define DEFINE_C_API_OWNED_PTR_METHODS(name, cpptype) \ + static std::unique_ptr take(name c) { \ + auto owned = std::unique_ptr(static_cast(c.ptr)); \ + c.ptr = nullptr; \ + return owned; \ + } \ + static name take(std::unique_ptr &&cpp) { \ + return name{cpp.release()}; \ + } \ + static cpptype *get(name c) { return static_cast(c.ptr); } + +DEFINE_C_API_OWNED_PTR_METHODS(mlirOwningBlock, Block) +DEFINE_C_API_OWNED_PTR_METHODS(mlirOwningRegion, Region) + +namespace { +struct OperationDeleter { + void operator()(Operation *op) { + if (op) + op->destroy(); + } +}; + +using OwnedOperation = std::unique_ptr; +} // end namespace + +static OwnedOperation take(mlirOwningOperation op) { + auto owned = OwnedOperation(static_cast(op.ptr)); + op.ptr = nullptr; + return owned; +} +static mlirOwningOperation take(OwnedOperation &&op) { + return mlirOwningOperation{op.release()}; +} +static Operation *get(mlirOwningOperation op) { + return static_cast(op.ptr); +} + +/* ========================================================================== */ +/* Methods for working with mlirContext. */ +/* ========================================================================== */ + +mlirContext mlirContextCreate() { + registerAllDialects(); + auto *context = new MLIRContext; + return wrap(context); +} + +void mlirContextDestroy(mlirContext context) { delete unwrap(context); } + +/* ========================================================================== */ +/* Methods for working with mlirLocation. */ +/* ========================================================================== */ + +mlirLocation mlirLocationCreateFileLineCol(mlirContext context, + const char *filename, unsigned line, + unsigned col) { + return wrap(FileLineColLoc::get(filename, line, col, unwrap(context))); +} + +mlirLocation mlirLocationCreateUnknown(mlirContext context) { + return wrap(UnknownLoc::get(unwrap(context))); +} + +/* ========================================================================== */ +/* Methods for working with mlirModule. */ +/* ========================================================================== */ + +mlirOwningModule mlirModuleCreate(mlirLocation location) { + return mlirOwningModule{ModuleOp::create(unwrap(location)).getOperation()}; +} + +mlirOwningModule mlirModuleParse(mlirContext context, const char *module) { + OwningModuleRef owning = parseSourceString(module, unwrap(context)); + return mlirOwningModule{owning.release().getOperation()}; +} + +void mlirModuleDestroy(mlirOwningModule module) { + // Transfer ownership to an OwningModuleRef so that its destructor is called. + OwningModuleRef owning(cast(static_cast(module.ptr))); +} + +mlirOperation mlirModuleGetOperation(mlirOwningModule module) { + return wrap(static_cast(module.ptr)); +} + +/* ========================================================================== */ +/* Methods for working with mlirOperation. */ +/* ========================================================================== */ + +mlirOwningOperation +mlirOperationCreate(const char *name, mlirLocation location, unsigned nResults, + mlirType *results, unsigned nOperands, mlirValue *operands, + unsigned nAttributes, mlirNamedAttribute *attributes, + unsigned nRegions, mlirOwningRegion *regions, + unsigned nSuccessors, mlirBlock *successors) { + OperationState state(unwrap(location), name); + SmallVector resultStorage; + SmallVector operandStorage; + SmallVector successorStorage; + state.addTypes(unwrapList(nResults, results, resultStorage)); + state.addOperands(unwrapList(nOperands, operands, operandStorage)); + state.addSuccessors(unwrapList(nSuccessors, successors, successorStorage)); + + for (unsigned i = 0; i < nAttributes; ++i) + state.addAttribute(attributes[i].name, unwrap(attributes[i].attribute)); + + for (unsigned i = 0; i < nRegions; ++i) + state.addRegion(take(regions[i])); + + return mlirOwningOperation{Operation::create(state)}; +} + +mlirOperation mlirOperationGet(mlirOwningOperation op) { return wrap(get(op)); } + +void mlirOperationDestroy(mlirOwningOperation op) { + // Transfer ownership to a temporary to call the destructor (custom deleter). + take(op); +} + +int mlirOperationIsNull(mlirOperation op) { return unwrap(op) == nullptr; } + +unsigned mlirOperationGetNumRegions(mlirOperation op) { + return unwrap(op)->getNumRegions(); +} + +mlirRegion mlirOperationGetRegion(mlirOperation op, unsigned pos) { + return wrap(&unwrap(op)->getRegion(pos)); +} + +mlirOperation mlirOperationGetNextInBlock(mlirOperation op) { + return wrap(unwrap(op)->getNextNode()); +} + +unsigned mlirOperationGetNumOperands(mlirOperation op) { + return unwrap(op)->getNumOperands(); +} + +mlirValue mlirOperationGetOperand(mlirOperation op, unsigned pos) { + return wrap(unwrap(op)->getOperand(pos)); +} + +unsigned mlirOperationGetNumResults(mlirOperation op) { + return unwrap(op)->getNumResults(); +} + +mlirValue mlirOperationGetResult(mlirOperation op, unsigned pos) { + return wrap(unwrap(op)->getResult(pos)); +} + +unsigned mlirOperationGetNumSuccessors(mlirOperation op) { + return unwrap(op)->getNumSuccessors(); +} + +mlirBlock mlirOperationGetSuccessor(mlirOperation op, unsigned pos) { + return wrap(unwrap(op)->getSuccessor(pos)); +} + +unsigned mlirOperationGetNumAttributes(mlirOperation op) { + return unwrap(op)->getAttrs().size(); +} + +mlirNamedAttribute mlirOperationGetAttribute(mlirOperation op, unsigned pos) { + NamedAttribute attr = unwrap(op)->getAttrs()[pos]; + return mlirNamedAttribute{attr.first.c_str(), wrap(attr.second)}; +} + +mlirAttribute mlirOperationGetAttributeByName(mlirOperation op, + const char *name) { + return wrap(unwrap(op)->getAttr(name)); +} + +void mlirOperationDump(mlirOperation op) { return unwrap(op)->dump(); } + +/* ========================================================================== */ +/* Methods for working with mlirRegion. */ +/* ========================================================================== */ + +mlirOwningRegion mlirRegionCreate() { return take(std::make_unique()); } + +mlirRegion mlirRegionGet(mlirOwningRegion region) { return wrap(get(region)); } + +mlirBlock mlirRegionGetFirstBlock(mlirRegion region) { + Region *cppRegion = unwrap(region); + if (cppRegion->empty()) + return wrap(static_cast(nullptr)); + return wrap(&cppRegion->front()); +} + +void mlirRegionAppendBlock(mlirRegion region, mlirOwningBlock block) { + unwrap(region)->push_back(take(block).release()); +} + +void mlirRegionInsertBlock(mlirRegion region, unsigned pos, + mlirOwningBlock block) { + auto &blockList = unwrap(region)->getBlocks(); + blockList.insert(std::next(blockList.begin(), pos), take(block).release()); +} + +void mlirRegionDestroy(mlirOwningRegion region) { + delete static_cast(region.ptr); +} + +int mlirRegionIsNull(mlirRegion region) { return unwrap(region) == nullptr; } + +/* ========================================================================== */ +/* Methods for working with mlirBlock. */ +/* ========================================================================== */ + +mlirOwningBlock mlirBlockCreate(unsigned nArgs, mlirType *args) { + auto b = std::make_unique(); + for (unsigned i = 0; i < nArgs; ++i) + b->addArgument(unwrap(args[i])); + return take(std::move(b)); +} + +mlirBlock mlirBlockGet(mlirOwningBlock block) { return wrap(get(block)); } + +mlirBlock mlirBlockGetNextInRegion(mlirBlock block) { + return wrap(unwrap(block)->getNextNode()); +} + +mlirOperation mlirBlockGetFirstOperation(mlirBlock block) { + Block *cppBlock = unwrap(block); + if (cppBlock->empty()) + return wrap(static_cast(nullptr)); + return wrap(&cppBlock->front()); +} + +void mlirBlockAppendOperation(mlirBlock block, mlirOwningOperation operation) { + unwrap(block)->push_back(take(operation).release()); +} + +void mlirBlockInsertOperation(mlirBlock block, unsigned pos, + mlirOwningOperation operation) { + auto &opList = unwrap(block)->getOperations(); + opList.insert(std::next(opList.begin(), pos), take(operation).release()); +} + +void mlirBlockDestroy(mlirOwningBlock block) { take(block); } + +int mlirBlockIsNull(mlirBlock block) { return unwrap(block) == nullptr; } + +unsigned mlirBlockGetNumArguments(mlirBlock block) { + return unwrap(block)->getNumArguments(); +} + +mlirValue mlirBlockGetArgument(mlirBlock block, unsigned pos) { + return wrap(unwrap(block)->getArgument(pos)); +} + +/* ========================================================================== */ +/* Methods for working with mlirValue. */ +/* ========================================================================== */ + +mlirType mlirValueGetType(mlirValue value) { + return wrap(unwrap(value).getType()); +} + +/* ========================================================================== */ +/* Methods for working with mlirType. */ +/* ========================================================================== */ + +mlirType mlirTypeParse(mlirContext context, const char *type) { + return wrap(mlir::parseType(type, unwrap(context))); +} + +void mlirTypeDump(mlirType type) { unwrap(type).dump(); } + +/* ========================================================================== */ +/* Methods for working with mlirAttribute. */ +/* ========================================================================== */ + +mlirAttribute mlirAttributeParse(mlirContext context, const char *attr) { + return wrap(mlir::parseAttribute(attr, unwrap(context))); +} + +void mlirAttributeDump(mlirAttribute attr) { unwrap(attr).dump(); } + +mlirNamedAttribute mlirNamedAttributeCreate(const char *name, + mlirAttribute attr) { + return mlirNamedAttribute{name, attr}; +} diff --git a/mlir/lib/CAPI/test.c b/mlir/lib/CAPI/test.c new file mode 100644 --- /dev/null +++ b/mlir/lib/CAPI/test.c @@ -0,0 +1,242 @@ +//===- test.c - Simple test of C APIs -------------------------------------===// +// +// 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 "mlir-c/IR.h" + +#include +#include +#include + +void populateLoopBody(mlirContext ctx, mlirBlock loopBody, + mlirLocation location, mlirBlock funcBody) { + mlirValue iv = mlirBlockGetArgument(loopBody, 0); + mlirValue funcArg0 = mlirBlockGetArgument(funcBody, 0); + mlirValue funcArg1 = mlirBlockGetArgument(funcBody, 1); + mlirType f32Type = mlirTypeParse(ctx, "f32"); + + mlirValue loadLHSOperands[] = { funcArg0, iv }; + mlirOwningOperation ownedLoadLHS = mlirOperationCreate( + "std.load", location, /*nResults=*/1, &f32Type, + sizeof(loadLHSOperands) / sizeof(mlirValue), loadLHSOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirOperation loadLHS = mlirOperationGet(ownedLoadLHS); + mlirBlockAppendOperation(loopBody, ownedLoadLHS); + + mlirValue loadRHSOperands[] = { funcArg1, iv }; + mlirOwningOperation ownedLoadRHS = mlirOperationCreate( + "std.load", location, /*nResults=*/1, &f32Type, + sizeof(loadRHSOperands) / sizeof(mlirValue), loadRHSOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirOperation loadRHS = mlirOperationGet(ownedLoadRHS); + mlirBlockAppendOperation(loopBody, ownedLoadRHS); + + mlirValue addOperands[] = {mlirOperationGetResult(loadLHS, 0), + mlirOperationGetResult(loadRHS, 0)}; + mlirOwningOperation ownedAdd = mlirOperationCreate( + "std.addf", location, /*nResults=*/1, &f32Type, + sizeof(addOperands) / sizeof(mlirValue), addOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirOperation add = mlirOperationGet(ownedAdd); + mlirBlockAppendOperation(loopBody, ownedAdd); + + mlirValue storeOperands[] = {mlirOperationGetResult(add, 0), funcArg0, iv}; + mlirOwningOperation ownedStore = mlirOperationCreate( + "std.store", location, /*nResults=*/0, /*results=*/NULL, + sizeof(storeOperands) / sizeof(mlirValue), storeOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirBlockAppendOperation(loopBody, ownedStore); + + mlirOwningOperation ownedYield = + mlirOperationCreate("scf.yield", location, /*nResults=*/0, + /*results=*/NULL, /*nOperands=*/0, + /*operands=*/NULL, /*nAttributes=*/0, + /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, + /*successors=*/NULL); + mlirBlockAppendOperation(loopBody, ownedYield); +} + +mlirOwningModule makeAdd(mlirContext ctx, mlirLocation location) { + mlirOwningModule moduleOp = mlirModuleCreate(location); + mlirOperation module = mlirModuleGetOperation(moduleOp); + mlirRegion moduleBodyRegion = mlirOperationGetRegion(module, 0); + mlirBlock moduleBody = mlirRegionGetFirstBlock(moduleBodyRegion); + + mlirType memrefType = mlirTypeParse(ctx, "memref"); + mlirType funcBodyArgTypes[] = { memrefType, memrefType }; + mlirOwningRegion ownedFuncBodyRegion = mlirRegionCreate(); + mlirOwningBlock ownedFuncBody = mlirBlockCreate( + sizeof(funcBodyArgTypes) / sizeof(mlirType), funcBodyArgTypes); + mlirBlock funcBody = mlirBlockGet(ownedFuncBody); + mlirRegionAppendBlock(mlirRegionGet(ownedFuncBodyRegion), ownedFuncBody); + + mlirAttribute funcTypeAttr = mlirAttributeParse( + ctx, "(memref, memref) -> ()"); + mlirAttribute funcNameAttr = mlirAttributeParse(ctx, "\"add\""); + mlirNamedAttribute funcAttrs[] = { + mlirNamedAttributeCreate("type", funcTypeAttr), + mlirNamedAttributeCreate("sym_name", funcNameAttr)}; + mlirOwningOperation ownedFunc = mlirOperationCreate( + "func", location, /*nResults=*/0, /*results=*/NULL, + /*nOperands=*/0, /*operands=*/NULL, + sizeof(funcAttrs) / sizeof(mlirNamedAttribute), funcAttrs, + /*nRegions=*/1, &ownedFuncBodyRegion, /*nSuccessors=*/0, + /*successors=*/NULL); + mlirBlockInsertOperation(moduleBody, 0, ownedFunc); + + mlirType indexType = mlirTypeParse(ctx, "index"); + mlirAttribute indexZeroLiteral = mlirAttributeParse(ctx, "0 : index"); + mlirNamedAttribute indexZeroValueAttr = + mlirNamedAttributeCreate("value", indexZeroLiteral); + mlirOwningOperation ownedConstZero = mlirOperationCreate( + "std.constant", location, /*nResults=*/1, &indexType, /*nOperands=*/0, + /*operands=*/NULL, /*nAttributes=*/1, &indexZeroValueAttr, /*nRegions=*/0, + /*regions=*/NULL, + /*nSuccessors=*/0, /*successors=*/0); + mlirOperation constZero = mlirOperationGet(ownedConstZero); + mlirBlockAppendOperation(funcBody, ownedConstZero); + + mlirValue funcArg0 = mlirBlockGetArgument(funcBody, 0); + mlirValue constZeroValue = mlirOperationGetResult(constZero, 0); + mlirValue dimOperands[] = { funcArg0, constZeroValue }; + mlirOwningOperation ownedDim = + mlirOperationCreate("std.dim", location, /*nResults=*/1, &indexType, + sizeof(dimOperands) / sizeof(mlirValue), dimOperands, + /*nAttributes=*/0, NULL, /*nRegions=*/0, + /*regions=*/NULL, + /*nSuccessors=*/0, /*successors=*/0); + mlirOperation dim = mlirOperationGet(ownedDim); + mlirBlockAppendOperation(funcBody, ownedDim); + + mlirOwningRegion ownedLoopBodyRegion = mlirRegionCreate(); + mlirOwningBlock ownedLoopBody = mlirBlockCreate(/*nArgs=*/1, &indexType); + mlirBlock loopBody = mlirBlockGet(ownedLoopBody); + mlirRegionAppendBlock(mlirRegionGet(ownedLoopBodyRegion), ownedLoopBody); + + mlirAttribute indexOneLiteral = mlirAttributeParse(ctx, "1 : index"); + mlirNamedAttribute indexOneValueAttr = + mlirNamedAttributeCreate("value", indexOneLiteral); + mlirOwningOperation ownedConstOne = mlirOperationCreate( + "std.constant", location, /*nResults=*/1, &indexType, /*nOperands=*/0, + /*operands=*/NULL, /*nAttributes=*/1, &indexOneValueAttr, /*nRegions=*/0, + /*regions=*/NULL, + /*nSuccessors=*/0, /*successors=*/0); + mlirOperation constOne = mlirOperationGet(ownedConstOne); + mlirBlockAppendOperation(funcBody, ownedConstOne); + + mlirValue dimValue = mlirOperationGetResult(dim, 0); + mlirValue constOneValue = mlirOperationGetResult(constOne, 0); + mlirValue loopOperands[] = { constZeroValue, dimValue, constOneValue }; + mlirOwningOperation ownedLoop = mlirOperationCreate( + "scf.for", location, /*nResults=*/0, /*results=*/NULL, + sizeof(loopOperands) / sizeof(mlirValue), loopOperands, + /*nAttributes=*/0, /*attributes=*/NULL, + /*nRegions=*/1, &ownedLoopBodyRegion, /*nSuccessors=*/0, + /*successors=*/NULL); + mlirBlockAppendOperation(funcBody, ownedLoop); + + populateLoopBody(ctx, loopBody, location, funcBody); + + mlirOwningOperation owningRet = + mlirOperationCreate("std.return", location, /*nResults=*/0, + /*results=*/NULL, /*nOperands=*/0, + /*operands=*/NULL, /*nAttributes=*/0, + /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, + /*successors=*/NULL); + mlirBlockAppendOperation(funcBody, owningRet); + + return moduleOp; +} + +struct OpListNode { + mlirOperation op; + struct OpListNode *next; +}; +typedef struct OpListNode OpListNode; + +struct ModuleStats { + unsigned numOperations; + unsigned numAttributes; + unsigned numBlocks; + unsigned numRegions; + unsigned numValues; +}; +typedef struct ModuleStats ModuleStats; + +void collectStatsSingle(OpListNode *head, ModuleStats *stats) { + mlirOperation operation = head->op; + stats->numOperations += 1; + stats->numValues += mlirOperationGetNumResults(operation); + stats->numAttributes += mlirOperationGetNumAttributes(operation); + + unsigned numRegions = mlirOperationGetNumRegions(operation);; + stats->numRegions += numRegions; + + for (unsigned i = 0; i < numRegions; ++i) { + mlirRegion region = mlirOperationGetRegion(operation, i); + for (mlirBlock block = mlirRegionGetFirstBlock(region); + !mlirBlockIsNull(block); block = mlirBlockGetNextInRegion(block)) { + ++stats->numBlocks; + stats->numValues += mlirBlockGetNumArguments(block); + + for (mlirOperation child = mlirBlockGetFirstOperation(block); + !mlirOperationIsNull(child); + child = mlirOperationGetNextInBlock(child)) { + OpListNode *node = malloc(sizeof(OpListNode)); + node->op = child; + node->next = head->next; + head->next = node; + } + } + } +} + +void collectStats(mlirOperation operation) { + OpListNode *head = malloc(sizeof(OpListNode)); + head->op = operation; + head->next = NULL; + + ModuleStats stats; + stats.numOperations = 0; + stats.numAttributes = 0; + stats.numBlocks = 0; + stats.numRegions = 0; + stats.numValues = 0; + + do { + collectStatsSingle(head, &stats); + OpListNode *next = head->next; + free(head); + head = next; + } while (head); + + printf("Number of operations: %u\n", stats.numOperations); + printf("Number of attributes: %u\n", stats.numAttributes); + printf("Number of blocks: %u\n", stats.numBlocks); + printf("Number of regions: %u\n", stats.numRegions); + printf("Number of values: %u\n", stats.numValues); +} + +int main() { + mlirContext ctx = mlirContextCreate(); + mlirLocation location = mlirLocationCreateUnknown(ctx); + + mlirOwningModule moduleOp = makeAdd(ctx, location); + mlirOperation module = mlirModuleGetOperation(moduleOp); + mlirOperationDump(module); + collectStats(module); + mlirModuleDestroy(moduleOp); + mlirContextDestroy(ctx); + + return 0; +} diff --git a/mlir/lib/CMakeLists.txt b/mlir/lib/CMakeLists.txt --- a/mlir/lib/CMakeLists.txt +++ b/mlir/lib/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(Analysis) add_subdirectory(Bindings) add_subdirectory(Conversion) +add_subdirectory(CAPI) add_subdirectory(Dialect) add_subdirectory(EDSC) add_subdirectory(ExecutionEngine)