xref: /llvm-project-15.0.7/mlir/test/CAPI/ir.c (revision 4e00a192)
1 //===- ir.c - Simple test of C APIs ---------------------------------------===//
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 /* RUN: mlir-capi-ir-test 2>&1 | FileCheck %s
11  */
12 
13 #include "mlir-c/IR.h"
14 #include "mlir-c/AffineExpr.h"
15 #include "mlir-c/AffineMap.h"
16 #include "mlir-c/BuiltinAttributes.h"
17 #include "mlir-c/BuiltinTypes.h"
18 #include "mlir-c/Diagnostics.h"
19 #include "mlir-c/Dialect/Standard.h"
20 #include "mlir-c/IntegerSet.h"
21 #include "mlir-c/Registration.h"
22 #include "mlir-c/Support.h"
23 
24 #include <assert.h>
25 #include <inttypes.h>
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 void populateLoopBody(MlirContext ctx, MlirBlock loopBody,
32                       MlirLocation location, MlirBlock funcBody) {
33   MlirValue iv = mlirBlockGetArgument(loopBody, 0);
34   MlirValue funcArg0 = mlirBlockGetArgument(funcBody, 0);
35   MlirValue funcArg1 = mlirBlockGetArgument(funcBody, 1);
36   MlirType f32Type =
37       mlirTypeParseGet(ctx, mlirStringRefCreateFromCString("f32"));
38 
39   MlirOperationState loadLHSState = mlirOperationStateGet(
40       mlirStringRefCreateFromCString("memref.load"), location);
41   MlirValue loadLHSOperands[] = {funcArg0, iv};
42   mlirOperationStateAddOperands(&loadLHSState, 2, loadLHSOperands);
43   mlirOperationStateAddResults(&loadLHSState, 1, &f32Type);
44   MlirOperation loadLHS = mlirOperationCreate(&loadLHSState);
45   mlirBlockAppendOwnedOperation(loopBody, loadLHS);
46 
47   MlirOperationState loadRHSState = mlirOperationStateGet(
48       mlirStringRefCreateFromCString("memref.load"), location);
49   MlirValue loadRHSOperands[] = {funcArg1, iv};
50   mlirOperationStateAddOperands(&loadRHSState, 2, loadRHSOperands);
51   mlirOperationStateAddResults(&loadRHSState, 1, &f32Type);
52   MlirOperation loadRHS = mlirOperationCreate(&loadRHSState);
53   mlirBlockAppendOwnedOperation(loopBody, loadRHS);
54 
55   MlirOperationState addState = mlirOperationStateGet(
56       mlirStringRefCreateFromCString("arith.addf"), location);
57   MlirValue addOperands[] = {mlirOperationGetResult(loadLHS, 0),
58                              mlirOperationGetResult(loadRHS, 0)};
59   mlirOperationStateAddOperands(&addState, 2, addOperands);
60   mlirOperationStateAddResults(&addState, 1, &f32Type);
61   MlirOperation add = mlirOperationCreate(&addState);
62   mlirBlockAppendOwnedOperation(loopBody, add);
63 
64   MlirOperationState storeState = mlirOperationStateGet(
65       mlirStringRefCreateFromCString("memref.store"), location);
66   MlirValue storeOperands[] = {mlirOperationGetResult(add, 0), funcArg0, iv};
67   mlirOperationStateAddOperands(&storeState, 3, storeOperands);
68   MlirOperation store = mlirOperationCreate(&storeState);
69   mlirBlockAppendOwnedOperation(loopBody, store);
70 
71   MlirOperationState yieldState = mlirOperationStateGet(
72       mlirStringRefCreateFromCString("scf.yield"), location);
73   MlirOperation yield = mlirOperationCreate(&yieldState);
74   mlirBlockAppendOwnedOperation(loopBody, yield);
75 }
76 
77 MlirModule makeAndDumpAdd(MlirContext ctx, MlirLocation location) {
78   MlirModule moduleOp = mlirModuleCreateEmpty(location);
79   MlirBlock moduleBody = mlirModuleGetBody(moduleOp);
80 
81   MlirType memrefType =
82       mlirTypeParseGet(ctx, mlirStringRefCreateFromCString("memref<?xf32>"));
83   MlirType funcBodyArgTypes[] = {memrefType, memrefType};
84   MlirRegion funcBodyRegion = mlirRegionCreate();
85   MlirBlock funcBody = mlirBlockCreate(
86       sizeof(funcBodyArgTypes) / sizeof(MlirType), funcBodyArgTypes);
87   mlirRegionAppendOwnedBlock(funcBodyRegion, funcBody);
88 
89   MlirAttribute funcTypeAttr = mlirAttributeParseGet(
90       ctx,
91       mlirStringRefCreateFromCString("(memref<?xf32>, memref<?xf32>) -> ()"));
92   MlirAttribute funcNameAttr =
93       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("\"add\""));
94   MlirNamedAttribute funcAttrs[] = {
95       mlirNamedAttributeGet(
96           mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("type")),
97           funcTypeAttr),
98       mlirNamedAttributeGet(
99           mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("sym_name")),
100           funcNameAttr)};
101   MlirOperationState funcState = mlirOperationStateGet(
102       mlirStringRefCreateFromCString("builtin.func"), location);
103   mlirOperationStateAddAttributes(&funcState, 2, funcAttrs);
104   mlirOperationStateAddOwnedRegions(&funcState, 1, &funcBodyRegion);
105   MlirOperation func = mlirOperationCreate(&funcState);
106   mlirBlockInsertOwnedOperation(moduleBody, 0, func);
107 
108   MlirType indexType =
109       mlirTypeParseGet(ctx, mlirStringRefCreateFromCString("index"));
110   MlirAttribute indexZeroLiteral =
111       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("0 : index"));
112   MlirNamedAttribute indexZeroValueAttr = mlirNamedAttributeGet(
113       mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("value")),
114       indexZeroLiteral);
115   MlirOperationState constZeroState = mlirOperationStateGet(
116       mlirStringRefCreateFromCString("arith.constant"), location);
117   mlirOperationStateAddResults(&constZeroState, 1, &indexType);
118   mlirOperationStateAddAttributes(&constZeroState, 1, &indexZeroValueAttr);
119   MlirOperation constZero = mlirOperationCreate(&constZeroState);
120   mlirBlockAppendOwnedOperation(funcBody, constZero);
121 
122   MlirValue funcArg0 = mlirBlockGetArgument(funcBody, 0);
123   MlirValue constZeroValue = mlirOperationGetResult(constZero, 0);
124   MlirValue dimOperands[] = {funcArg0, constZeroValue};
125   MlirOperationState dimState = mlirOperationStateGet(
126       mlirStringRefCreateFromCString("memref.dim"), location);
127   mlirOperationStateAddOperands(&dimState, 2, dimOperands);
128   mlirOperationStateAddResults(&dimState, 1, &indexType);
129   MlirOperation dim = mlirOperationCreate(&dimState);
130   mlirBlockAppendOwnedOperation(funcBody, dim);
131 
132   MlirRegion loopBodyRegion = mlirRegionCreate();
133   MlirBlock loopBody = mlirBlockCreate(0, NULL);
134   mlirBlockAddArgument(loopBody, indexType);
135   mlirRegionAppendOwnedBlock(loopBodyRegion, loopBody);
136 
137   MlirAttribute indexOneLiteral =
138       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("1 : index"));
139   MlirNamedAttribute indexOneValueAttr = mlirNamedAttributeGet(
140       mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("value")),
141       indexOneLiteral);
142   MlirOperationState constOneState = mlirOperationStateGet(
143       mlirStringRefCreateFromCString("arith.constant"), location);
144   mlirOperationStateAddResults(&constOneState, 1, &indexType);
145   mlirOperationStateAddAttributes(&constOneState, 1, &indexOneValueAttr);
146   MlirOperation constOne = mlirOperationCreate(&constOneState);
147   mlirBlockAppendOwnedOperation(funcBody, constOne);
148 
149   MlirValue dimValue = mlirOperationGetResult(dim, 0);
150   MlirValue constOneValue = mlirOperationGetResult(constOne, 0);
151   MlirValue loopOperands[] = {constZeroValue, dimValue, constOneValue};
152   MlirOperationState loopState = mlirOperationStateGet(
153       mlirStringRefCreateFromCString("scf.for"), location);
154   mlirOperationStateAddOperands(&loopState, 3, loopOperands);
155   mlirOperationStateAddOwnedRegions(&loopState, 1, &loopBodyRegion);
156   MlirOperation loop = mlirOperationCreate(&loopState);
157   mlirBlockAppendOwnedOperation(funcBody, loop);
158 
159   populateLoopBody(ctx, loopBody, location, funcBody);
160 
161   MlirOperationState retState = mlirOperationStateGet(
162       mlirStringRefCreateFromCString("std.return"), location);
163   MlirOperation ret = mlirOperationCreate(&retState);
164   mlirBlockAppendOwnedOperation(funcBody, ret);
165 
166   MlirOperation module = mlirModuleGetOperation(moduleOp);
167   mlirOperationDump(module);
168   // clang-format off
169   // CHECK: module {
170   // CHECK:   func @add(%[[ARG0:.*]]: memref<?xf32>, %[[ARG1:.*]]: memref<?xf32>) {
171   // CHECK:     %[[C0:.*]] = arith.constant 0 : index
172   // CHECK:     %[[DIM:.*]] = memref.dim %[[ARG0]], %[[C0]] : memref<?xf32>
173   // CHECK:     %[[C1:.*]] = arith.constant 1 : index
174   // CHECK:     scf.for %[[I:.*]] = %[[C0]] to %[[DIM]] step %[[C1]] {
175   // CHECK:       %[[LHS:.*]] = memref.load %[[ARG0]][%[[I]]] : memref<?xf32>
176   // CHECK:       %[[RHS:.*]] = memref.load %[[ARG1]][%[[I]]] : memref<?xf32>
177   // CHECK:       %[[SUM:.*]] = arith.addf %[[LHS]], %[[RHS]] : f32
178   // CHECK:       memref.store %[[SUM]], %[[ARG0]][%[[I]]] : memref<?xf32>
179   // CHECK:     }
180   // CHECK:     return
181   // CHECK:   }
182   // CHECK: }
183   // clang-format on
184 
185   return moduleOp;
186 }
187 
188 struct OpListNode {
189   MlirOperation op;
190   struct OpListNode *next;
191 };
192 typedef struct OpListNode OpListNode;
193 
194 struct ModuleStats {
195   unsigned numOperations;
196   unsigned numAttributes;
197   unsigned numBlocks;
198   unsigned numRegions;
199   unsigned numValues;
200   unsigned numBlockArguments;
201   unsigned numOpResults;
202 };
203 typedef struct ModuleStats ModuleStats;
204 
205 int collectStatsSingle(OpListNode *head, ModuleStats *stats) {
206   MlirOperation operation = head->op;
207   stats->numOperations += 1;
208   stats->numValues += mlirOperationGetNumResults(operation);
209   stats->numAttributes += mlirOperationGetNumAttributes(operation);
210 
211   unsigned numRegions = mlirOperationGetNumRegions(operation);
212 
213   stats->numRegions += numRegions;
214 
215   intptr_t numResults = mlirOperationGetNumResults(operation);
216   for (intptr_t i = 0; i < numResults; ++i) {
217     MlirValue result = mlirOperationGetResult(operation, i);
218     if (!mlirValueIsAOpResult(result))
219       return 1;
220     if (mlirValueIsABlockArgument(result))
221       return 2;
222     if (!mlirOperationEqual(operation, mlirOpResultGetOwner(result)))
223       return 3;
224     if (i != mlirOpResultGetResultNumber(result))
225       return 4;
226     ++stats->numOpResults;
227   }
228 
229   MlirRegion region = mlirOperationGetFirstRegion(operation);
230   while (!mlirRegionIsNull(region)) {
231     for (MlirBlock block = mlirRegionGetFirstBlock(region);
232          !mlirBlockIsNull(block); block = mlirBlockGetNextInRegion(block)) {
233       ++stats->numBlocks;
234       intptr_t numArgs = mlirBlockGetNumArguments(block);
235       stats->numValues += numArgs;
236       for (intptr_t j = 0; j < numArgs; ++j) {
237         MlirValue arg = mlirBlockGetArgument(block, j);
238         if (!mlirValueIsABlockArgument(arg))
239           return 5;
240         if (mlirValueIsAOpResult(arg))
241           return 6;
242         if (!mlirBlockEqual(block, mlirBlockArgumentGetOwner(arg)))
243           return 7;
244         if (j != mlirBlockArgumentGetArgNumber(arg))
245           return 8;
246         ++stats->numBlockArguments;
247       }
248 
249       for (MlirOperation child = mlirBlockGetFirstOperation(block);
250            !mlirOperationIsNull(child);
251            child = mlirOperationGetNextInBlock(child)) {
252         OpListNode *node = malloc(sizeof(OpListNode));
253         node->op = child;
254         node->next = head->next;
255         head->next = node;
256       }
257     }
258     region = mlirRegionGetNextInOperation(region);
259   }
260   return 0;
261 }
262 
263 int collectStats(MlirOperation operation) {
264   OpListNode *head = malloc(sizeof(OpListNode));
265   head->op = operation;
266   head->next = NULL;
267 
268   ModuleStats stats;
269   stats.numOperations = 0;
270   stats.numAttributes = 0;
271   stats.numBlocks = 0;
272   stats.numRegions = 0;
273   stats.numValues = 0;
274   stats.numBlockArguments = 0;
275   stats.numOpResults = 0;
276 
277   do {
278     int retval = collectStatsSingle(head, &stats);
279     if (retval) {
280       free(head);
281       return retval;
282     }
283     OpListNode *next = head->next;
284     free(head);
285     head = next;
286   } while (head);
287 
288   if (stats.numValues != stats.numBlockArguments + stats.numOpResults)
289     return 100;
290 
291   fprintf(stderr, "@stats\n");
292   fprintf(stderr, "Number of operations: %u\n", stats.numOperations);
293   fprintf(stderr, "Number of attributes: %u\n", stats.numAttributes);
294   fprintf(stderr, "Number of blocks: %u\n", stats.numBlocks);
295   fprintf(stderr, "Number of regions: %u\n", stats.numRegions);
296   fprintf(stderr, "Number of values: %u\n", stats.numValues);
297   fprintf(stderr, "Number of block arguments: %u\n", stats.numBlockArguments);
298   fprintf(stderr, "Number of op results: %u\n", stats.numOpResults);
299   // clang-format off
300   // CHECK-LABEL: @stats
301   // CHECK: Number of operations: 12
302   // CHECK: Number of attributes: 4
303   // CHECK: Number of blocks: 3
304   // CHECK: Number of regions: 3
305   // CHECK: Number of values: 9
306   // CHECK: Number of block arguments: 3
307   // CHECK: Number of op results: 6
308   // clang-format on
309   return 0;
310 }
311 
312 static void printToStderr(MlirStringRef str, void *userData) {
313   (void)userData;
314   fwrite(str.data, 1, str.length, stderr);
315 }
316 
317 static void printFirstOfEach(MlirContext ctx, MlirOperation operation) {
318   // Assuming we are given a module, go to the first operation of the first
319   // function.
320   MlirRegion region = mlirOperationGetRegion(operation, 0);
321   MlirBlock block = mlirRegionGetFirstBlock(region);
322   operation = mlirBlockGetFirstOperation(block);
323   region = mlirOperationGetRegion(operation, 0);
324   MlirOperation parentOperation = operation;
325   block = mlirRegionGetFirstBlock(region);
326   operation = mlirBlockGetFirstOperation(block);
327   assert(mlirModuleIsNull(mlirModuleFromOperation(operation)));
328 
329   // Verify that parent operation and block report correctly.
330   // CHECK: Parent operation eq: 1
331   fprintf(stderr, "Parent operation eq: %d\n",
332           mlirOperationEqual(mlirOperationGetParentOperation(operation),
333                              parentOperation));
334   // CHECK: Block eq: 1
335   fprintf(stderr, "Block eq: %d\n",
336           mlirBlockEqual(mlirOperationGetBlock(operation), block));
337   // CHECK: Block parent operation eq: 1
338   fprintf(
339       stderr, "Block parent operation eq: %d\n",
340       mlirOperationEqual(mlirBlockGetParentOperation(block), parentOperation));
341   // CHECK: Block parent region eq: 1
342   fprintf(stderr, "Block parent region eq: %d\n",
343           mlirRegionEqual(mlirBlockGetParentRegion(block), region));
344 
345   // In the module we created, the first operation of the first function is
346   // an "memref.dim", which has an attribute and a single result that we can
347   // use to test the printing mechanism.
348   mlirBlockPrint(block, printToStderr, NULL);
349   fprintf(stderr, "\n");
350   fprintf(stderr, "First operation: ");
351   mlirOperationPrint(operation, printToStderr, NULL);
352   fprintf(stderr, "\n");
353   // clang-format off
354   // CHECK:   %[[C0:.*]] = arith.constant 0 : index
355   // CHECK:   %[[DIM:.*]] = memref.dim %{{.*}}, %[[C0]] : memref<?xf32>
356   // CHECK:   %[[C1:.*]] = arith.constant 1 : index
357   // CHECK:   scf.for %[[I:.*]] = %[[C0]] to %[[DIM]] step %[[C1]] {
358   // CHECK:     %[[LHS:.*]] = memref.load %{{.*}}[%[[I]]] : memref<?xf32>
359   // CHECK:     %[[RHS:.*]] = memref.load %{{.*}}[%[[I]]] : memref<?xf32>
360   // CHECK:     %[[SUM:.*]] = arith.addf %[[LHS]], %[[RHS]] : f32
361   // CHECK:     memref.store %[[SUM]], %{{.*}}[%[[I]]] : memref<?xf32>
362   // CHECK:   }
363   // CHECK: return
364   // CHECK: First operation: {{.*}} = arith.constant 0 : index
365   // clang-format on
366 
367   // Get the operation name and print it.
368   MlirIdentifier ident = mlirOperationGetName(operation);
369   MlirStringRef identStr = mlirIdentifierStr(ident);
370   fprintf(stderr, "Operation name: '");
371   for (size_t i = 0; i < identStr.length; ++i)
372     fputc(identStr.data[i], stderr);
373   fprintf(stderr, "'\n");
374   // CHECK: Operation name: 'arith.constant'
375 
376   // Get the identifier again and verify equal.
377   MlirIdentifier identAgain = mlirIdentifierGet(ctx, identStr);
378   fprintf(stderr, "Identifier equal: %d\n",
379           mlirIdentifierEqual(ident, identAgain));
380   // CHECK: Identifier equal: 1
381 
382   // Get the block terminator and print it.
383   MlirOperation terminator = mlirBlockGetTerminator(block);
384   fprintf(stderr, "Terminator: ");
385   mlirOperationPrint(terminator, printToStderr, NULL);
386   fprintf(stderr, "\n");
387   // CHECK: Terminator: return
388 
389   // Get the attribute by index.
390   MlirNamedAttribute namedAttr0 = mlirOperationGetAttribute(operation, 0);
391   fprintf(stderr, "Get attr 0: ");
392   mlirAttributePrint(namedAttr0.attribute, printToStderr, NULL);
393   fprintf(stderr, "\n");
394   // CHECK: Get attr 0: 0 : index
395 
396   // Now re-get the attribute by name.
397   MlirAttribute attr0ByName = mlirOperationGetAttributeByName(
398       operation, mlirIdentifierStr(namedAttr0.name));
399   fprintf(stderr, "Get attr 0 by name: ");
400   mlirAttributePrint(attr0ByName, printToStderr, NULL);
401   fprintf(stderr, "\n");
402   // CHECK: Get attr 0 by name: 0 : index
403 
404   // Get a non-existing attribute and assert that it is null (sanity).
405   fprintf(stderr, "does_not_exist is null: %d\n",
406           mlirAttributeIsNull(mlirOperationGetAttributeByName(
407               operation, mlirStringRefCreateFromCString("does_not_exist"))));
408   // CHECK: does_not_exist is null: 1
409 
410   // Get result 0 and its type.
411   MlirValue value = mlirOperationGetResult(operation, 0);
412   fprintf(stderr, "Result 0: ");
413   mlirValuePrint(value, printToStderr, NULL);
414   fprintf(stderr, "\n");
415   fprintf(stderr, "Value is null: %d\n", mlirValueIsNull(value));
416   // CHECK: Result 0: {{.*}} = arith.constant 0 : index
417   // CHECK: Value is null: 0
418 
419   MlirType type = mlirValueGetType(value);
420   fprintf(stderr, "Result 0 type: ");
421   mlirTypePrint(type, printToStderr, NULL);
422   fprintf(stderr, "\n");
423   // CHECK: Result 0 type: index
424 
425   // Set a custom attribute.
426   mlirOperationSetAttributeByName(operation,
427                                   mlirStringRefCreateFromCString("custom_attr"),
428                                   mlirBoolAttrGet(ctx, 1));
429   fprintf(stderr, "Op with set attr: ");
430   mlirOperationPrint(operation, printToStderr, NULL);
431   fprintf(stderr, "\n");
432   // CHECK: Op with set attr: {{.*}} {custom_attr = true}
433 
434   // Remove the attribute.
435   fprintf(stderr, "Remove attr: %d\n",
436           mlirOperationRemoveAttributeByName(
437               operation, mlirStringRefCreateFromCString("custom_attr")));
438   fprintf(stderr, "Remove attr again: %d\n",
439           mlirOperationRemoveAttributeByName(
440               operation, mlirStringRefCreateFromCString("custom_attr")));
441   fprintf(stderr, "Removed attr is null: %d\n",
442           mlirAttributeIsNull(mlirOperationGetAttributeByName(
443               operation, mlirStringRefCreateFromCString("custom_attr"))));
444   // CHECK: Remove attr: 1
445   // CHECK: Remove attr again: 0
446   // CHECK: Removed attr is null: 1
447 
448   // Add a large attribute to verify printing flags.
449   int64_t eltsShape[] = {4};
450   int32_t eltsData[] = {1, 2, 3, 4};
451   mlirOperationSetAttributeByName(
452       operation, mlirStringRefCreateFromCString("elts"),
453       mlirDenseElementsAttrInt32Get(
454           mlirRankedTensorTypeGet(1, eltsShape, mlirIntegerTypeGet(ctx, 32),
455                                   mlirAttributeGetNull()),
456           4, eltsData));
457   MlirOpPrintingFlags flags = mlirOpPrintingFlagsCreate();
458   mlirOpPrintingFlagsElideLargeElementsAttrs(flags, 2);
459   mlirOpPrintingFlagsPrintGenericOpForm(flags);
460   mlirOpPrintingFlagsEnableDebugInfo(flags, /*prettyForm=*/0);
461   mlirOpPrintingFlagsUseLocalScope(flags);
462   fprintf(stderr, "Op print with all flags: ");
463   mlirOperationPrintWithFlags(operation, flags, printToStderr, NULL);
464   fprintf(stderr, "\n");
465   // clang-format off
466   // CHECK: Op print with all flags: %{{.*}} = "arith.constant"() {elts = opaque<"_", "0xDEADBEEF"> : tensor<4xi32>, value = 0 : index} : () -> index loc(unknown)
467   // clang-format on
468 
469   mlirOpPrintingFlagsDestroy(flags);
470 }
471 
472 static int constructAndTraverseIr(MlirContext ctx) {
473   MlirLocation location = mlirLocationUnknownGet(ctx);
474 
475   MlirModule moduleOp = makeAndDumpAdd(ctx, location);
476   MlirOperation module = mlirModuleGetOperation(moduleOp);
477   assert(!mlirModuleIsNull(mlirModuleFromOperation(module)));
478 
479   int errcode = collectStats(module);
480   if (errcode)
481     return errcode;
482 
483   printFirstOfEach(ctx, module);
484 
485   mlirModuleDestroy(moduleOp);
486   return 0;
487 }
488 
489 /// Creates an operation with a region containing multiple blocks with
490 /// operations and dumps it. The blocks and operations are inserted using
491 /// block/operation-relative API and their final order is checked.
492 static void buildWithInsertionsAndPrint(MlirContext ctx) {
493   MlirLocation loc = mlirLocationUnknownGet(ctx);
494   mlirContextSetAllowUnregisteredDialects(ctx, true);
495 
496   MlirRegion owningRegion = mlirRegionCreate();
497   MlirBlock nullBlock = mlirRegionGetFirstBlock(owningRegion);
498   MlirOperationState state = mlirOperationStateGet(
499       mlirStringRefCreateFromCString("insertion.order.test"), loc);
500   mlirOperationStateAddOwnedRegions(&state, 1, &owningRegion);
501   MlirOperation op = mlirOperationCreate(&state);
502   MlirRegion region = mlirOperationGetRegion(op, 0);
503 
504   // Use integer types of different bitwidth as block arguments in order to
505   // differentiate blocks.
506   MlirType i1 = mlirIntegerTypeGet(ctx, 1);
507   MlirType i2 = mlirIntegerTypeGet(ctx, 2);
508   MlirType i3 = mlirIntegerTypeGet(ctx, 3);
509   MlirType i4 = mlirIntegerTypeGet(ctx, 4);
510   MlirBlock block1 = mlirBlockCreate(1, &i1);
511   MlirBlock block2 = mlirBlockCreate(1, &i2);
512   MlirBlock block3 = mlirBlockCreate(1, &i3);
513   MlirBlock block4 = mlirBlockCreate(1, &i4);
514   // Insert blocks so as to obtain the 1-2-3-4 order,
515   mlirRegionInsertOwnedBlockBefore(region, nullBlock, block3);
516   mlirRegionInsertOwnedBlockBefore(region, block3, block2);
517   mlirRegionInsertOwnedBlockAfter(region, nullBlock, block1);
518   mlirRegionInsertOwnedBlockAfter(region, block3, block4);
519 
520   MlirOperationState op1State =
521       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op1"), loc);
522   MlirOperationState op2State =
523       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op2"), loc);
524   MlirOperationState op3State =
525       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op3"), loc);
526   MlirOperationState op4State =
527       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op4"), loc);
528   MlirOperationState op5State =
529       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op5"), loc);
530   MlirOperationState op6State =
531       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op6"), loc);
532   MlirOperationState op7State =
533       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op7"), loc);
534   MlirOperation op1 = mlirOperationCreate(&op1State);
535   MlirOperation op2 = mlirOperationCreate(&op2State);
536   MlirOperation op3 = mlirOperationCreate(&op3State);
537   MlirOperation op4 = mlirOperationCreate(&op4State);
538   MlirOperation op5 = mlirOperationCreate(&op5State);
539   MlirOperation op6 = mlirOperationCreate(&op6State);
540   MlirOperation op7 = mlirOperationCreate(&op7State);
541 
542   // Insert operations in the first block so as to obtain the 1-2-3-4 order.
543   MlirOperation nullOperation = mlirBlockGetFirstOperation(block1);
544   assert(mlirOperationIsNull(nullOperation));
545   mlirBlockInsertOwnedOperationBefore(block1, nullOperation, op3);
546   mlirBlockInsertOwnedOperationBefore(block1, op3, op2);
547   mlirBlockInsertOwnedOperationAfter(block1, nullOperation, op1);
548   mlirBlockInsertOwnedOperationAfter(block1, op3, op4);
549 
550   // Append operations to the rest of blocks to make them non-empty and thus
551   // printable.
552   mlirBlockAppendOwnedOperation(block2, op5);
553   mlirBlockAppendOwnedOperation(block3, op6);
554   mlirBlockAppendOwnedOperation(block4, op7);
555 
556   mlirOperationDump(op);
557   mlirOperationDestroy(op);
558   mlirContextSetAllowUnregisteredDialects(ctx, false);
559   // clang-format off
560   // CHECK-LABEL:  "insertion.order.test"
561   // CHECK:      ^{{.*}}(%{{.*}}: i1
562   // CHECK:        "dummy.op1"
563   // CHECK-NEXT:   "dummy.op2"
564   // CHECK-NEXT:   "dummy.op3"
565   // CHECK-NEXT:   "dummy.op4"
566   // CHECK:      ^{{.*}}(%{{.*}}: i2
567   // CHECK:        "dummy.op5"
568   // CHECK:      ^{{.*}}(%{{.*}}: i3
569   // CHECK:        "dummy.op6"
570   // CHECK:      ^{{.*}}(%{{.*}}: i4
571   // CHECK:        "dummy.op7"
572   // clang-format on
573 }
574 
575 /// Creates operations with type inference and tests various failure modes.
576 static int createOperationWithTypeInference(MlirContext ctx) {
577   MlirLocation loc = mlirLocationUnknownGet(ctx);
578   MlirAttribute iAttr = mlirIntegerAttrGet(mlirIntegerTypeGet(ctx, 32), 4);
579 
580   // The shape.const_size op implements result type inference and is only used
581   // for that reason.
582   MlirOperationState state = mlirOperationStateGet(
583       mlirStringRefCreateFromCString("shape.const_size"), loc);
584   MlirNamedAttribute valueAttr = mlirNamedAttributeGet(
585       mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("value")), iAttr);
586   mlirOperationStateAddAttributes(&state, 1, &valueAttr);
587   mlirOperationStateEnableResultTypeInference(&state);
588 
589   // Expect result type inference to succeed.
590   MlirOperation op = mlirOperationCreate(&state);
591   if (mlirOperationIsNull(op)) {
592     fprintf(stderr, "ERROR: Result type inference unexpectedly failed");
593     return 1;
594   }
595 
596   // CHECK: RESULT_TYPE_INFERENCE: !shape.size
597   fprintf(stderr, "RESULT_TYPE_INFERENCE: ");
598   mlirTypeDump(mlirValueGetType(mlirOperationGetResult(op, 0)));
599   fprintf(stderr, "\n");
600   mlirOperationDestroy(op);
601   return 0;
602 }
603 
604 /// Dumps instances of all builtin types to check that C API works correctly.
605 /// Additionally, performs simple identity checks that a builtin type
606 /// constructed with C API can be inspected and has the expected type. The
607 /// latter achieves full coverage of C API for builtin types. Returns 0 on
608 /// success and a non-zero error code on failure.
609 static int printBuiltinTypes(MlirContext ctx) {
610   // Integer types.
611   MlirType i32 = mlirIntegerTypeGet(ctx, 32);
612   MlirType si32 = mlirIntegerTypeSignedGet(ctx, 32);
613   MlirType ui32 = mlirIntegerTypeUnsignedGet(ctx, 32);
614   if (!mlirTypeIsAInteger(i32) || mlirTypeIsAF32(i32))
615     return 1;
616   if (!mlirTypeIsAInteger(si32) || !mlirIntegerTypeIsSigned(si32))
617     return 2;
618   if (!mlirTypeIsAInteger(ui32) || !mlirIntegerTypeIsUnsigned(ui32))
619     return 3;
620   if (mlirTypeEqual(i32, ui32) || mlirTypeEqual(i32, si32))
621     return 4;
622   if (mlirIntegerTypeGetWidth(i32) != mlirIntegerTypeGetWidth(si32))
623     return 5;
624   fprintf(stderr, "@types\n");
625   mlirTypeDump(i32);
626   fprintf(stderr, "\n");
627   mlirTypeDump(si32);
628   fprintf(stderr, "\n");
629   mlirTypeDump(ui32);
630   fprintf(stderr, "\n");
631   // CHECK-LABEL: @types
632   // CHECK: i32
633   // CHECK: si32
634   // CHECK: ui32
635 
636   // Index type.
637   MlirType index = mlirIndexTypeGet(ctx);
638   if (!mlirTypeIsAIndex(index))
639     return 6;
640   mlirTypeDump(index);
641   fprintf(stderr, "\n");
642   // CHECK: index
643 
644   // Floating-point types.
645   MlirType bf16 = mlirBF16TypeGet(ctx);
646   MlirType f16 = mlirF16TypeGet(ctx);
647   MlirType f32 = mlirF32TypeGet(ctx);
648   MlirType f64 = mlirF64TypeGet(ctx);
649   if (!mlirTypeIsABF16(bf16))
650     return 7;
651   if (!mlirTypeIsAF16(f16))
652     return 9;
653   if (!mlirTypeIsAF32(f32))
654     return 10;
655   if (!mlirTypeIsAF64(f64))
656     return 11;
657   mlirTypeDump(bf16);
658   fprintf(stderr, "\n");
659   mlirTypeDump(f16);
660   fprintf(stderr, "\n");
661   mlirTypeDump(f32);
662   fprintf(stderr, "\n");
663   mlirTypeDump(f64);
664   fprintf(stderr, "\n");
665   // CHECK: bf16
666   // CHECK: f16
667   // CHECK: f32
668   // CHECK: f64
669 
670   // None type.
671   MlirType none = mlirNoneTypeGet(ctx);
672   if (!mlirTypeIsANone(none))
673     return 12;
674   mlirTypeDump(none);
675   fprintf(stderr, "\n");
676   // CHECK: none
677 
678   // Complex type.
679   MlirType cplx = mlirComplexTypeGet(f32);
680   if (!mlirTypeIsAComplex(cplx) ||
681       !mlirTypeEqual(mlirComplexTypeGetElementType(cplx), f32))
682     return 13;
683   mlirTypeDump(cplx);
684   fprintf(stderr, "\n");
685   // CHECK: complex<f32>
686 
687   // Vector (and Shaped) type. ShapedType is a common base class for vectors,
688   // memrefs and tensors, one cannot create instances of this class so it is
689   // tested on an instance of vector type.
690   int64_t shape[] = {2, 3};
691   MlirType vector =
692       mlirVectorTypeGet(sizeof(shape) / sizeof(int64_t), shape, f32);
693   if (!mlirTypeIsAVector(vector) || !mlirTypeIsAShaped(vector))
694     return 14;
695   if (!mlirTypeEqual(mlirShapedTypeGetElementType(vector), f32) ||
696       !mlirShapedTypeHasRank(vector) || mlirShapedTypeGetRank(vector) != 2 ||
697       mlirShapedTypeGetDimSize(vector, 0) != 2 ||
698       mlirShapedTypeIsDynamicDim(vector, 0) ||
699       mlirShapedTypeGetDimSize(vector, 1) != 3 ||
700       !mlirShapedTypeHasStaticShape(vector))
701     return 15;
702   mlirTypeDump(vector);
703   fprintf(stderr, "\n");
704   // CHECK: vector<2x3xf32>
705 
706   // Ranked tensor type.
707   MlirType rankedTensor = mlirRankedTensorTypeGet(
708       sizeof(shape) / sizeof(int64_t), shape, f32, mlirAttributeGetNull());
709   if (!mlirTypeIsATensor(rankedTensor) ||
710       !mlirTypeIsARankedTensor(rankedTensor) ||
711       !mlirAttributeIsNull(mlirRankedTensorTypeGetEncoding(rankedTensor)))
712     return 16;
713   mlirTypeDump(rankedTensor);
714   fprintf(stderr, "\n");
715   // CHECK: tensor<2x3xf32>
716 
717   // Unranked tensor type.
718   MlirType unrankedTensor = mlirUnrankedTensorTypeGet(f32);
719   if (!mlirTypeIsATensor(unrankedTensor) ||
720       !mlirTypeIsAUnrankedTensor(unrankedTensor) ||
721       mlirShapedTypeHasRank(unrankedTensor))
722     return 17;
723   mlirTypeDump(unrankedTensor);
724   fprintf(stderr, "\n");
725   // CHECK: tensor<*xf32>
726 
727   // MemRef type.
728   MlirAttribute memSpace2 = mlirIntegerAttrGet(mlirIntegerTypeGet(ctx, 64), 2);
729   MlirType memRef = mlirMemRefTypeContiguousGet(
730       f32, sizeof(shape) / sizeof(int64_t), shape, memSpace2);
731   if (!mlirTypeIsAMemRef(memRef) ||
732       !mlirAttributeEqual(mlirMemRefTypeGetMemorySpace(memRef), memSpace2))
733     return 18;
734   mlirTypeDump(memRef);
735   fprintf(stderr, "\n");
736   // CHECK: memref<2x3xf32, 2>
737 
738   // Unranked MemRef type.
739   MlirAttribute memSpace4 = mlirIntegerAttrGet(mlirIntegerTypeGet(ctx, 64), 4);
740   MlirType unrankedMemRef = mlirUnrankedMemRefTypeGet(f32, memSpace4);
741   if (!mlirTypeIsAUnrankedMemRef(unrankedMemRef) ||
742       mlirTypeIsAMemRef(unrankedMemRef) ||
743       !mlirAttributeEqual(mlirUnrankedMemrefGetMemorySpace(unrankedMemRef),
744                           memSpace4))
745     return 19;
746   mlirTypeDump(unrankedMemRef);
747   fprintf(stderr, "\n");
748   // CHECK: memref<*xf32, 4>
749 
750   // Tuple type.
751   MlirType types[] = {unrankedMemRef, f32};
752   MlirType tuple = mlirTupleTypeGet(ctx, 2, types);
753   if (!mlirTypeIsATuple(tuple) || mlirTupleTypeGetNumTypes(tuple) != 2 ||
754       !mlirTypeEqual(mlirTupleTypeGetType(tuple, 0), unrankedMemRef) ||
755       !mlirTypeEqual(mlirTupleTypeGetType(tuple, 1), f32))
756     return 20;
757   mlirTypeDump(tuple);
758   fprintf(stderr, "\n");
759   // CHECK: tuple<memref<*xf32, 4>, f32>
760 
761   // Function type.
762   MlirType funcInputs[2] = {mlirIndexTypeGet(ctx), mlirIntegerTypeGet(ctx, 1)};
763   MlirType funcResults[3] = {mlirIntegerTypeGet(ctx, 16),
764                              mlirIntegerTypeGet(ctx, 32),
765                              mlirIntegerTypeGet(ctx, 64)};
766   MlirType funcType = mlirFunctionTypeGet(ctx, 2, funcInputs, 3, funcResults);
767   if (mlirFunctionTypeGetNumInputs(funcType) != 2)
768     return 21;
769   if (mlirFunctionTypeGetNumResults(funcType) != 3)
770     return 22;
771   if (!mlirTypeEqual(funcInputs[0], mlirFunctionTypeGetInput(funcType, 0)) ||
772       !mlirTypeEqual(funcInputs[1], mlirFunctionTypeGetInput(funcType, 1)))
773     return 23;
774   if (!mlirTypeEqual(funcResults[0], mlirFunctionTypeGetResult(funcType, 0)) ||
775       !mlirTypeEqual(funcResults[1], mlirFunctionTypeGetResult(funcType, 1)) ||
776       !mlirTypeEqual(funcResults[2], mlirFunctionTypeGetResult(funcType, 2)))
777     return 24;
778   mlirTypeDump(funcType);
779   fprintf(stderr, "\n");
780   // CHECK: (index, i1) -> (i16, i32, i64)
781 
782   return 0;
783 }
784 
785 void callbackSetFixedLengthString(const char *data, intptr_t len,
786                                   void *userData) {
787   strncpy(userData, data, len);
788 }
789 
790 bool stringIsEqual(const char *lhs, MlirStringRef rhs) {
791   if (strlen(lhs) != rhs.length) {
792     return false;
793   }
794   return !strncmp(lhs, rhs.data, rhs.length);
795 }
796 
797 int printBuiltinAttributes(MlirContext ctx) {
798   MlirAttribute floating =
799       mlirFloatAttrDoubleGet(ctx, mlirF64TypeGet(ctx), 2.0);
800   if (!mlirAttributeIsAFloat(floating) ||
801       fabs(mlirFloatAttrGetValueDouble(floating) - 2.0) > 1E-6)
802     return 1;
803   fprintf(stderr, "@attrs\n");
804   mlirAttributeDump(floating);
805   // CHECK-LABEL: @attrs
806   // CHECK: 2.000000e+00 : f64
807 
808   // Exercise mlirAttributeGetType() just for the first one.
809   MlirType floatingType = mlirAttributeGetType(floating);
810   mlirTypeDump(floatingType);
811   // CHECK: f64
812 
813   MlirAttribute integer = mlirIntegerAttrGet(mlirIntegerTypeGet(ctx, 32), 42);
814   if (!mlirAttributeIsAInteger(integer) ||
815       mlirIntegerAttrGetValueInt(integer) != 42)
816     return 2;
817   mlirAttributeDump(integer);
818   // CHECK: 42 : i32
819 
820   MlirAttribute boolean = mlirBoolAttrGet(ctx, 1);
821   if (!mlirAttributeIsABool(boolean) || !mlirBoolAttrGetValue(boolean))
822     return 3;
823   mlirAttributeDump(boolean);
824   // CHECK: true
825 
826   const char data[] = "abcdefghijklmnopqestuvwxyz";
827   MlirAttribute opaque =
828       mlirOpaqueAttrGet(ctx, mlirStringRefCreateFromCString("std"), 3, data,
829                         mlirNoneTypeGet(ctx));
830   if (!mlirAttributeIsAOpaque(opaque) ||
831       !stringIsEqual("std", mlirOpaqueAttrGetDialectNamespace(opaque)))
832     return 4;
833 
834   MlirStringRef opaqueData = mlirOpaqueAttrGetData(opaque);
835   if (opaqueData.length != 3 ||
836       strncmp(data, opaqueData.data, opaqueData.length))
837     return 5;
838   mlirAttributeDump(opaque);
839   // CHECK: #std.abc
840 
841   MlirAttribute string =
842       mlirStringAttrGet(ctx, mlirStringRefCreate(data + 3, 2));
843   if (!mlirAttributeIsAString(string))
844     return 6;
845 
846   MlirStringRef stringValue = mlirStringAttrGetValue(string);
847   if (stringValue.length != 2 ||
848       strncmp(data + 3, stringValue.data, stringValue.length))
849     return 7;
850   mlirAttributeDump(string);
851   // CHECK: "de"
852 
853   MlirAttribute flatSymbolRef =
854       mlirFlatSymbolRefAttrGet(ctx, mlirStringRefCreate(data + 5, 3));
855   if (!mlirAttributeIsAFlatSymbolRef(flatSymbolRef))
856     return 8;
857 
858   MlirStringRef flatSymbolRefValue =
859       mlirFlatSymbolRefAttrGetValue(flatSymbolRef);
860   if (flatSymbolRefValue.length != 3 ||
861       strncmp(data + 5, flatSymbolRefValue.data, flatSymbolRefValue.length))
862     return 9;
863   mlirAttributeDump(flatSymbolRef);
864   // CHECK: @fgh
865 
866   MlirAttribute symbols[] = {flatSymbolRef, flatSymbolRef};
867   MlirAttribute symbolRef =
868       mlirSymbolRefAttrGet(ctx, mlirStringRefCreate(data + 8, 2), 2, symbols);
869   if (!mlirAttributeIsASymbolRef(symbolRef) ||
870       mlirSymbolRefAttrGetNumNestedReferences(symbolRef) != 2 ||
871       !mlirAttributeEqual(mlirSymbolRefAttrGetNestedReference(symbolRef, 0),
872                           flatSymbolRef) ||
873       !mlirAttributeEqual(mlirSymbolRefAttrGetNestedReference(symbolRef, 1),
874                           flatSymbolRef))
875     return 10;
876 
877   MlirStringRef symbolRefLeaf = mlirSymbolRefAttrGetLeafReference(symbolRef);
878   MlirStringRef symbolRefRoot = mlirSymbolRefAttrGetRootReference(symbolRef);
879   if (symbolRefLeaf.length != 3 ||
880       strncmp(data + 5, symbolRefLeaf.data, symbolRefLeaf.length) ||
881       symbolRefRoot.length != 2 ||
882       strncmp(data + 8, symbolRefRoot.data, symbolRefRoot.length))
883     return 11;
884   mlirAttributeDump(symbolRef);
885   // CHECK: @ij::@fgh::@fgh
886 
887   MlirAttribute type = mlirTypeAttrGet(mlirF32TypeGet(ctx));
888   if (!mlirAttributeIsAType(type) ||
889       !mlirTypeEqual(mlirF32TypeGet(ctx), mlirTypeAttrGetValue(type)))
890     return 12;
891   mlirAttributeDump(type);
892   // CHECK: f32
893 
894   MlirAttribute unit = mlirUnitAttrGet(ctx);
895   if (!mlirAttributeIsAUnit(unit))
896     return 13;
897   mlirAttributeDump(unit);
898   // CHECK: unit
899 
900   int64_t shape[] = {1, 2};
901 
902   int bools[] = {0, 1};
903   uint8_t uints8[] = {0u, 1u};
904   int8_t ints8[] = {0, 1};
905   uint32_t uints32[] = {0u, 1u};
906   int32_t ints32[] = {0, 1};
907   uint64_t uints64[] = {0u, 1u};
908   int64_t ints64[] = {0, 1};
909   float floats[] = {0.0f, 1.0f};
910   double doubles[] = {0.0, 1.0};
911   MlirAttribute encoding = mlirAttributeGetNull();
912   MlirAttribute boolElements = mlirDenseElementsAttrBoolGet(
913       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 1), encoding),
914       2, bools);
915   MlirAttribute uint8Elements = mlirDenseElementsAttrUInt8Get(
916       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeUnsignedGet(ctx, 8),
917                               encoding),
918       2, uints8);
919   MlirAttribute int8Elements = mlirDenseElementsAttrInt8Get(
920       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 8), encoding),
921       2, ints8);
922   MlirAttribute uint32Elements = mlirDenseElementsAttrUInt32Get(
923       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeUnsignedGet(ctx, 32),
924                               encoding),
925       2, uints32);
926   MlirAttribute int32Elements = mlirDenseElementsAttrInt32Get(
927       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 32), encoding),
928       2, ints32);
929   MlirAttribute uint64Elements = mlirDenseElementsAttrUInt64Get(
930       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeUnsignedGet(ctx, 64),
931                               encoding),
932       2, uints64);
933   MlirAttribute int64Elements = mlirDenseElementsAttrInt64Get(
934       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 64), encoding),
935       2, ints64);
936   MlirAttribute floatElements = mlirDenseElementsAttrFloatGet(
937       mlirRankedTensorTypeGet(2, shape, mlirF32TypeGet(ctx), encoding), 2,
938       floats);
939   MlirAttribute doubleElements = mlirDenseElementsAttrDoubleGet(
940       mlirRankedTensorTypeGet(2, shape, mlirF64TypeGet(ctx), encoding), 2,
941       doubles);
942 
943   if (!mlirAttributeIsADenseElements(boolElements) ||
944       !mlirAttributeIsADenseElements(uint8Elements) ||
945       !mlirAttributeIsADenseElements(int8Elements) ||
946       !mlirAttributeIsADenseElements(uint32Elements) ||
947       !mlirAttributeIsADenseElements(int32Elements) ||
948       !mlirAttributeIsADenseElements(uint64Elements) ||
949       !mlirAttributeIsADenseElements(int64Elements) ||
950       !mlirAttributeIsADenseElements(floatElements) ||
951       !mlirAttributeIsADenseElements(doubleElements))
952     return 14;
953 
954   if (mlirDenseElementsAttrGetBoolValue(boolElements, 1) != 1 ||
955       mlirDenseElementsAttrGetUInt8Value(uint8Elements, 1) != 1 ||
956       mlirDenseElementsAttrGetInt8Value(int8Elements, 1) != 1 ||
957       mlirDenseElementsAttrGetUInt32Value(uint32Elements, 1) != 1 ||
958       mlirDenseElementsAttrGetInt32Value(int32Elements, 1) != 1 ||
959       mlirDenseElementsAttrGetUInt64Value(uint64Elements, 1) != 1 ||
960       mlirDenseElementsAttrGetInt64Value(int64Elements, 1) != 1 ||
961       fabsf(mlirDenseElementsAttrGetFloatValue(floatElements, 1) - 1.0f) >
962           1E-6f ||
963       fabs(mlirDenseElementsAttrGetDoubleValue(doubleElements, 1) - 1.0) > 1E-6)
964     return 15;
965 
966   mlirAttributeDump(boolElements);
967   mlirAttributeDump(uint8Elements);
968   mlirAttributeDump(int8Elements);
969   mlirAttributeDump(uint32Elements);
970   mlirAttributeDump(int32Elements);
971   mlirAttributeDump(uint64Elements);
972   mlirAttributeDump(int64Elements);
973   mlirAttributeDump(floatElements);
974   mlirAttributeDump(doubleElements);
975   // CHECK: dense<{{\[}}[false, true]]> : tensor<1x2xi1>
976   // CHECK: dense<{{\[}}[0, 1]]> : tensor<1x2xui8>
977   // CHECK: dense<{{\[}}[0, 1]]> : tensor<1x2xi8>
978   // CHECK: dense<{{\[}}[0, 1]]> : tensor<1x2xui32>
979   // CHECK: dense<{{\[}}[0, 1]]> : tensor<1x2xi32>
980   // CHECK: dense<{{\[}}[0, 1]]> : tensor<1x2xui64>
981   // CHECK: dense<{{\[}}[0, 1]]> : tensor<1x2xi64>
982   // CHECK: dense<{{\[}}[0.000000e+00, 1.000000e+00]]> : tensor<1x2xf32>
983   // CHECK: dense<{{\[}}[0.000000e+00, 1.000000e+00]]> : tensor<1x2xf64>
984 
985   MlirAttribute splatBool = mlirDenseElementsAttrBoolSplatGet(
986       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 1), encoding),
987       1);
988   MlirAttribute splatUInt8 = mlirDenseElementsAttrUInt8SplatGet(
989       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeUnsignedGet(ctx, 8),
990                               encoding),
991       1);
992   MlirAttribute splatInt8 = mlirDenseElementsAttrInt8SplatGet(
993       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 8), encoding),
994       1);
995   MlirAttribute splatUInt32 = mlirDenseElementsAttrUInt32SplatGet(
996       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeUnsignedGet(ctx, 32),
997                               encoding),
998       1);
999   MlirAttribute splatInt32 = mlirDenseElementsAttrInt32SplatGet(
1000       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 32), encoding),
1001       1);
1002   MlirAttribute splatUInt64 = mlirDenseElementsAttrUInt64SplatGet(
1003       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeUnsignedGet(ctx, 64),
1004                               encoding),
1005       1);
1006   MlirAttribute splatInt64 = mlirDenseElementsAttrInt64SplatGet(
1007       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 64), encoding),
1008       1);
1009   MlirAttribute splatFloat = mlirDenseElementsAttrFloatSplatGet(
1010       mlirRankedTensorTypeGet(2, shape, mlirF32TypeGet(ctx), encoding), 1.0f);
1011   MlirAttribute splatDouble = mlirDenseElementsAttrDoubleSplatGet(
1012       mlirRankedTensorTypeGet(2, shape, mlirF64TypeGet(ctx), encoding), 1.0);
1013 
1014   if (!mlirAttributeIsADenseElements(splatBool) ||
1015       !mlirDenseElementsAttrIsSplat(splatBool) ||
1016       !mlirAttributeIsADenseElements(splatUInt8) ||
1017       !mlirDenseElementsAttrIsSplat(splatUInt8) ||
1018       !mlirAttributeIsADenseElements(splatInt8) ||
1019       !mlirDenseElementsAttrIsSplat(splatInt8) ||
1020       !mlirAttributeIsADenseElements(splatUInt32) ||
1021       !mlirDenseElementsAttrIsSplat(splatUInt32) ||
1022       !mlirAttributeIsADenseElements(splatInt32) ||
1023       !mlirDenseElementsAttrIsSplat(splatInt32) ||
1024       !mlirAttributeIsADenseElements(splatUInt64) ||
1025       !mlirDenseElementsAttrIsSplat(splatUInt64) ||
1026       !mlirAttributeIsADenseElements(splatInt64) ||
1027       !mlirDenseElementsAttrIsSplat(splatInt64) ||
1028       !mlirAttributeIsADenseElements(splatFloat) ||
1029       !mlirDenseElementsAttrIsSplat(splatFloat) ||
1030       !mlirAttributeIsADenseElements(splatDouble) ||
1031       !mlirDenseElementsAttrIsSplat(splatDouble))
1032     return 16;
1033 
1034   if (mlirDenseElementsAttrGetBoolSplatValue(splatBool) != 1 ||
1035       mlirDenseElementsAttrGetUInt8SplatValue(splatUInt8) != 1 ||
1036       mlirDenseElementsAttrGetInt8SplatValue(splatInt8) != 1 ||
1037       mlirDenseElementsAttrGetUInt32SplatValue(splatUInt32) != 1 ||
1038       mlirDenseElementsAttrGetInt32SplatValue(splatInt32) != 1 ||
1039       mlirDenseElementsAttrGetUInt64SplatValue(splatUInt64) != 1 ||
1040       mlirDenseElementsAttrGetInt64SplatValue(splatInt64) != 1 ||
1041       fabsf(mlirDenseElementsAttrGetFloatSplatValue(splatFloat) - 1.0f) >
1042           1E-6f ||
1043       fabs(mlirDenseElementsAttrGetDoubleSplatValue(splatDouble) - 1.0) > 1E-6)
1044     return 17;
1045 
1046   uint8_t *uint8RawData =
1047       (uint8_t *)mlirDenseElementsAttrGetRawData(uint8Elements);
1048   int8_t *int8RawData = (int8_t *)mlirDenseElementsAttrGetRawData(int8Elements);
1049   uint32_t *uint32RawData =
1050       (uint32_t *)mlirDenseElementsAttrGetRawData(uint32Elements);
1051   int32_t *int32RawData =
1052       (int32_t *)mlirDenseElementsAttrGetRawData(int32Elements);
1053   uint64_t *uint64RawData =
1054       (uint64_t *)mlirDenseElementsAttrGetRawData(uint64Elements);
1055   int64_t *int64RawData =
1056       (int64_t *)mlirDenseElementsAttrGetRawData(int64Elements);
1057   float *floatRawData = (float *)mlirDenseElementsAttrGetRawData(floatElements);
1058   double *doubleRawData =
1059       (double *)mlirDenseElementsAttrGetRawData(doubleElements);
1060   if (uint8RawData[0] != 0u || uint8RawData[1] != 1u || int8RawData[0] != 0 ||
1061       int8RawData[1] != 1 || uint32RawData[0] != 0u || uint32RawData[1] != 1u ||
1062       int32RawData[0] != 0 || int32RawData[1] != 1 || uint64RawData[0] != 0u ||
1063       uint64RawData[1] != 1u || int64RawData[0] != 0 || int64RawData[1] != 1 ||
1064       floatRawData[0] != 0.0f || floatRawData[1] != 1.0f ||
1065       doubleRawData[0] != 0.0 || doubleRawData[1] != 1.0)
1066     return 18;
1067 
1068   mlirAttributeDump(splatBool);
1069   mlirAttributeDump(splatUInt8);
1070   mlirAttributeDump(splatInt8);
1071   mlirAttributeDump(splatUInt32);
1072   mlirAttributeDump(splatInt32);
1073   mlirAttributeDump(splatUInt64);
1074   mlirAttributeDump(splatInt64);
1075   mlirAttributeDump(splatFloat);
1076   mlirAttributeDump(splatDouble);
1077   // CHECK: dense<true> : tensor<1x2xi1>
1078   // CHECK: dense<1> : tensor<1x2xui8>
1079   // CHECK: dense<1> : tensor<1x2xi8>
1080   // CHECK: dense<1> : tensor<1x2xui32>
1081   // CHECK: dense<1> : tensor<1x2xi32>
1082   // CHECK: dense<1> : tensor<1x2xui64>
1083   // CHECK: dense<1> : tensor<1x2xi64>
1084   // CHECK: dense<1.000000e+00> : tensor<1x2xf32>
1085   // CHECK: dense<1.000000e+00> : tensor<1x2xf64>
1086 
1087   mlirAttributeDump(mlirElementsAttrGetValue(floatElements, 2, uints64));
1088   mlirAttributeDump(mlirElementsAttrGetValue(doubleElements, 2, uints64));
1089   // CHECK: 1.000000e+00 : f32
1090   // CHECK: 1.000000e+00 : f64
1091 
1092   int64_t indices[] = {0, 1};
1093   int64_t one = 1;
1094   MlirAttribute indicesAttr = mlirDenseElementsAttrInt64Get(
1095       mlirRankedTensorTypeGet(2, shape, mlirIntegerTypeGet(ctx, 64), encoding),
1096       2, indices);
1097   MlirAttribute valuesAttr = mlirDenseElementsAttrFloatGet(
1098       mlirRankedTensorTypeGet(1, &one, mlirF32TypeGet(ctx), encoding), 1,
1099       floats);
1100   MlirAttribute sparseAttr = mlirSparseElementsAttribute(
1101       mlirRankedTensorTypeGet(2, shape, mlirF32TypeGet(ctx), encoding),
1102       indicesAttr, valuesAttr);
1103   mlirAttributeDump(sparseAttr);
1104   // CHECK: sparse<{{\[}}[0, 1]], 0.000000e+00> : tensor<1x2xf32>
1105 
1106   return 0;
1107 }
1108 
1109 int printAffineMap(MlirContext ctx) {
1110   MlirAffineMap emptyAffineMap = mlirAffineMapEmptyGet(ctx);
1111   MlirAffineMap affineMap = mlirAffineMapZeroResultGet(ctx, 3, 2);
1112   MlirAffineMap constAffineMap = mlirAffineMapConstantGet(ctx, 2);
1113   MlirAffineMap multiDimIdentityAffineMap =
1114       mlirAffineMapMultiDimIdentityGet(ctx, 3);
1115   MlirAffineMap minorIdentityAffineMap =
1116       mlirAffineMapMinorIdentityGet(ctx, 3, 2);
1117   unsigned permutation[] = {1, 2, 0};
1118   MlirAffineMap permutationAffineMap = mlirAffineMapPermutationGet(
1119       ctx, sizeof(permutation) / sizeof(unsigned), permutation);
1120 
1121   fprintf(stderr, "@affineMap\n");
1122   mlirAffineMapDump(emptyAffineMap);
1123   mlirAffineMapDump(affineMap);
1124   mlirAffineMapDump(constAffineMap);
1125   mlirAffineMapDump(multiDimIdentityAffineMap);
1126   mlirAffineMapDump(minorIdentityAffineMap);
1127   mlirAffineMapDump(permutationAffineMap);
1128   // CHECK-LABEL: @affineMap
1129   // CHECK: () -> ()
1130   // CHECK: (d0, d1, d2)[s0, s1] -> ()
1131   // CHECK: () -> (2)
1132   // CHECK: (d0, d1, d2) -> (d0, d1, d2)
1133   // CHECK: (d0, d1, d2) -> (d1, d2)
1134   // CHECK: (d0, d1, d2) -> (d1, d2, d0)
1135 
1136   if (!mlirAffineMapIsIdentity(emptyAffineMap) ||
1137       mlirAffineMapIsIdentity(affineMap) ||
1138       mlirAffineMapIsIdentity(constAffineMap) ||
1139       !mlirAffineMapIsIdentity(multiDimIdentityAffineMap) ||
1140       mlirAffineMapIsIdentity(minorIdentityAffineMap) ||
1141       mlirAffineMapIsIdentity(permutationAffineMap))
1142     return 1;
1143 
1144   if (!mlirAffineMapIsMinorIdentity(emptyAffineMap) ||
1145       mlirAffineMapIsMinorIdentity(affineMap) ||
1146       !mlirAffineMapIsMinorIdentity(multiDimIdentityAffineMap) ||
1147       !mlirAffineMapIsMinorIdentity(minorIdentityAffineMap) ||
1148       mlirAffineMapIsMinorIdentity(permutationAffineMap))
1149     return 2;
1150 
1151   if (!mlirAffineMapIsEmpty(emptyAffineMap) ||
1152       mlirAffineMapIsEmpty(affineMap) || mlirAffineMapIsEmpty(constAffineMap) ||
1153       mlirAffineMapIsEmpty(multiDimIdentityAffineMap) ||
1154       mlirAffineMapIsEmpty(minorIdentityAffineMap) ||
1155       mlirAffineMapIsEmpty(permutationAffineMap))
1156     return 3;
1157 
1158   if (mlirAffineMapIsSingleConstant(emptyAffineMap) ||
1159       mlirAffineMapIsSingleConstant(affineMap) ||
1160       !mlirAffineMapIsSingleConstant(constAffineMap) ||
1161       mlirAffineMapIsSingleConstant(multiDimIdentityAffineMap) ||
1162       mlirAffineMapIsSingleConstant(minorIdentityAffineMap) ||
1163       mlirAffineMapIsSingleConstant(permutationAffineMap))
1164     return 4;
1165 
1166   if (mlirAffineMapGetSingleConstantResult(constAffineMap) != 2)
1167     return 5;
1168 
1169   if (mlirAffineMapGetNumDims(emptyAffineMap) != 0 ||
1170       mlirAffineMapGetNumDims(affineMap) != 3 ||
1171       mlirAffineMapGetNumDims(constAffineMap) != 0 ||
1172       mlirAffineMapGetNumDims(multiDimIdentityAffineMap) != 3 ||
1173       mlirAffineMapGetNumDims(minorIdentityAffineMap) != 3 ||
1174       mlirAffineMapGetNumDims(permutationAffineMap) != 3)
1175     return 6;
1176 
1177   if (mlirAffineMapGetNumSymbols(emptyAffineMap) != 0 ||
1178       mlirAffineMapGetNumSymbols(affineMap) != 2 ||
1179       mlirAffineMapGetNumSymbols(constAffineMap) != 0 ||
1180       mlirAffineMapGetNumSymbols(multiDimIdentityAffineMap) != 0 ||
1181       mlirAffineMapGetNumSymbols(minorIdentityAffineMap) != 0 ||
1182       mlirAffineMapGetNumSymbols(permutationAffineMap) != 0)
1183     return 7;
1184 
1185   if (mlirAffineMapGetNumResults(emptyAffineMap) != 0 ||
1186       mlirAffineMapGetNumResults(affineMap) != 0 ||
1187       mlirAffineMapGetNumResults(constAffineMap) != 1 ||
1188       mlirAffineMapGetNumResults(multiDimIdentityAffineMap) != 3 ||
1189       mlirAffineMapGetNumResults(minorIdentityAffineMap) != 2 ||
1190       mlirAffineMapGetNumResults(permutationAffineMap) != 3)
1191     return 8;
1192 
1193   if (mlirAffineMapGetNumInputs(emptyAffineMap) != 0 ||
1194       mlirAffineMapGetNumInputs(affineMap) != 5 ||
1195       mlirAffineMapGetNumInputs(constAffineMap) != 0 ||
1196       mlirAffineMapGetNumInputs(multiDimIdentityAffineMap) != 3 ||
1197       mlirAffineMapGetNumInputs(minorIdentityAffineMap) != 3 ||
1198       mlirAffineMapGetNumInputs(permutationAffineMap) != 3)
1199     return 9;
1200 
1201   if (!mlirAffineMapIsProjectedPermutation(emptyAffineMap) ||
1202       !mlirAffineMapIsPermutation(emptyAffineMap) ||
1203       mlirAffineMapIsProjectedPermutation(affineMap) ||
1204       mlirAffineMapIsPermutation(affineMap) ||
1205       mlirAffineMapIsProjectedPermutation(constAffineMap) ||
1206       mlirAffineMapIsPermutation(constAffineMap) ||
1207       !mlirAffineMapIsProjectedPermutation(multiDimIdentityAffineMap) ||
1208       !mlirAffineMapIsPermutation(multiDimIdentityAffineMap) ||
1209       !mlirAffineMapIsProjectedPermutation(minorIdentityAffineMap) ||
1210       mlirAffineMapIsPermutation(minorIdentityAffineMap) ||
1211       !mlirAffineMapIsProjectedPermutation(permutationAffineMap) ||
1212       !mlirAffineMapIsPermutation(permutationAffineMap))
1213     return 10;
1214 
1215   intptr_t sub[] = {1};
1216 
1217   MlirAffineMap subMap = mlirAffineMapGetSubMap(
1218       multiDimIdentityAffineMap, sizeof(sub) / sizeof(intptr_t), sub);
1219   MlirAffineMap majorSubMap =
1220       mlirAffineMapGetMajorSubMap(multiDimIdentityAffineMap, 1);
1221   MlirAffineMap minorSubMap =
1222       mlirAffineMapGetMinorSubMap(multiDimIdentityAffineMap, 1);
1223 
1224   mlirAffineMapDump(subMap);
1225   mlirAffineMapDump(majorSubMap);
1226   mlirAffineMapDump(minorSubMap);
1227   // CHECK: (d0, d1, d2) -> (d1)
1228   // CHECK: (d0, d1, d2) -> (d0)
1229   // CHECK: (d0, d1, d2) -> (d2)
1230 
1231   return 0;
1232 }
1233 
1234 int printAffineExpr(MlirContext ctx) {
1235   MlirAffineExpr affineDimExpr = mlirAffineDimExprGet(ctx, 5);
1236   MlirAffineExpr affineSymbolExpr = mlirAffineSymbolExprGet(ctx, 5);
1237   MlirAffineExpr affineConstantExpr = mlirAffineConstantExprGet(ctx, 5);
1238   MlirAffineExpr affineAddExpr =
1239       mlirAffineAddExprGet(affineDimExpr, affineSymbolExpr);
1240   MlirAffineExpr affineMulExpr =
1241       mlirAffineMulExprGet(affineDimExpr, affineSymbolExpr);
1242   MlirAffineExpr affineModExpr =
1243       mlirAffineModExprGet(affineDimExpr, affineSymbolExpr);
1244   MlirAffineExpr affineFloorDivExpr =
1245       mlirAffineFloorDivExprGet(affineDimExpr, affineSymbolExpr);
1246   MlirAffineExpr affineCeilDivExpr =
1247       mlirAffineCeilDivExprGet(affineDimExpr, affineSymbolExpr);
1248 
1249   // Tests mlirAffineExprDump.
1250   fprintf(stderr, "@affineExpr\n");
1251   mlirAffineExprDump(affineDimExpr);
1252   mlirAffineExprDump(affineSymbolExpr);
1253   mlirAffineExprDump(affineConstantExpr);
1254   mlirAffineExprDump(affineAddExpr);
1255   mlirAffineExprDump(affineMulExpr);
1256   mlirAffineExprDump(affineModExpr);
1257   mlirAffineExprDump(affineFloorDivExpr);
1258   mlirAffineExprDump(affineCeilDivExpr);
1259   // CHECK-LABEL: @affineExpr
1260   // CHECK: d5
1261   // CHECK: s5
1262   // CHECK: 5
1263   // CHECK: d5 + s5
1264   // CHECK: d5 * s5
1265   // CHECK: d5 mod s5
1266   // CHECK: d5 floordiv s5
1267   // CHECK: d5 ceildiv s5
1268 
1269   // Tests methods of affine binary operation expression, takes add expression
1270   // as an example.
1271   mlirAffineExprDump(mlirAffineBinaryOpExprGetLHS(affineAddExpr));
1272   mlirAffineExprDump(mlirAffineBinaryOpExprGetRHS(affineAddExpr));
1273   // CHECK: d5
1274   // CHECK: s5
1275 
1276   // Tests methods of affine dimension expression.
1277   if (mlirAffineDimExprGetPosition(affineDimExpr) != 5)
1278     return 1;
1279 
1280   // Tests methods of affine symbol expression.
1281   if (mlirAffineSymbolExprGetPosition(affineSymbolExpr) != 5)
1282     return 2;
1283 
1284   // Tests methods of affine constant expression.
1285   if (mlirAffineConstantExprGetValue(affineConstantExpr) != 5)
1286     return 3;
1287 
1288   // Tests methods of affine expression.
1289   if (mlirAffineExprIsSymbolicOrConstant(affineDimExpr) ||
1290       !mlirAffineExprIsSymbolicOrConstant(affineSymbolExpr) ||
1291       !mlirAffineExprIsSymbolicOrConstant(affineConstantExpr) ||
1292       mlirAffineExprIsSymbolicOrConstant(affineAddExpr) ||
1293       mlirAffineExprIsSymbolicOrConstant(affineMulExpr) ||
1294       mlirAffineExprIsSymbolicOrConstant(affineModExpr) ||
1295       mlirAffineExprIsSymbolicOrConstant(affineFloorDivExpr) ||
1296       mlirAffineExprIsSymbolicOrConstant(affineCeilDivExpr))
1297     return 4;
1298 
1299   if (!mlirAffineExprIsPureAffine(affineDimExpr) ||
1300       !mlirAffineExprIsPureAffine(affineSymbolExpr) ||
1301       !mlirAffineExprIsPureAffine(affineConstantExpr) ||
1302       !mlirAffineExprIsPureAffine(affineAddExpr) ||
1303       mlirAffineExprIsPureAffine(affineMulExpr) ||
1304       mlirAffineExprIsPureAffine(affineModExpr) ||
1305       mlirAffineExprIsPureAffine(affineFloorDivExpr) ||
1306       mlirAffineExprIsPureAffine(affineCeilDivExpr))
1307     return 5;
1308 
1309   if (mlirAffineExprGetLargestKnownDivisor(affineDimExpr) != 1 ||
1310       mlirAffineExprGetLargestKnownDivisor(affineSymbolExpr) != 1 ||
1311       mlirAffineExprGetLargestKnownDivisor(affineConstantExpr) != 5 ||
1312       mlirAffineExprGetLargestKnownDivisor(affineAddExpr) != 1 ||
1313       mlirAffineExprGetLargestKnownDivisor(affineMulExpr) != 1 ||
1314       mlirAffineExprGetLargestKnownDivisor(affineModExpr) != 1 ||
1315       mlirAffineExprGetLargestKnownDivisor(affineFloorDivExpr) != 1 ||
1316       mlirAffineExprGetLargestKnownDivisor(affineCeilDivExpr) != 1)
1317     return 6;
1318 
1319   if (!mlirAffineExprIsMultipleOf(affineDimExpr, 1) ||
1320       !mlirAffineExprIsMultipleOf(affineSymbolExpr, 1) ||
1321       !mlirAffineExprIsMultipleOf(affineConstantExpr, 5) ||
1322       !mlirAffineExprIsMultipleOf(affineAddExpr, 1) ||
1323       !mlirAffineExprIsMultipleOf(affineMulExpr, 1) ||
1324       !mlirAffineExprIsMultipleOf(affineModExpr, 1) ||
1325       !mlirAffineExprIsMultipleOf(affineFloorDivExpr, 1) ||
1326       !mlirAffineExprIsMultipleOf(affineCeilDivExpr, 1))
1327     return 7;
1328 
1329   if (!mlirAffineExprIsFunctionOfDim(affineDimExpr, 5) ||
1330       mlirAffineExprIsFunctionOfDim(affineSymbolExpr, 5) ||
1331       mlirAffineExprIsFunctionOfDim(affineConstantExpr, 5) ||
1332       !mlirAffineExprIsFunctionOfDim(affineAddExpr, 5) ||
1333       !mlirAffineExprIsFunctionOfDim(affineMulExpr, 5) ||
1334       !mlirAffineExprIsFunctionOfDim(affineModExpr, 5) ||
1335       !mlirAffineExprIsFunctionOfDim(affineFloorDivExpr, 5) ||
1336       !mlirAffineExprIsFunctionOfDim(affineCeilDivExpr, 5))
1337     return 8;
1338 
1339   // Tests 'IsA' methods of affine binary operation expression.
1340   if (!mlirAffineExprIsAAdd(affineAddExpr))
1341     return 9;
1342 
1343   if (!mlirAffineExprIsAMul(affineMulExpr))
1344     return 10;
1345 
1346   if (!mlirAffineExprIsAMod(affineModExpr))
1347     return 11;
1348 
1349   if (!mlirAffineExprIsAFloorDiv(affineFloorDivExpr))
1350     return 12;
1351 
1352   if (!mlirAffineExprIsACeilDiv(affineCeilDivExpr))
1353     return 13;
1354 
1355   if (!mlirAffineExprIsABinary(affineAddExpr))
1356     return 14;
1357 
1358   // Test other 'IsA' method on affine expressions.
1359   if (!mlirAffineExprIsAConstant(affineConstantExpr))
1360     return 15;
1361 
1362   if (!mlirAffineExprIsADim(affineDimExpr))
1363     return 16;
1364 
1365   if (!mlirAffineExprIsASymbol(affineSymbolExpr))
1366     return 17;
1367 
1368   // Test equality and nullity.
1369   MlirAffineExpr otherDimExpr = mlirAffineDimExprGet(ctx, 5);
1370   if (!mlirAffineExprEqual(affineDimExpr, otherDimExpr))
1371     return 18;
1372 
1373   if (mlirAffineExprIsNull(affineDimExpr))
1374     return 19;
1375 
1376   return 0;
1377 }
1378 
1379 int affineMapFromExprs(MlirContext ctx) {
1380   MlirAffineExpr affineDimExpr = mlirAffineDimExprGet(ctx, 0);
1381   MlirAffineExpr affineSymbolExpr = mlirAffineSymbolExprGet(ctx, 1);
1382   MlirAffineExpr exprs[] = {affineDimExpr, affineSymbolExpr};
1383   MlirAffineMap map = mlirAffineMapGet(ctx, 3, 3, 2, exprs);
1384 
1385   // CHECK-LABEL: @affineMapFromExprs
1386   fprintf(stderr, "@affineMapFromExprs");
1387   // CHECK: (d0, d1, d2)[s0, s1, s2] -> (d0, s1)
1388   mlirAffineMapDump(map);
1389 
1390   if (mlirAffineMapGetNumResults(map) != 2)
1391     return 1;
1392 
1393   if (!mlirAffineExprEqual(mlirAffineMapGetResult(map, 0), affineDimExpr))
1394     return 2;
1395 
1396   if (!mlirAffineExprEqual(mlirAffineMapGetResult(map, 1), affineSymbolExpr))
1397     return 3;
1398 
1399   MlirAffineExpr affineDim2Expr = mlirAffineDimExprGet(ctx, 1);
1400   MlirAffineExpr composed = mlirAffineExprCompose(affineDim2Expr, map);
1401   // CHECK: s1
1402   mlirAffineExprDump(composed);
1403   if (!mlirAffineExprEqual(composed, affineSymbolExpr))
1404     return 4;
1405 
1406   return 0;
1407 }
1408 
1409 int printIntegerSet(MlirContext ctx) {
1410   MlirIntegerSet emptySet = mlirIntegerSetEmptyGet(ctx, 2, 1);
1411 
1412   // CHECK-LABEL: @printIntegerSet
1413   fprintf(stderr, "@printIntegerSet");
1414 
1415   // CHECK: (d0, d1)[s0] : (1 == 0)
1416   mlirIntegerSetDump(emptySet);
1417 
1418   if (!mlirIntegerSetIsCanonicalEmpty(emptySet))
1419     return 1;
1420 
1421   MlirIntegerSet anotherEmptySet = mlirIntegerSetEmptyGet(ctx, 2, 1);
1422   if (!mlirIntegerSetEqual(emptySet, anotherEmptySet))
1423     return 2;
1424 
1425   // Construct a set constrained by:
1426   //   d0 - s0 == 0,
1427   //   d1 - 42 >= 0.
1428   MlirAffineExpr negOne = mlirAffineConstantExprGet(ctx, -1);
1429   MlirAffineExpr negFortyTwo = mlirAffineConstantExprGet(ctx, -42);
1430   MlirAffineExpr d0 = mlirAffineDimExprGet(ctx, 0);
1431   MlirAffineExpr d1 = mlirAffineDimExprGet(ctx, 1);
1432   MlirAffineExpr s0 = mlirAffineSymbolExprGet(ctx, 0);
1433   MlirAffineExpr negS0 = mlirAffineMulExprGet(negOne, s0);
1434   MlirAffineExpr d0minusS0 = mlirAffineAddExprGet(d0, negS0);
1435   MlirAffineExpr d1minus42 = mlirAffineAddExprGet(d1, negFortyTwo);
1436   MlirAffineExpr constraints[] = {d0minusS0, d1minus42};
1437   bool flags[] = {true, false};
1438 
1439   MlirIntegerSet set = mlirIntegerSetGet(ctx, 2, 1, 2, constraints, flags);
1440   // CHECK: (d0, d1)[s0] : (
1441   // CHECK-DAG: d0 - s0 == 0
1442   // CHECK-DAG: d1 - 42 >= 0
1443   mlirIntegerSetDump(set);
1444 
1445   // Transform d1 into s0.
1446   MlirAffineExpr s1 = mlirAffineSymbolExprGet(ctx, 1);
1447   MlirAffineExpr repl[] = {d0, s1};
1448   MlirIntegerSet replaced = mlirIntegerSetReplaceGet(set, repl, &s0, 1, 2);
1449   // CHECK: (d0)[s0, s1] : (
1450   // CHECK-DAG: d0 - s0 == 0
1451   // CHECK-DAG: s1 - 42 >= 0
1452   mlirIntegerSetDump(replaced);
1453 
1454   if (mlirIntegerSetGetNumDims(set) != 2)
1455     return 3;
1456   if (mlirIntegerSetGetNumDims(replaced) != 1)
1457     return 4;
1458 
1459   if (mlirIntegerSetGetNumSymbols(set) != 1)
1460     return 5;
1461   if (mlirIntegerSetGetNumSymbols(replaced) != 2)
1462     return 6;
1463 
1464   if (mlirIntegerSetGetNumInputs(set) != 3)
1465     return 7;
1466 
1467   if (mlirIntegerSetGetNumConstraints(set) != 2)
1468     return 8;
1469 
1470   if (mlirIntegerSetGetNumEqualities(set) != 1)
1471     return 9;
1472 
1473   if (mlirIntegerSetGetNumInequalities(set) != 1)
1474     return 10;
1475 
1476   MlirAffineExpr cstr1 = mlirIntegerSetGetConstraint(set, 0);
1477   MlirAffineExpr cstr2 = mlirIntegerSetGetConstraint(set, 1);
1478   bool isEq1 = mlirIntegerSetIsConstraintEq(set, 0);
1479   bool isEq2 = mlirIntegerSetIsConstraintEq(set, 1);
1480   if (!mlirAffineExprEqual(cstr1, isEq1 ? d0minusS0 : d1minus42))
1481     return 11;
1482   if (!mlirAffineExprEqual(cstr2, isEq2 ? d0minusS0 : d1minus42))
1483     return 12;
1484 
1485   return 0;
1486 }
1487 
1488 int registerOnlyStd() {
1489   MlirContext ctx = mlirContextCreate();
1490   // The built-in dialect is always loaded.
1491   if (mlirContextGetNumLoadedDialects(ctx) != 1)
1492     return 1;
1493 
1494   MlirDialectHandle stdHandle = mlirGetDialectHandle__std__();
1495 
1496   MlirDialect std = mlirContextGetOrLoadDialect(
1497       ctx, mlirDialectHandleGetNamespace(stdHandle));
1498   if (!mlirDialectIsNull(std))
1499     return 2;
1500 
1501   mlirDialectHandleRegisterDialect(stdHandle, ctx);
1502 
1503   std = mlirContextGetOrLoadDialect(ctx,
1504                                     mlirDialectHandleGetNamespace(stdHandle));
1505   if (mlirDialectIsNull(std))
1506     return 3;
1507 
1508   MlirDialect alsoStd = mlirDialectHandleLoadDialect(stdHandle, ctx);
1509   if (!mlirDialectEqual(std, alsoStd))
1510     return 4;
1511 
1512   MlirStringRef stdNs = mlirDialectGetNamespace(std);
1513   MlirStringRef alsoStdNs = mlirDialectHandleGetNamespace(stdHandle);
1514   if (stdNs.length != alsoStdNs.length ||
1515       strncmp(stdNs.data, alsoStdNs.data, stdNs.length))
1516     return 5;
1517 
1518   fprintf(stderr, "@registration\n");
1519   // CHECK-LABEL: @registration
1520 
1521   // CHECK: std.cond_br is_registered: 1
1522   fprintf(stderr, "std.cond_br is_registered: %d\n",
1523           mlirContextIsRegisteredOperation(
1524               ctx, mlirStringRefCreateFromCString("std.cond_br")));
1525 
1526   // CHECK: std.not_existing_op is_registered: 0
1527   fprintf(stderr, "std.not_existing_op is_registered: %d\n",
1528           mlirContextIsRegisteredOperation(
1529               ctx, mlirStringRefCreateFromCString("std.not_existing_op")));
1530 
1531   // CHECK: not_existing_dialect.not_existing_op is_registered: 0
1532   fprintf(stderr, "not_existing_dialect.not_existing_op is_registered: %d\n",
1533           mlirContextIsRegisteredOperation(
1534               ctx, mlirStringRefCreateFromCString(
1535                        "not_existing_dialect.not_existing_op")));
1536 
1537   mlirContextDestroy(ctx);
1538   return 0;
1539 }
1540 
1541 /// Tests backreference APIs
1542 static int testBackreferences() {
1543   fprintf(stderr, "@test_backreferences\n");
1544 
1545   MlirContext ctx = mlirContextCreate();
1546   mlirContextSetAllowUnregisteredDialects(ctx, true);
1547   MlirLocation loc = mlirLocationUnknownGet(ctx);
1548 
1549   MlirOperationState opState =
1550       mlirOperationStateGet(mlirStringRefCreateFromCString("invalid.op"), loc);
1551   MlirRegion region = mlirRegionCreate();
1552   MlirBlock block = mlirBlockCreate(0, NULL);
1553   mlirRegionAppendOwnedBlock(region, block);
1554   mlirOperationStateAddOwnedRegions(&opState, 1, &region);
1555   MlirOperation op = mlirOperationCreate(&opState);
1556   MlirIdentifier ident =
1557       mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("identifier"));
1558 
1559   if (!mlirContextEqual(ctx, mlirOperationGetContext(op))) {
1560     fprintf(stderr, "ERROR: Getting context from operation failed\n");
1561     return 1;
1562   }
1563   if (!mlirOperationEqual(op, mlirBlockGetParentOperation(block))) {
1564     fprintf(stderr, "ERROR: Getting parent operation from block failed\n");
1565     return 2;
1566   }
1567   if (!mlirContextEqual(ctx, mlirIdentifierGetContext(ident))) {
1568     fprintf(stderr, "ERROR: Getting context from identifier failed\n");
1569     return 3;
1570   }
1571 
1572   mlirOperationDestroy(op);
1573   mlirContextDestroy(ctx);
1574 
1575   // CHECK-LABEL: @test_backreferences
1576   return 0;
1577 }
1578 
1579 /// Tests operand APIs.
1580 int testOperands() {
1581   fprintf(stderr, "@testOperands\n");
1582   // CHECK-LABEL: @testOperands
1583 
1584   MlirContext ctx = mlirContextCreate();
1585   mlirRegisterAllDialects(ctx);
1586   mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("test"));
1587   MlirLocation loc = mlirLocationUnknownGet(ctx);
1588   MlirType indexType = mlirIndexTypeGet(ctx);
1589 
1590   // Create some constants to use as operands.
1591   MlirAttribute indexZeroLiteral =
1592       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("0 : index"));
1593   MlirNamedAttribute indexZeroValueAttr = mlirNamedAttributeGet(
1594       mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("value")),
1595       indexZeroLiteral);
1596   MlirOperationState constZeroState = mlirOperationStateGet(
1597       mlirStringRefCreateFromCString("arith.constant"), loc);
1598   mlirOperationStateAddResults(&constZeroState, 1, &indexType);
1599   mlirOperationStateAddAttributes(&constZeroState, 1, &indexZeroValueAttr);
1600   MlirOperation constZero = mlirOperationCreate(&constZeroState);
1601   MlirValue constZeroValue = mlirOperationGetResult(constZero, 0);
1602 
1603   MlirAttribute indexOneLiteral =
1604       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("1 : index"));
1605   MlirNamedAttribute indexOneValueAttr = mlirNamedAttributeGet(
1606       mlirIdentifierGet(ctx, mlirStringRefCreateFromCString("value")),
1607       indexOneLiteral);
1608   MlirOperationState constOneState = mlirOperationStateGet(
1609       mlirStringRefCreateFromCString("arith.constant"), loc);
1610   mlirOperationStateAddResults(&constOneState, 1, &indexType);
1611   mlirOperationStateAddAttributes(&constOneState, 1, &indexOneValueAttr);
1612   MlirOperation constOne = mlirOperationCreate(&constOneState);
1613   MlirValue constOneValue = mlirOperationGetResult(constOne, 0);
1614 
1615   // Create the operation under test.
1616   mlirContextSetAllowUnregisteredDialects(ctx, true);
1617   MlirOperationState opState =
1618       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op"), loc);
1619   MlirValue initialOperands[] = {constZeroValue};
1620   mlirOperationStateAddOperands(&opState, 1, initialOperands);
1621   MlirOperation op = mlirOperationCreate(&opState);
1622 
1623   // Test operand APIs.
1624   intptr_t numOperands = mlirOperationGetNumOperands(op);
1625   fprintf(stderr, "Num Operands: %" PRIdPTR "\n", numOperands);
1626   // CHECK: Num Operands: 1
1627 
1628   MlirValue opOperand = mlirOperationGetOperand(op, 0);
1629   fprintf(stderr, "Original operand: ");
1630   mlirValuePrint(opOperand, printToStderr, NULL);
1631   // CHECK: Original operand: {{.+}} arith.constant 0 : index
1632 
1633   mlirOperationSetOperand(op, 0, constOneValue);
1634   opOperand = mlirOperationGetOperand(op, 0);
1635   fprintf(stderr, "Updated operand: ");
1636   mlirValuePrint(opOperand, printToStderr, NULL);
1637   // CHECK: Updated operand: {{.+}} arith.constant 1 : index
1638 
1639   mlirOperationDestroy(op);
1640   mlirOperationDestroy(constZero);
1641   mlirOperationDestroy(constOne);
1642   mlirContextDestroy(ctx);
1643 
1644   return 0;
1645 }
1646 
1647 /// Tests clone APIs.
1648 int testClone() {
1649   fprintf(stderr, "@testClone\n");
1650   // CHECK-LABEL: @testClone
1651 
1652   MlirContext ctx = mlirContextCreate();
1653   mlirRegisterAllDialects(ctx);
1654   mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("std"));
1655   MlirLocation loc = mlirLocationUnknownGet(ctx);
1656   MlirType indexType = mlirIndexTypeGet(ctx);
1657   MlirStringRef valueStringRef = mlirStringRefCreateFromCString("value");
1658 
1659   MlirAttribute indexZeroLiteral =
1660       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("0 : index"));
1661   MlirNamedAttribute indexZeroValueAttr = mlirNamedAttributeGet(
1662       mlirIdentifierGet(ctx, valueStringRef), indexZeroLiteral);
1663   MlirOperationState constZeroState = mlirOperationStateGet(
1664       mlirStringRefCreateFromCString("arith.constant"), loc);
1665   mlirOperationStateAddResults(&constZeroState, 1, &indexType);
1666   mlirOperationStateAddAttributes(&constZeroState, 1, &indexZeroValueAttr);
1667   MlirOperation constZero = mlirOperationCreate(&constZeroState);
1668 
1669   MlirAttribute indexOneLiteral =
1670       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("1 : index"));
1671   MlirOperation constOne = mlirOperationClone(constZero);
1672   mlirOperationSetAttributeByName(constOne, valueStringRef, indexOneLiteral);
1673 
1674   mlirOperationPrint(constZero, printToStderr, NULL);
1675   mlirOperationPrint(constOne, printToStderr, NULL);
1676   // CHECK: arith.constant 0 : index
1677   // CHECK: arith.constant 1 : index
1678 
1679   mlirOperationDestroy(constZero);
1680   mlirOperationDestroy(constOne);
1681   mlirContextDestroy(ctx);
1682   return 0;
1683 }
1684 
1685 // Wraps a diagnostic into additional text we can match against.
1686 MlirLogicalResult errorHandler(MlirDiagnostic diagnostic, void *userData) {
1687   fprintf(stderr, "processing diagnostic (userData: %" PRIdPTR ") <<\n",
1688           (intptr_t)userData);
1689   mlirDiagnosticPrint(diagnostic, printToStderr, NULL);
1690   fprintf(stderr, "\n");
1691   MlirLocation loc = mlirDiagnosticGetLocation(diagnostic);
1692   mlirLocationPrint(loc, printToStderr, NULL);
1693   assert(mlirDiagnosticGetNumNotes(diagnostic) == 0);
1694   fprintf(stderr, "\n>> end of diagnostic (userData: %" PRIdPTR ")\n",
1695           (intptr_t)userData);
1696   return mlirLogicalResultSuccess();
1697 }
1698 
1699 // Logs when the delete user data callback is called
1700 static void deleteUserData(void *userData) {
1701   fprintf(stderr, "deleting user data (userData: %" PRIdPTR ")\n",
1702           (intptr_t)userData);
1703 }
1704 
1705 int testTypeID(MlirContext ctx) {
1706   fprintf(stderr, "@testTypeID\n");
1707 
1708   // Test getting and comparing type and attribute type ids.
1709   MlirType i32 = mlirIntegerTypeGet(ctx, 32);
1710   MlirTypeID i32ID = mlirTypeGetTypeID(i32);
1711   MlirType ui32 = mlirIntegerTypeUnsignedGet(ctx, 32);
1712   MlirTypeID ui32ID = mlirTypeGetTypeID(ui32);
1713   MlirType f32 = mlirF32TypeGet(ctx);
1714   MlirTypeID f32ID = mlirTypeGetTypeID(f32);
1715   MlirAttribute i32Attr = mlirIntegerAttrGet(i32, 1);
1716   MlirTypeID i32AttrID = mlirAttributeGetTypeID(i32Attr);
1717 
1718   if (mlirTypeIDIsNull(i32ID) || mlirTypeIDIsNull(ui32ID) ||
1719       mlirTypeIDIsNull(f32ID) || mlirTypeIDIsNull(i32AttrID)) {
1720     fprintf(stderr, "ERROR: Expected type ids to be present\n");
1721     return 1;
1722   }
1723 
1724   if (!mlirTypeIDEqual(i32ID, ui32ID) ||
1725       mlirTypeIDHashValue(i32ID) != mlirTypeIDHashValue(ui32ID)) {
1726     fprintf(
1727         stderr,
1728         "ERROR: Expected different integer types to have the same type id\n");
1729     return 2;
1730   }
1731 
1732   if (mlirTypeIDEqual(i32ID, f32ID) ||
1733       mlirTypeIDHashValue(i32ID) == mlirTypeIDHashValue(f32ID)) {
1734     fprintf(stderr,
1735             "ERROR: Expected integer type id to not equal float type id\n");
1736     return 3;
1737   }
1738 
1739   if (mlirTypeIDEqual(i32ID, i32AttrID) ||
1740       mlirTypeIDHashValue(i32ID) == mlirTypeIDHashValue(i32AttrID)) {
1741     fprintf(stderr, "ERROR: Expected integer type id to not equal integer "
1742                     "attribute type id\n");
1743     return 4;
1744   }
1745 
1746   MlirLocation loc = mlirLocationUnknownGet(ctx);
1747   MlirType indexType = mlirIndexTypeGet(ctx);
1748   MlirStringRef valueStringRef = mlirStringRefCreateFromCString("value");
1749 
1750   // Create a registered operation, which should have a type id.
1751   MlirAttribute indexZeroLiteral =
1752       mlirAttributeParseGet(ctx, mlirStringRefCreateFromCString("0 : index"));
1753   MlirNamedAttribute indexZeroValueAttr = mlirNamedAttributeGet(
1754       mlirIdentifierGet(ctx, valueStringRef), indexZeroLiteral);
1755   MlirOperationState constZeroState = mlirOperationStateGet(
1756       mlirStringRefCreateFromCString("arith.constant"), loc);
1757   mlirOperationStateAddResults(&constZeroState, 1, &indexType);
1758   mlirOperationStateAddAttributes(&constZeroState, 1, &indexZeroValueAttr);
1759   MlirOperation constZero = mlirOperationCreate(&constZeroState);
1760 
1761   if (!mlirOperationVerify(constZero)) {
1762     fprintf(stderr, "ERROR: Expected operation to verify correctly\n");
1763     return 5;
1764   }
1765 
1766   if (mlirOperationIsNull(constZero)) {
1767     fprintf(stderr, "ERROR: Expected registered operation to be present\n");
1768     return 6;
1769   }
1770 
1771   MlirTypeID registeredOpID = mlirOperationGetTypeID(constZero);
1772 
1773   if (mlirTypeIDIsNull(registeredOpID)) {
1774     fprintf(stderr,
1775             "ERROR: Expected registered operation type id to be present\n");
1776     return 7;
1777   }
1778 
1779   // Create an unregistered operation, which should not have a type id.
1780   mlirContextSetAllowUnregisteredDialects(ctx, true);
1781   MlirOperationState opState =
1782       mlirOperationStateGet(mlirStringRefCreateFromCString("dummy.op"), loc);
1783   MlirOperation unregisteredOp = mlirOperationCreate(&opState);
1784   if (mlirOperationIsNull(unregisteredOp)) {
1785     fprintf(stderr, "ERROR: Expected unregistered operation to be present\n");
1786     return 8;
1787   }
1788 
1789   MlirTypeID unregisteredOpID = mlirOperationGetTypeID(unregisteredOp);
1790 
1791   if (!mlirTypeIDIsNull(unregisteredOpID)) {
1792     fprintf(stderr,
1793             "ERROR: Expected unregistered operation type id to be null\n");
1794     return 9;
1795   }
1796 
1797   mlirOperationDestroy(constZero);
1798   mlirOperationDestroy(unregisteredOp);
1799 
1800   return 0;
1801 }
1802 
1803 int testSymbolTable(MlirContext ctx) {
1804   fprintf(stderr, "@testSymbolTable\n");
1805 
1806   const char *moduleString = "func private @foo()"
1807                              "func private @bar()";
1808   const char *otherModuleString = "func private @qux()"
1809                                   "func private @foo()";
1810 
1811   MlirModule module =
1812       mlirModuleCreateParse(ctx, mlirStringRefCreateFromCString(moduleString));
1813   MlirModule otherModule = mlirModuleCreateParse(
1814       ctx, mlirStringRefCreateFromCString(otherModuleString));
1815 
1816   MlirSymbolTable symbolTable =
1817       mlirSymbolTableCreate(mlirModuleGetOperation(module));
1818 
1819   MlirOperation funcFoo =
1820       mlirSymbolTableLookup(symbolTable, mlirStringRefCreateFromCString("foo"));
1821   if (mlirOperationIsNull(funcFoo))
1822     return 1;
1823 
1824   MlirOperation funcBar =
1825       mlirSymbolTableLookup(symbolTable, mlirStringRefCreateFromCString("bar"));
1826   if (mlirOperationEqual(funcFoo, funcBar))
1827     return 2;
1828 
1829   MlirOperation missing =
1830       mlirSymbolTableLookup(symbolTable, mlirStringRefCreateFromCString("qux"));
1831   if (!mlirOperationIsNull(missing))
1832     return 3;
1833 
1834   MlirBlock moduleBody = mlirModuleGetBody(module);
1835   MlirBlock otherModuleBody = mlirModuleGetBody(otherModule);
1836   MlirOperation operation = mlirBlockGetFirstOperation(otherModuleBody);
1837   mlirOperationRemoveFromParent(operation);
1838   mlirBlockAppendOwnedOperation(moduleBody, operation);
1839 
1840   // At this moment, the operation is still missing from the symbol table.
1841   MlirOperation stillMissing =
1842       mlirSymbolTableLookup(symbolTable, mlirStringRefCreateFromCString("qux"));
1843   if (!mlirOperationIsNull(stillMissing))
1844     return 4;
1845 
1846   // After it is added to the symbol table, and not only the operation with
1847   // which the table is associated, it can be looked up.
1848   mlirSymbolTableInsert(symbolTable, operation);
1849   MlirOperation funcQux =
1850       mlirSymbolTableLookup(symbolTable, mlirStringRefCreateFromCString("qux"));
1851   if (!mlirOperationEqual(operation, funcQux))
1852     return 5;
1853 
1854   // Erasing from the symbol table also removes the operation.
1855   mlirSymbolTableErase(symbolTable, funcBar);
1856   MlirOperation nowMissing =
1857       mlirSymbolTableLookup(symbolTable, mlirStringRefCreateFromCString("bar"));
1858   if (!mlirOperationIsNull(nowMissing))
1859     return 6;
1860 
1861   // Adding a symbol with the same name to the table should rename.
1862   MlirOperation duplicateNameOp = mlirBlockGetFirstOperation(otherModuleBody);
1863   mlirOperationRemoveFromParent(duplicateNameOp);
1864   mlirBlockAppendOwnedOperation(moduleBody, duplicateNameOp);
1865   MlirAttribute newName = mlirSymbolTableInsert(symbolTable, duplicateNameOp);
1866   MlirStringRef newNameStr = mlirStringAttrGetValue(newName);
1867   if (mlirStringRefEqual(newNameStr, mlirStringRefCreateFromCString("foo")))
1868     return 7;
1869   MlirAttribute updatedName = mlirOperationGetAttributeByName(
1870       duplicateNameOp, mlirSymbolTableGetSymbolAttributeName());
1871   if (!mlirAttributeEqual(updatedName, newName))
1872     return 8;
1873 
1874   mlirOperationDump(mlirModuleGetOperation(module));
1875   mlirOperationDump(mlirModuleGetOperation(otherModule));
1876   // clang-format off
1877   // CHECK-LABEL: @testSymbolTable
1878   // CHECK: module
1879   // CHECK:   func private @foo
1880   // CHECK:   func private @qux
1881   // CHECK:   func private @foo{{.+}}
1882   // CHECK: module
1883   // CHECK-NOT: @qux
1884   // CHECK-NOT: @foo
1885   // clang-format on
1886 
1887   mlirSymbolTableDestroy(symbolTable);
1888   mlirModuleDestroy(module);
1889   mlirModuleDestroy(otherModule);
1890 
1891   return 0;
1892 }
1893 
1894 void testDiagnostics() {
1895   MlirContext ctx = mlirContextCreate();
1896   MlirDiagnosticHandlerID id = mlirContextAttachDiagnosticHandler(
1897       ctx, errorHandler, (void *)42, deleteUserData);
1898   fprintf(stderr, "@test_diagnostics\n");
1899   MlirLocation unknownLoc = mlirLocationUnknownGet(ctx);
1900   mlirEmitError(unknownLoc, "test diagnostics");
1901   MlirLocation fileLineColLoc = mlirLocationFileLineColGet(
1902       ctx, mlirStringRefCreateFromCString("file.c"), 1, 2);
1903   mlirEmitError(fileLineColLoc, "test diagnostics");
1904   MlirLocation callSiteLoc = mlirLocationCallSiteGet(
1905       mlirLocationFileLineColGet(
1906           ctx, mlirStringRefCreateFromCString("other-file.c"), 2, 3),
1907       fileLineColLoc);
1908   mlirEmitError(callSiteLoc, "test diagnostics");
1909   MlirLocation null = {0};
1910   MlirLocation nameLoc =
1911       mlirLocationNameGet(ctx, mlirStringRefCreateFromCString("named"), null);
1912   mlirEmitError(nameLoc, "test diagnostics");
1913   MlirLocation locs[2] = {nameLoc, callSiteLoc};
1914   MlirAttribute nullAttr = {0};
1915   MlirLocation fusedLoc = mlirLocationFusedGet(ctx, 2, locs, nullAttr);
1916   mlirEmitError(fusedLoc, "test diagnostics");
1917   mlirContextDetachDiagnosticHandler(ctx, id);
1918   mlirEmitError(unknownLoc, "more test diagnostics");
1919   // CHECK-LABEL: @test_diagnostics
1920   // CHECK: processing diagnostic (userData: 42) <<
1921   // CHECK:   test diagnostics
1922   // CHECK:   loc(unknown)
1923   // CHECK: >> end of diagnostic (userData: 42)
1924   // CHECK: processing diagnostic (userData: 42) <<
1925   // CHECK:   test diagnostics
1926   // CHECK:   loc("file.c":1:2)
1927   // CHECK: >> end of diagnostic (userData: 42)
1928   // CHECK: processing diagnostic (userData: 42) <<
1929   // CHECK:   test diagnostics
1930   // CHECK:   loc(callsite("other-file.c":2:3 at "file.c":1:2))
1931   // CHECK: >> end of diagnostic (userData: 42)
1932   // CHECK: processing diagnostic (userData: 42) <<
1933   // CHECK:   test diagnostics
1934   // CHECK:   loc("named")
1935   // CHECK: >> end of diagnostic (userData: 42)
1936   // CHECK: processing diagnostic (userData: 42) <<
1937   // CHECK:   test diagnostics
1938   // CHECK:   loc(fused["named", callsite("other-file.c":2:3 at "file.c":1:2)])
1939   // CHECK: deleting user data (userData: 42)
1940   // CHECK-NOT: processing diagnostic
1941   // CHECK:     more test diagnostics
1942   mlirContextDestroy(ctx);
1943 }
1944 
1945 int main() {
1946   MlirContext ctx = mlirContextCreate();
1947   mlirRegisterAllDialects(ctx);
1948   if (constructAndTraverseIr(ctx))
1949     return 1;
1950   buildWithInsertionsAndPrint(ctx);
1951   if (createOperationWithTypeInference(ctx))
1952     return 2;
1953 
1954   if (printBuiltinTypes(ctx))
1955     return 3;
1956   if (printBuiltinAttributes(ctx))
1957     return 4;
1958   if (printAffineMap(ctx))
1959     return 5;
1960   if (printAffineExpr(ctx))
1961     return 6;
1962   if (affineMapFromExprs(ctx))
1963     return 7;
1964   if (printIntegerSet(ctx))
1965     return 8;
1966   if (registerOnlyStd())
1967     return 9;
1968   if (testBackreferences())
1969     return 10;
1970   if (testOperands())
1971     return 11;
1972   if (testClone())
1973     return 12;
1974   if (testTypeID(ctx))
1975     return 13;
1976   if (testSymbolTable(ctx))
1977     return 14;
1978 
1979   mlirContextDestroy(ctx);
1980 
1981   testDiagnostics();
1982   return 0;
1983 }
1984