diff --git a/include/circt/Dialect/LLHD/IR/ExtractOps.td b/include/circt/Dialect/LLHD/IR/ExtractOps.td index fe10284a525..2618d6f5648 100644 --- a/include/circt/Dialect/LLHD/IR/ExtractOps.td +++ b/include/circt/Dialect/LLHD/IR/ExtractOps.td @@ -53,6 +53,8 @@ def LLHD_ExtractSliceOp : LLHD_Op<"extract_slice", [ unsigned getSliceSize() { return getLLHDTypeWidth(result().getType()); } unsigned getTargetSize() { return getLLHDTypeWidth(target().getType()); } }]; + + let hasFolder = 1; } def LLHD_DynExtractSliceOp : LLHD_Op<"dyn_extract_slice", [ @@ -100,6 +102,8 @@ def LLHD_DynExtractSliceOp : LLHD_Op<"dyn_extract_slice", [ unsigned getSliceWidth() { return getLLHDTypeWidth(result().getType()); } unsigned getTargetWidth() { return getLLHDTypeWidth(target().getType()); } }]; + + let hasCanonicalizer = 1; } def LLHD_ExtractElementOp : LLHD_Op<"extract_element", [ @@ -222,4 +226,6 @@ def LLHD_DynExtractElementOp : LLHD_Op<"dyn_extract_element", [ return targetType.cast().getElementType(); } }]; + + let hasCanonicalizer = 1; } diff --git a/include/circt/Dialect/LLHD/IR/LLHDCanonicalization.td b/include/circt/Dialect/LLHD/IR/LLHDCanonicalization.td index 0ab771bff34..d7f4da8322c 100644 --- a/include/circt/Dialect/LLHD/IR/LLHDCanonicalization.td +++ b/include/circt/Dialect/LLHD/IR/LLHDCanonicalization.td @@ -8,6 +8,10 @@ #define CIRCT_DIALECT_LLHD_IR_CANONICALIZATION_TD include "circt/Dialect/LLHD/IR/LLHD.td" +include "mlir/Dialect/StandardOps/IR/Ops.td" + +def IndexAttrFromSignlessInteger : NativeCodeCall< + "$_builder.getIndexAttr($0.cast().getValue().getZExtValue())">; //===----------------------------------------------------------------------===// // XorOp @@ -48,12 +52,28 @@ def BooleanNeqToXor : Pat< (LLHD_NeqOp I1:$lhs, I1:$rhs), (LLHD_XorOp $lhs, $rhs)>; +//===----------------------------------------------------------------------===// +// DynExtractSliceOp +//===----------------------------------------------------------------------===// + +def DynExtractSliceWithLLHDConstOpStart : Pat< + (LLHD_DynExtractSliceOp $target, (LLHD_ConstOp $start)), + (LLHD_ExtractSliceOp $target, (IndexAttrFromSignlessInteger $start))>; + +def DynExtractSliceWithConstantOpStart : Pat< + (LLHD_DynExtractSliceOp $target, (ConstantOp $start)), + (LLHD_ExtractSliceOp $target, (IndexAttrFromSignlessInteger $start))>; + +//===----------------------------------------------------------------------===// +// DynExtractElementOp +//===----------------------------------------------------------------------===// + +def DynExtractElementWithLLHDConstOpIndex : Pat< + (LLHD_DynExtractElementOp $target, (LLHD_ConstOp $index)), + (LLHD_ExtractElementOp $target, (IndexAttrFromSignlessInteger $index))>; -// TODO: dexts(target,constant c) -> exts(target, c) -// TODO: dextf(target,constant c) -> extf(target, c) -// TODO: exts(shr(hidden, base, constant amt), 0) -> exts(base, amt) (folder) -// (if amt + sliceWidth <= baseWidth, common pattern of moore to -// extract bits) -// TODO: exts(exts(target, a), b) -> exts(target, a+b) (folder) +def DynExtractElementWithConstantOpIndex : Pat< + (LLHD_DynExtractElementOp $target, (ConstantOp $index)), + (LLHD_ExtractElementOp $target, (IndexAttrFromSignlessInteger $index))>; #endif // CIRCT_DIALECT_LLHD_IR_CANONICALIZATION_TD diff --git a/lib/Dialect/LLHD/IR/LLHDCanonicalization.cpp b/lib/Dialect/LLHD/IR/LLHDCanonicalization.cpp index baa5fab245c..1735acc251d 100644 --- a/lib/Dialect/LLHD/IR/LLHDCanonicalization.cpp +++ b/lib/Dialect/LLHD/IR/LLHDCanonicalization.cpp @@ -3,6 +3,7 @@ //===----------------------------------------------------------------------===// #include "circt/Dialect/LLHD/IR/LLHDOps.h" +#include "mlir/Dialect/StandardOps/IR/Ops.h" #include "mlir/IR/PatternMatch.h" using namespace mlir; @@ -10,7 +11,7 @@ using namespace mlir; namespace { /// Include the patterns defined in the Declarative Rewrite framework. #include "circt/Dialect/LLHD/IR/LLHDCanonicalization.inc" -} // anonymous namespace +} // namespace void llhd::XorOp::getCanonicalizationPatterns(OwningRewritePatternList &results, MLIRContext *context) { @@ -31,3 +32,15 @@ void llhd::NeqOp::getCanonicalizationPatterns(OwningRewritePatternList &results, MLIRContext *context) { results.insert(context); } + +void llhd::DynExtractSliceOp::getCanonicalizationPatterns( + OwningRewritePatternList &results, MLIRContext *context) { + results.insert(context); +} + +void llhd::DynExtractElementOp::getCanonicalizationPatterns( + OwningRewritePatternList &results, MLIRContext *context) { + results.insert(context); +} diff --git a/lib/Dialect/LLHD/IR/LLHDOps.cpp b/lib/Dialect/LLHD/IR/LLHDOps.cpp index 43a517ff0c2..cf36522ffe7 100644 --- a/lib/Dialect/LLHD/IR/LLHDOps.cpp +++ b/lib/Dialect/LLHD/IR/LLHDOps.cpp @@ -387,6 +387,76 @@ OpFoldResult llhd::ShrOp::fold(ArrayRef operands) { }); } +//===----------------------------------------------------------------------===// +// ExtractSliceOp +//===----------------------------------------------------------------------===// + +OpFoldResult llhd::ExtractSliceOp::fold(ArrayRef operands) { + uint64_t extractStart = startAttr().getInt(); + + // llhd.extract_slice(target, 0) with sliceWidth==targetWidth => target + if (extractStart == 0 && getSliceSize() == getTargetSize()) + return target(); + + // llhd.extract_slice(llhd.shr(hidden, base, constant amt), start) + // with amt + start + sliceWidth <= baseWidth + // => llhd.extract_slice(base, amt + start) + if (auto shrOp = target().getDefiningOp()) { + IntegerAttr intAttr; + if (matchPattern(shrOp.amount(), m_Constant(&intAttr))) { + uint64_t amt = intAttr.getValue().getZExtValue(); + + if (amt + extractStart + getSliceSize() <= shrOp.getBaseWidth()) { + targetMutable().assign(shrOp.base()); + setAttr("start", + IntegerAttr::get(startAttr().getType(), amt + extractStart)); + return result(); + } + } + } + + // llhd.extract_slice(llhd.extract_slice(target, a), b) + // => llhd.extract_slice(target, a+b) + if (auto extOp = target().getDefiningOp()) { + targetMutable().assign(extOp.target()); + auto newStart = extractStart + extOp.startAttr().getInt(); + setAttr("start", IntegerAttr::get(startAttr().getType(), newStart)); + return result(); + } + + // llhd.extract_slice(llhd.insert_slice(target, slice, a), b) + if (auto insertOp = target().getDefiningOp()) { + uint64_t insertStart = insertOp.startAttr().getInt(); + // with b >= a && b + resultWidth <= a + sliceWidth + // => llhd.extract_slice(slice, b-a) + if (extractStart >= insertStart && + extractStart + getSliceSize() <= + insertStart + insertOp.getSliceSize()) { + targetMutable().assign(insertOp.slice()); + setAttr("start", IntegerAttr::get(startAttr().getType(), + extractStart - insertStart)); + return result(); + } + // with b + resultWidth <= a or b >= a + insertedSliceWidth + // => llhd.extract_slice(target, b) + if (extractStart + getSliceSize() <= insertStart || + extractStart >= insertStart + insertOp.getSliceSize()) { + targetMutable().assign(insertOp.target()); + return result(); + } + } + + if (!operands[0]) + return nullptr; + + if (auto intAttr = operands[0].dyn_cast()) + return IntegerAttr::get(result().getType(), + intAttr.getValue().extractBitsAsZExtValue( + getSliceSize(), extractStart)); + + return nullptr; +} + //===----------------------------------------------------------------------===// // WaitOp //===----------------------------------------------------------------------===// diff --git a/test/Dialect/LLHD/Canonicalization/arithmetic.mlir b/test/Dialect/LLHD/Canonicalization/arithmetic.mlir index b1a1425ba27..2bf92ec0d30 100644 --- a/test/Dialect/LLHD/Canonicalization/arithmetic.mlir +++ b/test/Dialect/LLHD/Canonicalization/arithmetic.mlir @@ -1,4 +1,4 @@ -// RUN: circt-opt %s -mlir-print-op-generic -canonicalize | circt-opt | circt-opt | FileCheck %s +// RUN: circt-opt %s -canonicalize | FileCheck %s // CHECK-LABEL: @check_neg_folding func @check_neg_folding() -> (i16) { diff --git a/test/Dialect/LLHD/Canonicalization/extract.mlir b/test/Dialect/LLHD/Canonicalization/extract.mlir new file mode 100644 index 00000000000..6a9554e2c06 --- /dev/null +++ b/test/Dialect/LLHD/Canonicalization/extract.mlir @@ -0,0 +1,127 @@ +// RUN: circt-opt %s -canonicalize | FileCheck %s + +// CHECK-LABEL: @dyn_extract_slice_to_static_extract +// CHECK-SAME: %[[INT:.*]]: i32 +// CHECK-SAME: %[[SIG:.*]]: !llhd.sig +// CHECK-SAME: %[[ARRAY:.*]]: !llhd.array<10xi1> +// CHECK-SAME: %[[ARRAYSIG:.*]]: !llhd.sig> +func @dyn_extract_slice_to_static_extract(%int : i32, %sig : !llhd.sig, %array : !llhd.array<10xi1>, %arraysig : !llhd.sig>) + -> (i16, i16, !llhd.sig, !llhd.sig, !llhd.array<5xi1>, !llhd.array<5xi1>, !llhd.sig>, !llhd.sig>) { + %ind1 = llhd.const 1 : i8 + %ind2 = constant 2 : i8 + // CHECK-NEXT: %[[EXTINT1:.*]] = llhd.extract_slice %[[INT]], 1 : i32 -> i16 + %0 = llhd.dyn_extract_slice %int, %ind1 : (i32, i8) -> i16 + // CHECK-NEXT: %[[EXTINT2:.*]] = llhd.extract_slice %[[INT]], 2 : i32 -> i16 + %1 = llhd.dyn_extract_slice %int, %ind2 : (i32, i8) -> i16 + // CHECK-NEXT: %[[EXTSIG1:.*]] = llhd.extract_slice %[[SIG]], 1 : !llhd.sig -> !llhd.sig + %2 = llhd.dyn_extract_slice %sig, %ind1 : (!llhd.sig, i8) -> !llhd.sig + // CHECK-NEXT: %[[EXTSIG2:.*]] = llhd.extract_slice %[[SIG]], 2 : !llhd.sig -> !llhd.sig + %3 = llhd.dyn_extract_slice %sig, %ind2 : (!llhd.sig, i8) -> !llhd.sig + // CHECK-NEXT: %[[EXTARRAY1:.*]] = llhd.extract_slice %[[ARRAY]], 1 : !llhd.array<10xi1> -> !llhd.array<5xi1> + %4 = llhd.dyn_extract_slice %array, %ind1 : (!llhd.array<10xi1>, i8) -> !llhd.array<5xi1> + // CHECK-NEXT: %[[EXTARRAY2:.*]] = llhd.extract_slice %[[ARRAY]], 2 : !llhd.array<10xi1> -> !llhd.array<5xi1> + %5 = llhd.dyn_extract_slice %array, %ind2 : (!llhd.array<10xi1>, i8) -> !llhd.array<5xi1> + // CHECK-NEXT: %[[EXTARRAYSIG1:.*]] = llhd.extract_slice %[[ARRAYSIG]], 1 : !llhd.sig> -> !llhd.sig> + %6 = llhd.dyn_extract_slice %arraysig, %ind1 : (!llhd.sig>, i8) -> !llhd.sig> + // CHECK-NEXT: %[[EXTARRAYSIG2:.*]] = llhd.extract_slice %[[ARRAYSIG]], 2 : !llhd.sig> -> !llhd.sig> + %7 = llhd.dyn_extract_slice %arraysig, %ind2 : (!llhd.sig>, i8) -> !llhd.sig> + + // CHECK-NEXT: return %[[EXTINT1]], %[[EXTINT2]], %[[EXTSIG1]], %[[EXTSIG2]], %[[EXTARRAY1]], %[[EXTARRAY2]], %[[EXTARRAYSIG1]], %[[EXTARRAYSIG2]] : i16, i16, !llhd.sig, !llhd.sig, !llhd.array<5xi1>, !llhd.array<5xi1>, !llhd.sig>, !llhd.sig> + return %0, %1, %2, %3, %4, %5, %6, %7 : i16, i16, !llhd.sig, !llhd.sig, !llhd.array<5xi1>, !llhd.array<5xi1>, !llhd.sig>, !llhd.sig> +} + +// CHECK-LABEL: @dyn_extract_element_to_static_extract +// CHECK-SAME: %[[ARRAY:.*]]: !llhd.array<10xi1> +// CHECK-SAME: %[[ARRAYSIG:.*]]: !llhd.sig> +func @dyn_extract_element_to_static_extract(%array : !llhd.array<10xi1>, %arraysig : !llhd.sig>) + -> (i1, i1, !llhd.sig, !llhd.sig) { + %ind1 = llhd.const 1 : i8 + %ind2 = constant 2 : i8 + // CHECK-NEXT: %[[EXTSIG1:.*]] = llhd.extract_element %[[ARRAY]], 1 : !llhd.array<10xi1> -> i1 + %0 = llhd.dyn_extract_element %array, %ind1 : (!llhd.array<10xi1>, i8) -> i1 + // CHECK-NEXT: %[[EXTSIG2:.*]] = llhd.extract_element %[[ARRAY]], 2 : !llhd.array<10xi1> -> i1 + %1 = llhd.dyn_extract_element %array, %ind2 : (!llhd.array<10xi1>, i8) -> i1 + // CHECK-NEXT: %[[EXTARRAYSIG1:.*]] = llhd.extract_element %[[ARRAYSIG]], 1 : !llhd.sig> -> !llhd.sig + %2 = llhd.dyn_extract_element %arraysig, %ind1 : (!llhd.sig>, i8) -> !llhd.sig + // CHECK-NEXT: %[[EXTARRAYSIG2:.*]] = llhd.extract_element %[[ARRAYSIG]], 2 : !llhd.sig> -> !llhd.sig + %3 = llhd.dyn_extract_element %arraysig, %ind2 : (!llhd.sig>, i8) -> !llhd.sig + + // CHECK-NEXT: return %[[EXTSIG1]], %[[EXTSIG2]], %[[EXTARRAYSIG1]], %[[EXTARRAYSIG2]] : i1, i1, !llhd.sig, !llhd.sig + return %0, %1, %2, %3 : i1, i1, !llhd.sig, !llhd.sig +} + +// CHECK-LABEL: @extract_slice_folding +// CHECK-SAME: %[[INT:.*]]: i32 +// CHECK-SAME: %[[SIG:.*]]: !llhd.sig +// CHECK-SAME: %[[ARRAY:.*]]: !llhd.array<10xi1> +// CHECK-SAME: %[[ARRAYSIG:.*]]: !llhd.sig> +func @extract_slice_folding(%int : i32, %sig : !llhd.sig, %array : !llhd.array<10xi1>, %arraysig : !llhd.sig>) + -> (i32, !llhd.sig, !llhd.array<10xi1>, !llhd.sig>, i8, !llhd.sig, !llhd.array<2xi1>, !llhd.sig>, + i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i24, i24, !llhd.array<2xi1>, !llhd.array<1xi1>) { + // CHECK-NEXT: %[[VAL_4:.*]] = llhd.const 3 : i32 + %c = llhd.const 3 : i32 + + %0 = llhd.extract_slice %int, 0 : i32 -> i32 + %1 = llhd.extract_slice %sig, 0 : !llhd.sig -> !llhd.sig + %2 = llhd.extract_slice %array, 0 : !llhd.array<10xi1> -> !llhd.array<10xi1> + %3 = llhd.extract_slice %arraysig, 0 : !llhd.sig> -> !llhd.sig> + + %exint = llhd.extract_slice %int, 2 : i32 -> i16 + %exsig = llhd.extract_slice %sig, 2 : !llhd.sig -> !llhd.sig + %exarray = llhd.extract_slice %array, 2 : !llhd.array<10xi1> -> !llhd.array<5xi1> + %exarraysig = llhd.extract_slice %arraysig, 2 : !llhd.sig> -> !llhd.sig> + // CHECK-NEXT: %[[VAL_5:.*]] = llhd.extract_slice %[[INT]], 3 : i32 -> i8 + %4 = llhd.extract_slice %exint, 1 : i16 -> i8 + // CHECK-NEXT: %[[VAL_6:.*]] = llhd.extract_slice %[[SIG]], 3 : !llhd.sig -> !llhd.sig + %5 = llhd.extract_slice %exsig, 1 : !llhd.sig -> !llhd.sig + // CHECK-NEXT: %[[VAL_7:.*]] = llhd.extract_slice %[[ARRAY]], 3 : !llhd.array<10xi1> -> !llhd.array<2xi1> + %6 = llhd.extract_slice %exarray, 1 : !llhd.array<5xi1> -> !llhd.array<2xi1> + // CHECK-NEXT: %[[VAL_8:.*]] = llhd.extract_slice %[[ARRAYSIG]], 3 : !llhd.sig> -> !llhd.sig> + %7 = llhd.extract_slice %exarraysig, 1 : !llhd.sig> -> !llhd.sig> + + // CHECK-NEXT: %[[VAL_9:.*]] = llhd.insert_slice %[[INT]], %[[VAL_5]], 7 : i32, i8 + %insint = llhd.insert_slice %int, %4, 7 : i32, i8 + // CHECK-NEXT: %[[VAL_10:.*]] = llhd.insert_slice %[[ARRAY]], %[[VAL_7]], 6 : !llhd.array<10xi1>, !llhd.array<2xi1> + %insarray = llhd.insert_slice %array, %6, 6 : !llhd.array<10xi1>, !llhd.array<2xi1> + // extract only from the part before the inserted slice + // CHECK-NEXT: %[[VAL_11:.*]] = llhd.extract_slice %[[INT]], 3 : i32 -> i4 + %8 = llhd.extract_slice %insint, 3 : i32 -> i4 + // CHECK-NEXT: %[[VAL_12:.*]] = llhd.extract_slice %[[ARRAY]], 4 : !llhd.array<10xi1> -> !llhd.array<2xi1> + %9 = llhd.extract_slice %insarray, 4 : !llhd.array<10xi1> -> !llhd.array<2xi1> + // extract only from the inserted slice + // CHECK-NEXT: %[[VAL_13:.*]] = llhd.extract_slice %[[INT]], 4 : i32 -> i4 + %10 = llhd.extract_slice %insint, 8 : i32 -> i4 + %11 = llhd.extract_slice %insarray, 6 : !llhd.array<10xi1> -> !llhd.array<2xi1> + // extract only from the part after the inserted slice + // CHECK-NEXT: %[[VAL_14:.*]] = llhd.extract_slice %[[INT]], 15 : i32 -> i4 + %12 = llhd.extract_slice %insint, 15 : i32 -> i4 + // CHECK-NEXT: %[[VAL_15:.*]] = llhd.extract_slice %[[ARRAY]], 8 : !llhd.array<10xi1> -> !llhd.array<2xi1> + %13 = llhd.extract_slice %insarray, 8 : !llhd.array<10xi1> -> !llhd.array<2xi1> + // extract from both + // CHECK-NEXT: %[[VAL_16:.*]] = llhd.extract_slice %[[VAL_9]], 6 : i32 -> i4 + %14 = llhd.extract_slice %insint, 6 : i32 -> i4 + // CHECK-NEXT: %[[VAL_17:.*]] = llhd.extract_slice %[[VAL_10]], 5 : !llhd.array<10xi1> -> !llhd.array<2xi1> + %15 = llhd.extract_slice %insarray, 5 : !llhd.array<10xi1> -> !llhd.array<2xi1> + + // CHECK-NEXT: %[[VAL_18:.*]] = llhd.shr %[[INT]], %[[INT]], %[[VAL_4]] : (i32, i32, i32) -> i32 + %shrint = llhd.shr %int, %int, %c : (i32, i32, i32) -> i32 + // only extract from base value + // CHECK-NEXT: %[[VAL_19:.*]] = llhd.extract_slice %[[INT]], 8 : i32 -> i24 + %16 = llhd.extract_slice %shrint, 5 : i32 -> i24 + // offset too big + // CHECK-NEXT: %[[VAL_20:.*]] = llhd.extract_slice %[[VAL_18]], 6 : i32 -> i24 + %17 = llhd.extract_slice %shrint, 6 : i32 -> i24 + // CHECK-NEXT: %[[VAL_21:.*]] = llhd.shr %[[ARRAY]], %[[ARRAY]], %[[VAL_4]] : (!llhd.array<10xi1>, !llhd.array<10xi1>, i32) -> !llhd.array<10xi1> + %shrarray = llhd.shr %array, %array, %c : (!llhd.array<10xi1>, !llhd.array<10xi1>, i32) -> !llhd.array<10xi1> + // only extract from base value + // CHECK-NEXT: %[[VAL_22:.*]] = llhd.extract_slice %[[ARRAY]], 8 : !llhd.array<10xi1> -> !llhd.array<2xi1> + %18 = llhd.extract_slice %shrarray, 5 : !llhd.array<10xi1> -> !llhd.array<2xi1> + // offset too big + // CHECK-NEXT: %[[VAL_23:.*]] = llhd.extract_slice %[[VAL_21]], 7 : !llhd.array<10xi1> -> !llhd.array<1xi1> + %19 = llhd.extract_slice %shrarray, 7 : !llhd.array<10xi1> -> !llhd.array<1xi1> + + // CHECK-NEXT: return %[[INT]], %[[SIG]], %[[ARRAY]], %[[ARRAYSIG]], %[[VAL_5]], %[[VAL_6]], %[[VAL_7]], %[[VAL_8]], %[[VAL_11]], %[[VAL_12]], %[[VAL_13]], %[[VAL_7]], %[[VAL_14]], %[[VAL_15]], %[[VAL_16]], %[[VAL_17]], %[[VAL_19]], %[[VAL_20]], %[[VAL_22]], %[[VAL_23]] : i32, !llhd.sig, !llhd.array<10xi1>, !llhd.sig>, i8, !llhd.sig, !llhd.array<2xi1>, !llhd.sig>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i24, i24, !llhd.array<2xi1>, !llhd.array<1xi1> + return %0, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19 + : i32, !llhd.sig, !llhd.array<10xi1>, !llhd.sig>, i8, !llhd.sig, !llhd.array<2xi1>, !llhd.sig>, + i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i4, !llhd.array<2xi1>, i24, i24, !llhd.array<2xi1>, !llhd.array<1xi1> +}