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,201 @@ +//===- 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(mlirModule, const void); + +#undef DEFINE_C_API_STRUCT + +struct mlirNamedAttribute { + const char *name; + mlirAttribute attribute; +}; +typedef struct mlirNamedAttribute mlirNamedAttribute; + +struct mlirOperationState { + const char *name; + mlirLocation location; + unsigned nResults; + mlirType *results; + unsigned nOperands; + mlirValue *operands; + unsigned nRegions; + mlirRegion *regions; + unsigned nSuccessors; + mlirBlock *successors; + unsigned nAttributes; + mlirNamedAttribute *attributes; +}; +typedef struct mlirOperationState mlirOperationState; + +mlirOperationState mlirOperationStateFromName(const char *name); +void mlirOperationStateAddResults(mlirOperationState *state, unsigned n, + mlirType *results); +void mlirOperationStateAddOperands(mlirOperationState *state, unsigned n, + mlirValue *operands); +void mlirOperationStateAddRegions(mlirOperationState *state, unsigned n, + mlirRegion *regions); +void mlirOperationStateAddSuccessors(mlirOperationState *state, unsigned n, + mlirBlock *successors); +void mlirOperationStateAddAttributes(mlirOperationState *state, unsigned n, + mlirNamedAttribute *attributes); + +//----------------------------------------------------------------------------// +// 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. +mlirModule mlirModuleCreate(mlirLocation location); +/// Parses a module from string. +mlirModule mlirModuleParse(mlirContext context, const char *module); +/// Deletes a module. +void mlirModuleDestroy(mlirModule module); + +/// Views the module as a generic operation. +mlirOperation mlirModuleGetOperation(mlirModule module); + +//============================================================================// +// Operation + +//----------------------------------------------------------------------------// +// Creation and Deletion. + +/// Creates an operation. +mlirOperation mlirOperationCreate(const char *name, mlirLocation location, + unsigned nResults, mlirType *results, + unsigned nOperands, mlirValue *operands, + unsigned nAttributes, + mlirNamedAttribute *attributes, + unsigned nRegions, mlirRegion *regions, + unsigned nSuccessors, mlirBlock *successors); + +/// Deletes an operation. +void mlirOperationDestroy(mlirOperation 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 + +mlirRegion mlirRegionCreate(); +mlirBlock mlirRegionGetFirstBlock(mlirRegion region); +void mlirRegionAppendBlock(mlirRegion region, mlirBlock block); +void mlirRegionInsertBlock(mlirRegion region, unsigned pos, mlirBlock block); +void mlirRegionDestroy(mlirRegion region); +int mlirRegionIsNull(mlirRegion region); + +//============================================================================// +// Block + +mlirBlock mlirBlockCreate(unsigned nArgs, mlirType *args); +mlirBlock mlirBlockGetNextInRegion(mlirBlock block); +mlirOperation mlirBlockGetFirstOperation(mlirBlock block); +void mlirBlockAppendOperation(mlirBlock block, mlirOperation operation); +void mlirBlockInsertOperation(mlirBlock block, unsigned pos, + mlirOperation operation); +void mlirBlockDestroy(mlirBlock 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,341 @@ +//===- 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) +DEFINE_C_API_METHODS(mlirModule, ModuleOp) + +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; +} + +/* ========================================================================== */ +/* 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. */ +/* ========================================================================== */ + +mlirModule mlirModuleCreate(mlirLocation location) { + return wrap(ModuleOp::create(unwrap(location))); +} + +mlirModule mlirModuleParse(mlirContext context, const char *module) { + OwningModuleRef owning = parseSourceString(module, unwrap(context)); + return mlirModule{owning.release().getOperation()}; +} + +void mlirModuleDestroy(mlirModule module) { + // Transfer ownership to an OwningModuleRef so that its destructor is called. + OwningModuleRef(unwrap(module)); +} + +mlirOperation mlirModuleGetOperation(mlirModule module) { + return wrap(unwrap(module).getOperation()); +} + +/* ========================================================================== */ +/* Methods for working with mlirOperation. */ +/* ========================================================================== */ + +mlirOperationState mlirOperationStatePrepare(mlirLocation loc, + const char *name) { + mlirOperationState state; + state.name = name; + state.location = loc; + state.nResults = 0; + state.results = nullptr; + state.nOperands = 0; + state.operands = nullptr; + state.nRegions = 0; + state.regions = nullptr; + state.nSuccessors = 0; + state.successors = nullptr; + state.nAttributes = 0; + state.attributes = nullptr; + return state; +} + +#define APPEND_ELEMS(type, sizeName, elemName) \ + state->elemName = \ + (type *)realloc(state->elemName, (state->sizeName + n) * sizeof(type)); \ + memcpy(state->elemName + state->sizeName, elemName, n * sizeof(type)); \ + state->sizeName += n; + +void mlirOperationStateAddResults(mlirOperationState *state, unsigned n, + mlirType *results) { + APPEND_ELEMS(mlirType, nResults, results); +} + +void mlirOperationStateAddOperands(mlirOperationState *state, unsigned n, + mlirValue *operands) { + APPEND_ELEMS(mlirValue, nOperands, operands); +} +void mlirOperationStateAddRegions(mlirOperationState *state, unsigned n, + mlirRegion *regions) { + APPEND_ELEMS(mlirRegion, nRegions, regions); +} +void mlirOperationStateAddSuccessors(mlirOperationState *state, unsigned n, + mlirBlock *successors) { + APPEND_ELEMS(mlirBlock, nSuccessors, successors); +} +void mlirOperationStateAddAttributes(mlirOperationState *state, unsigned n, + mlirNamedAttribute *attributes) { + APPEND_ELEMS(mlirNamedAttribute, nAttributes, attributes); +} + +mlirOperation mlirOperationCreate(const char *name, mlirLocation location, + unsigned nResults, mlirType *results, + unsigned nOperands, mlirValue *operands, + unsigned nAttributes, + mlirNamedAttribute *attributes, + unsigned nRegions, mlirRegion *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(std::unique_ptr(unwrap(regions[i]))); + + return mlirOperation{Operation::create(state)}; +} + +void mlirOperationDestroy(mlirOperation op) { unwrap(op)->erase(); } + +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. */ +/* ========================================================================== */ + +mlirRegion mlirRegionCreate() { return wrap(new 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, mlirBlock block) { + unwrap(region)->push_back(unwrap(block)); +} + +void mlirRegionInsertBlock(mlirRegion region, unsigned pos, mlirBlock block) { + auto &blockList = unwrap(region)->getBlocks(); + blockList.insert(std::next(blockList.begin(), pos), unwrap(block)); +} + +void mlirRegionDestroy(mlirRegion region) { + delete static_cast(region.ptr); +} + +int mlirRegionIsNull(mlirRegion region) { return unwrap(region) == nullptr; } + +/* ========================================================================== */ +/* Methods for working with mlirBlock. */ +/* ========================================================================== */ + +mlirBlock mlirBlockCreate(unsigned nArgs, mlirType *args) { + Block *b = new Block; + for (unsigned i = 0; i < nArgs; ++i) + b->addArgument(unwrap(args[i])); + return wrap(b); +} + +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, mlirOperation operation) { + unwrap(block)->push_back(unwrap(operation)); +} + +void mlirBlockInsertOperation(mlirBlock block, unsigned pos, + mlirOperation operation) { + auto &opList = unwrap(block)->getOperations(); + opList.insert(std::next(opList.begin(), pos), unwrap(operation)); +} + +void mlirBlockDestroy(mlirBlock block) { delete unwrap(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,233 @@ +//===- 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 }; + mlirOperation loadLHS = mlirOperationCreate( + "std.load", location, /*nResults=*/1, &f32Type, + sizeof(loadLHSOperands) / sizeof(mlirValue), loadLHSOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirBlockAppendOperation(loopBody, loadLHS); + + mlirValue loadRHSOperands[] = { funcArg1, iv }; + mlirOperation loadRHS = mlirOperationCreate( + "std.load", location, /*nResults=*/1, &f32Type, + sizeof(loadRHSOperands) / sizeof(mlirValue), loadRHSOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirBlockAppendOperation(loopBody, loadRHS); + + mlirValue addOperands[] = {mlirOperationGetResult(loadLHS, 0), + mlirOperationGetResult(loadRHS, 0)}; + mlirOperation add = mlirOperationCreate( + "std.addf", location, /*nResults=*/1, &f32Type, + sizeof(addOperands) / sizeof(mlirValue), addOperands, + /*nAttributes=*/0, /*attributes=*/NULL, /*nRegions=*/0, + /*regions=*/NULL, /*nSuccessors=*/0, /*successors=*/NULL); + mlirBlockAppendOperation(loopBody, add); + + mlirValue storeOperands[] = {mlirOperationGetResult(add, 0), funcArg0, iv}; + mlirOperation store = 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, store); + + mlirOperation yield = + 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, yield); +} + +mlirModule makeAdd(mlirContext ctx, mlirLocation location) { + mlirModule 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 }; + mlirRegion funcBodyRegion = mlirRegionCreate(); + mlirBlock funcBody = mlirBlockCreate( + sizeof(funcBodyArgTypes) / sizeof(mlirType), funcBodyArgTypes); + mlirRegionAppendBlock(funcBodyRegion, funcBody); + + mlirAttribute funcTypeAttr = mlirAttributeParse( + ctx, "(memref, memref) -> ()"); + mlirAttribute funcNameAttr = mlirAttributeParse(ctx, "\"add\""); + mlirNamedAttribute funcAttrs[] = { + mlirNamedAttributeCreate("type", funcTypeAttr), + mlirNamedAttributeCreate("sym_name", funcNameAttr)}; + mlirOperation func = mlirOperationCreate( + "func", location, /*nResults=*/0, /*results=*/NULL, + /*nOperands=*/0, /*operands=*/NULL, + sizeof(funcAttrs) / sizeof(mlirNamedAttribute), funcAttrs, + /*nRegions=*/1, &funcBodyRegion, /*nSuccessors=*/0, + /*successors=*/NULL); + mlirBlockInsertOperation(moduleBody, 0, func); + + mlirType indexType = mlirTypeParse(ctx, "index"); + mlirAttribute indexZeroLiteral = mlirAttributeParse(ctx, "0 : index"); + mlirNamedAttribute indexZeroValueAttr = + mlirNamedAttributeCreate("value", indexZeroLiteral); + mlirOperation constZero = mlirOperationCreate( + "std.constant", location, /*nResults=*/1, &indexType, /*nOperands=*/0, + /*operands=*/NULL, /*nAttributes=*/1, &indexZeroValueAttr, /*nRegions=*/0, + /*regions=*/NULL, + /*nSuccessors=*/0, /*successors=*/0); + mlirBlockAppendOperation(funcBody, constZero); + + mlirValue funcArg0 = mlirBlockGetArgument(funcBody, 0); + mlirValue constZeroValue = mlirOperationGetResult(constZero, 0); + mlirValue dimOperands[] = { funcArg0, constZeroValue }; + mlirOperation dim = + mlirOperationCreate("std.dim", location, /*nResults=*/1, &indexType, + sizeof(dimOperands) / sizeof(mlirValue), dimOperands, + /*nAttributes=*/0, NULL, /*nRegions=*/0, + /*regions=*/NULL, + /*nSuccessors=*/0, /*successors=*/0); + mlirBlockAppendOperation(funcBody, dim); + + mlirRegion loopBodyRegion = mlirRegionCreate(); + mlirBlock loopBody = mlirBlockCreate(/*nArgs=*/1, &indexType); + mlirRegionAppendBlock(loopBodyRegion, loopBody); + + mlirAttribute indexOneLiteral = mlirAttributeParse(ctx, "1 : index"); + mlirNamedAttribute indexOneValueAttr = + mlirNamedAttributeCreate("value", indexOneLiteral); + mlirOperation constOne = mlirOperationCreate( + "std.constant", location, /*nResults=*/1, &indexType, /*nOperands=*/0, + /*operands=*/NULL, /*nAttributes=*/1, &indexOneValueAttr, /*nRegions=*/0, + /*regions=*/NULL, + /*nSuccessors=*/0, /*successors=*/0); + mlirBlockAppendOperation(funcBody, constOne); + + mlirValue dimValue = mlirOperationGetResult(dim, 0); + mlirValue constOneValue = mlirOperationGetResult(constOne, 0); + mlirValue loopOperands[] = { constZeroValue, dimValue, constOneValue }; + mlirOperation loop = mlirOperationCreate( + "scf.for", location, /*nResults=*/0, /*results=*/NULL, + sizeof(loopOperands) / sizeof(mlirValue), loopOperands, + /*nAttributes=*/0, /*attributes=*/NULL, + /*nRegions=*/1, &loopBodyRegion, /*nSuccessors=*/0, /*successors=*/NULL); + mlirBlockAppendOperation(funcBody, loop); + + populateLoopBody(ctx, loopBody, location, funcBody); + + mlirOperation ret = + 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, ret); + + 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); + + mlirModule 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)