-
Notifications
You must be signed in to change notification settings - Fork 341
Comb Interval Range Analysis and Comb Opt Narrowing pass #8425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…implement anything - just returns unknown for every operator
…the truthtable and parity operator.
… just return the value of bits that can be removed.
…d add test for new pass.
…p implementations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good to me! Mostly just nits, the only big thing is where this int range analysis should live (expanded on below). @uenoku since this is along the lines of synthesis, is there any chance you could take a quick look at it too?
@@ -0,0 +1,256 @@ | |||
//===- InferIntRangeInterfaceImpls.cpp - Integer range impls for comb -===// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a little unusual for something like this to live in lib/Dialect/<dialect>
since it goes beyond the actual dialect definition, maybe it would make more sense to have it in lib/Analysis
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, when creating an analysis we often create a test pass in this file that just runs the analysis and prints out the results in a checkable format, and then use this to create some FileCheck tests for the analysis. It would be nice to do that here too (and if this moves to Analysis then you could just add it in that file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TaoBi22 - agree with this suggestion - there's currently no lib/Analysis/Comb hierarchy and given that I've got an implementation for both HW and Comb would it be sensible to introduce the directory structure in lib/Analysis?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that in MLIR these files live here say, lib/Dialect/Arith/IR/InferIntRangeInterfaceImpls.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current location for these files is fine.
One could make an argument that this logic should be tied more to the transformation pass and less to the dialect definition in which case you could implement them as external models and move them to the Transforms
folder (or a new Analysis
folder). Both seem fine to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I don't have strong feelings on this so if it matches what's done upstream then feel free to ignore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok will stick with as is for now - if the space of analyses grows then will perhaps make sense to separate as per Bea's suggestion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…matting corrections
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! 🎉
Just added some drive-by comments.
@@ -0,0 +1,256 @@ | |||
//===- InferIntRangeInterfaceImpls.cpp - Integer range impls for comb -===// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current location for these files is fine.
One could make an argument that this logic should be tied more to the transformation pass and less to the dialect definition in which case you could implement them as external models and move them to the Transforms
folder (or a new Analysis
folder). Both seem fine to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for interesting work! I think the interface is definitely worth to have 👍
High-level comments:
- Is it possible to have a test for range interface decoupled from narrowing pass? I think it's a bit difficult to track the correctness of the analysis. i.e. we don't have a test for range interface tests of comb.mux etc.
- Please use camelBack for variable names
…ctually executes the pass
@uenoku/@maerhart - have addressed all the comments above - would you have time to take another pass and approve if you feel its ready? Major changes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding a test pass. Could you add a test for replicate, extract and icmp? There is a correctness issue in add/mul pattern and crash with the following case, once after the issue was fixed PR look good to me.
hw.module private @InitReg1(in %clock: !seq.clock, in %reset: i1, in %io_d: i32, in %io_en: i1, out io_q: i32) {
%false = hw.constant false
%c1_i32 = hw.constant 1 : i32
%c0_i32 = hw.constant 0 : i32
%reg = seq.firreg %4 clock %clock sym @__reg__ reset async %reset, %c0_i32 : i32
%reg2 = seq.firreg %reg2 clock %clock sym @__reg2__ reset sync %reset, %c0_i32 : i32
%reg3 = seq.firreg %reg3 clock %clock sym @__reg3__ reset async %reset, %c1_i32 : i32
%0 = comb.concat %false, %reg : i1, i32
%1 = comb.concat %false, %reg2 : i1, i32
%2 = comb.add %0, %1 : i33
%3 = comb.extract %2 from 1 : (i33) -> i32
%4 = comb.mux bin %io_en, %io_d, %3 : i32
hw.output %reg : i32
}
circt-opt: /scratch/hidetou/circt/llvm/llvm/lib/Support/APInt.cpp:285: int llvm::APInt::compare(const llvm::APInt &) const: Assertion `BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"' failed.
PLEASE submit a bug report to https://github.com/llvm/circt and include the crash backtrace.
Stack dump:
0. Program arguments: ./build/bin/circt-opt --comb-int-range-narrowing a.mlir
#0 0x0000000000cdccc7 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /scratch/hidetou/circt/llvm/llvm/lib/Support/Unix/Signals.inc:804:13
#1 0x0000000000cdac00 llvm::sys::RunSignalHandlers() /scratch/hidetou/circt/llvm/llvm/lib/Support/Signals.cpp:106:18
#2 0x0000000000cdd5da SignalHandler(int, siginfo_t*, void*) /scratch/hidetou/circt/llvm/llvm/lib/Support/Unix/Signals.inc:0:3
#3 0x00007ff6960e3cf0 __restore_rt (/lib64/libpthread.so.0+0x12cf0)
#4 0x00007ff69519cacf raise (/lib64/libc.so.6+0x4eacf)
#5 0x00007ff69516fea5 abort (/lib64/libc.so.6+0x21ea5)
#6 0x00007ff69516fd79 _nl_load_domain.cold.0 (/lib64/libc.so.6+0x21d79)
#7 0x00007ff695195426 (/lib64/libc.so.6+0x47426)
#8 0x0000000000cf2ee6 (./build/bin/circt-opt+0xcf2ee6)
#9 0x0000000002dfbf69 llvm::APInt::ult(llvm::APInt const&) const /scratch/hidetou/circt/llvm/llvm/include/llvm/ADT/APInt.h:1111:58
#10 0x0000000002dfbf69 mlir::ConstantIntRanges::rangeUnion(mlir::ConstantIntRanges const&) const /scratch/hidetou/circt/llvm/mlir/lib/Interfaces/InferIntRangeInterface.cpp:93:35
#11 0x0000000000f5907c llvm::APInt::APInt(llvm::APInt&&) /scratch/hidetou/circt/llvm/llvm/include/llvm/ADT/APInt.h:184:39
#12 0x0000000000f5907c mlir::ConstantIntRanges::ConstantIntRanges(mlir::ConstantIntRanges&&) /scratch/hidetou/circt/llvm/llvm/../mlir/include/mlir/Interfaces/InferIntRangeInterface.h:27:7
#13 0x0000000000f5907c std::_Optional_payload_base<mlir::ConstantIntRanges>::_Storage<mlir::ConstantIntRanges, false>::_Storage<mlir::ConstantIntRanges>(std::in_place_t, mlir::ConstantIntRanges&&) /sifive/tools/gcc/gcc/11.2.0/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/optional:225:8
#14 0x0000000000f5907c std::_Optional_payload_base<mlir::ConstantIntRanges>::_Optional_payload_base<mlir::ConstantIntRanges>(std::in_place_t, mlir::ConstantIntRanges&&) /sifive/tools/gcc/gcc/11.2.0/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/optional:116:4
#15 0x0000000000f5907c std::_Optional_payload<mlir::ConstantIntRanges, true, false, false>::_Optional_payload<mlir::ConstantIntRanges>(std::in_place_t, mlir::ConstantIntRanges&&) /sifive/tools/gcc/gcc/11.2.0/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/optional:358:42
#16 0x0000000000f5907c std::_Optional_payload<mlir::ConstantIntRanges, false, false, false>::_Optional_payload<mlir::ConstantIntRanges>(std::in_place_t, mlir::ConstantIntRanges&&) /sifive/tools/gcc/gcc/11.2.0/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/optional:392:57
#17 0x0000000000f5907c std::_Optional_base<mlir::ConstantIntRanges, false, false>::_Optional_base<mlir::ConstantIntRanges, false>(std::in_place_t, mlir::ConstantIntRanges&&) /sifive/tools/gcc/gcc/11.2.0/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/optional:484:4
#18 0x0000000000f5907c std::optional<mlir::ConstantIntRanges>::optional<mlir::ConstantIntRanges, true>(mlir::ConstantIntRanges&&) /sifive/tools/gcc/gcc/11.2.0/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../include/c++/11.2.0/optional:707:4
#19 0x0000000000f5907c mlir::IntegerValueRange::IntegerValueRange(mlir::ConstantIntRanges) /scratch/hidetou/circt/llvm/llvm/../mlir/include/mlir/Interfaces/InferIntRangeInterface.h:117:48
#20 0x0000000000f5907c mlir::IntegerValueRange::join(mlir::IntegerValueRange const&, mlir::IntegerValueRange const&) /scratch/hidetou/circt/llvm/llvm/../mlir/include/mlir/Interfaces/InferIntRangeInterface.h:145:12
#21 0x0000000000f58f5e llvm::function_ref<void (mlir::Value, mlir::IntegerValueRange const&)>::operator()(mlir::Value, mlir::IntegerValueRange const&) const /scratch/hidetou/circt/llvm/llvm/include/llvm/ADT/STLFunctionalExtras.h:69:12
#22 0x0000000000f58f5e circt::comb::MuxOp::inferResultRangesFromOptional(llvm::ArrayRef<mlir::IntegerValueRange>, llvm::function_ref<void (mlir::Value, mlir::IntegerValueRange const&)>) /scratch/hidetou/circt/lib/Dialect/Comb/InferIntRangeInterfaceImpls.cpp:227:3
#23 0x0000000000f4d103 mlir::detail::InferIntRangeInterfaceInterfaceTraits::Model<circt::comb::MuxOp>::inferResultRangesFromOptional(mlir::detail::InferIntRangeInterfaceInterfaceTraits::Concept const*, mlir::Operation*, llvm::ArrayRef<mlir::IntegerValueRange>, llvm::function_ref<void (mlir::Value, mlir::IntegerValueRange const&)>) /scratch/hidetou/circt/build/tools/mlir/include/mlir/Interfaces/InferIntRangeInterface.h.inc:131:3
Value lhs = op.getOperand(0); | ||
Value rhs = op.getOperand(1); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this implicitly assumes operations are binary. Add/Mul are variadic so please insert a condition to check op is binary or handle variadic operations as well.
Not sure that's root cause, but I have an example that comb-int-range-narrowing breaks circt-lec. This is basically same logical_ops
in test but %7 has 3 operands.
hw.module @logical_ops(in %a : i8, in %b : i9, in %c : i10, in %d : i16, out res : i18) {
%c0_i2 = hw.constant 0 : i2
%false = hw.constant false
%c0_i9 = hw.constant 0 : i9
%c0_i8 = hw.constant 0 : i8
%0 = comb.concat %c0_i9, %a : i9, i8
%1 = comb.concat %c0_i8, %b : i8, i9
%2 = comb.and %0, %1 : i17
%3 = comb.concat %false, %2 : i1, i17
%4 = comb.concat %c0_i8, %c : i8, i10
%5 = comb.or %3, %4 : i18
%6 = comb.concat %c0_i2, %d : i2, i16
%7 = comb.add %5, %6, %6 : i18
hw.output %7 : i18
}
$ ./build/bin/circt-opt --comb-int-range-narrowing ./test/Dialect/Comb/comb-int-range-narrowing.mlir -o after.mlir
$ ./build/bin/circt-lec after.mlir ./test/Dialect/Comb/comb-int-range-narrowing.mlir --c1 logical_ops --c2 logical_ops --shared-libs ../z3/build/libz3.so
c1 != c2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have included a check for binary operators at time of writing - will extend to variadic operators in a subsequent PR, where I'll also add support for narrowing more operators. Good catch!
void comb::ICmpOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges, | ||
SetIntRangeFn setResultRange) { | ||
comb::ICmpPredicate combPred = getPredicate(); | ||
intrange::CmpPredicate pred = static_cast<intrange::CmpPredicate>(combPred); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explicitly convert comb predicate to intrange predicate? There are comb predicates that are specific hardware so this cast is dangerous.
SetIntRangeFn setResultRange) { | ||
// Right-shift and truncate (trunaction implicitly handled) | ||
auto lowBit = getLowBit(); | ||
auto umin = argRanges[0].umin().ushl_sat(lowBit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this is the cause of the InitReg1 bug above - thanks for spotting this error
…owing pass, fix bug in extraction analysis
@uenoku - have addressed your remaining comments with the following:
|
Building on the existing MLIR integer interval range analysis framework, build the interface for the comb dialect. Use the interval range analysis to develop a comb opt narrowing pass, that reduces a comb opt based on the interval range of the operation. Currently this is only supported for addition, subtraction and multiplication, but this could be extended in the future. Future work will leverage the interval analysis to validate the combination of consecutive addition operators into a multi-operand addition.