Commit Graph

807 Commits

Author SHA1 Message Date
Nikita Popov d222bab672 [InstCombine] Handle GEP scalar/vector base mismatch (PR55363)
30a12f3f63 switched the type check
to use the GEP result type rather than the GEP operand type.
However, the GEP result types may match even if the operand types
don't, in case GEPs with scalar/vector base and vector index
are compared.

Fixes https://github.com/llvm/llvm-project/issues/55363.
2022-05-10 11:26:43 +02:00
Nikita Popov 82190f917a [InstCombine] Fold icmp of select with implied condition
When threading the icmp over the select, check whether the
condition can be folded when taking into account the select
condition.
2022-05-06 17:13:32 +02:00
Nikita Popov 0863abe3ac [InstCombine] Fold icmp of select with non-constant operand
Try to push an icmp into a select even if the icmp operand isn't
constant - perform a generic SimplifyICmpInst instead.

This doesn't appear to impact compile-time much, and forming
logical and/or is generally profitable, as we have very good
support for them.
2022-05-06 16:04:39 +02:00
Nikita Popov b457ac4240 [InstCombine] Extract icmp of select transform (NFC)
To make it either to extend to the case where the other operand
is not a constant.
2022-05-06 14:46:44 +02:00
Nikita Popov 95fedfab6c [InstCombine] Handle non-canonical GEP index in indexed compare fold (PR55228)
Normally the index type will already be canonicalized here, but
this is not guaranteed depending on visitation order. The code
was already accounting for a potentially needed sext, but a trunc
may also be needed.

Add a ConstantExpr::getSExtOrTrunc() helper method to make this
simpler. This matches the corresponding IRBuilder method in behavior.

Fixes https://github.com/llvm/llvm-project/issues/55228.
2022-05-02 17:56:01 +02:00
Sanjay Patel 903aa5e0f8 [InstCombine] try to fold icmp with mismatched extended operands
If a value is known to be non-negative and zexted,
that's the same thing as sexted.

So for the purpose of looking past the casts with
an icmp, treat it as if it was a sext:
https://alive2.llvm.org/ce/z/_BDsGV

This is necessary, but not enough to solve the
motivating problem:
https://github.com/llvm/llvm-project/issues/55013

Differential Revision: https://reviews.llvm.org/D124419
2022-04-26 14:26:36 -04:00
Nikita Popov 2bec8d6d59 [InstCombine] Fold X + Y + C u< X
This is a variation on the X + Y u< X fold with an extra constant.
Proof: https://alive2.llvm.org/ce/z/VNb8pY
2022-04-25 12:53:39 +02:00
Alexander Shaposhnikov 6cf10b7e6e [InstCombine] Fold srem(X, PowerOf2) == C into (X & Mask) == C for positive C
This diff extends InstCombinerImpl::foldICmpSRemConstant to handle the cases
srem(X, PowerOf2) == C and
srem(X, PowerOf2) != C
for positive C.
This addresses the issue https://github.com/llvm/llvm-project/issues/54650

Differential revision: https://reviews.llvm.org/D122942

Test plan: make check-all
2022-04-03 03:57:05 +00:00
Sanjay Patel 5f8c2b884d [InstCombine] limit icmp fold with sub if other sub user is a phi
This is a hacky fix for:
https://github.com/llvm/llvm-project/issues/54558

As discussed there, codegen regressed when we opened up this transform
to allow extra uses ( 61580d0949 ), and it's not clear how to
undo the transforms at the later stage of compilation.

As noted in the code comments, there's a set of remaining folds that
are still limited to one-use, so we can try harder to refine and
expand the limitations on these folds, but it's likely to be an
up-and-down battle as we find and overcome similar regressions.

Differential Revision: https://reviews.llvm.org/D122909
2022-04-02 19:23:42 -04:00
Sanjay Patel 97ac0cd6c4 [InstCombine] fold fcmp with lossy casted constant (2nd try)
This is a retry of 9397bdc67e - that was reverted until
we had a clang warning in place to alert users about a
possible mistake in source. The warning was added with
ab982eace6.

This is noted as a missing clang warning in #54222,
but it is also a missing optimization opportunity.

Alive2 proofs:
https://alive2.llvm.org/ce/z/Q8drDq
https://alive2.llvm.org/ce/z/pE6LRt

I don't see a single conversion for all predicates
using "getFCmpCode" logic, so other predicates are
left as a TODO item.
2022-04-02 19:23:01 -04:00
Simon Pilgrim 7e4cf582cf [InstCombine] Add general constant support to eq/ne icmp(add(X,C1),add(Y,C2)) -> icmp(add(X,C1-C2),Y) fold
A further extension for Issue #32161

For eq/ne comparisons - the sign mismatch and bounds constraints are redundant, so if the that fold fails, fallback and just fold the constants directly.

https://alive2.llvm.org/ce/z/cdodNQ

The loop rotation test change looks mostly benign - the backend doesn't seem to suffer? https://gcc.godbolt.org/z/dErMY78To

Differential Revision: https://reviews.llvm.org/D121551
2022-03-15 14:17:38 +00:00
Sanjay Patel 3491f2f4b0 [InstCombine] replace negated operand in fcmp with 0.0
X (any pred) -X --> X (any pred) 0.0

This works with all FP values and preserves FMF.
Alive2 examples:
https://alive2.llvm.org/ce/z/dj6jhp

This can also create one of the patterns that we match as "fabs"
as shown in one of the test diffs.
2022-03-10 12:53:32 -05:00
Sanjay Patel 9fac110bf7 Revert "[InstCombine] fold fcmp with lossy casted constant"
This reverts commit 9397bdc67e.

This optimization is likely to surprise programmers as seen
in post-commit comments, so we should add a clang warning
first (that is proposed in D121306).
2022-03-10 10:22:22 -05:00
Simon Pilgrim 808d9d260b [InstCombine] Add vector support to icmp(add(X,C1),add(Y,C2)) -> icmp(add(X,C1-C2),Y) fold
As discussed on Issue #32161 this fold can be generalized a lot more than it currently is, but this patch at least adds vector support.

Differential Revision: https://reviews.llvm.org/D121358
2022-03-10 13:30:48 +00:00
Sanjay Patel 9397bdc67e [InstCombine] fold fcmp with lossy casted constant
This is noted as a missing clang warning in #54222
(and we should still make that enhancement).

Alive2 proofs:
https://alive2.llvm.org/ce/z/Q8drDq
https://alive2.llvm.org/ce/z/pE6LRt

I don't see a single conversion for all predicates
using "getFCmpCode" logic, so other predicates are
left as a TODO item.
2022-03-08 12:41:12 -05:00
serge-sans-paille 59630917d6 Cleanup includes: Transform/Scalar
Estimated impact on preprocessor output line:
before: 1062981579
after:  1062494547

Discourse thread: https://discourse.llvm.org/t/include-what-you-use-include-cleanup
Differential Revision: https://reviews.llvm.org/D120817
2022-03-03 07:56:34 +01:00
Nikita Popov 61580d0949 Reapply [InstCombine] Remove one-use limitation from X-Y==0 fold
This is a recommit without changes. I originally reverted this
due to a significant code-size regression on tramp3d-v4, however
further investigation showed that in the tramp3d-v4 case this
change enables additional optimizations (in particular more
jump threading), which happens to reduce the size of a function
just enough to be eligible for inlining at hot callsites, which
results in the code size increase. As such, this was just bad
luck.

-----

This one-use limitation is artificial, we do not increase
instruction count if we perform the fold with multiple uses. The
motivating case is shown in @sub_eq_zero_select, where the one-use
limitation causes us to miss a subsequent select fold.

I believe the backend is pretty good about reusing flag-producing
subs for cmps with same operands, so I think doing this is fine.

Differential Revision: https://reviews.llvm.org/D120337
2022-03-02 16:43:33 +01:00
Nikita Popov aa551ad198 Revert "[InstCombine] Remove one-use limitation from X-Y==0 fold"
This reverts commit 65dc78d63e.

This caused a major code-size regression on tramp3d-v4, revert
until I can investigate.
2022-02-24 08:50:40 +01:00
Nikita Popov 65dc78d63e [InstCombine] Remove one-use limitation from X-Y==0 fold
This one-use limitation is artificial, we do not increase
instruction count if we perform the fold with multiple uses. The
motivating case is shown in @sub_eq_zero_select, where the one-use
limitation causes us to miss a subsequent select fold.

I believe the backend is pretty good about reusing flag-producing
subs for cmps with same operands, so I think doing this is fine.

Differential Revision: https://reviews.llvm.org/D120337
2022-02-23 09:37:30 +01:00
Philip Reames 6f9d557e08 [instcombine] Cleanup foldAllocaCmp slightly [NFC] 2022-02-18 18:49:39 -08:00
Nikita Popov e714b98fff [InstCombine] Check type compatibility in indexed load fold
This fold could use a rewrite to an offset-based implementation,
but for now make sure it doesn't crash with opaque pointers.
2022-02-11 10:16:27 +01:00
Nikita Popov 3571bdb4f3 [InstCombine] Require equal source element type in icmp of gep fold
Without opaque pointers, this is implicitly enforced. This previously
resulted in a miscompile.
2022-02-11 09:38:28 +01:00
Simon Pilgrim aca355a3bb [InstCombine] Extend fold (icmp sgt smin(PosA, B) 0) -> (icmp sgt B 0) to support smin intrinsic
Replace matchSelectPattern pattern match with the more general m_SMin so that it can handle smin intrinsics as well as the icmp+select pattern

Noticed while reviewing regressions from D98152
2022-02-10 13:28:15 +00:00
Max Kazantsev 70b3beb0e2 [InstCombine] Generalize and-reduce pattern to handle `ne` case as well as `eq`
Following Sanjay's proposal from discussion in D118317, this patch
generalizes and-reduce handling to fold the following pattern
```
  icmp ne (bitcast(icmp ne (lhs, rhs)), 0)
```
into
```
  icmp ne (bitcast(lhs), bitcast(rhs))
```

https://alive2.llvm.org/ce/z/WDcuJ_

Differential Revision: https://reviews.llvm.org/D118431
Reviewed By: lebedev.ri
2022-01-31 12:14:08 +07:00
Max Kazantsev 3b194ca7ab Recommit "[InstCombine] Fold and-reduce idiom"
Checks of original vector types made more thorough.

Differential Revision: https://reviews.llvm.org/D118317
2022-01-29 11:27:48 +07:00
Hans Wennborg fabaca10b8 Revert "[InstCombine] Fold and-reduce idiom"
It causes builds to fail with

llvm/include/llvm/Support/Casting.h:269:
typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*)
[with X = llvm::IntegerType; Y = const llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = const llvm::IntegerType*]:
Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.

See the code review for link to a reproducer.

> This patch introduces folding of and-reduce idiom and generates code
> that is easier to read and which is lest costly in terms of icmp operations.
> The folding is
> ```
>   icmp eq (bitcast(icmp ne (lhs, rhs)), 0)
> ```
> into
> ```
>   icmp eq(bitcast(lhs), bitcast(rhs))
> ```
>
> See PR53419.
>
> Differential Revision: https://reviews.llvm.org/D118317
> Reviewed By: lebedev.ri, spatel

This reverts commit 8599bb0f26.

This also revertes the dependent change:

"[Test] Add 'ne' tests for and-reduce pattern folding"

This reverts commit a4aaa59953.
2022-01-28 12:16:03 +01:00
Max Kazantsev 8599bb0f26 [InstCombine] Fold and-reduce idiom
This patch introduces folding of and-reduce idiom and generates code
that is easier to read and which is lest costly in terms of icmp operations.
The folding is
```
  icmp eq (bitcast(icmp ne (lhs, rhs)), 0)
```
into
```
  icmp eq(bitcast(lhs), bitcast(rhs))
```

See PR53419.

Differential Revision: https://reviews.llvm.org/D118317
Reviewed By: lebedev.ri, spatel
2022-01-28 11:20:08 +07:00
Nadav Rotem 191a6e9dfa optimize icmp-ugt-ashr
This diff optimizes the sequence icmp-ugt(ashr,C_1) C_2. InstCombine
already implements this optimization for sgt, and this patch adds
support ugt. This patch adds the check for UGT.

@craig.topper came up with the idea and proof:

  define i1 @src(i8 %x, i8 %y, i8 %c) {
    %cp1 = add i8 %c, 1
    %i = shl i8 %cp1, %y
    %i.2 = ashr i8 %i, %y
    %cmp = icmp eq i8 %cp1, %i.2
    ;Assume: C + 1 == (((C + 1) << y) >> y)
    call void @llvm.assume(i1 %cmp)

    ; uncomment for the sgt case
    %j = shl i8 %cp1, %y
    %j.2 = sub i8 %j, 1
    %cmp2 = icmp ne i8 %j.2, 127
    ;Assume (((c + 1 ) << y) - 1) != 127
    call void @llvm.assume(i1 %cmp2)

    %s = ashr i8 %x, %y
    %r = icmp sgt i8 %s, %c
    ret i1 %r
  }

  define i1 @tgt(i8 %x, i8 %y, i8 %c) {
    %cp1 = add i8 %c, 1
    %j = shl i8 %cp1, %y
    %j.2 = sub i8 %j, 1

    %r = icmp sgt i8 %x, %j.2
    ret i1 %r
  }

  declare void @llvm.assume(i1)

  This change is related to the optimizations in D117252.

  Differential Revision: https://reviews.llvm.org/D117365
2022-01-20 09:31:46 -08:00
Nadav Rotem 9551fc57b7 Fold ashr-exact into a icmp-ugt.
This commit optimizes the code sequence:
  icmp-XXX (ashr-exact (X, C_1), C_2).

Instcombine already implements this optimization for sgt, and this
patch adds support to additional predicates. The transformation is legal
for all predicates if the 'exact' flag is set, and to SGE, UGE, SLT, ULT
when the exact flag is not present.

This pattern is found in the std::vector bounds checks code of the at()
method.

Alive2 proof:
https://alive2.llvm.org/ce/z/JT_WL8

Differential Revision: https://reviews.llvm.org/D117252
2022-01-14 12:58:44 -08:00
Sanjay Patel 02455bea6b [InstCombine] remove unnecessary use check on X >>exact == 0 fold
The transform replaces one icmp with another, so we should
not care if the shift has another use.
2022-01-14 12:52:16 -05:00
Craig Topper cbcbbd6ac8 [ValueTracking][SelectionDAG] Rename ComputeMinSignedBits->ComputeMaxSignificantBits. NFC
This function returns an upper bound on the number of bits needed
to represent the signed value. Use "Max" to match similar functions
in KnownBits like countMaxActiveBits.

Rename APInt::getMinSignedBits->getSignificantBits. Keeping the old
name around to keep this patch size down. Will do a bulk rename as
follow up.

Rename KnownBits::countMaxSignedBits->countMaxSignificantBits.

Reviewed By: lebedev.ri, RKSimon, spatel

Differential Revision: https://reviews.llvm.org/D116522
2022-01-03 11:33:30 -08:00
Sanjay Patel 6c716c8589 [InstCombine] add more folds for unsigned overflow checks
((Op1 + C) & C) u<  Op1 --> Op1 != 0
 ((Op1 + C) & C) u>= Op1 --> Op1 == 0
 Op0 u>  ((Op0 + C) & C) --> Op0 != 0
 Op0 u<= ((Op0 + C) & C) --> Op0 == 0

https://alive2.llvm.org/ce/z/iUfXJN
https://alive2.llvm.org/ce/z/caAtjj

  define i1 @src(i8 %x, i8 %y) {
    ; the add/mask must be with a low-bit mask (0x01ff...)
    %y1 = add i8 %y, 1
    %pop = call i8 @llvm.ctpop.i8(i8 %y1)
    %ismask = icmp eq i8 %pop, 1
    call void @llvm.assume(i1 %ismask)

    %a = add i8 %x, %y
    %m = and i8 %a, %y
    %r = icmp ult i8 %m, %x
    ret i1 %r
  }

  define i1 @tgt(i8 %x, i8 %y) {
    %r = icmp ne i8 %x, 0
    ret i1 %r
  }

I suspect this can be generalized in some way, but this
is the pattern I'm seeing in a motivating test based on
issue #52851.
2021-12-29 15:53:56 -05:00
Nikita Popov 7d850a0c4d [InstCombine] Make indexed compare fold opaque ptr compatible
We need to make sure that the GEP source element types match.

A caveat here is that the used GEP source element type can be
arbitrary if no offset is stripped from the original GEP -- the
transform is somewhat inconsistent in that it always starts from
a GEP, but might not actually look through it if it has multiple
indices.
2021-12-28 11:47:20 +01:00
Nikita Popov 30a12f3f63 [InstCombine] Fix GEP with same index comparison with opaque pointers
We need to also check that the source element type is the same,
otherwise the indices may have different meaning. The added
addrspacecast demonstrates that we do still need to check the
pointer type.
2021-12-28 09:23:28 +01:00
Sanjay Patel f55d1eb374 [InstCombine] use decomposeBitTestICmp to make icmp (trunc X), C more consistent
This is a follow-on suggested in D112634.
Two folds that were added with that patch are subsumed in the call to
decomposeBitTestICmp, and two other folds are potentially inverted.

The deleted folds were very specialized by instcombine standards
because they were restricted to legal integer types based on the data
layout. This generalizes the canonical form independent of target/types.

This change has a reasonable chance of exposing regressions either in
IR or codegen, but I don't have any evidence for either of those yet.
A spot check of asm across several in-tree targets shows variations
that I expect are mostly neutral.

We have one improvement in an existing IR test that I noted with a
comment. Using mask ops might also make more code match with D114272.

Differential Revision: https://reviews.llvm.org/D114386
2021-11-28 09:59:37 -05:00
Zarko Todorovski 0d3add216f [llvm][NFC] Inclusive language: Reword replace uses of sanity in llvm/lib/Transform comments and asserts
Reworded some comments and asserts to avoid usage of `sanity check/test`

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D114372
2021-11-23 13:22:55 -05:00
Sanjay Patel 8fce94f916 [InstCombine] canonicalize icmp with trunc op into mask and cmp, part 2
If C is a high-bit mask:
(trunc X) u< C --> (X & C) != C (are any masked-high-bits clear?)

If C is low-bit mask:
(trunc X) u> C --> (X & ~C) != 0 (are any masked-high-bits set?)

If C is not-of-power-of-2 (one clear bit):
(trunc X) u> C --> (X & (C+1)) == C+1 (are all masked-high-bits set?)

This extends the fold added with:
acabad9ff6 (https://alive2.llvm.org/ce/z/aFr7qV)

Using decomposeBitTestICmp() to generalize this is a planned follow-up, but that requires removing an inverse fold.

Here are Alive2 generalizations for these folds:
https://alive2.llvm.org/ce/z/u-ZpC_ (ult, the previous patch)
https://alive2.llvm.org/ce/z/YsuAu2 (ult, this patch)
https://alive2.llvm.org/ce/z/ekktQP (ugt, low bitmask)
https://alive2.llvm.org/ce/z/pJY9wR (ugt, one clear bit)

Differential Revision: https://reviews.llvm.org/D112634
2021-11-16 09:27:30 -05:00
Nikita Popov 1376301c87 [InstCombine] Canonicalize range test idiom
InstCombine converts range tests of the form (X > C1 && X < C2) or
(X < C1 || X > C2) into checks of the form (X + C3 < C4) or
(X + C3 > C4). It is possible to express all range tests in either
of these forms (with different choices of constants), but currently
neither of them is considered canonical. We may have equivalent
range tests using either ult or ugt.

This proposes to canonicalize all range tests to use ult. An
alternative would be to canonicalize to either ult or ugt depending
on the specific constants involved -- e.g. in practice we currently
generate ult for && style ranges and ugt for || style ranges when
going through the insertRangeTest() helper. In fact, the "clamp like"
fold was relying on this, which is why I had to tweak it to not
assume whether inversion is needed based on just the predicate.

Proof: https://alive2.llvm.org/ce/z/_SP_rQ

Differential Revision: https://reviews.llvm.org/D113366
2021-11-08 21:15:46 +01:00
David Green 61225c0818 [ValueTracking][InstCombine] Introduce and use ComputeMinSignedBits
This introduces a new ComputeMinSignedBits method for ValueTracking that
returns the BitWidth - SignBits + 1 from ComputeSignBits, and represents
the minimum bit size for the value as a signed integer.  Similar to the
existing APInt::getMinSignedBits method, this can make some of the
reasoning around ComputeSignBits more natural.

See https://reviews.llvm.org/D112298
2021-11-05 14:41:37 +00:00
Sanjay Patel c85df3c7d5 [InstCombine] refactor fold for icmp with trunc op; NFC
There are at least 3 related folds we can add here - see D112634.
2021-11-03 12:43:15 -04:00
Kazu Hirata c714da2ceb [Transforms] Use {DenseSet,SetVector,SmallPtrSet}::contains (NFC) 2021-10-31 07:57:32 -07:00
David Green 11630dbbc3 [InstCombine] Fold BW/2+1 tops bits are same pattern
Match "icmp eq (trunc (lsr A, BW), (ashr (trunc A), BW-1))", which checks
the top BW/2 + 1 bits are all the same. Create "A >=s INT_MIN && A <=s
INT_MAX", which we generate as "icmp ult (add A, 2^BW-1), 2^BW" to skip
a few steps of instcombining.
https://alive2.llvm.org/ce/z/NjH6Ty
https://alive2.llvm.org/ce/z/_fEQ9P

Differential Revision: https://reviews.llvm.org/D109155
2021-10-29 12:30:20 +01:00
Sanjay Patel acabad9ff6 [InstCombine] try to canonicalize icmp with trunc op into mask and cmp
The motivating test is based on:
https://llvm.org/PR52260

We have better analysis for X == 0, so try harder to form that.
2021-10-26 17:43:28 -04:00
Philip Reames 3c06ecaa1e [instcombine] Fix oss-fuzz 39934 (mul matcher can match non-instruction)
Fixes a crash observed by oss-fuzz in 39934.  Issue at hand is that code expects a pattern match on m_Mul to imply the operand is a mul instruction, however mul constexprs are also valid here.
2021-10-24 14:42:03 -07:00
Simon Pilgrim 71e39e3f18 [ADT] Add APInt::isNegatedPowerOf2() helper
Inspired by D111968, provide a isNegatedPowerOf2() wrapper instead of obfuscating code with (-Value).isPowerOf2() patterns, which I'm sure are likely avenues for typos.....

Differential Revision: https://reviews.llvm.org/D111998
2021-10-19 14:38:21 +01:00
Sanjay Patel 02928fcb8c [InstCombine] improve code comments; NFC 2021-10-13 10:40:44 -04:00
Sanjay Patel 59441c7329 [InstCombine] fold signbit check of X | (X -1)
There may be some other patterns like this or a generalization,
but this is an example that I noticed would definitely regress
with a planned follow-up to D111410.

https://alive2.llvm.org/ce/z/GVpQDb
2021-10-11 16:14:13 -04:00
Sanjay Patel 05281d95f2 [InstCombine] move fold for "(X-Y) == 0"; NFC
This consolidates related folds that all have a
similar use restriction that may not be necessary.
2021-10-10 11:26:03 -04:00
Sanjay Patel da210f5d34 [InstCombine] canonicalize "(C2 - Y) > C" as (Y + ~C2) < ~C
The test diffs show that we have better analysis/folds for 'add'
(although we should at least have the simplifications
independently, so we don't have the one-use restriction).

This is related to solving regressions that would appear in
transforms related to D111410, and that is part of a series
of enhancements that may eventually helpi solve PR34047.

https://alive2.llvm.org/ce/z/3tB9KG

  define i1 @src(i8 %x, i8 %C, i8 %C2) {
    %sub = sub nuw i8 %C2, %x
    %r = icmp slt i8 %sub, %C
    ret i1 %r
  }

  define i1 @tgt(i8 %x, i8 %C, i8 %C2) {
    %Cnot = xor i8 %C, -1
    %C2not = xor i8 %C2, -1
    %add = add nuw i8 %x, %C2not
    %r = icmp sgt i8 %add, %Cnot
    ret i1 %r
  }
2021-10-10 11:06:49 -04:00
Sanjay Patel acafde09a3 [InstCombine] enhance icmp with sub folds
There were 2 related but over-specified folds for:
C1 - X == C

One allowed multi-use but was limited to equal constants.
The other allowed different constants but disallowed multi-use.

This combines the 2 folds into a more general match.
The test diffs show the multi-use cases that were falling
through the cracks.

https://alive2.llvm.org/ce/z/4_hEt2

  define i1 @src(i8 %x, i8 %subC, i8 %C) {
    %s = sub i8 %subC, %x
    %r = icmp eq i8 %s, %C
    ret i1 %r
  }

  define i1 @tgt(i8 %x, i8 %subC, i8 %C) {
    %newC = sub i8 %subC, %C
    %isneg = icmp eq i8 %x, %newC
    ret i1 %isneg
  }
2021-10-09 11:39:49 -04:00