CIRCT 23.0.0git
Loading...
Searching...
No Matches
ArcTypes.cpp
Go to the documentation of this file.
1//===- ArcTypes.cpp -------------------------------------------------------===//
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
13#include "mlir/IR/Builders.h"
14#include "mlir/IR/DialectImplementation.h"
15#include "llvm/ADT/TypeSwitch.h"
16
17using namespace circt;
18using namespace arc;
19using namespace mlir;
20
21static ParseResult parseXInDimList(AsmParser &p, Type &elementType);
22static void printXInDimList(AsmPrinter &p, Type elementType);
23
24#define GET_TYPEDEF_CLASSES
25#include "circt/Dialect/Arc/ArcTypes.cpp.inc"
26
27/// Compute the bit width a type will have when allocated as part of the
28/// simulator's storage. This includes any padding and alignment that may be
29/// necessary once the type has been mapped to LLVM. The idea is for this
30/// function to be conservative, such that we provide sufficient storage bytes
31/// for any type.
32std::optional<uint64_t> circt::arc::computeLLVMBitWidth(Type type) {
33 if (isa<seq::ClockType>(type))
34 return 1;
35
36 if (auto intType = dyn_cast<IntegerType>(type))
37 return intType.getWidth();
38
39 auto computeForArrayType = [&](auto arrayType) -> std::optional<uint64_t> {
40 // Compute element width.
41 auto maybeWidth = computeLLVMBitWidth(arrayType.getElementType());
42 if (!maybeWidth)
43 return {};
44 // Each element must be at least one byte.
45 auto width = std::max<uint64_t>(*maybeWidth, 8);
46 // Align elements to their own size, up to 16 bytes.
47 auto alignment = llvm::bit_ceil(std::min<uint64_t>(width, 16 * 8));
48 auto alignedWidth = llvm::alignToPowerOf2(width, alignment);
49 // Multiply by the number of elements in the array.
50 return arrayType.getNumElements() * alignedWidth;
51 };
52
53 if (auto arrayType = dyn_cast<hw::ArrayType>(type))
54 return computeForArrayType(arrayType);
55
56 if (auto arrayRefType = dyn_cast<ArrayRefType>(type))
57 return computeForArrayType(arrayRefType);
58
59 if (auto structType = dyn_cast<hw::StructType>(type)) {
60 uint64_t structWidth = 0;
61 uint64_t structAlignment = 8;
62 for (auto element : structType.getElements()) {
63 // Compute element width.
64 auto maybeWidth = computeLLVMBitWidth(element.type);
65 if (!maybeWidth)
66 return {};
67 // Each element must be at least one byte.
68 auto width = std::max<uint64_t>(*maybeWidth, 8);
69 // Align elements to their own size, up to 16 bytes.
70 auto alignment = llvm::bit_ceil(std::min<uint64_t>(width, 16 * 8));
71 auto alignedWidth = llvm::alignToPowerOf2(width, alignment);
72 // Pad the struct size to align the element to its alignment need, and add
73 // the element.
74 structWidth = llvm::alignToPowerOf2(structWidth, alignment);
75 structWidth += alignedWidth;
76 // Keep track of the struct's alignment need.
77 structAlignment = std::max<uint64_t>(alignment, structAlignment);
78 }
79 // Pad the struct size to align its end with the alignment.
80 return llvm::alignToPowerOf2(structWidth, structAlignment);
81 }
82
83 // A union's variants all overlap at the same base address, so its size is
84 // determined by the largest variant rather than their sum. Honor any explicit
85 // per-variant bit offset, and pad the whole thing to the union's alignment.
86 if (auto unionType = dyn_cast<hw::UnionType>(type)) {
87 uint64_t unionWidth = 0;
88 uint64_t unionAlignment = 8;
89 for (auto element : unionType.getElements()) {
90 // Compute variant width.
91 auto maybeWidth = computeLLVMBitWidth(element.type);
92 if (!maybeWidth)
93 return {};
94 // Each variant must be at least one byte.
95 auto width = std::max<uint64_t>(*maybeWidth, 8);
96 // Align variants to their own size, up to 16 bytes.
97 auto alignment = llvm::bit_ceil(std::min<uint64_t>(width, 16 * 8));
98 auto alignedWidth = llvm::alignToPowerOf2(width, alignment);
99 // The union must be large enough to hold this variant at its offset.
100 unionWidth =
101 std::max<uint64_t>(unionWidth, element.offset + alignedWidth);
102 // Keep track of the union's alignment need.
103 unionAlignment = std::max<uint64_t>(alignment, unionAlignment);
104 }
105 // Pad the union size to align its end with the alignment.
106 return llvm::alignToPowerOf2(unionWidth, unionAlignment);
107 }
108
109 // We don't know anything about any other types.
110 return {};
111}
112
113unsigned StateType::getBitWidth() { return *computeLLVMBitWidth(getType()); }
114
115LogicalResult
116StateType::verify(llvm::function_ref<InFlightDiagnostic()> emitError,
117 Type innerType) {
118 // A coroutine's program counter and persistent state have a layout that is
119 // only fixed once coroutines are lowered. Permit them as state types with a
120 // deferred bit width; lowering later replaces them with concrete types.
121 if (isa<CoroutinePCType, CoroutineStateType>(innerType))
122 return success();
123 if (!computeLLVMBitWidth(innerType))
124 return emitError() << "state type must have a known bit width; got "
125 << innerType;
126 return success();
127}
128
129unsigned MemoryType::getStride() {
130 unsigned stride = (getWordType().getWidth() + 7) / 8;
131 return llvm::alignToPowerOf2(stride, llvm::bit_ceil(std::min(stride, 16U)));
132}
133
134size_t ArrayRefType::getNumElements() const { return getSize(); }
135
136std::optional<int64_t> ArrayRefType::getBitWidth() const {
137 auto elementBitWidth = hw::getBitWidth(getElementType());
138 if (elementBitWidth < 0)
139 return std::nullopt;
140 int64_t numElements = getNumElements();
141 if (numElements < 0)
142 return std::nullopt;
143 return numElements * elementBitWidth;
144}
145
146ShapedType ArrayRefType::cloneWith(std::optional<ArrayRef<int64_t>> shape,
147 Type elementType) const {
148 llvm_unreachable("ArrayRefType::cloneWith not implemented!");
149}
150
151bool ArrayRefType::hasRank() const { return true; }
152
153ArrayRef<int64_t> ArrayRefType::getShape() const {
154 const uint64_t &size = getImpl()->size;
155 return ArrayRef<int64_t>(reinterpret_cast<const int64_t *>(&size), 1);
156}
157
158static ParseResult parseXInDimList(AsmParser &p, Type &elementType) {
159 return failure(p.parseXInDimensionList() || p.parseType(elementType));
160}
161
162static void printXInDimList(AsmPrinter &p, Type elementType) {
163 p << "x" << elementType;
164}
165
166LogicalResult
167ArrayRefType::verify(llvm::function_ref<InFlightDiagnostic()> emitError,
168 Type elementType, uint64_t size) {
169 if (size == 0) {
170 return emitError() << "must have nonzero element count";
171 }
172 return success();
173}
174
175void ArcDialect::registerTypes() {
176 addTypes<
177#define GET_TYPEDEF_LIST
178#include "circt/Dialect/Arc/ArcTypes.cpp.inc"
179 >();
180}
static void printXInDimList(AsmPrinter &p, Type elementType)
Definition ArcTypes.cpp:162
static ParseResult parseXInDimList(AsmParser &p, Type &elementType)
Definition ArcTypes.cpp:158
MlirType uint64_t numElements
Definition CHIRRTL.cpp:30
MlirType elementType
Definition CHIRRTL.cpp:29
Definition arc.py:1
std::optional< uint64_t > computeLLVMBitWidth(mlir::Type type)
Compute the bit width a type will have when allocated as part of the simulator's storage.
mlir::Type innerType(mlir::Type type)
Definition ESITypes.cpp:422
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.