CIRCT 24.0.0git
Loading...
Searching...
No Matches
HWArithOps.cpp
Go to the documentation of this file.
1//===- HWArithOps.cpp - Implement the HW arithmetic operations ------------===//
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 file implement the HW arithmetic ops.
10//
11//===----------------------------------------------------------------------===//
12
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/PatternMatch.h"
18#include "llvm/ADT/APSInt.h"
19
20using namespace circt;
21using namespace hwarith;
22
23namespace circt {
24namespace hwarith {
25#include "circt/Dialect/HWArith/HWArithCanonicalizations.h.inc"
26
27}
28} // namespace circt
29
30//===----------------------------------------------------------------------===//
31// CastOp
32//===----------------------------------------------------------------------===//
33
34LogicalResult CastOp::verify() {
35 auto inType = getIn().getType();
36 auto outType = getOut().getType();
37 bool isInSignless = !isHWArithIntegerType(inType);
38 bool isOutSignless = !isHWArithIntegerType(outType);
39
40 if (isInSignless && isOutSignless)
41 return emitError("at least one type needs to carry sign semantics (ui/si)");
42
43 if (isInSignless) {
44 unsigned inBitWidth = inType.getIntOrFloatBitWidth();
45 unsigned outBitWidth = outType.getIntOrFloatBitWidth();
46 if (inBitWidth < outBitWidth)
47 return emitError("bit extension is undefined for a signless type");
48 }
49
50 return success();
51}
52
53void CastOp::getCanonicalizationPatterns(RewritePatternSet &results,
54 MLIRContext *context) {
55 results.insert<EliminateCast>(context);
56}
57
58//===----------------------------------------------------------------------===//
59// ConstantOp
60//===----------------------------------------------------------------------===//
61
62APSInt ConstantOp::getConstantValue() { return getRawValueAttr().getAPSInt(); }
63
64OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
65 assert(adaptor.getOperands().empty() && "constant has no operands");
66 return getRawValueAttr();
67}
68
69void ConstantOp::print(OpAsmPrinter &p) {
70 p << " ";
71 if (getType() == getRawValueAttr().getType()) {
72 p.printAttribute(getRawValueAttr());
73 } else {
74 // The result is a type alias of the value's type.
75 p.printAttributeWithoutType(getRawValueAttr());
76 p << " : " << getType();
77 }
78 p.printOptionalAttrDict(getOperation()->getAttrs(),
79 /*elidedAttrs=*/{getRawValueAttrName()});
80}
81
82ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
83 auto loc = parser.getCurrentLocation();
84 APInt value;
85 Type type;
86 if (parser.parseInteger(value) || parser.parseColonType(type) ||
87 parser.parseOptionalAttrDict(result.attributes))
88 return failure();
89
90 // The type may be a type alias of an integer type, which determines the
91 // value's type.
92 auto intType = hw::type_dyn_cast<IntegerType>(type);
93 if (!intType)
94 return parser.emitError(loc, "expected an integer type, but got ") << type;
95 unsigned width = intType.getWidth();
96 bool fits = value.isNegative()
97 ? !intType.isUnsigned() && value.getSignificantBits() <= width
98 : value.getActiveBits() + intType.isSigned() <= width;
99 if (!fits)
100 return parser.emitError(loc, "constant out of range for type ") << type;
101
102 result.addAttribute(getRawValueAttrName(result.name),
103 IntegerAttr::get(intType, value.sextOrTrunc(width)));
104 result.addTypes(type);
105 return success();
106}
107
108LogicalResult ConstantOp::verify() {
109 // The result type may be a type alias of the value's type.
110 if (getRawValueAttr().getType() != hw::getCanonicalType(getType()))
111 return emitOpError("value type ")
112 << getRawValueAttr().getType()
113 << " doesn't match the canonical result type "
114 << hw::getCanonicalType(getType());
115 return success();
116}
117
118//===----------------------------------------------------------------------===//
119// AddOp
120//===----------------------------------------------------------------------===//
121
122LogicalResult AddOp::inferReturnTypes(MLIRContext *context,
123 std::optional<Location> loc,
124 ValueRange operands, DictionaryAttr attrs,
125 mlir::PropertyRef properties,
126 mlir::RegionRange regions,
127 SmallVectorImpl<Type> &results) {
128 auto lhs = cast<IntegerType>(operands[0].getType());
129 auto rhs = cast<IntegerType>(operands[1].getType());
130 IntegerType::SignednessSemantics signedness;
131 unsigned resultWidth = inferAddResultType(signedness, lhs, rhs);
132
133 results.push_back(IntegerType::get(context, resultWidth, signedness));
134 return success();
135}
136
137//===----------------------------------------------------------------------===//
138// SubOp
139//===----------------------------------------------------------------------===//
140
141LogicalResult SubOp::inferReturnTypes(MLIRContext *context,
142 std::optional<Location> loc,
143 ValueRange operands, DictionaryAttr attrs,
144 mlir::PropertyRef properties,
145 mlir::RegionRange regions,
146 SmallVectorImpl<Type> &results) {
147 auto lhs = cast<IntegerType>(operands[0].getType());
148 auto rhs = cast<IntegerType>(operands[1].getType());
149 // The result type rules are identical to the ones for an addition
150 // With one exception: all results are signed!
151 IntegerType::SignednessSemantics signedness;
152 unsigned resultWidth = inferAddResultType(signedness, lhs, rhs);
153 signedness = IntegerType::Signed;
154
155 results.push_back(IntegerType::get(context, resultWidth, signedness));
156 return success();
157}
158
159//===----------------------------------------------------------------------===//
160// MulOp
161//===----------------------------------------------------------------------===//
162
163static IntegerType::SignednessSemantics
164getSignedInheritedSignedness(IntegerType lhs, IntegerType rhs) {
165 // Signed operands are dominant and enforce a signed result
166 if (lhs.getSignedness() == rhs.getSignedness()) {
167 // the signedness is also identical to the operands
168 return lhs.getSignedness();
169 } else {
170 // For mixed signedness the result is always signed
171 return IntegerType::Signed;
172 }
173}
174
175LogicalResult MulOp::inferReturnTypes(MLIRContext *context,
176 std::optional<Location> loc,
177 ValueRange operands, DictionaryAttr attrs,
178 mlir::PropertyRef properties,
179 mlir::RegionRange regions,
180 SmallVectorImpl<Type> &results) {
181 auto lhs = cast<IntegerType>(operands[0].getType());
182 auto rhs = cast<IntegerType>(operands[1].getType());
183 // the result width stays the same no matter the signedness
184 unsigned resultWidth = lhs.getWidth() + rhs.getWidth();
185 IntegerType::SignednessSemantics signedness =
187
188 results.push_back(IntegerType::get(context, resultWidth, signedness));
189 return success();
190}
191
192//===----------------------------------------------------------------------===//
193// DivOp
194//===----------------------------------------------------------------------===//
195
196LogicalResult DivOp::inferReturnTypes(MLIRContext *context,
197 std::optional<Location> loc,
198 ValueRange operands, DictionaryAttr attrs,
199 mlir::PropertyRef properties,
200 mlir::RegionRange regions,
201 SmallVectorImpl<Type> &results) {
202 auto lhs = cast<IntegerType>(operands[0].getType());
203 auto rhs = cast<IntegerType>(operands[1].getType());
204 // The result width is always at least as large as the bit width of lhs
205 unsigned resultWidth = lhs.getWidth();
206
207 // if the divisor is signed, then the result width needs to be extended by 1
208 if (rhs.isSigned())
209 ++resultWidth;
210
211 IntegerType::SignednessSemantics signedness =
213
214 results.push_back(IntegerType::get(context, resultWidth, signedness));
215 return success();
216}
217
218//===----------------------------------------------------------------------===//
219// Utility
220//===----------------------------------------------------------------------===//
221
222namespace circt {
223namespace hwarith {
224
225unsigned inferAddResultType(IntegerType::SignednessSemantics &signedness,
226 IntegerType lhs, IntegerType rhs) {
227 // the result width is never less than max(w1, w2) + 1
228 unsigned resultWidth = std::max(lhs.getWidth(), rhs.getWidth()) + 1;
229
230 if (lhs.getSignedness() == rhs.getSignedness()) {
231 // max(w1, w2) + 1 in case both operands use the same signedness
232 // the signedness is also identical to the operands
233 signedness = lhs.getSignedness();
234 } else {
235 // For mixed signedness the result is always signed
236 signedness = IntegerType::Signed;
237
238 // Regarding the result width two case need to be considered:
239 if ((lhs.isUnsigned() && lhs.getWidth() >= rhs.getWidth()) ||
240 (rhs.isUnsigned() && rhs.getWidth() >= lhs.getWidth())) {
241 // 1. the unsigned width is >= the signed width,
242 // then the width needs to be increased by 1
243 ++resultWidth;
244 }
245 // 2. the unsigned width is < the signed width,
246 // then no further adjustment is needed
247 }
248 return resultWidth;
249}
250
251static LogicalResult verifyBinOp(Operation *binOp) {
252 auto ops = binOp->getOperands();
253 if (ops.size() != 2)
254 return binOp->emitError() << "expected 2 operands but got " << ops.size();
255
256 return success();
257}
258
259} // namespace hwarith
260} // namespace circt
261
262//===----------------------------------------------------------------------===//
263// TableGen generated logic.
264//===----------------------------------------------------------------------===//
265
266// Provide the autogenerated implementation guts for the Op classes.
267#define GET_OP_CLASSES
268#include "circt/Dialect/HWArith/HWArith.cpp.inc"
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static IntegerType::SignednessSemantics getSignedInheritedSignedness(IntegerType lhs, IntegerType rhs)
static LogicalResult verifyBinOp(Operation *binOp)
bool isHWArithIntegerType(::mlir::Type type)
unsigned inferAddResultType(IntegerType::SignednessSemantics &signedness, IntegerType lhs, IntegerType rhs)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.