3
3
#pragma once
4
4
5
5
VAST_RELAX_WARNINGS
6
+ #include < mlir/Analysis/DataLayoutAnalysis.h>
7
+
6
8
#include < mlir/Conversion/LLVMCommon/TypeConverter.h>
7
9
#include < mlir/Dialect/Func/IR/FuncOps.h>
8
10
#include < mlir/Dialect/LLVMIR/LLVMTypes.h>
@@ -211,6 +213,84 @@ namespace vast::conv::tc {
211
213
}
212
214
};
213
215
216
+ // Really basic draft of how union lowering works, it should however be able to
217
+ // handle most of the usual basic use-cases.
218
+ struct union_lowering
219
+ {
220
+ using self_t = union_lowering;
221
+
222
+ const mlir::DataLayout &dl;
223
+ hl::UnionDeclOp union_decl;
224
+
225
+ std::vector< mlir_type > fields = {};
226
+
227
+ union_lowering (const mlir::DataLayout &dl, hl::UnionDeclOp union_decl)
228
+ : dl(dl), union_decl(union_decl)
229
+ {}
230
+
231
+ union_lowering (const union_lowering &) = delete ;
232
+ union_lowering (const union_lowering &&) = delete ;
233
+
234
+ unsigned align (mlir_type t) { return dl.getTypeABIAlignment (t); }
235
+ unsigned size (mlir_type t ) { return dl.getTypeSize (t); }
236
+
237
+ self_t &compute_lowering ()
238
+ {
239
+ mlir_type result;
240
+ for (auto field_type : union_decl.getFieldTypes ())
241
+ result = merge (result, handle_field (storage_type (field_type)));
242
+
243
+ // TODO(conv:hl-to-ll-geps): Set packed.
244
+ // We need to reconstruct the actual union type, should be a method
245
+ // of `UnionDeclOp` maybe?
246
+ // append_padding_bytes(union_decl.getType(), result);
247
+ fields.push_back (result);
248
+
249
+ return *this ;
250
+ }
251
+
252
+ // This maybe should be extracted outside.
253
+ mlir_type storage_type (mlir_type type)
254
+ {
255
+ // convert for mem - basically do things like `i1 -> i8`.
256
+ // bitfield has some extras
257
+ return mlir::IntegerType::get (type.getContext (), size (type) * 8 );
258
+ }
259
+
260
+ void append_padding_bytes (mlir_type union_type, mlir_type field_type)
261
+ {
262
+ VAST_TODO (" Unions that need padding!" );
263
+ // fields.push_back(array of size difference);
264
+ }
265
+
266
+ mlir_type merge (mlir_type current, mlir_type next)
267
+ {
268
+ if (!current)
269
+ return next;
270
+
271
+ if (align (current) < align (next))
272
+ return next;
273
+
274
+ if (align (current) == align (next) && size (next) > size (current))
275
+ return next;
276
+
277
+ return current;
278
+ }
279
+
280
+ mlir_type handle_field (mlir_type field_type)
281
+ {
282
+ // TODO(conv:hl-to-ll-geps): Bitfields.
283
+ // TODO(conv:hl-to-ll-geps): Something related to zero initialization.
284
+ return field_type;
285
+ }
286
+
287
+ static gap::generator< mlir_type > final_fields (std::vector< mlir_type > fields)
288
+ {
289
+ for (auto ft : fields)
290
+ co_yield ft;
291
+ }
292
+ };
293
+
214
294
// Requires that the named types *always* map to llvm struct types.
215
295
// TODO(lukas): What about type aliases.
216
296
struct FullLLVMTypeConverter : LLVMTypeConverter,
@@ -237,7 +317,13 @@ namespace vast::conv::tc {
237
317
if (!def) {
238
318
return {};
239
319
}
240
- return { def.getFieldTypes () };
320
+ if (auto union_decl = mlir::dyn_cast< hl::UnionDeclOp >(*def)) {
321
+ auto dl = this ->getDataLayoutAnalysis ()->getAtOrAbove (union_decl);
322
+ auto fields = union_lowering{ dl, union_decl }.compute_lowering ().fields ;
323
+ return { union_lowering::final_fields (std::move (fields)) };
324
+ } else {
325
+ return { def.getFieldTypes () };
326
+ }
241
327
}
242
328
243
329
maybe_type_t convert_elaborated_type (hl::ElaboratedType t) {
@@ -254,5 +340,4 @@ namespace vast::conv::tc {
254
340
return { raw };
255
341
}
256
342
};
257
-
258
343
} // namespace vast::conv::tc
0 commit comments