CIRCT 20.0.0git
Loading...
Searching...
No Matches
HWToLLVM.cpp
Go to the documentation of this file.
1//===- HWToLLVM.cpp - HW to LLVM Conversion Pass --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This is the main HW to LLVM Conversion Pass Implementation.
10//
11//===----------------------------------------------------------------------===//
12
15#include "circt/Support/LLVM.h"
17#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
18#include "mlir/Conversion/LLVMCommon/Pattern.h"
19#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
20#include "mlir/Pass/Pass.h"
21#include "mlir/Transforms/DialectConversion.h"
22#include "llvm/ADT/TypeSwitch.h"
23
24namespace circt {
25#define GEN_PASS_DEF_CONVERTHWTOLLVM
26#include "circt/Conversion/Passes.h.inc"
27} // namespace circt
28
29using namespace mlir;
30using namespace circt;
31
32//===----------------------------------------------------------------------===//
33// Endianess Converter
34//===----------------------------------------------------------------------===//
35
36uint32_t
38 uint32_t index) {
39 // This is hardcoded for little endian machines for now.
40 return TypeSwitch<Type, uint32_t>(type)
41 .Case<hw::ArrayType>(
42 [&](hw::ArrayType ty) { return ty.getNumElements() - index - 1; })
43 .Case<hw::StructType>([&](hw::StructType ty) {
44 return ty.getElements().size() - index - 1;
45 });
46}
47
48uint32_t
50 StringRef fieldName) {
51 auto fieldIter = type.getElements();
52 size_t index = 0;
53
54 for (const auto *iter = fieldIter.begin(); iter != fieldIter.end(); ++iter) {
55 if (iter->name == fieldName) {
57 }
58 ++index;
59 }
60
61 // Verifier of StructExtractOp has to ensure that the field name is indeed
62 // present.
63 llvm_unreachable("Field name attribute of hw::StructExtractOp invalid");
64 return 0;
65}
66
67//===----------------------------------------------------------------------===//
68// Helpers
69//===----------------------------------------------------------------------===//
70
71/// Create a zext operation by one bit on the given value. This is useful when
72/// passing unsigned indexes to a GEP instruction, which treats indexes as
73/// signed values, to avoid unexpected "sign overflows".
74static Value zextByOne(Location loc, ConversionPatternRewriter &rewriter,
75 Value value) {
76 auto valueTy = value.getType();
77 auto zextTy = IntegerType::get(valueTy.getContext(),
78 valueTy.getIntOrFloatBitWidth() + 1);
79 return rewriter.create<LLVM::ZExtOp>(loc, zextTy, value);
80}
81
82//===----------------------------------------------------------------------===//
83// Extraction operation conversions
84//===----------------------------------------------------------------------===//
85
86namespace {
87/// Convert a StructExplodeOp to the LLVM dialect.
88/// Pattern: struct_explode(input) =>
89/// struct_extract(input, structElements_index(index)) ...
90struct StructExplodeOpConversion
91 : public ConvertOpToLLVMPattern<hw::StructExplodeOp> {
92 using ConvertOpToLLVMPattern<hw::StructExplodeOp>::ConvertOpToLLVMPattern;
93
94 LogicalResult
95 matchAndRewrite(hw::StructExplodeOp op, OpAdaptor adaptor,
96 ConversionPatternRewriter &rewriter) const override {
97
98 SmallVector<Value> replacements;
99
100 for (size_t i = 0,
101 e = cast<LLVM::LLVMStructType>(adaptor.getInput().getType())
102 .getBody()
103 .size();
104 i < e; ++i)
105
106 replacements.push_back(rewriter.create<LLVM::ExtractValueOp>(
107 op->getLoc(), adaptor.getInput(),
109 op.getInput().getType(), i)));
110
111 rewriter.replaceOp(op, replacements);
112 return success();
113 }
114};
115} // namespace
116
117namespace {
118/// Convert a StructExtractOp to LLVM dialect.
119/// Pattern: struct_extract(input, fieldname) =>
120/// extractvalue(input, fieldname_to_index(fieldname))
121struct StructExtractOpConversion
122 : public ConvertOpToLLVMPattern<hw::StructExtractOp> {
123 using ConvertOpToLLVMPattern<hw::StructExtractOp>::ConvertOpToLLVMPattern;
124
125 LogicalResult
126 matchAndRewrite(hw::StructExtractOp op, OpAdaptor adaptor,
127 ConversionPatternRewriter &rewriter) const override {
128
130 op.getInput().getType(), op.getFieldIndex());
131 rewriter.replaceOpWithNewOp<LLVM::ExtractValueOp>(op, adaptor.getInput(),
132 fieldIndex);
133 return success();
134 }
135};
136} // namespace
137
138namespace {
139/// Convert an ArrayGetOp to the LLVM dialect.
140/// Pattern: array_get(input, index) =>
141/// load(gep(store(input, alloca), zext(index)))
142struct ArrayGetOpConversion : public ConvertOpToLLVMPattern<hw::ArrayGetOp> {
143 using ConvertOpToLLVMPattern<hw::ArrayGetOp>::ConvertOpToLLVMPattern;
144
145 LogicalResult
146 matchAndRewrite(hw::ArrayGetOp op, OpAdaptor adaptor,
147 ConversionPatternRewriter &rewriter) const override {
148
149 Value arrPtr;
150 if (auto load = adaptor.getInput().getDefiningOp<LLVM::LoadOp>()) {
151 // In this case the array was loaded from an existing address, so we can
152 // just grab that address instead of reallocating the array on the stack.
153 arrPtr = load.getAddr();
154 } else {
155 auto oneC = rewriter.create<LLVM::ConstantOp>(
156 op->getLoc(), IntegerType::get(rewriter.getContext(), 32),
157 rewriter.getI32IntegerAttr(1));
158 arrPtr = rewriter.create<LLVM::AllocaOp>(
159 op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()),
160 adaptor.getInput().getType(), oneC,
161 /*alignment=*/4);
162 rewriter.create<LLVM::StoreOp>(op->getLoc(), adaptor.getInput(), arrPtr);
163 }
164
165 auto arrTy = typeConverter->convertType(op.getInput().getType());
166 auto elemTy = typeConverter->convertType(op.getResult().getType());
167 auto zextIndex = zextByOne(op->getLoc(), rewriter, op.getIndex());
168
169 // During the ongoing migration to opaque types, use the constructor that
170 // accepts an element type when the array pointer type is opaque, and
171 // otherwise use the typed pointer constructor.
172 auto gep = rewriter.create<LLVM::GEPOp>(
173 op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()), arrTy,
174 arrPtr, ArrayRef<LLVM::GEPArg>{0, zextIndex});
175 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, elemTy, gep);
176
177 return success();
178 }
179};
180} // namespace
181
182namespace {
183/// Convert an ArraySliceOp to the LLVM dialect.
184/// Pattern: array_slice(input, lowIndex) =>
185/// load(bitcast(gep(store(input, alloca), zext(lowIndex))))
186struct ArraySliceOpConversion
187 : public ConvertOpToLLVMPattern<hw::ArraySliceOp> {
188 using ConvertOpToLLVMPattern<hw::ArraySliceOp>::ConvertOpToLLVMPattern;
189
190 LogicalResult
191 matchAndRewrite(hw::ArraySliceOp op, OpAdaptor adaptor,
192 ConversionPatternRewriter &rewriter) const override {
193
194 auto dstTy = typeConverter->convertType(op.getDst().getType());
195
196 auto oneC = rewriter.create<LLVM::ConstantOp>(
197 op->getLoc(), rewriter.getI32Type(), rewriter.getI32IntegerAttr(1));
198
199 auto arrPtr = rewriter.create<LLVM::AllocaOp>(
200 op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()),
201 adaptor.getInput().getType(), oneC,
202 /*alignment=*/4);
203
204 rewriter.create<LLVM::StoreOp>(op->getLoc(), adaptor.getInput(), arrPtr);
205
206 auto zextIndex = zextByOne(op->getLoc(), rewriter, op.getLowIndex());
207
208 // During the ongoing migration to opaque types, use the constructor that
209 // accepts an element type when the array pointer type is opaque, and
210 // otherwise use the typed pointer constructor.
211 auto gep = rewriter.create<LLVM::GEPOp>(
212 op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()), dstTy,
213 arrPtr, ArrayRef<LLVM::GEPArg>{0, zextIndex});
214
215 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, dstTy, gep);
216
217 return success();
218 }
219};
220} // namespace
221
222//===----------------------------------------------------------------------===//
223// Insertion operations conversion
224//===----------------------------------------------------------------------===//
225
226namespace {
227/// Convert a StructInjectOp to LLVM dialect.
228/// Pattern: struct_inject(input, index, value) =>
229/// insertvalue(input, value, index)
230struct StructInjectOpConversion
231 : public ConvertOpToLLVMPattern<hw::StructInjectOp> {
232 using ConvertOpToLLVMPattern<hw::StructInjectOp>::ConvertOpToLLVMPattern;
233
234 LogicalResult
235 matchAndRewrite(hw::StructInjectOp op, OpAdaptor adaptor,
236 ConversionPatternRewriter &rewriter) const override {
237
239 op.getInput().getType(), op.getFieldIndex());
240
241 rewriter.replaceOpWithNewOp<LLVM::InsertValueOp>(
242 op, adaptor.getInput(), op.getNewValue(), fieldIndex);
243
244 return success();
245 }
246};
247} // namespace
248
249//===----------------------------------------------------------------------===//
250// Concat operations conversion
251//===----------------------------------------------------------------------===//
252
253namespace {
254/// Lower an ArrayConcatOp operation to the LLVM dialect.
255struct ArrayConcatOpConversion
256 : public ConvertOpToLLVMPattern<hw::ArrayConcatOp> {
257 using ConvertOpToLLVMPattern<hw::ArrayConcatOp>::ConvertOpToLLVMPattern;
258
259 LogicalResult
260 matchAndRewrite(hw::ArrayConcatOp op, OpAdaptor adaptor,
261 ConversionPatternRewriter &rewriter) const override {
262
263 hw::ArrayType arrTy = cast<hw::ArrayType>(op.getResult().getType());
264 Type resultTy = typeConverter->convertType(arrTy);
265
266 Value arr = rewriter.create<LLVM::UndefOp>(op->getLoc(), resultTy);
267
268 // Attention: j is hardcoded for little endian machines.
269 size_t j = op.getInputs().size() - 1, k = 0;
270
271 for (size_t i = 0, e = arrTy.getNumElements(); i < e; ++i) {
272 Value element = rewriter.create<LLVM::ExtractValueOp>(
273 op->getLoc(), adaptor.getInputs()[j], k);
274 arr = rewriter.create<LLVM::InsertValueOp>(op->getLoc(), arr, element, i);
275
276 ++k;
277 if (k >=
278 cast<hw::ArrayType>(op.getInputs()[j].getType()).getNumElements()) {
279 k = 0;
280 --j;
281 }
282 }
283
284 rewriter.replaceOp(op, arr);
285 return success();
286 }
287};
288} // namespace
289
290//===----------------------------------------------------------------------===//
291// Bitwise conversions
292//===----------------------------------------------------------------------===//
293
294namespace {
295/// Lower an ArrayConcatOp operation to the LLVM dialect.
296/// Pattern: hw.bitcast(input) ==> load(bitcast_ptr(store(input, alloca)))
297/// This is necessary because we cannot bitcast aggregate types directly in
298/// LLVMIR.
299struct BitcastOpConversion : public ConvertOpToLLVMPattern<hw::BitcastOp> {
300 using ConvertOpToLLVMPattern<hw::BitcastOp>::ConvertOpToLLVMPattern;
301
302 LogicalResult
303 matchAndRewrite(hw::BitcastOp op, OpAdaptor adaptor,
304 ConversionPatternRewriter &rewriter) const override {
305
306 Type resultTy = typeConverter->convertType(op.getResult().getType());
307
308 auto oneC = rewriter.createOrFold<LLVM::ConstantOp>(
309 op->getLoc(), rewriter.getI32Type(), rewriter.getI32IntegerAttr(1));
310
311 auto ptr = rewriter.create<LLVM::AllocaOp>(
312 op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()),
313 adaptor.getInput().getType(), oneC,
314 /*alignment=*/4);
315
316 rewriter.create<LLVM::StoreOp>(op->getLoc(), adaptor.getInput(), ptr);
317
318 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, resultTy, ptr);
319
320 return success();
321 }
322};
323} // namespace
324
325//===----------------------------------------------------------------------===//
326// Value creation conversions
327//===----------------------------------------------------------------------===//
328
329namespace {
330struct HWConstantOpConversion : public ConvertToLLVMPattern {
331 explicit HWConstantOpConversion(MLIRContext *ctx,
332 LLVMTypeConverter &typeConverter)
333 : ConvertToLLVMPattern(hw::ConstantOp::getOperationName(), ctx,
334 typeConverter) {}
335
336 LogicalResult
337 matchAndRewrite(Operation *op, ArrayRef<Value> operand,
338 ConversionPatternRewriter &rewriter) const override {
339 // Get the ConstOp.
340 auto constOp = cast<hw::ConstantOp>(op);
341 // Get the converted llvm type.
342 auto intType = typeConverter->convertType(constOp.getValueAttr().getType());
343 // Replace the operation with an llvm constant op.
344 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(op, intType,
345 constOp.getValueAttr());
346
347 return success();
348 }
349};
350} // namespace
351
352namespace {
353/// Convert an ArrayCreateOp with dynamic elements to the LLVM dialect. An
354/// equivalent and initialized llvm dialect array type is generated.
355struct HWDynamicArrayCreateOpConversion
356 : public ConvertOpToLLVMPattern<hw::ArrayCreateOp> {
357 using ConvertOpToLLVMPattern<hw::ArrayCreateOp>::ConvertOpToLLVMPattern;
358
359 LogicalResult
360 matchAndRewrite(hw::ArrayCreateOp op, OpAdaptor adaptor,
361 ConversionPatternRewriter &rewriter) const override {
362 auto arrayTy = typeConverter->convertType(op->getResult(0).getType());
363 assert(arrayTy);
364
365 Value arr = rewriter.create<LLVM::UndefOp>(op->getLoc(), arrayTy);
366 for (size_t i = 0, e = op.getInputs().size(); i < e; ++i) {
367 Value input =
368 adaptor
370 op.getResult().getType(), i)];
371 arr = rewriter.create<LLVM::InsertValueOp>(op->getLoc(), arr, input, i);
372 }
373
374 rewriter.replaceOp(op, arr);
375 return success();
376 }
377};
378} // namespace
379
380namespace {
381
382/// Convert an ArrayCreateOp with constant elements to the LLVM dialect. An
383/// equivalent and initialized llvm dialect array type is generated.
384class AggregateConstantOpConversion
385 : public ConvertOpToLLVMPattern<hw::AggregateConstantOp> {
386 using ConvertOpToLLVMPattern<hw::AggregateConstantOp>::ConvertOpToLLVMPattern;
387
388 bool containsArrayAndStructAggregatesOnly(Type type) const;
389
390 bool isMultiDimArrayOfIntegers(Type type,
391 SmallVectorImpl<int64_t> &dims) const;
392
393 void flatten(Type type, Attribute attr,
394 SmallVectorImpl<Attribute> &output) const;
395
396 Value constructAggregate(OpBuilder &builder,
397 const TypeConverter &typeConverter, Location loc,
398 Type type, Attribute data) const;
399
400public:
401 explicit AggregateConstantOpConversion(
402 LLVMTypeConverter &typeConverter,
403 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp>
404 &constAggregateGlobalsMap,
405 Namespace &globals)
406 : ConvertOpToLLVMPattern(typeConverter),
407 constAggregateGlobalsMap(constAggregateGlobalsMap), globals(globals) {}
408
409 LogicalResult
410 matchAndRewrite(hw::AggregateConstantOp op, OpAdaptor adaptor,
411 ConversionPatternRewriter &rewriter) const override;
412
413private:
414 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp>
415 &constAggregateGlobalsMap;
416 Namespace &globals;
417};
418} // namespace
419
420namespace {
421/// Convert a StructCreateOp operation to the LLVM dialect. An equivalent and
422/// initialized llvm dialect struct type is generated.
423struct HWStructCreateOpConversion
424 : public ConvertOpToLLVMPattern<hw::StructCreateOp> {
425 using ConvertOpToLLVMPattern<hw::StructCreateOp>::ConvertOpToLLVMPattern;
426
427 LogicalResult
428 matchAndRewrite(hw::StructCreateOp op, OpAdaptor adaptor,
429 ConversionPatternRewriter &rewriter) const override {
430
431 auto resTy = typeConverter->convertType(op.getResult().getType());
432
433 Value tup = rewriter.create<LLVM::UndefOp>(op->getLoc(), resTy);
434 for (size_t i = 0, e = cast<LLVM::LLVMStructType>(resTy).getBody().size();
435 i < e; ++i) {
436 Value input =
438 op.getResult().getType(), i)];
439 tup = rewriter.create<LLVM::InsertValueOp>(op->getLoc(), tup, input, i);
440 }
441
442 rewriter.replaceOp(op, tup);
443 return success();
444 }
445};
446} // namespace
447
448//===----------------------------------------------------------------------===//
449// Pattern implementations
450//===----------------------------------------------------------------------===//
451
452bool AggregateConstantOpConversion::containsArrayAndStructAggregatesOnly(
453 Type type) const {
454 if (auto intType = dyn_cast<IntegerType>(type))
455 return true;
456
457 if (auto arrTy = dyn_cast<hw::ArrayType>(type))
458 return containsArrayAndStructAggregatesOnly(arrTy.getElementType());
459
460 if (auto structTy = dyn_cast<hw::StructType>(type)) {
461 SmallVector<Type> innerTypes;
462 structTy.getInnerTypes(innerTypes);
463 return llvm::all_of(innerTypes, [&](auto ty) {
464 return containsArrayAndStructAggregatesOnly(ty);
465 });
466 }
467
468 return false;
469}
470
471bool AggregateConstantOpConversion::isMultiDimArrayOfIntegers(
472 Type type, SmallVectorImpl<int64_t> &dims) const {
473 if (auto intType = dyn_cast<IntegerType>(type))
474 return true;
475
476 if (auto arrTy = dyn_cast<hw::ArrayType>(type)) {
477 dims.push_back(arrTy.getNumElements());
478 return isMultiDimArrayOfIntegers(arrTy.getElementType(), dims);
479 }
480
481 return false;
482}
483
484void AggregateConstantOpConversion::flatten(
485 Type type, Attribute attr, SmallVectorImpl<Attribute> &output) const {
486 if (isa<IntegerType>(type)) {
487 assert(isa<IntegerAttr>(attr));
488 output.push_back(attr);
489 return;
490 }
491
492 auto arrAttr = cast<ArrayAttr>(attr);
493 for (size_t i = 0, e = arrAttr.size(); i < e; ++i) {
494 auto element =
496
497 flatten(cast<hw::ArrayType>(type).getElementType(), element, output);
498 }
499}
500
501Value AggregateConstantOpConversion::constructAggregate(
502 OpBuilder &builder, const TypeConverter &typeConverter, Location loc,
503 Type type, Attribute data) const {
504 Type llvmType = typeConverter.convertType(type);
505
506 auto getElementType = [](Type type, size_t index) {
507 if (auto arrTy = dyn_cast<hw::ArrayType>(type)) {
508 return arrTy.getElementType();
509 }
510
511 assert(isa<hw::StructType>(type));
512 auto structTy = cast<hw::StructType>(type);
513 SmallVector<Type> innerTypes;
514 structTy.getInnerTypes(innerTypes);
515 return innerTypes[index];
516 };
517
518 return TypeSwitch<Type, Value>(type)
519 .Case<IntegerType>([&](auto ty) {
520 return builder.create<LLVM::ConstantOp>(loc, cast<TypedAttr>(data));
521 })
522 .Case<hw::ArrayType, hw::StructType>([&](auto ty) {
523 Value aggVal = builder.create<LLVM::UndefOp>(loc, llvmType);
524 auto arrayAttr = cast<ArrayAttr>(data);
525 for (size_t i = 0, e = arrayAttr.size(); i < e; ++i) {
526 size_t currIdx =
528 Attribute input = arrayAttr[currIdx];
529 Type elementType = getElementType(ty, currIdx);
530
531 Value element = constructAggregate(builder, typeConverter, loc,
532 elementType, input);
533 aggVal = builder.create<LLVM::InsertValueOp>(loc, aggVal, element, i);
534 }
535
536 return aggVal;
537 });
538}
539
540LogicalResult AggregateConstantOpConversion::matchAndRewrite(
541 hw::AggregateConstantOp op, OpAdaptor adaptor,
542 ConversionPatternRewriter &rewriter) const {
543 Type aggregateType = op.getResult().getType();
544
545 // TODO: Only arrays and structs supported at the moment.
546 if (!containsArrayAndStructAggregatesOnly(aggregateType))
547 return failure();
548
549 auto llvmTy = typeConverter->convertType(op.getResult().getType());
550 auto typeAttrPair = std::make_pair(aggregateType, adaptor.getFields());
551
552 if (!constAggregateGlobalsMap.count(typeAttrPair) ||
553 !constAggregateGlobalsMap[typeAttrPair]) {
554 auto ipSave = rewriter.saveInsertionPoint();
555
556 Operation *parent = op->getParentOp();
557 while (!isa<mlir::ModuleOp>(parent->getParentOp())) {
558 parent = parent->getParentOp();
559 }
560
561 rewriter.setInsertionPoint(parent);
562
563 // Create a global region for this static array.
564 auto name = globals.newName("_aggregate_const_global");
565
566 SmallVector<int64_t> dims;
567 if (isMultiDimArrayOfIntegers(aggregateType, dims)) {
568 SmallVector<Attribute> ints;
569 flatten(aggregateType, adaptor.getFields(), ints);
570 assert(!ints.empty());
571 auto shapedType = RankedTensorType::get(
572 dims, cast<IntegerAttr>(ints.front()).getType());
573 auto denseAttr = DenseElementsAttr::get(shapedType, ints);
574
575 constAggregateGlobalsMap[typeAttrPair] = rewriter.create<LLVM::GlobalOp>(
576 op.getLoc(), llvmTy, true, LLVM::Linkage::Internal, name, denseAttr);
577 } else {
578 auto global = rewriter.create<LLVM::GlobalOp>(op.getLoc(), llvmTy, false,
579 LLVM::Linkage::Internal,
580 name, Attribute());
581 Block *blk = new Block();
582 global.getInitializerRegion().push_back(blk);
583 rewriter.setInsertionPointToStart(blk);
584
585 Value aggregate =
586 constructAggregate(rewriter, *typeConverter, op.getLoc(),
587 aggregateType, adaptor.getFields());
588 rewriter.create<LLVM::ReturnOp>(op.getLoc(), aggregate);
589 constAggregateGlobalsMap[typeAttrPair] = global;
590 }
591
592 rewriter.restoreInsertionPoint(ipSave);
593 }
594
595 // Get the global array address and load it to return an array value.
596 auto addr = rewriter.create<LLVM::AddressOfOp>(
597 op->getLoc(), constAggregateGlobalsMap[typeAttrPair]);
598 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, llvmTy, addr);
599
600 return success();
601}
602
603//===----------------------------------------------------------------------===//
604// Type conversions
605//===----------------------------------------------------------------------===//
606
607static Type convertArrayType(hw::ArrayType type, LLVMTypeConverter &converter) {
608 auto elementTy = converter.convertType(type.getElementType());
609 return LLVM::LLVMArrayType::get(elementTy, type.getNumElements());
610}
611
612static Type convertStructType(hw::StructType type,
613 LLVMTypeConverter &converter) {
614 llvm::SmallVector<Type, 8> elements;
615 mlir::SmallVector<mlir::Type> types;
616 type.getInnerTypes(types);
617
618 for (int i = 0, e = types.size(); i < e; ++i)
619 elements.push_back(converter.convertType(
621
622 return LLVM::LLVMStructType::getLiteral(&converter.getContext(), elements);
623}
624
625//===----------------------------------------------------------------------===//
626// Pass initialization
627//===----------------------------------------------------------------------===//
628
629namespace {
630struct HWToLLVMLoweringPass
631 : public circt::impl::ConvertHWToLLVMBase<HWToLLVMLoweringPass> {
632 void runOnOperation() override;
633};
634} // namespace
635
637 LLVMTypeConverter &converter, RewritePatternSet &patterns,
638 Namespace &globals,
639 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp>
640 &constAggregateGlobalsMap) {
641 MLIRContext *ctx = converter.getDialect()->getContext();
642
643 // Value creation conversion patterns.
644 patterns.add<HWConstantOpConversion>(ctx, converter);
645 patterns.add<HWDynamicArrayCreateOpConversion, HWStructCreateOpConversion>(
646 converter);
647 patterns.add<AggregateConstantOpConversion>(
648 converter, constAggregateGlobalsMap, globals);
649
650 // Bitwise conversion patterns.
651 patterns.add<BitcastOpConversion>(converter);
652
653 // Extraction operation conversion patterns.
654 patterns.add<ArrayGetOpConversion, ArraySliceOpConversion,
655 ArrayConcatOpConversion, StructExplodeOpConversion,
656 StructExtractOpConversion, StructInjectOpConversion>(converter);
657}
658
659void circt::populateHWToLLVMTypeConversions(LLVMTypeConverter &converter) {
660 converter.addConversion(
661 [&](hw::ArrayType arr) { return convertArrayType(arr, converter); });
662 converter.addConversion(
663 [&](hw::StructType tup) { return convertStructType(tup, converter); });
664}
665
666void HWToLLVMLoweringPass::runOnOperation() {
667 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp> constAggregateGlobalsMap;
668 Namespace globals;
669 SymbolCache cache;
670 cache.addDefinitions(getOperation());
671 globals.add(cache);
672
673 RewritePatternSet patterns(&getContext());
674 auto converter = mlir::LLVMTypeConverter(&getContext());
676
677 LLVMConversionTarget target(getContext());
678 target.addIllegalDialect<hw::HWDialect>();
679
680 // Setup the conversion.
682 constAggregateGlobalsMap);
683
684 // Apply the partial conversion.
685 if (failed(
686 applyPartialConversion(getOperation(), target, std::move(patterns))))
687 signalPassFailure();
688}
689
690/// Create an HW to LLVM conversion pass.
691std::unique_ptr<OperationPass<ModuleOp>> circt::createConvertHWToLLVMPass() {
692 return std::make_unique<HWToLLVMLoweringPass>();
693}
assert(baseType &&"element must be base type")
MlirType elementType
Definition CHIRRTL.cpp:29
static Type convertStructType(hw::StructType type, LLVMTypeConverter &converter)
Definition HWToLLVM.cpp:612
static Value zextByOne(Location loc, ConversionPatternRewriter &rewriter, Value value)
Create a zext operation by one bit on the given value.
Definition HWToLLVM.cpp:74
static Type convertArrayType(hw::ArrayType type, LLVMTypeConverter &converter)
Definition HWToLLVM.cpp:607
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition Namespace.h:30
void add(mlir::ModuleOp module)
Definition Namespace.h:48
void addDefinitions(mlir::Operation *top)
Populate the symbol cache with all symbol-defining operations within the 'top' operation.
Definition SymCache.cpp:23
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Definition SymCache.h:85
create(*sub_arrays)
Definition hw.py:504
create(elements)
Definition hw.py:483
create(array_value, idx)
Definition hw.py:450
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateHWToLLVMConversionPatterns(mlir::LLVMTypeConverter &converter, RewritePatternSet &patterns, Namespace &globals, DenseMap< std::pair< Type, ArrayAttr >, mlir::LLVM::GlobalOp > &constAggregateGlobalsMap)
Get the HW to LLVM conversion patterns.
std::unique_ptr< OperationPass< ModuleOp > > createConvertHWToLLVMPass()
Create an HW to LLVM conversion pass.
Definition HWToLLVM.cpp:691
void populateHWToLLVMTypeConversions(mlir::LLVMTypeConverter &converter)
Get the HW to LLVM type conversions.
Definition hw.py:1
static uint32_t convertToLLVMEndianess(Type type, uint32_t index)
Convert an index into a HW ArrayType or StructType to LLVM Endianess.
Definition HWToLLVM.cpp:37
static uint32_t llvmIndexOfStructField(hw::StructType type, StringRef fieldName)
Get the index of a specific StructType field in the LLVM lowering of the StructType.
Definition HWToLLVM.cpp:49