diff --git a/mlir/docs/CAPI.md b/mlir/docs/CAPI.md --- a/mlir/docs/CAPI.md +++ b/mlir/docs/CAPI.md @@ -97,37 +97,32 @@ its first argument is `Y`, and it is the responsibility of the caller to ensure it is indeed the case. -### Returning String References +### Auxiliary Types + +#### `StringRef` Numerous MLIR functions return instances of `StringRef` to refer to a non-owning segment of a string. This segment may or may not be null-terminated. In C API, -these functions take an additional callback argument of type -`MlirStringCallback` (pointer to a function with signature `void (*)(const char -*, intptr_t, void *)`) and a pointer to user-defined data. This callback is -invoked with a pointer to the string segment, its size and is forwarded the -user-defined data. The caller is in charge of managing the string segment -according to its memory model: for strings owned by the object (e.g., string -attributes), the caller can store the pointer and the size and use them directly -as long as the parent object is live or copy the string to a new location with a -null terminator if expected; for generated strings (e.g., in printing), the -caller is expected to copy the string segment if it intends to use it later. - -**Note:** this interface may be revised in the near future. - -### Conversion To String and Printing - -IR objects can be converted to a string representation, for example for -printing, using `mlirXPrint(MlirX, MlirStringCallback, void *)` functions. These -functions accept take arguments a callback with signature `void (*)(const char -*, intptr_t, void *)` and a pointer to user-defined data. They call the callback -and supply it with chunks of the string representation, provided as a pointer to -the first character and a length, and forward the user-defined data unmodified. -It is up to the caller to allocate memory if the string representation must be -stored and perform the copy. There is no guarantee that the pointer supplied to -the callback points to a null-terminated string, the size argument should be -used to find the end of the string. The callback may be called multiple times -with consecutive chunks of the string representation (the printing itself is -buffered). +these are represented as instances of `MlirStringRef` structure that contains a +pointer to the first character of the string fragment (`str`) and the fragment +length (`length`). Note that the fragment is _not necessarily_ null-terminated, +the `length` field must be used to identify the last character. `MlirStringRef` +is a non-owning pointer, the caller is in charge of perfoming the copy or +ensuring that the pointee outlives all uses of `MlirStringRef`. + +### Printing + +IR objects can be printed using `mlirXPrint(MlirX, MlirStringCallback, void *)` +functions. These functions accept take arguments a callback with signature `void +(*)(const char *, intptr_t, void *)` and a pointer to user-defined data. They +call the callback and supply it with chunks of the string representation, +provided as a pointer to the first character and a length, and forward the +user-defined data unmodified. It is up to the caller to allocate memory if the +string representation must be stored and perform the copy. There is no guarantee +that the pointer supplied to the callback points to a null-terminated string, +the size argument should be used to find the end of the string. The callback may +be called multiple times with consecutive chunks of the string representation +(the printing itself is buffered). *Rationale*: this approach allows the caller to have full control of the allocation and avoid unnecessary allocation and copying inside the printer. diff --git a/mlir/include/mlir-c/StandardAttributes.h b/mlir/include/mlir-c/StandardAttributes.h --- a/mlir/include/mlir-c/StandardAttributes.h +++ b/mlir/include/mlir-c/StandardAttributes.h @@ -16,6 +16,7 @@ #include "mlir-c/AffineMap.h" #include "mlir-c/IR.h" +#include "mlir-c/Support.h" #ifdef __cplusplus extern "C" { @@ -152,13 +153,9 @@ * is associated. The namespace string is owned by the context. */ const char *mlirOpaqueAttrGetDialectNamespace(MlirAttribute attr); -/** Calls the provided callback with the opaque byte data stored in the given - * opaque attribute. The callback is invoked once, and the data it receives is - * not necessarily null terminated. The data remains live as long as the context - * in which the attribute lives. */ -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirOpaqueAttrGetData(MlirAttribute attr, MlirStringCallback callback, - void *userData); +/** Returns the raw data as a string reference. The data remains live as long as + * the context in which the attribute lives. */ +MlirStringRef mlirOpaqueAttrGetData(MlirAttribute attr); /*============================================================================*/ /* String attribute. */ @@ -178,13 +175,9 @@ MlirAttribute mlirStringAttrTypedGet(MlirType type, intptr_t length, const char *data); -/** Calls the provided callback with the string stored in the given string - * attribute. The callback is invoked once, and the data it receives is not - * necessarily null terminated. The data remains live as long as the context in - * which the attribute lives. */ -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirStringAttrGetValue(MlirAttribute attr, MlirStringCallback callback, - void *userData); +/** Returns the attribute values as a string reference. The data remains live as + * long as the context in which the attribute lives. */ +MlirStringRef mlirStringAttrGetValue(MlirAttribute attr); /*============================================================================*/ /* SymbolRef attribute. */ @@ -201,23 +194,13 @@ const char *symbol, intptr_t numReferences, MlirAttribute *references); -/** Calls the provided callback with the string containing the root referenced - * symbol. The callback is invoked once, and the data it receives is not - * necessarily null terminated. The data remains live as long as the context in - * which the attribute lives. */ -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirSymbolRefAttrGetRootReference(MlirAttribute attr, - MlirStringCallback callback, - void *userData); - -/** Calls the provided callback with the string containing the leaf referenced - * symbol. The callback is invoked once, and the data it receives is not - * necessarily null terminated. The data remains live as long as the context in - * which the attribute lives. */ -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirSymbolRefAttrGetLeafReference(MlirAttribute attr, - MlirStringCallback callback, - void *userData); +/** Returns the string reference to the root referenced symbol. The data remains + * live as long as the context in which the attribute lives. */ +MlirStringRef mlirSymbolRefAttrGetRootReference(MlirAttribute attr); + +/** Returns the stirng reference to the leaf referenced symbol. The data remains + * live as long as the context in which the attribute lives. */ +MlirStringRef mlirSymbolRefAttrGetLeafReference(MlirAttribute attr); /** Returns the number of references nested in the given symbol reference * attribute. */ @@ -240,14 +223,9 @@ MlirAttribute mlirFlatSymbolRefAttrGet(MlirContext ctx, intptr_t length, const char *symbol); -/** Calls the provided callback with the string containing the referenced - * symbol. The callback is invoked once, and the data it receives is not - * necessarily null terminated. The data remains live as long as the context in - * which the attribute lives. */ -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirFloatSymbolRefAttrGetValue(MlirAttribute attr, - MlirStringCallback callback, - void *userData); +/** Returns the referenced symbol as a string reference. The data remains live + * as long as the context in which the attribute lives. */ +MlirStringRef mlirFlatSymbolRefAttrGetValue(MlirAttribute attr); /*============================================================================*/ /* Type attribute. */ @@ -383,10 +361,7 @@ uint64_t mlirDenseElementsAttrGetUInt64SplatValue(MlirAttribute attr); float mlirDenseElementsAttrGetFloatSplatValue(MlirAttribute attr); double mlirDenseElementsAttrGetDoubleSplatValue(MlirAttribute attr); -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirDenseElementsAttrGetStringSplatValue(MlirAttribute attr, - MlirStringCallback callback, - void *userData); +MlirStringRef mlirDenseElementsAttrGetStringSplatValue(MlirAttribute attr); /** Returns the pos-th value (flat contiguous indexing) of a specific type * contained by the given dense elements attribute. */ @@ -397,10 +372,8 @@ uint64_t mlirDenseElementsAttrGetUInt64Value(MlirAttribute attr, intptr_t pos); float mlirDenseElementsAttrGetFloatValue(MlirAttribute attr, intptr_t pos); double mlirDenseElementsAttrGetDoubleValue(MlirAttribute attr, intptr_t pos); -/* TODO: consider exposing StringRef and using it instead of the callback. */ -void mlirDenseElementsAttrGetStringValue(MlirAttribute attr, intptr_t pos, - MlirStringCallback callback, - void *userData); +MlirStringRef mlirDenseElementsAttrGetStringValue(MlirAttribute attr, + intptr_t pos); /*============================================================================*/ /* Opaque elements attribute. */ diff --git a/mlir/include/mlir-c/Support.h b/mlir/include/mlir-c/Support.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir-c/Support.h @@ -0,0 +1,57 @@ +/*===-- mlir-c/Support.h - Helpers for C API to Core MLIR ---------*- 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the auxiliary data structures used in C APIs to core *| +|* MLIR functionality. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef MLIR_C_SUPPORT_H +#define MLIR_C_SUPPORT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MlirStringRef. */ +/*============================================================================*/ + +/** A pointer to a sized fragment of a string, not necessarily null-terminated. + * Does not own the underlying string. This is equivalent to llvm::StringRef. + */ +struct MlirStringRef { + const char *data; /**< Pointer to the first symbol. */ + size_t length; /**< Length of the fragment. */ +}; +typedef struct MlirStringRef MlirStringRef; + +/** Constructs a string reference from the pointer and length. The pointer need + * not reference to a null-terminated string. + */ +inline MlirStringRef mlirStringRefCreate(const char *str, size_t length) { + MlirStringRef result; + result.data = str; + result.length = length; + return result; +} + +/** Constructs a string reference from a null-terminated C string. Prefer + * mlirStringRefCreate if the length of the string is known. + */ +MlirStringRef mlirStringRefCreateFromCString(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif // MLIR_C_SUPPORT_H diff --git a/mlir/include/mlir/CAPI/Support.h b/mlir/include/mlir/CAPI/Support.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/CAPI/Support.h @@ -0,0 +1,31 @@ +//===- Support.h - C API Helpers Implementation -----------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains definitions for converting MLIR C++ objects into helper +// C structures for the purpose of C API. This file should not be included from +// C++ code other than C API implementation nor from C code. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_CAPI_SUPPORT_H +#define MLIR_CAPI_SUPPORT_H + +#include "mlir-c/Support.h" +#include "llvm/ADT/StringRef.h" + +/// Converts a StringRef into its MLIR C API equivalent. +inline MlirStringRef wrap(llvm::StringRef ref) { + return mlirStringRefCreate(ref.data(), ref.size()); +} + +/// Creates a StringRef out of its MLIR C API equivalent. +inline llvm::StringRef unwrap(MlirStringRef ref) { + return llvm::StringRef(ref.data, ref.length); +} + +#endif // MLIR_CAPI_SUPPORT_H diff --git a/mlir/lib/Bindings/Python/IRModules.cpp b/mlir/lib/Bindings/Python/IRModules.cpp --- a/mlir/lib/Bindings/Python/IRModules.cpp +++ b/mlir/lib/Bindings/Python/IRModules.cpp @@ -285,10 +285,8 @@ c.def_property_readonly( "value", [](PyStringAttribute &self) { - PySinglePartStringAccumulator accum; - mlirStringAttrGetValue(self.attr, accum.getCallback(), - accum.getUserData()); - return accum.takeValue(); + MlirStringRef stringRef = mlirStringAttrGetValue(self.attr); + return py::str(stringRef.data, stringRef.length); }, "Returns the value of the string attribute"); } diff --git a/mlir/lib/CAPI/IR/CMakeLists.txt b/mlir/lib/CAPI/IR/CMakeLists.txt --- a/mlir/lib/CAPI/IR/CMakeLists.txt +++ b/mlir/lib/CAPI/IR/CMakeLists.txt @@ -4,6 +4,7 @@ IR.cpp StandardAttributes.cpp StandardTypes.cpp + Support.cpp EXCLUDE_FROM_LIBMLIR diff --git a/mlir/lib/CAPI/IR/StandardAttributes.cpp b/mlir/lib/CAPI/IR/StandardAttributes.cpp --- a/mlir/lib/CAPI/IR/StandardAttributes.cpp +++ b/mlir/lib/CAPI/IR/StandardAttributes.cpp @@ -9,6 +9,7 @@ #include "mlir-c/StandardAttributes.h" #include "mlir/CAPI/AffineMap.h" #include "mlir/CAPI/IR.h" +#include "mlir/CAPI/Support.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/StandardTypes.h" @@ -165,10 +166,8 @@ return unwrap(attr).cast().getDialectNamespace().c_str(); } -void mlirOpaqueAttrGetData(MlirAttribute attr, MlirStringCallback callback, - void *userData) { - StringRef data = unwrap(attr).cast().getAttrData(); - callback(data.data(), static_cast(data.size()), userData); +MlirStringRef mlirOpaqueAttrGetData(MlirAttribute attr) { + return wrap(unwrap(attr).cast().getAttrData()); } /*============================================================================*/ @@ -189,10 +188,8 @@ return wrap(StringAttr::get(StringRef(data, length), unwrap(type))); } -void mlirStringAttrGetValue(MlirAttribute attr, MlirStringCallback callback, - void *userData) { - StringRef data = unwrap(attr).cast().getValue(); - callback(data.data(), static_cast(data.size()), userData); +MlirStringRef mlirStringAttrGetValue(MlirAttribute attr) { + return wrap(unwrap(attr).cast().getValue()); } /*============================================================================*/ @@ -213,18 +210,12 @@ return wrap(SymbolRefAttr::get(StringRef(symbol, length), refs, unwrap(ctx))); } -void mlirSymbolRefAttrGetRootReference(MlirAttribute attr, - MlirStringCallback callback, - void *userData) { - StringRef ref = unwrap(attr).cast().getRootReference(); - callback(ref.data(), ref.size(), userData); +MlirStringRef mlirSymbolRefAttrGetRootReference(MlirAttribute attr) { + return wrap(unwrap(attr).cast().getRootReference()); } -void mlirSymbolRefAttrGetLeafReference(MlirAttribute attr, - MlirStringCallback callback, - void *userData) { - StringRef ref = unwrap(attr).cast().getLeafReference(); - callback(ref.data(), ref.size(), userData); +MlirStringRef mlirSymbolRefAttrGetLeafReference(MlirAttribute attr) { + return wrap(unwrap(attr).cast().getLeafReference()); } intptr_t mlirSymbolRefAttrGetNumNestedReferences(MlirAttribute attr) { @@ -250,11 +241,8 @@ return wrap(FlatSymbolRefAttr::get(StringRef(symbol, length), unwrap(ctx))); } -void mlirFloatSymbolRefAttrGetValue(MlirAttribute attr, - MlirStringCallback callback, - void *userData) { - StringRef symbol = unwrap(attr).cast().getValue(); - callback(symbol.data(), symbol.size(), userData); +MlirStringRef mlirFlatSymbolRefAttrGetValue(MlirAttribute attr) { + return wrap(unwrap(attr).cast().getValue()); } /*============================================================================*/ @@ -477,12 +465,9 @@ double mlirDenseElementsAttrGetDoubleSplatValue(MlirAttribute attr) { return unwrap(attr).cast().getSplatValue(); } -void mlirDenseElementsAttrGetStringSplatValue(MlirAttribute attr, - MlirStringCallback callback, - void *userData) { - StringRef str = - unwrap(attr).cast().getSplatValue(); - callback(str.data(), str.size(), userData); +MlirStringRef mlirDenseElementsAttrGetStringSplatValue(MlirAttribute attr) { + return wrap( + unwrap(attr).cast().getSplatValue()); } //===----------------------------------------------------------------------===// @@ -518,13 +503,11 @@ return *(unwrap(attr).cast().getValues().begin() + pos); } -void mlirDenseElementsAttrGetStringValue(MlirAttribute attr, intptr_t pos, - MlirStringCallback callback, - void *userData) { - StringRef str = +MlirStringRef mlirDenseElementsAttrGetStringValue(MlirAttribute attr, + intptr_t pos) { + return wrap( *(unwrap(attr).cast().getValues().begin() + - pos); - callback(str.data(), str.size(), userData); + pos)); } /*============================================================================*/ diff --git a/mlir/lib/CAPI/IR/Support.cpp b/mlir/lib/CAPI/IR/Support.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/CAPI/IR/Support.cpp @@ -0,0 +1,15 @@ +//===- Support.cpp - Helpers for C interface to MLIR API ------------------===// +// +// 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/Support.h" + +#include + +MlirStringRef mlirStringRefCreateFromCString(const char *str) { + return mlirStringRefCreate(str, strlen(str)); +} diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c --- a/mlir/test/CAPI/ir.c +++ b/mlir/test/CAPI/ir.c @@ -408,31 +408,36 @@ mlirAttributeDump(boolean); const char data[] = "abcdefghijklmnopqestuvwxyz"; - char buffer[10]; MlirAttribute opaque = mlirOpaqueAttrGet(ctx, "std", 3, data, mlirNoneTypeGet(ctx)); if (!mlirAttributeIsAOpaque(opaque) || strcmp("std", mlirOpaqueAttrGetDialectNamespace(opaque))) return 4; - mlirOpaqueAttrGetData(opaque, callbackSetFixedLengthString, buffer); - if (buffer[0] != 'a' || buffer[1] != 'b' || buffer[2] != 'c') + + MlirStringRef opaqueData = mlirOpaqueAttrGetData(opaque); + if (opaqueData.length != 3 || + strncmp(data, opaqueData.data, opaqueData.length)) return 5; mlirAttributeDump(opaque); MlirAttribute string = mlirStringAttrGet(ctx, 2, data + 3); if (!mlirAttributeIsAString(string)) return 6; - mlirStringAttrGetValue(string, callbackSetFixedLengthString, buffer); - if (buffer[0] != 'd' || buffer[1] != 'e') + + MlirStringRef stringValue = mlirStringAttrGetValue(string); + if (stringValue.length != 2 || + strncmp(data + 3, stringValue.data, stringValue.length)) return 7; mlirAttributeDump(string); MlirAttribute flatSymbolRef = mlirFlatSymbolRefAttrGet(ctx, 3, data + 5); if (!mlirAttributeIsAFlatSymbolRef(flatSymbolRef)) return 8; - mlirFloatSymbolRefAttrGetValue(flatSymbolRef, callbackSetFixedLengthString, - buffer); - if (buffer[0] != 'f' || buffer[1] != 'g' || buffer[2] != 'h') + + MlirStringRef flatSymbolRefValue = + mlirFlatSymbolRefAttrGetValue(flatSymbolRef); + if (flatSymbolRefValue.length != 3 || + strncmp(data + 5, flatSymbolRefValue.data, flatSymbolRefValue.length)) return 9; mlirAttributeDump(flatSymbolRef); @@ -445,12 +450,13 @@ !mlirAttributeEqual(mlirSymbolRefAttrGetNestedReference(symbolRef, 1), flatSymbolRef)) return 10; - mlirSymbolRefAttrGetLeafReference(symbolRef, callbackSetFixedLengthString, - buffer); - mlirSymbolRefAttrGetRootReference(symbolRef, callbackSetFixedLengthString, - buffer + 3); - if (buffer[0] != 'f' || buffer[1] != 'g' || buffer[2] != 'h' || - buffer[3] != 'i' || buffer[4] != 'j') + + MlirStringRef symbolRefLeaf = mlirSymbolRefAttrGetLeafReference(symbolRef); + MlirStringRef symbolRefRoot = mlirSymbolRefAttrGetRootReference(symbolRef); + if (symbolRefLeaf.length != 3 || + strncmp(data + 5, symbolRefLeaf.data, symbolRefLeaf.length) || + symbolRefRoot.length != 2 || + strncmp(data + 8, symbolRefRoot.data, symbolRefRoot.length)) return 11; mlirAttributeDump(symbolRef);