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