-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[InstCombine][Docs] Update InstCombine contributor guide #144228
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -404,11 +404,32 @@ The use of TargetTransformInfo is only allowed for hooks for target-specific | |
| intrinsics, such as `TargetTransformInfo::instCombineIntrinsic()`. These are | ||
| already inherently target-dependent anyway. | ||
|
|
||
| If some canonicalization narrow/widen the integer width of expressions, please | ||
| check `shouldChangeType()` first. Otherwise, we may evaluate the expression | ||
| in illegal/inefficient types. For vector types, follow the instructions below. | ||
|
|
||
| For vector-specific transforms that require cost-modelling, the VectorCombine | ||
| pass can be used instead. In very rare circumstances, if there are no other | ||
| alternatives, target-dependent transforms may be accepted into | ||
| AggressiveInstCombine. | ||
|
|
||
| Generally, we prefer unsigned operations over signed operations in the middle-end, even | ||
| if signed operations are more efficient on some targets. The following is an incomplete | ||
| list of canonicalizations that implemented in InstCombine: | ||
dtcxzyw marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| | Original Pattern | Canonical Form | Condition | | ||
| |------------------------------|----------------------------|-------------------------------| | ||
| | `icmp spred X, Y` | `icmp samesign upred X, Y` | `sign(X) == sign(Y)` | | ||
| | `smin/smax X, Y` | `umin/umax X, Y` | `sign(X) == sign(Y)` | | ||
| | `sext X` | `zext nneg X` | `X >=s 0` | | ||
| | `sitofp X` | `uitofp nneg X` | `X >=s 0` | | ||
| | `ashr X, Y` | `lshr X, Y` | `X >=s 0` | | ||
| | `sdiv/srem X, Y` | `udiv/urem X, Y` | `X >=s 0 && Y >=s 0` | | ||
| | `add X, Y` | `or disjoint X, Y` | `(X & Y) != 0` | | ||
| | `mul X, C` | `shl X, Log2(C)` | `isPowerOf2(C)` | | ||
| | `select Cond1, Cond2, false` | `and Cond1, Cond2` | `impliesPoison(Cond2, Cond1)` | | ||
| | `select Cond1, true, Cond2` | `or Cond1, Cond2` | `impliesPoison(Cond2, Cond1)` | | ||
|
|
||
| ### PatternMatch | ||
|
|
||
| Many transforms make use of the matching infrastructure defined in | ||
|
|
@@ -531,6 +552,19 @@ need to add a one-use check for the inner instruction. | |
| One-use checks can be performed using the `m_OneUse()` matcher, or the | ||
| `V->hasOneUse()` method. | ||
|
|
||
| ### Flag handling | ||
|
|
||
| When possible, propagate poison-generating flags like `nuw` and `nsw` since they may be | ||
| hard to salvage later. If it is not free (e.g. requires additional complexity like `willNotOverflow` | ||
| or KnownBits queries), don't do that. | ||
dtcxzyw marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Be careful with in-place operand/predicate changes, as poison-generating flags may not be valid for new | ||
| operands. It is recommended to create a new instruction with carefully handling of flags. If not | ||
dtcxzyw marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| applicable, call `Instruction::dropPoisonGeneratingFlags()` to clear flags in a conservative manner. | ||
|
|
||
| Do not rely on fcmp's `nsz` flag to perform optimizations. It is meaningless for fcmp so it should not affect | ||
| the optimization. | ||
|
Comment on lines
+565
to
+566
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is nsz meaningless for fcmp? I thought there are some optimizations already that take nsz on fcmp into account, with the property that -0. == +0.?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0.0 and -0.0 are considered equal, even if nsz is absent.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps I'm confused about something? See CmpInst::isEquivalence, which is used in some places: // Returns true if either operand of CmpInst is a provably non-zero
// floating-point constant.
static bool hasNonZeroFPOperands(const CmpInst *Cmp) {
auto *LHS = dyn_cast<Constant>(Cmp->getOperand(0));
auto *RHS = dyn_cast<Constant>(Cmp->getOperand(1));
if (auto *Const = LHS ? LHS : RHS) {
using namespace llvm::PatternMatch;
return match(Const, m_NonZeroNotDenormalFP());
}
return false;
}
// Floating-point equality is not an equivalence when comparing +0.0 with
// -0.0, when comparing NaN with another value, or when flushing
// denormals-to-zero.
bool CmpInst::isEquivalence(bool Invert) const {
switch (Invert ? getInversePredicate() : getPredicate()) {
case CmpInst::Predicate::ICMP_EQ:
return true;
case CmpInst::Predicate::FCMP_UEQ:
if (!hasNoNaNs())
return false;
[[fallthrough]];
case CmpInst::Predicate::FCMP_OEQ:
return hasNonZeroFPOperands(this);
default:
return false;
}
}
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @artagnon Note that this does not actually checks the nsz flag, it checks whether the operands are non-zero. That's fine. |
||
|
|
||
| ### Generalization | ||
|
|
||
| Transforms can both be too specific (only handling some odd subset of patterns, | ||
|
|
@@ -558,6 +592,11 @@ guidelines. | |
| use of ValueTracking queries. Whether this makes sense depends on the case, | ||
| but it's usually a good idea to only handle the constant pattern first, and | ||
| then generalize later if it seems useful. | ||
| * When possible, handle more canonical patterns as well. It is encouraged to avoid | ||
| potential phase-ordering issues. For example, if the motivating transform holds for | ||
| `add`, it also holds for `or disjoint`. See the canonicalization list above for details. | ||
| In most cases, it can be easily implemented with matchers like | ||
| `m_AddLike/m_SExtLike/m_LogicalAnd/m_LogicalOr`. | ||
|
|
||
| ## Guidelines for reviewers | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.