Skip to content

Commit 26b437b

Browse files
zero9178Jiahui17
andauthored
[handshake] Add constant folding to ext(u|s)i ops (#802)
No constant folding of these ops existed up until now. Having these kinds of constant folding is useful besides being an optimization, since it allows code to assume that if an operand can be calculated as a constant, it'll be a constant. This PR adds such a constant folding pattern for `extui` and `extsi` ops. Part of #792 --------- Co-authored-by: Jiahui Xu <jxu@ethz.ch>
1 parent 8f356fd commit 26b437b

11 files changed

Lines changed: 186 additions & 152 deletions

File tree

include/dynamatic/Dialect/Handshake/HandshakeArithOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ def Handshake_ExtSIOp : Handshake_Arith_IToICastOp<"extsi"> {
315315

316316
def Handshake_ExtUIOp : Handshake_Arith_IToICastOp<"extui"> {
317317
let summary = "Integer signed width extension.";
318+
let hasCanonicalizer = 1;
318319
}
319320

320321
def Handshake_MaximumFOp : Handshake_Arith_FloatBinaryOp<"maximumf", [

integration-test/if_convert/buffer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"comment": "To achieve better II"
2929
},
3030
{
31-
"pred": "extsi2",
31+
"pred": "constant11",
3232
"outid": 0,
3333
"slots": 4,
3434
"type": "fifo_break_none",

integration-test/loop_path/buffer.json

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77
"comment": "To avoid deadlock"
88
},
99
{
10-
"pred": "cmpi2",
10+
"pred": "fork1",
1111
"outid": 0,
1212
"slots": 2,
1313
"type": "fifo_break_none",
1414
"comment": "To achieve better II"
1515
},
1616
{
17-
"pred": "fork3",
18-
"outid": 0,
17+
"pred": "fork5",
18+
"outid": 1,
1919
"slots": 2,
2020
"type": "fifo_break_none",
2121
"comment": "To achieve better II"
2222
},
2323
{
24-
"pred": "trunci0",
24+
"pred": "fork11",
2525
"outid": 0,
2626
"slots": 2,
2727
"type": "fifo_break_none",
@@ -33,12 +33,5 @@
3333
"slots": 2,
3434
"type": "fifo_break_none",
3535
"comment": "Buffer non-spec token to prevent II=2 locking (placed before spec_commit to avoid the effect of non-deterministic naming)"
36-
},
37-
{
38-
"pred": "fork11",
39-
"outid": 0,
40-
"slots": 2,
41-
"type": "fifo_break_none",
42-
"comment": "To absorb latency for spec_commit4 (ctrl)"
4336
}
4437
]

integration-test/nested_loop/buffer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"comment": "Buffer non-spec token to prevent II=2 locking"
3636
},
3737
{
38-
"pred": "extsi3",
38+
"pred": "constant18",
3939
"outid": 0,
4040
"slots": 4,
4141
"type": "fifo_break_none",

integration-test/single_loop/buffer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"comment": "To absorb latency for spec_commit4 (data)"
1515
},
1616
{
17-
"pred": "extsi1",
17+
"pred": "constant9",
1818
"outid": 0,
1919
"slots": 5,
2020
"type": "fifo_break_none",

lib/Dialect/Handshake/HandshakeCanonicalization.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ def ExtSIOfExtUI : Pat<
2525
(Handshake_ExtSIOp (Handshake_ExtUIOp $x)), (Handshake_ExtUIOp $x)
2626
>;
2727

28+
def ExtUIOfConst : Pat<
29+
(Handshake_ExtUIOp:$ext (Handshake_ConstantOp $attr, $ctrl)),
30+
(Handshake_ConstantOp (NativeCodeCall<"constantFoldExt($0.getOwner(), $1)"> $ext, $attr), $ctrl)
31+
>;
32+
33+
def ExtSIOfConst : Pat<
34+
(Handshake_ExtSIOp:$ext (Handshake_ConstantOp $attr, $ctrl)),
35+
(Handshake_ConstantOp (NativeCodeCall<"constantFoldExt($0.getOwner(), $1)"> $ext, $attr), $ctrl)
36+
>;
37+
2838
//===----------------------------------------------------------------------===//
2939
// TruncIOp
3040
//===----------------------------------------------------------------------===//

lib/Dialect/Handshake/HandshakeOps.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,21 @@ static unsigned getDataBitWidth(Value val) {
187187
return cast<handshake::ChannelType>(val.getType()).getDataBitWidth();
188188
}
189189

190+
static IntegerAttr constantFoldExt(Operation *op, Attribute attr) {
191+
auto integerAttr = cast<IntegerAttr>(attr);
192+
if (auto extUI = dyn_cast<ExtUIOp>(op))
193+
return IntegerAttr::get(
194+
extUI.getType().getDataType(),
195+
integerAttr.getValue().zext(extUI.getType().getDataBitWidth()));
196+
197+
if (auto extSI = dyn_cast<ExtSIOp>(op))
198+
return IntegerAttr::get(
199+
extSI.getType().getDataType(),
200+
integerAttr.getValue().sext(extSI.getType().getDataBitWidth()));
201+
202+
llvm_unreachable("only expected extui and extsi");
203+
}
204+
190205
namespace {
191206
#include "lib/Dialect/Handshake/HandshakeCanonicalization.inc"
192207
} // namespace
@@ -1883,7 +1898,7 @@ static OpFoldResult foldExtOp(Op op) {
18831898

18841899
void ExtSIOp::getCanonicalizationPatterns(RewritePatternSet &results,
18851900
MLIRContext *context) {
1886-
results.add<ExtSIOfExtUI>(context);
1901+
results.add<ExtSIOfExtUI, ExtSIOfConst>(context);
18871902
}
18881903

18891904
OpFoldResult ExtSIOp::fold(FoldAdaptor adaptor) { return foldExtOp(*this); }
@@ -1912,6 +1927,11 @@ LogicalResult ExtSIOp::verify() { return verifyExtOp(*this); }
19121927

19131928
OpFoldResult ExtUIOp::fold(FoldAdaptor adaptor) { return foldExtOp(*this); }
19141929

1930+
void ExtUIOp::getCanonicalizationPatterns(RewritePatternSet &results,
1931+
MLIRContext *context) {
1932+
results.add<ExtUIOfConst>(context);
1933+
}
1934+
19151935
LogicalResult ExtUIOp::verify() { return verifyExtOp(*this); }
19161936

19171937
//===----------------------------------------------------------------------===//

test/Transforms/HandshakeOptimizeBitwidths/arith-forward.mlir

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,10 @@ handshake.func @xoriFW(%arg0: !handshake.channel<i8>, %arg1: !handshake.channel<
134134
// CHECK-LABEL: handshake.func @shliFW(
135135
// CHECK-SAME: %[[VAL_0:.*]]: !handshake.channel<i16>,
136136
// CHECK-SAME: %[[VAL_1:.*]]: !handshake.control<>, ...) -> !handshake.channel<i32> attributes {argNames = ["arg0", "start"], resNames = ["out0"]} {
137-
// CHECK: %[[VAL_2:.*]] = constant %[[VAL_1]] {value = 4 : i4} : <>, <i4>
138-
// CHECK: %[[VAL_3:.*]] = extsi %[[VAL_0]] : <i16> to <i32>
139-
// CHECK: %[[VAL_4:.*]] = extsi %[[VAL_2]] : <i4> to <i32>
140-
// CHECK: %[[VAL_5:.*]] = shli %[[VAL_3]], %[[VAL_4]] : <i32>
141-
// CHECK: end %[[VAL_5]] : <i32>
137+
// CHECK: %[[VAL_2:.*]] = extsi %[[VAL_0]] : <i16> to <i32>
138+
// CHECK: %[[VAL_3:.*]] = constant %[[VAL_1]] {value = 4 : i32} : <>, <i32>
139+
// CHECK: %[[VAL_4:.*]] = shli %[[VAL_2]], %[[VAL_3]] : <i32>
140+
// CHECK: end %[[VAL_4]] : <i32>
142141
// CHECK: }
143142
handshake.func @shliFW(%arg0: !handshake.channel<i16>, %start: !handshake.control<>) -> !handshake.channel<i32> {
144143
%cst = handshake.constant %start {value = 4 : i4} : <>, <i4>
@@ -153,12 +152,11 @@ handshake.func @shliFW(%arg0: !handshake.channel<i16>, %start: !handshake.contro
153152
// CHECK-LABEL: handshake.func @shrsiFW(
154153
// CHECK-SAME: %[[VAL_0:.*]]: !handshake.channel<i16>,
155154
// CHECK-SAME: %[[VAL_1:.*]]: !handshake.control<>, ...) -> !handshake.channel<i32> attributes {argNames = ["arg0", "start"], resNames = ["out0"]} {
156-
// CHECK: %[[VAL_2:.*]] = constant %[[VAL_1]] {value = 4 : i4} : <>, <i4>
157-
// CHECK: %[[VAL_3:.*]] = extui %[[VAL_2]] : <i4> to <i16>
158-
// CHECK: %[[VAL_4:.*]] = shrsi %[[VAL_0]], %[[VAL_3]] : <i16>
159-
// CHECK: %[[VAL_5:.*]] = trunci %[[VAL_4]] : <i16> to <i12>
160-
// CHECK: %[[VAL_6:.*]] = extsi %[[VAL_5]] : <i12> to <i32>
161-
// CHECK: end %[[VAL_6]] : <i32>
155+
// CHECK: %[[VAL_2:.*]] = constant %[[VAL_1]] {value = 4 : i16} : <>, <i16>
156+
// CHECK: %[[VAL_3:.*]] = shrsi %[[VAL_0]], %[[VAL_2]] : <i16>
157+
// CHECK: %[[VAL_4:.*]] = trunci %[[VAL_3]] : <i16> to <i12>
158+
// CHECK: %[[VAL_5:.*]] = extsi %[[VAL_4]] : <i12> to <i32>
159+
// CHECK: end %[[VAL_5]] : <i32>
162160
// CHECK: }
163161
handshake.func @shrsiFW(%arg0: !handshake.channel<i16>, %start: !handshake.control<>) -> !handshake.channel<i32> {
164162
%cst = handshake.constant %start {value = 4 : i4} : <>, <i4>
@@ -173,12 +171,11 @@ handshake.func @shrsiFW(%arg0: !handshake.channel<i16>, %start: !handshake.contr
173171
// CHECK-LABEL: handshake.func @shruiFW(
174172
// CHECK-SAME: %[[VAL_0:.*]]: !handshake.channel<i16>,
175173
// CHECK-SAME: %[[VAL_1:.*]]: !handshake.control<>, ...) -> !handshake.channel<i32> attributes {argNames = ["arg0", "start"], resNames = ["out0"]} {
176-
// CHECK: %[[VAL_2:.*]] = constant %[[VAL_1]] {value = 4 : i4} : <>, <i4>
177-
// CHECK: %[[VAL_3:.*]] = extui %[[VAL_2]] : <i4> to <i16>
178-
// CHECK: %[[VAL_4:.*]] = shrui %[[VAL_0]], %[[VAL_3]] : <i16>
179-
// CHECK: %[[VAL_5:.*]] = trunci %[[VAL_4]] : <i16> to <i12>
180-
// CHECK: %[[VAL_6:.*]] = extsi %[[VAL_5]] : <i12> to <i32>
181-
// CHECK: end %[[VAL_6]] : <i32>
174+
// CHECK: %[[VAL_2:.*]] = constant %[[VAL_1]] {value = 4 : i16} : <>, <i16>
175+
// CHECK: %[[VAL_3:.*]] = shrui %[[VAL_0]], %[[VAL_2]] : <i16>
176+
// CHECK: %[[VAL_4:.*]] = trunci %[[VAL_3]] : <i16> to <i12>
177+
// CHECK: %[[VAL_5:.*]] = extsi %[[VAL_4]] : <i12> to <i32>
178+
// CHECK: end %[[VAL_5]] : <i32>
182179
// CHECK: }
183180
handshake.func @shruiFW(%arg0: !handshake.channel<i16>, %start: !handshake.control<>) -> !handshake.channel<i32> {
184181
%cst = handshake.constant %start {value = 4 : i4} : <>, <i4>

0 commit comments

Comments
 (0)