blob: 6adb9db3331c5acfe36496fdc0512d483790309a [file] [log] [blame] [view]
Alex Zinenko75f239e2020-08-05 12:36:161# MLIR C API
2
3**Current status: Under development, API unstable, built by default.**
4
5## Design
6
7Many languages can interoperate with C but have a harder time with C++ due to
8name mangling and memory model differences. Although the C API for MLIR can be
9used directly from C, it is primarily intended to be wrapped in higher-level
10language- or library-specific constructs. Therefore the API tends towards
11simplicity and feature minimalism.
12
13**Note:** while the C API is expected to be more stable than C++ API, it
14currently offers no stability guarantees.
15
16### Scope
17
18The API is provided for core IR components (attributes, blocks, operations,
19regions, types, values), Passes and some fundamental type and attribute kinds.
20The core IR API is intentionally low-level, e.g. exposes a plain list of
21operation's operands and attributes without attempting to assign "semantic"
22names to them. Users of specific dialects are expected to wrap the core API in a
23dialect-specific way, for example, by implementing an ODS backend.
24
25### Object Model
26
27Core IR components are exposed as opaque _handles_ to an IR object existing in
28C++. They are not intended to be inspected by the API users (and, in many cases,
29cannot be meaningfully inspected). Instead the users are expected to pass
30handles to the appropriate manipulation functions.
31
32The handle _may or may not_ own the underlying object.
33
34### Naming Convention and Ownership Model
35
36All objects are prefixed with `Mlir`. They are typedefs and should be used
37without `struct`.
38
39All functions are prefixed with `mlir`.
40
41Functions primarily operating on an instance of `MlirX` are prefixed with
42`mlirX`. They take the instance being acted upon as their first argument (except
43for creation functions). For example, `mlirOperationGetNumOperands` inspects an
44`MlirOperation`, which it takes as its first operand.
45
46The *ownership* model is encoded in the naming convention as follows.
47
48- By default, the ownership is not transerred.
49- Functions that tranfer the ownership of the result to the caller can be in
50 one of two forms:
51 * functions that create a new object have the name `mlirXCreate<...>`, for
52 example, `mlirOperationCreate`;
53 * functions that detach an object from a parent object have the name
54 `mlirYTake<...>`, for example `mlirOperationStateTakeRegion`.
55- Functions that take ownership of some of their arguments have the form
56 `mlirY<...>OwnedX<...>` where `X` can refer to the type or any other
57 sufficiently unique description of the argument, the ownership of which will
58 be taken by the callee, for example `mlirRegionAppendOwnedBlock`.
59- Functions that create an object by default do not transfer its ownership to
60 the caller, i.e. one of other objects passed in as an argument retains the
61 ownership, they have the form `mlirX<...>Get`. For example,
62 `mlirTypeParseGet`.
63- Functions that destroy an object owned by the caller are of the form
64 `mlirXDestroy`.
65
66If the code owns an object, it is responsible for destroying the object when it
67is no longer necessary. If an object that owns other objects is destroyed, any
68handles to those objects become invalid. Note that types and attributes are
69owned by the `MlirContext` in which they were created.
70
71### Nullity
72
73A handle may refer to a _null_ object. It is the responsibility of the caller to
Alex Zinenko321aa192020-08-11 16:25:0974check if an object is null by using `mlirXIsNull(MlirX)`. API functions do _not_
Alex Zinenko75f239e2020-08-05 12:36:1675expect null objects as arguments unless explicitly stated otherwise. API
76functions _may_ return null objects.
77
Alex Zinenko321aa192020-08-11 16:25:0978### Conversion To String and Printing
79
80IR objects can be converted to a string representation, for example for
81printing, using `mlirXPrint(MlirX, MlirPrintCallback, void *)` functions. These
82functions accept take arguments a callback with signature `void (*)(const char
83*, intptr_t, void *)` and a pointer to user-defined data. They call the callback
84and supply it with chunks of the string representation, provided as a pointer to
85the first character and a length, and forward the user-defined data unmodified.
86It is up to the caller to allocate memory if the string representation must be
87stored and perform the copy. There is no guarantee that the pointer supplied to
88the callback points to a null-terminated string, the size argument should be
89used to find the end of the string. The callback may be called multiple times
90with consecutive chunks of the string representation (the printing itself is
91bufferred).
92
93*Rationale*: this approach allows the caller to have full control of the
94allocation and avoid unnecessary allocation and copying inside the printer.
95
96For convenience, `mlirXDump(MlirX)` functions are provided to print the given
97object to the standard error stream.
98
Alex Zinenko75f239e2020-08-05 12:36:1699### Common Patterns
100
101The API adopts the following patterns for recurrent functionality in MLIR.
102
103#### Indexed Components
104
105An object has an _indexed component_ if it has fields accessible using a
106zero-based contiguous integer index, typically arrays. For example, an
107`MlirBlock` has its arguments as a indexed component. An object may have several
108such components. For example, an `MlirOperation` has attributes, operands,
109regions, results and successors.
110
111For indexed components, the following pair of functions is provided.
112
Alex Zinenkoaf838582020-08-11 16:34:32113- `intptr_t mlirXGetNum<Y>s(MlirX)` returns the upper bound on the index.
114- `MlirY mlirXGet<Y>(MlirX, intptr_t pos)` returns 'pos'-th subobject.
115
116The sizes are accepted and returned as signed pointer-sized integers, i.e.
117`intptr_t`. This typedef is avalable in C99.
Alex Zinenko75f239e2020-08-05 12:36:16118
119Note that the name of subobject in the function does not necessarily match the
120type of the subobject. For example, `mlirOperationGetOperand` returns a
121`MlirValue`.
122
123#### Iterable Components
124
125An object has an _iterable component_ if it has iterators accessing its fields
126in some order other than integer indexing, typically linked lists. For example,
127an `MlirBlock` has an iterable list of operations it contains. An object may
128have several iterable components.
129
130For iterable components, the following triple of functions is provided.
131
132- `MlirY mlirXGetFirst<Y>(MlirX)` returns the first subobject in the list.
133- `MlirY mlirYGetNextIn<X>(MlirY)` returns the next subobject in the list that
134 contains the given object, or a null object if the given object is the last
135 in this list.
136- `int mlirYIsNull(MlirY)` returns 1 if the given object is null.
137
138Note that the name of subobject in the function may or may not match its type.
139
140This approach enables one to iterate as follows.
141
142```c++
143MlirY iter;
144for (iter = mlirXGetFirst<Y>(x); !mlirYIsNull(iter);
145 iter = mlirYGetNextIn<X>(iter)) {
146 /* User 'iter'. */
147}
148```