Skip to content

Commit 74f5778

Browse files
committed
[mlir] expose standard types to C API
Provide C API for MLIR standard types. Since standard types live under lib/IR in core MLIR, place the C APIs in the IR library as well (standard ops will go into a separate library). This also defines a placeholder for affine maps that are necessary to construct a memref, but are not yet exposed to the C API. Reviewed By: stellaraccident Differential Revision: https://reviews.llvm.org/D86094
1 parent 9f63dc3 commit 74f5778

File tree

13 files changed

+886
-45
lines changed

13 files changed

+886
-45
lines changed

mlir/docs/CAPI.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,28 @@ check if an object is null by using `mlirXIsNull(MlirX)`. API functions do _not_
7575
expect null objects as arguments unless explicitly stated otherwise. API
7676
functions _may_ return null objects.
7777

78+
### Type Hierarchies
79+
80+
MLIR objects can form type hierarchies in C++. For example, all IR classes
81+
representing types are derived from `mlir::Type`, some of them may also be also
82+
derived from common base classes such as `mlir::ShapedType` or dialect-specific
83+
base classes. Type hierarchies are exposed to C API through naming conventions
84+
as follows.
85+
86+
- Only the top-level class of each hierarchy is exposed, e.g. `MlirType` is
87+
defined as a type but `MlirShapedType` is not. This avoids the need for
88+
explicit upcasting when passing an object of a derived type to a function
89+
that expects a base type (this happens more often in core/standard APIs,
90+
while downcasting usually involves further checks anyway).
91+
- A type `Y` that derives from `X` provides a function `int mlirXIsAY(MlirX)`
92+
that returns a non-zero value if the given dynamic instance of `X` is also
93+
an instance of `Y`. For example, `int MlirTypeIsAInteger(MlirType)`.
94+
- A function that expects a derived type as its first argument takes the base
95+
type instead and documents the expectation by using `Y` in its name
96+
`MlirY<...>(MlirX, ...)`. This function asserts that the dynamic instance of
97+
its first argument is `Y`, and it is the responsibility of the caller to
98+
ensure it is indeed the case.
99+
78100
### Conversion To String and Printing
79101

80102
IR objects can be converted to a string representation, for example for
@@ -96,11 +118,11 @@ allocation and avoid unnecessary allocation and copying inside the printer.
96118
For convenience, `mlirXDump(MlirX)` functions are provided to print the given
97119
object to the standard error stream.
98120

99-
### Common Patterns
121+
## Common Patterns
100122

101123
The API adopts the following patterns for recurrent functionality in MLIR.
102124

103-
#### Indexed Components
125+
### Indexed Components
104126

105127
An object has an _indexed component_ if it has fields accessible using a
106128
zero-based contiguous integer index, typically arrays. For example, an
@@ -120,7 +142,7 @@ Note that the name of subobject in the function does not necessarily match the
120142
type of the subobject. For example, `mlirOperationGetOperand` returns a
121143
`MlirValue`.
122144

123-
#### Iterable Components
145+
### Iterable Components
124146

125147
An object has an _iterable component_ if it has iterators accessing its fields
126148
in some order other than integer indexing, typically linked lists. For example,
@@ -146,3 +168,17 @@ for (iter = mlirXGetFirst<Y>(x); !mlirYIsNull(iter);
146168
/* User 'iter'. */
147169
}
148170
```
171+
172+
## Extending the API
173+
174+
### Extensions for Dialect Attributes and Types
175+
176+
Dialect attributes and types can follow the example of standard attrbutes and
177+
types, provided that implementations live in separate directories, i.e.
178+
`include/mlir-c/<...>Dialect/` and `lib/CAPI/<...>Dialect/`. The core APIs
179+
provide implementation-private headers in `include/mlir/CAPI/IR` that allow one
180+
to convert between opaque C structures for core IR components and their C++
181+
counterparts. `wrap` converts a C++ class into a C structure and `unwrap` does
182+
the inverse conversion. Once the a C++ object is available, the API
183+
implementation should rely on `isa` to implement `mlirXIsAY` and is expected to
184+
use `cast` inside other API calls.

mlir/include/mlir-c/AffineMap.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*===-- mlir-c/AffineMap.h - C API for MLIR Affine maps -----------*- C -*-===*\
2+
|* *|
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4+
|* Exceptions. *|
5+
|* See https://llvm.org/LICENSE.txt for license information. *|
6+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7+
|* *|
8+
\*===----------------------------------------------------------------------===*/
9+
10+
#ifndef MLIR_C_AFFINEMAP_H
11+
#define MLIR_C_AFFINEMAP_H
12+
13+
#include "mlir-c/IR.h"
14+
15+
#ifdef __cplusplus
16+
extern "C" {
17+
#endif
18+
19+
DEFINE_C_API_STRUCT(MlirAffineMap, const void);
20+
21+
#ifdef __cplusplus
22+
}
23+
#endif
24+
25+
#endif // MLIR_C_AFFINEMAP_H

mlir/include/mlir-c/IR.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ DEFINE_C_API_STRUCT(MlirType, const void);
5656
DEFINE_C_API_STRUCT(MlirLocation, const void);
5757
DEFINE_C_API_STRUCT(MlirModule, const void);
5858

59-
#undef DEFINE_C_API_STRUCT
60-
6159
/** Named MLIR attribute.
6260
*
6361
* A named attribute is essentially a (name, attribute) pair where the name is
@@ -314,6 +312,9 @@ void mlirValuePrint(MlirValue value, MlirPrintCallback callback,
314312
/** Parses a type. The type is owned by the context. */
315313
MlirType mlirTypeParseGet(MlirContext context, const char *type);
316314

315+
/** Checks if two types are equal. */
316+
int mlirTypeEqual(MlirType t1, MlirType t2);
317+
317318
/** Prints a location by sending chunks of the string representation and
318319
* forwarding `userData to `callback`. Note that the callback may be called
319320
* several times with consecutive chunks of the string. */

mlir/include/mlir-c/StandardTypes.h

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/*===-- mlir-c/StandardTypes.h - C API for MLIR Standard types ----*- C -*-===*\
2+
|* *|
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4+
|* Exceptions. *|
5+
|* See https://llvm.org/LICENSE.txt for license information. *|
6+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7+
|* *|
8+
\*===----------------------------------------------------------------------===*/
9+
10+
#ifndef MLIR_C_STANDARDTYPES_H
11+
#define MLIR_C_STANDARDTYPES_H
12+
13+
#include "mlir-c/AffineMap.h"
14+
#include "mlir-c/IR.h"
15+
#include <stdint.h>
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
/*============================================================================*/
22+
/* Integer types. */
23+
/*============================================================================*/
24+
25+
/** Checks whether the given type is an integer type. */
26+
int mlirTypeIsAInteger(MlirType type);
27+
28+
/** Creates a signless integer type of the given bitwidth in the context. The
29+
* type is owned by the context. */
30+
MlirType mlirIntegerTypeGet(MlirContext ctx, unsigned bitwidth);
31+
32+
/** Creates a signed integer type of the given bitwidth in the context. The type
33+
* is owned by the context. */
34+
MlirType mlirIntegerTypeSignedGet(MlirContext ctx, unsigned bitwidth);
35+
36+
/** Creates an unsigned integer type of the given bitwidth in the context. The
37+
* type is owned by the context. */
38+
MlirType mlirIntegerTypeUnsignedGet(MlirContext ctx, unsigned bitwidth);
39+
40+
/** Returns the bitwidth of an integer type. */
41+
unsigned mlirIntegerTypeGetWidth(MlirType type);
42+
43+
/** Checks whether the given integer type is signless. */
44+
int mlirIntegerTypeIsSignless(MlirType type);
45+
46+
/** Checks whether the given integer type is signed. */
47+
int mlirIntegerTypeIsSigned(MlirType type);
48+
49+
/** Checks whether the given integer type is unsigned. */
50+
int mlirIntegerTypeIsUnsigned(MlirType type);
51+
52+
/*============================================================================*/
53+
/* Index type. */
54+
/*============================================================================*/
55+
56+
/** Checks whether the given type is an index type. */
57+
int mlirTypeIsAIndex(MlirType type);
58+
59+
/** Creates an index type in the given context. The type is owned by the
60+
* context. */
61+
MlirType mlirIndexTypeGet(MlirContext ctx);
62+
63+
/*============================================================================*/
64+
/* Floating-point types. */
65+
/*============================================================================*/
66+
67+
/** Checks whether the given type is a bf16 type. */
68+
int mlirTypeIsABF16(MlirType type);
69+
70+
/** Creates a bf16 type in the given context. The type is owned by the
71+
* context. */
72+
MlirType mlirBF16TypeGet(MlirContext ctx);
73+
74+
/** Checks whether the given type is an f16 type. */
75+
int mlirTypeIsAF16(MlirType type);
76+
77+
/** Creates an f16 type in the given context. The type is owned by the
78+
* context. */
79+
MlirType mlirF16TypeGet(MlirContext ctx);
80+
81+
/** Checks whether the given type is an f32 type. */
82+
int mlirTypeIsAF32(MlirType type);
83+
84+
/** Creates an f32 type in the given context. The type is owned by the
85+
* context. */
86+
MlirType mlirF32TypeGet(MlirContext ctx);
87+
88+
/** Checks whether the given type is an f64 type. */
89+
int mlirTypeIsAF64(MlirType type);
90+
91+
/** Creates a f64 type in the given context. The type is owned by the
92+
* context. */
93+
MlirType mlirF64TypeGet(MlirContext ctx);
94+
95+
/*============================================================================*/
96+
/* None type. */
97+
/*============================================================================*/
98+
99+
/** Checks whether the given type is a None type. */
100+
int mlirTypeIsANone(MlirType type);
101+
102+
/** Creates a None type in the given context. The type is owned by the
103+
* context. */
104+
MlirType mlirNoneTypeGet(MlirContext ctx);
105+
106+
/*============================================================================*/
107+
/* Complex type. */
108+
/*============================================================================*/
109+
110+
/** Checks whether the given type is a Complex type. */
111+
int mlirTypeIsAComplex(MlirType type);
112+
113+
/** Creates a complex type with the given element type in the same context as
114+
* the element type. The type is owned by the context. */
115+
MlirType mlirComplexTypeGet(MlirType elementType);
116+
117+
/** Returns the element type of the given complex type. */
118+
MlirType mlirComplexTypeGetElementType(MlirType type);
119+
120+
/*============================================================================*/
121+
/* Shaped type. */
122+
/*============================================================================*/
123+
124+
/** Checks whether the given type is a Shaped type. */
125+
int mlirTypeIsAShaped(MlirType type);
126+
127+
/** Returns the element type of the shaped type. */
128+
MlirType mlirShapedTypeGetElementType(MlirType type);
129+
130+
/** Checks whether the given shaped type is ranked. */
131+
int mlirShapedTypeHasRank(MlirType type);
132+
133+
/** Returns the rank of the given ranked shaped type. */
134+
int64_t mlirShapedTypeGetRank(MlirType type);
135+
136+
/** Checks whether the given shaped type has a static shape. */
137+
int mlirShapedTypeHasStaticShape(MlirType type);
138+
139+
/** Checks wither the dim-th dimension of the given shaped type is dynamic. */
140+
int mlirShapedTypeIsDynamicDim(MlirType type, intptr_t dim);
141+
142+
/** Returns the dim-th dimension of the given ranked shaped type. */
143+
int64_t mlirShapedTypeGetDimSize(MlirType type, intptr_t dim);
144+
145+
/** Checks whether the given value is used as a placeholder for dynamic sizes
146+
* in shaped types. */
147+
int mlirShapedTypeIsDynamicSize(int64_t size);
148+
149+
/** Checks whether the given value is used as a placeholder for dynamic strides
150+
* and offsets in shaped types. */
151+
int mlirShapedTypeIsDynamicStrideOrOffset(int64_t val);
152+
153+
/*============================================================================*/
154+
/* Vector type. */
155+
/*============================================================================*/
156+
157+
/** Checks whether the given type is a Vector type. */
158+
int mlirTypeIsAVector(MlirType type);
159+
160+
/** Creates a vector type of the shape identified by its rank and dimensios,
161+
* with the given element type in the same context as the element type. The type
162+
* is owned by the context. */
163+
MlirType mlirVectorTypeGet(intptr_t rank, int64_t *shape, MlirType elementType);
164+
165+
/*============================================================================*/
166+
/* Ranked / Unranked Tensor type. */
167+
/*============================================================================*/
168+
169+
/** Checks whether the given type is a Tensor type. */
170+
int mlirTypeIsATensor(MlirType type);
171+
172+
/** Checks whether the given type is a ranked tensor type. */
173+
int mlirTypeIsARankedTensor(MlirType type);
174+
175+
/** Checks whether the given type is an unranked tensor type. */
176+
int mlirTypeIsAUnrankedTensor(MlirType type);
177+
178+
/** Creates a tensor type of a fixed rank with the given shape and element type
179+
* in the same context as the element type. The type is owned by the context. */
180+
MlirType mlirRankedTensorTypeGet(intptr_t rank, int64_t *shape,
181+
MlirType elementType);
182+
183+
/** Creates an unranked tensor type with the given element type in the same
184+
* context as the element type. The type is owned by the context. */
185+
MlirType mlirUnrankedTensorTypeGet(MlirType elementType);
186+
187+
/*============================================================================*/
188+
/* Ranked / Unranked MemRef type. */
189+
/*============================================================================*/
190+
191+
/** Checks whether the given type is a MemRef type. */
192+
int mlirTypeIsAMemRef(MlirType type);
193+
194+
/** Checks whether the given type is an UnrankedMemRef type. */
195+
int mlirTypeIsAUnrankedMemRef(MlirType type);
196+
197+
/** Creates a MemRef type with the given rank and shape, a potentially empty
198+
* list of affine layout maps, the given memory space and element type, in the
199+
* same context as element type. The type is owned by the context. */
200+
MlirType mlirMemRefTypeGet(MlirType elementType, intptr_t rank, int64_t *shape,
201+
intptr_t numMaps, MlirAttribute *affineMaps,
202+
unsigned memorySpace);
203+
204+
/** Creates a MemRef type with the given rank, shape, memory space and element
205+
* type in the same context as the element type. The type has no affine maps,
206+
* i.e. represents a default row-major contiguous memref. The type is owned by
207+
* the context. */
208+
MlirType mlirMemRefTypeContiguousGet(MlirType elementType, intptr_t rank,
209+
int64_t *shape, unsigned memorySpace);
210+
211+
/** Creates an Unranked MemRef type with the given element type and in the given
212+
* memory space. The type is owned by the context of element type. */
213+
MlirType mlirUnrankedMemRefTypeGet(MlirType elementType, unsigned memorySpace);
214+
215+
/** Returns the number of affine layout maps in the given MemRef type. */
216+
intptr_t mlirMemRefTypeGetNumAffineMaps(MlirType type);
217+
218+
/** Returns the pos-th affine map of the given MemRef type. */
219+
MlirAffineMap mlirMemRefTypeGetAffineMap(MlirType type, intptr_t pos);
220+
221+
/** Returns the memory space of the given MemRef type. */
222+
unsigned mlirMemRefTypeGetMemorySpace(MlirType type);
223+
224+
/** Returns the memory spcae of the given Unranked MemRef type. */
225+
unsigned mlirUnrankedMemrefGetMemorySpace(MlirType type);
226+
227+
/*============================================================================*/
228+
/* Tuple type. */
229+
/*============================================================================*/
230+
231+
/** Checks whether the given type is a tuple type. */
232+
int mlirTypeIsATuple(MlirType type);
233+
234+
/** Creates a tuple type that consists of the given list of elemental types. The
235+
* type is owned by the context. */
236+
MlirType mlirTupleTypeGet(MlirContext ctx, intptr_t numElements,
237+
MlirType *elements);
238+
239+
/** Returns the number of types contained in a tuple. */
240+
intptr_t mlirTupleTypeGetNumTypes(MlirType type);
241+
242+
/** Returns the pos-th type in the tuple type. */
243+
MlirType mlirTupleTypeGetType(MlirType type, intptr_t pos);
244+
245+
#ifdef __cplusplus
246+
}
247+
#endif
248+
249+
#endif // MLIR_C_STANDARDTYPES_H

mlir/include/mlir/CAPI/AffineMap.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===- AffineMap.h - C API Utils for Affine Maps ----------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains declarations of implementation details of the C API for
10+
// MLIR Affine maps. This file should not be included from C++ code other than
11+
// C API implementation nor from C code.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef MLIR_CAPI_AFFINEMAP_H
16+
#define MLIR_CAPI_AFFINEMAP_H
17+
18+
#include "mlir-c/AffineMap.h"
19+
#include "mlir/CAPI/Wrap.h"
20+
#include "mlir/IR/AffineMap.h"
21+
22+
DEFINE_C_API_METHODS(MlirAffineMap, mlir::AffineMap)
23+
24+
#endif // MLIR_CAPI_AFFINEMAP_H

0 commit comments

Comments
 (0)