CIRCT 24.0.0git
Loading...
Searching...
No Matches
CombFolds.cpp File Reference
#include "circt/Dialect/Comb/CombDialect.h"
#include "circt/Dialect/Comb/CombOps.h"
#include "circt/Dialect/HW/HWAttributes.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Support/Naming.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/Matchers.h"
#include "mlir/IR/PatternMatch.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/KnownBits.h"
Include dependency graph for CombFolds.cpp:

Go to the source code of this file.

Functions

static bool isOpTriviallyRecursive (Operation *op)
static Value createGenericOp (Location loc, OperationName name, ArrayRef< Value > operands, OpBuilder &builder)
 Create a new instance of a generic operation that only has value operands, and has a single result value whose type matches the first operand.
static TypedAttr getIntAttr (const APInt &value, MLIRContext *context)
static void getConcatOperands (Value v, SmallVectorImpl< Value > &result)
 Flatten concat and mux operands into a vector.
static bool hasSVAttributes (Operation *op)
template<typename SubType>
static ComplementMatcher< SubType > m_Complement (const SubType &subExpr)
static bool shouldBeFlattened (Operation *op)
 Return true if the op will be flattened afterwards.
static bool tryFlatteningOperands (Operation *op, PatternRewriter &rewriter)
 Flattens a single input in op if hasOneUse is true and it can be defined as an Op.
static std::pair< size_t, size_t > getLowestBitAndHighestBitRequired (Operation *op, bool narrowTrailingBits, size_t originalOpWidth)
template<class OpTy>
static bool narrowOperationWidth (OpTy op, size_t lowestBit, size_t highestBit, PatternRewriter &rewriter)
template<class OpTy>
static bool narrowOperationWidth (OpTy op, bool narrowTrailingBits, PatternRewriter &rewriter)
static Attribute constFoldBinaryOp (ArrayRef< Attribute > operands, hw::PEO paramOpcode)
 Performs constant folding calculate with element-wise behavior on the two attributes in operands and returns the result if possible.
static LogicalResult extractConcatToConcatExtract (ExtractOp op, ConcatOp innerCat, PatternRewriter &rewriter, ArrayRef< size_t > prefixWidths={})
static bool extractFromReplicate (ExtractOp op, ReplicateOp replicate, PatternRewriter &rewriter)
static bool extractFromAdd (ExtractOp op, AddOp add, PatternRewriter &rewriter)
 Fold a single-bit extract of a two-operand add into an icmp when bit bitIdx is known in both operands and the low bitIdx bits of one operand are a known constant c: extract(bitIdx, add(x, c)) -> icmp ugt/ule x[bitIdx-1:0], ~c[bitIdx-1:0] Bit bitIdx of lhs + rhs is lhs[bitIdx] ^ rhs[bitIdx] ^ carry, and the low bitIdx bits carry into bit bitIdx iff x[bitIdx-1:0] >_u ~c.
static Attribute constFoldAssociativeOp (ArrayRef< Attribute > operands, hw::PEO paramOpcode)
static bool canonicalizeLogicalCstWithConcat (Operation *logicalOp, size_t concatIdx, const APInt &cst, PatternRewriter &rewriter)
 When we find a logical operation (and, or, xor) with a constant e.g.
static bool canCombineOppositeBinCmpIntoConstant (OperandRange operands)
template<typename Op>
static Value getCommonOperand (Op op)
 Returns a single common operand that all inputs of the operation op can be traced back to, or an empty Value if no such operand exists.
template<typename Op>
static bool canonicalizeIdempotentInputs (Op op, PatternRewriter &rewriter)
 Canonicalize an idempotent operation op so that only one input of any kind occurs.
static void canonicalizeXorIcmpTrue (XorOp op, unsigned icmpOperand, PatternRewriter &rewriter)
static bool subLowBitsCannotBorrow (Value lhs, Value rhs, unsigned numBits)
 Returns true if subtracting the low numBits bits of rhs from those of lhs can never borrow from bit numBits: the smallest possible value of lhs's low bits must be at least the largest possible value of rhs's.
static bool addLowBitsCannotCarry (ValueRange operands, unsigned numBits)
 Returns true if adding the low numBits bits of all operands can never carry into bit numBits: the largest possible sum of those bits (every bit not known to be zero taken as one) must still fit in numBits bits.
template<class Op, bool isSigned>
static OpFoldResult foldDiv (Op op, ArrayRef< Attribute > constants)
template<class Op, bool isSigned>
static OpFoldResult foldMod (Op op, ArrayRef< Attribute > constants)
static bool getMuxChainCondConstant (Value cond, Value indexValue, bool isInverted, std::function< void(hw::ConstantOp)> constantFn)
 Check to see if the condition to the specified mux is an equality comparison indexValue and one or more constants.
static Value extractOperandFromFullyAssociative (Operation *fullyAssoc, size_t operandNo, PatternRewriter &rewriter)
 Given a fully associative variadic operation like (a+b+c+d), break the expression into two parts, one without the specified operand (e.g.
static bool foldCommonMuxOperation (MuxOp mux, Operation *trueOp, Operation *falseOp, PatternRewriter &rewriter)
 Fold things like mux(cond, x|y|z|a, a) -> (x|y|z)&replicate(cond)|a and mux(cond, a, x|y|z|a) -> (x|y|z)&replicate(~cond) | a` (when isTrueOperand is true.
static bool foldMuxOfUniformArrays (MuxOp op, PatternRewriter &rewriter)
static bool assumeMuxCondInOperand (Value muxCond, Value muxValue, bool constCond, PatternRewriter &rewriter)
 If the mux condition is an operand to the op defining its true or false value, replace the condition with 1 or 0.
static bool applyCmpPredicate (ICmpPredicate predicate, const APInt &lhs, const APInt &rhs)
static bool applyCmpPredicateToEqualOperands (ICmpPredicate predicate)
template<typename Range>
static size_t computeCommonPrefixLength (const Range &a, const Range &b)
static size_t getTotalWidth (ArrayRef< Value > operands)
static LogicalResult matchAndRewriteCompareConcat (ICmpOp op, Operation *lhs, Operation *rhs, PatternRewriter &rewriter)
 Reduce the strength icmp(concat(...), concat(...)) by doing a element-wise comparison on common prefix and suffixes.
static void combineEqualityICmpWithKnownBitsAndConstant (ICmpOp cmpOp, const KnownBits &bitAnalysis, const APInt &rhsCst, PatternRewriter &rewriter)
 Given an equality comparison with a constant value and some operand that has known bits, simplify the comparison to check only the unknown bits of the input.
static void combineEqualityICmpWithXorOfConstant (ICmpOp cmpOp, XorOp xorOp, const APInt &rhs, PatternRewriter &rewriter)

Function Documentation

◆ addLowBitsCannotCarry()

bool addLowBitsCannotCarry ( ValueRange operands,
unsigned numBits )
static

Returns true if adding the low numBits bits of all operands can never carry into bit numBits: the largest possible sum of those bits (every bit not known to be zero taken as one) must still fit in numBits bits.

Definition at line 1629 of file CombFolds.cpp.

References circt::comb::computeKnownBits().

◆ applyCmpPredicate()

bool applyCmpPredicate ( ICmpPredicate predicate,
const APInt & lhs,
const APInt & rhs )
static

Definition at line 3012 of file CombFolds.cpp.

◆ applyCmpPredicateToEqualOperands()

bool applyCmpPredicateToEqualOperands ( ICmpPredicate predicate)
static

Definition at line 3049 of file CombFolds.cpp.

Referenced by matchAndRewriteCompareConcat().

◆ assumeMuxCondInOperand()

bool assumeMuxCondInOperand ( Value muxCond,
Value muxValue,
bool constCond,
PatternRewriter & rewriter )
static

If the mux condition is an operand to the op defining its true or false value, replace the condition with 1 or 0.

Definition at line 2630 of file CombFolds.cpp.

References hw.ConstantOp::create().

◆ canCombineOppositeBinCmpIntoConstant()

bool canCombineOppositeBinCmpIntoConstant ( OperandRange operands)
static

Definition at line 911 of file CombFolds.cpp.

◆ canonicalizeIdempotentInputs()

template<typename Op>
bool canonicalizeIdempotentInputs ( Op op,
PatternRewriter & rewriter )
static

Canonicalize an idempotent operation op so that only one input of any kind occurs.

Example: and(x, y, x, z) -> and(x, y, z)

Definition at line 1023 of file CombFolds.cpp.

References circt::replaceOpWithNewOpAndCopyNamehint().

◆ canonicalizeLogicalCstWithConcat()

bool canonicalizeLogicalCstWithConcat ( Operation * logicalOp,
size_t concatIdx,
const APInt & cst,
PatternRewriter & rewriter )
static

When we find a logical operation (and, or, xor) with a constant e.g.

X & 42, we want to push the constant into the computation of X if it leads to simplification.

This function handles the case where the logical operation has a concat operand. We check to see if we can simplify the concat, e.g. when it has constant operands.

This returns true when a simplification happens.

Definition at line 833 of file CombFolds.cpp.

References assert(), hw.ConstantOp::create(), createGenericOp(), and circt::replaceOpAndCopyNamehint().

◆ canonicalizeXorIcmpTrue()

void canonicalizeXorIcmpTrue ( XorOp op,
unsigned icmpOperand,
PatternRewriter & rewriter )
static

Definition at line 1419 of file CombFolds.cpp.

References circt::replaceOpAndCopyNamehint().

◆ combineEqualityICmpWithKnownBitsAndConstant()

void combineEqualityICmpWithKnownBitsAndConstant ( ICmpOp cmpOp,
const KnownBits & bitAnalysis,
const APInt & rhsCst,
PatternRewriter & rewriter )
static

Given an equality comparison with a constant value and some operand that has known bits, simplify the comparison to check only the unknown bits of the input.

One simple example of this is that concat(0, stuff) == 0 can be simplified to stuff == 0, or and(x, 3) == 0 can be simplified to extract x[1:0] == 0

Definition at line 3220 of file CombFolds.cpp.

References hw.ConstantOp::create(), and circt::replaceOpWithNewOpAndCopyNamehint().

◆ combineEqualityICmpWithXorOfConstant()

void combineEqualityICmpWithXorOfConstant ( ICmpOp cmpOp,
XorOp xorOp,
const APInt & rhs,
PatternRewriter & rewriter )
static

◆ computeCommonPrefixLength()

template<typename Range>
size_t computeCommonPrefixLength ( const Range & a,
const Range & b )
static

Definition at line 3093 of file CombFolds.cpp.

Referenced by matchAndRewriteCompareConcat().

◆ constFoldAssociativeOp()

Attribute constFoldAssociativeOp ( ArrayRef< Attribute > operands,
hw::PEO paramOpcode )
static

Definition at line 798 of file CombFolds.cpp.

References assert().

◆ constFoldBinaryOp()

Attribute constFoldBinaryOp ( ArrayRef< Attribute > operands,
hw::PEO paramOpcode )
static

Performs constant folding calculate with element-wise behavior on the two attributes in operands and returns the result if possible.

Definition at line 367 of file CombFolds.cpp.

References assert().

Referenced by foldDiv(), and foldMod().

◆ createGenericOp()

Value createGenericOp ( Location loc,
OperationName name,
ArrayRef< Value > operands,
OpBuilder & builder )
static

Create a new instance of a generic operation that only has value operands, and has a single result value whose type matches the first operand.

This should not be used to create instances of ops with attributes or with more complicated type signatures.

Definition at line 40 of file CombFolds.cpp.

Referenced by canonicalizeLogicalCstWithConcat(), extractOperandFromFullyAssociative(), and tryFlatteningOperands().

◆ extractConcatToConcatExtract()

LogicalResult extractConcatToConcatExtract ( ExtractOp op,
ConcatOp innerCat,
PatternRewriter & rewriter,
ArrayRef< size_t > prefixWidths = {} )
static

Definition at line 552 of file CombFolds.cpp.

◆ extractFromAdd()

bool extractFromAdd ( ExtractOp op,
AddOp add,
PatternRewriter & rewriter )
static

Fold a single-bit extract of a two-operand add into an icmp when bit bitIdx is known in both operands and the low bitIdx bits of one operand are a known constant c: extract(bitIdx, add(x, c)) -> icmp ugt/ule x[bitIdx-1:0], ~c[bitIdx-1:0] Bit bitIdx of lhs + rhs is lhs[bitIdx] ^ rhs[bitIdx] ^ carry, and the low bitIdx bits carry into bit bitIdx iff x[bitIdx-1:0] >_u ~c.

Returns true if op was replaced, false otherwise.

Definition at line 655 of file CombFolds.cpp.

References circt::comb::computeKnownBits(), hw.ConstantOp::create(), and circt::replaceOpWithNewOpAndCopyNamehint().

◆ extractFromReplicate()

bool extractFromReplicate ( ExtractOp op,
ReplicateOp replicate,
PatternRewriter & rewriter )
static

Definition at line 618 of file CombFolds.cpp.

References circt::replaceOpWithNewOpAndCopyNamehint().

◆ extractOperandFromFullyAssociative()

Value extractOperandFromFullyAssociative ( Operation * fullyAssoc,
size_t operandNo,
PatternRewriter & rewriter )
static

Given a fully associative variadic operation like (a+b+c+d), break the expression into two parts, one without the specified operand (e.g.

tmp = a+b+d) and one that combines that into the full expression (e.g. tmp+c), and return the inner expression.

NOTE: This mutates the operation in place if it only has a single user, which assumes that user will be removed.

Definition at line 2370 of file CombFolds.cpp.

References assert(), createGenericOp(), and circt::replaceOpAndCopyNamehint().

◆ foldCommonMuxOperation()

bool foldCommonMuxOperation ( MuxOp mux,
Operation * trueOp,
Operation * falseOp,
PatternRewriter & rewriter )
static

Fold things like mux(cond, x|y|z|a, a) -> (x|y|z)&replicate(cond)|a and mux(cond, a, x|y|z|a) -> (x|y|z)&replicate(~cond) | a` (when isTrueOperand is true.

Return true on successful transformation, false if not.

These are various forms of "predicated ops" that can be handled with a replicate/and combination. */ static bool foldCommonMuxValue(MuxOp op, bool isTrueOperand, PatternRewriter &rewriter) { Check to see the operand in question is an operation. If it is a port, we can't simplify it. Operation *subExpr = (isTrueOperand ? op.getFalseValue() : op.getTrueValue()).getDefiningOp(); if (!subExpr || subExpr->getNumOperands() < 2) return false;

If this isn't an operation we can handle, don't spend energy on it. if (!isa<AndOp, XorOp, OrOp, MuxOp>(subExpr)) return false;

Check to see if the common value occurs in the operand list for the subexpression op. If so, then we can simplify it. Value commonValue = isTrueOperand ? op.getTrueValue() : op.getFalseValue(); size_t opNo = 0, e = subExpr->getNumOperands(); while (opNo != e && subExpr->getOperand(opNo) != commonValue) ++opNo; if (opNo == e) return false;

If we got a hit, then go ahead and simplify it! Value cond = op.getCond();

mux(cond, a, mux(cond2, a, b)) -> mux(cond|cond2, a, b) mux(cond, a, mux(cond2, b, a)) -> mux(cond|~cond2, a, b) mux(cond, mux(cond2, a, b), a) -> mux(~cond|cond2, a, b) mux(cond, mux(cond2, b, a), a) -> mux(~cond|~cond2, a, b) if (auto subMux = dyn_cast<MuxOp>(subExpr)) { if (subMux == op) return false;

Value otherValue; Value subCond = subMux.getCond();

Invert th subCond if needed and dig out the 'b' value. if (subMux.getTrueValue() == commonValue) otherValue = subMux.getFalseValue(); else if (subMux.getFalseValue() == commonValue) { otherValue = subMux.getTrueValue(); subCond = createOrFoldNot(rewriter, op.getLoc(), subCond); } else { We can't fold mux(cond, a, mux(a, x, y)). return false; }

Invert the outer cond if needed, and combine the mux conditions. if (!isTrueOperand) cond = createOrFoldNot(rewriter, op.getLoc(), cond); cond = rewriter.createOrFold<OrOp>(op.getLoc(), cond, subCond, false); replaceOpWithNewOpAndCopyNamehint<MuxOp>(rewriter, op, cond, commonValue, otherValue, op.getTwoState()); return true; }

Invert the condition if needed. Or/Xor invert when dealing with TrueOperand, And inverts for False operand. bool isaAndOp = isa<AndOp>(subExpr); if (isTrueOperand ^ isaAndOp) cond = createOrFoldNot(rewriter, op.getLoc(), cond);

auto extendedCond = rewriter.createOrFold<ReplicateOp>(op.getLoc(), op.getType(), cond);

Cache this information before subExpr is erased by extraction below. bool isaXorOp = isa<XorOp>(subExpr); bool isaOrOp = isa<OrOp>(subExpr);

Handle the fully associative ops, start by pulling out the subexpression from a many operand version of the op. auto restOfAssoc = extractOperandFromFullyAssociative(subExpr, opNo, rewriter);

mux(cond, x|y|z|a, a) -> (x|y|z)&replicate(cond) | a mux(cond, x^y^z^a, a) -> (x^y^z)&replicate(cond) ^ a if (isaOrOp || isaXorOp) { auto masked = rewriter.createOrFold<AndOp>(op.getLoc(), extendedCond, restOfAssoc, false); if (isaXorOp) replaceOpWithNewOpAndCopyNamehint<XorOp>(rewriter, op, masked, commonValue, false); else replaceOpWithNewOpAndCopyNamehint<OrOp>(rewriter, op, masked, commonValue, false); return true; }

mux(cond, a, x&y&z&a) -> ((x&y&z)|replicate(cond)) & a assert(isaAndOp && "unexpected operation here"); auto masked = rewriter.createOrFold<OrOp>(op.getLoc(), extendedCond, restOfAssoc, false); replaceOpWithNewOpAndCopyNamehint<AndOp>(rewriter, op, masked, commonValue, false); return true; }

/** This function is invoke when we find a mux with true/false operations that have the same opcode. Check to see if we can strength reduce the mux by applying it to less data by applying this transformation: mux(cond, op(a, b), op(a, c)) -> op(a, mux(cond, b, c))

Definition at line 2516 of file CombFolds.cpp.

References getConcatOperands(), circt::replaceOpAndCopyNamehint(), and circt::replaceOpWithNewOpAndCopyNamehint().

◆ foldDiv()

template<class Op, bool isSigned>
OpFoldResult foldDiv ( Op op,
ArrayRef< Attribute > constants )
static

Definition at line 1836 of file CombFolds.cpp.

References constFoldBinaryOp().

◆ foldMod()

template<class Op, bool isSigned>
OpFoldResult foldMod ( Op op,
ArrayRef< Attribute > constants )
static

Definition at line 1863 of file CombFolds.cpp.

References constFoldBinaryOp(), and getIntAttr().

◆ foldMuxOfUniformArrays()

bool foldMuxOfUniformArrays ( MuxOp op,
PatternRewriter & rewriter )
static

Definition at line 2611 of file CombFolds.cpp.

◆ getCommonOperand()

template<typename Op>
Value getCommonOperand ( Op op)
static

Returns a single common operand that all inputs of the operation op can be traced back to, or an empty Value if no such operand exists.

For example for or(a[0], a[1], ..., a[n-1]) this function returns a (assuming the bit-width of a is n).

Definition at line 988 of file CombFolds.cpp.

◆ getConcatOperands()

void getConcatOperands ( Value v,
SmallVectorImpl< Value > & result )
static

Flatten concat and mux operands into a vector.

Definition at line 54 of file CombFolds.cpp.

References concat(), and getConcatOperands().

Referenced by foldCommonMuxOperation(), getConcatOperands(), and matchAndRewriteCompareConcat().

◆ getIntAttr()

TypedAttr getIntAttr ( const APInt & value,
MLIRContext * context )
static

Definition at line 48 of file CombFolds.cpp.

References context.

◆ getLowestBitAndHighestBitRequired()

std::pair< size_t, size_t > getLowestBitAndHighestBitRequired ( Operation * op,
bool narrowTrailingBits,
size_t originalOpWidth )
static

Definition at line 189 of file CombFolds.cpp.

References assert().

Referenced by narrowOperationWidth().

◆ getMuxChainCondConstant()

bool getMuxChainCondConstant ( Value cond,
Value indexValue,
bool isInverted,
std::function< void(hw::ConstantOp)> constantFn )
static

Check to see if the condition to the specified mux is an equality comparison indexValue and one or more constants.

If so, put the constants in the constants vector and return true, otherwise return false.

This is part of foldMuxChain.

Definition at line 2202 of file CombFolds.cpp.

References getMuxChainCondConstant().

Referenced by getMuxChainCondConstant().

◆ getTotalWidth()

size_t getTotalWidth ( ArrayRef< Value > operands)
static

Definition at line 3107 of file CombFolds.cpp.

References assert().

Referenced by matchAndRewriteCompareConcat().

◆ hasSVAttributes()

bool hasSVAttributes ( Operation * op)
static

Definition at line 69 of file CombFolds.cpp.

Referenced by findNestedElseIf().

◆ isOpTriviallyRecursive()

bool isOpTriviallyRecursive ( Operation * op)
static

Definition at line 29 of file CombFolds.cpp.

◆ m_Complement()

template<typename SubType>
ComplementMatcher< SubType > m_Complement ( const SubType & subExpr)
inlinestatic

Definition at line 87 of file CombFolds.cpp.

◆ matchAndRewriteCompareConcat()

LogicalResult matchAndRewriteCompareConcat ( ICmpOp op,
Operation * lhs,
Operation * rhs,
PatternRewriter & rewriter )
static

Reduce the strength icmp(concat(...), concat(...)) by doing a element-wise comparison on common prefix and suffixes.

Returns success() if a rewriting happens. This handles both concat and replicate.

Definition at line 3122 of file CombFolds.cpp.

References applyCmpPredicateToEqualOperands(), assert(), computeCommonPrefixLength(), failure(), getConcatOperands(), getTotalWidth(), circt::replaceOpWithNewOpAndCopyNamehint(), and success().

◆ narrowOperationWidth() [1/2]

template<class OpTy>
bool narrowOperationWidth ( OpTy op,
bool narrowTrailingBits,
PatternRewriter & rewriter )
static

Definition at line 266 of file CombFolds.cpp.

References getLowestBitAndHighestBitRequired(), and narrowOperationWidth().

◆ narrowOperationWidth() [2/2]

template<class OpTy>
bool narrowOperationWidth ( OpTy op,
size_t lowestBit,
size_t highestBit,
PatternRewriter & rewriter )
static

Definition at line 220 of file CombFolds.cpp.

References hw.ConstantOp::create().

Referenced by narrowOperationWidth().

◆ shouldBeFlattened()

bool shouldBeFlattened ( Operation * op)
static

Return true if the op will be flattened afterwards.

Op will be flattend if it has a single user which has a same op type. User must be in same block.

Definition at line 93 of file CombFolds.cpp.

References assert().

Referenced by tryFlatteningOperands().

◆ subLowBitsCannotBorrow()

bool subLowBitsCannotBorrow ( Value lhs,
Value rhs,
unsigned numBits )
static

Returns true if subtracting the low numBits bits of rhs from those of lhs can never borrow from bit numBits: the smallest possible value of lhs's low bits must be at least the largest possible value of rhs's.

Definition at line 1576 of file CombFolds.cpp.

References circt::comb::computeKnownBits().

◆ tryFlatteningOperands()

bool tryFlatteningOperands ( Operation * op,
PatternRewriter & rewriter )
static

Flattens a single input in op if hasOneUse is true and it can be defined as an Op.

Returns true if successful, and false otherwise.

Example: op(1, 2, op(3, 4), 5) -> op(1, 2, 3, 4, 5) // returns true

Definition at line 111 of file CombFolds.cpp.

References createGenericOp(), circt::replaceOpAndCopyNamehint(), and shouldBeFlattened().