Summary
LLVM currently leaves optimized IR with an unsigned remainder result compared
back to its own dividend even when the same remainder also feeds
x - urem(x, C).
For unsigned positive constant C:
%rem = urem T %x, C
%rounded = sub nuw T %x, %rem
%cmp = icmp eq T %x, %rem
%cmp is equivalent to %rounded == 0. The ne form is equivalent to
%rounded != 0.
This is not a standalone urem deletion opportunity for the reviewed corpus
rows, because %rem remains needed by %rounded. The issue is a narrower
canonicalization / combined-transform opportunity: when %rounded already
exists, the branch condition can be expressed through that value instead of
comparing the dividend against the remainder.
Example
One representative corpus row in bench/faiss/optimized/test_cppcontrib_sa_decode.ll:
%478 = urem i64 %0, 3
%479 = sub nuw i64 %0, %478
%.not1067 = icmp eq i64 %0, %478
br i1 %.not1067, label %.loopexit, label %.preheader.lr.ph
The compare can be represented as:
%.not1067 = icmp eq i64 %479, 0
because %479 = %0 - (%0 % 3), so %479 is zero exactly when %0 < 3, which
is also exactly when %0 % 3 == %0.
The same relation applies to ne:
%cmp = icmp ne T %x, %rem
can be represented as:
%cmp = icmp ne T %rounded, 0
when %rounded = sub nuw T %x, %rem is already present.
Corpus Evidence
The source exploration scanned the full optimized corpus:
- 38,659 optimized
.ll files scanned;
- 38 raw target-relation rows;
- 8 files;
- 7 projects.
Review result:
- all 38 rows are shared-use rows;
- 0 rows are compare-only
urem deletion candidates;
- each reviewed row has the
urem result compared with the dividend and also
used in x - urem(x, C).
Distribution:
| Dimension |
Values |
| Projects |
faiss: 29, folly: 2, node: 2, opencv: 2, linux: 1, llvm: 1, mold: 1 |
| Divisors |
3: 34, 96: 2, 384: 1, 24: 1 |
| Predicates |
eq: 36, ne: 2 |
Representative rows:
| Source |
Shape |
bench/faiss/optimized/test_cppcontrib_sa_decode.ll:5186 |
%478 = urem i64 %0, 3; %479 = sub nuw i64 %0, %478; icmp eq i64 %0, %478 |
bench/folly/optimized/SpookyHashV1.ll:938 |
%220 = urem i64 %.0, 96; %.idx = sub nuw i64 %.0, %220; icmp eq i64 %.0, %220 |
bench/node/optimized/libnode.string_bytes.ll:2373 |
%0 = urem i64 %cond, 3; compare uses ne against %cond |
Expected Canonicalization
Initial scope:
%rem = urem T %x, C
%rounded = sub nuw T %x, %rem
%cmp = icmp eq T %x, %rem
to:
%cmp = icmp eq T %rounded, 0
and:
%cmp = icmp ne T %x, %rem
to:
%cmp = icmp ne T %rounded, 0
The transform should require that %rounded already exists or that creating it
is profitable for another use. It should not create a new sub solely to
rewrite the comparison.
Profitability Notes
A local POC separates two cases:
- compare-only
urem(x, C) vs x, where deleting urem would be clearly
profitable;
- shared-use corpus shape, where
urem remains live for x - urem(x, C).
The reviewed corpus evidence is the second case.
Local llvm-mca Measurements
Each row is measured as a separate function body with llvm-mca, 100
iterations.
Compare-only contrast, not corpus evidence:
| Target model |
Function |
Instructions / 100 iters |
Total cycles / 100 iters |
Total uOps / 100 iters |
Block RThroughput |
x86-64 x86-64 |
current urem i64 x, 3 + compare |
800 |
308 |
900 |
2.3 |
x86-64 x86-64 |
folded x < 3 compare |
300 |
104 |
300 |
1.0 |
AArch64 generic |
current urem i64 x, 3 + compare |
800 |
1202 |
800 |
2.7 |
AArch64 generic |
folded x < 3 compare |
300 |
201 |
300 |
1.0 |
RISC-V rocket-rv64 |
current urem i64 x, 3 + compare |
1200 |
11001 |
1300 |
13.0 |
RISC-V rocket-rv64 |
folded x < 3 compare |
200 |
201 |
200 |
2.0 |
Shared-use corpus shape:
| Target model |
Function |
Instructions / 100 iters |
Total cycles / 100 iters |
Total uOps / 100 iters |
Block RThroughput |
x86-64 x86-64 |
current shared-use form |
800 |
346 |
1000 |
2.5 |
x86-64 x86-64 |
compare canonicalized, urem still live |
800 |
343 |
1000 |
2.5 |
AArch64 generic |
current shared-use form |
800 |
1202 |
800 |
2.7 |
AArch64 generic |
compare canonicalized, urem still live |
800 |
1102 |
800 |
2.7 |
RISC-V rocket-rv64 |
current shared-use form |
1400 |
11201 |
1500 |
15.0 |
RISC-V rocket-rv64 |
compare canonicalized, urem still live |
1300 |
11101 |
1400 |
14.0 |
These measurements suggest the shared-use canonicalization is modest by itself,
but it exposes the existing rounded-down multiple and avoids expressing the
branch condition through the remainder value directly. It may be more valuable
as a canonical form for subsequent simplification or target lowering.
Legality Notes
For unsigned remainder by positive constant C, %rem = urem %x, C satisfies
0 <= %rem < C. Therefore:
and, when %rounded = %x - %rem:
%rounded == 0 <=> %x < C <=> %rem == %x
The sub nuw form seen in the corpus is consistent with %rem <= %x.
Initial guards:
urem divisor is a positive nonzero constant;
- compare is same-SSA dividend against the
urem result;
- predicate is
eq or ne;
%rounded = sub nuw %x, %rem already exists;
- do not introduce a new
%rounded solely for this rewrite unless a separate
profitability rule justifies it.
Scope Boundaries
This issue is not a request for:
- signed remainder (
srem);
- modulo-zero divisibility tests;
- variable divisors;
- deleting
urem when the remainder still has non-comparison uses;
- creating new
x - urem(x, C) expressions solely to rewrite a compare;
- LLVM patch authoring;
- LLVM test authoring.
Reproduction Data
Local source exploration packet:
optimization_attempts/attempts/2026-07-03-urem-result-dividend-compare-exploration/
Key artifacts:
2026-07-03-urem-result-dividend-compare-raw.jsonl
2026-07-03-urem-result-dividend-compare-summary.md
2026-07-03-urem-cost-poc.ll
2026-07-03-urem-cost-poc.md
2026-07-03-urem-cost-poc.x86_64.s
2026-07-03-urem-cost-poc.aarch64.s
2026-07-03-urem-cost-poc.riscv64.s
Local issue draft packet:
optimization_attempts/attempts/2026-07-04-urem-result-dividend-shared-use-issue-draft/
Key artifacts:
2026-07-04-llvm-issue-urem-result-dividend-shared-use.md
2026-07-04-urem-cost-measurement.md
Non-Goals
This local draft does not include an LLVM patch, LLVM test, full backend
benchmark, or implementation plan. It is intended for human review before any
external issue submission.
AliveProof : https://alive2.llvm.org/ce/z/FP8UQy
Compiler-explorer: https://compiler-explorer.com/z/TrcMvPr39
Summary
LLVM currently leaves optimized IR with an unsigned remainder result compared
back to its own dividend even when the same remainder also feeds
x - urem(x, C).For unsigned positive constant
C:%cmpis equivalent to%rounded == 0. Theneform is equivalent to%rounded != 0.This is not a standalone
uremdeletion opportunity for the reviewed corpusrows, because
%remremains needed by%rounded. The issue is a narrowercanonicalization / combined-transform opportunity: when
%roundedalreadyexists, the branch condition can be expressed through that value instead of
comparing the dividend against the remainder.
Example
One representative corpus row in
bench/faiss/optimized/test_cppcontrib_sa_decode.ll:The compare can be represented as:
because
%479 = %0 - (%0 % 3), so%479is zero exactly when%0 < 3, whichis also exactly when
%0 % 3 == %0.The same relation applies to
ne:can be represented as:
when
%rounded = sub nuw T %x, %remis already present.Corpus Evidence
The source exploration scanned the full optimized corpus:
.llfiles scanned;Review result:
uremdeletion candidates;uremresult compared with the dividend and alsoused in
x - urem(x, C).Distribution:
faiss: 29,folly: 2,node: 2,opencv: 2,linux: 1,llvm: 1,mold: 13: 34,96: 2,384: 1,24: 1eq: 36,ne: 2Representative rows:
bench/faiss/optimized/test_cppcontrib_sa_decode.ll:5186%478 = urem i64 %0, 3;%479 = sub nuw i64 %0, %478;icmp eq i64 %0, %478bench/folly/optimized/SpookyHashV1.ll:938%220 = urem i64 %.0, 96;%.idx = sub nuw i64 %.0, %220;icmp eq i64 %.0, %220bench/node/optimized/libnode.string_bytes.ll:2373%0 = urem i64 %cond, 3; compare usesneagainst%condExpected Canonicalization
Initial scope:
to:
and:
to:
The transform should require that
%roundedalready exists or that creating itis profitable for another use. It should not create a new
subsolely torewrite the comparison.
Profitability Notes
A local POC separates two cases:
urem(x, C)vsx, where deletinguremwould be clearlyprofitable;
uremremains live forx - urem(x, C).The reviewed corpus evidence is the second case.
Local
llvm-mcaMeasurementsEach row is measured as a separate function body with
llvm-mca, 100iterations.
Compare-only contrast, not corpus evidence:
x86-64urem i64 x, 3+ comparex86-64x < 3comparegenericurem i64 x, 3+ comparegenericx < 3comparerocket-rv64urem i64 x, 3+ comparerocket-rv64x < 3compareShared-use corpus shape:
x86-64x86-64uremstill livegenericgenericuremstill liverocket-rv64rocket-rv64uremstill liveThese measurements suggest the shared-use canonicalization is modest by itself,
but it exposes the existing rounded-down multiple and avoids expressing the
branch condition through the remainder value directly. It may be more valuable
as a canonical form for subsequent simplification or target lowering.
Legality Notes
For unsigned remainder by positive constant
C,%rem = urem %x, Csatisfies0 <= %rem < C. Therefore:and, when
%rounded = %x - %rem:The
sub nuwform seen in the corpus is consistent with%rem <= %x.Initial guards:
uremdivisor is a positive nonzero constant;uremresult;eqorne;%rounded = sub nuw %x, %remalready exists;%roundedsolely for this rewrite unless a separateprofitability rule justifies it.
Scope Boundaries
This issue is not a request for:
srem);uremwhen the remainder still has non-comparison uses;x - urem(x, C)expressions solely to rewrite a compare;Reproduction Data
Local source exploration packet:
Key artifacts:
2026-07-03-urem-result-dividend-compare-raw.jsonl2026-07-03-urem-result-dividend-compare-summary.md2026-07-03-urem-cost-poc.ll2026-07-03-urem-cost-poc.md2026-07-03-urem-cost-poc.x86_64.s2026-07-03-urem-cost-poc.aarch64.s2026-07-03-urem-cost-poc.riscv64.sLocal issue draft packet:
Key artifacts:
2026-07-04-llvm-issue-urem-result-dividend-shared-use.md2026-07-04-urem-cost-measurement.mdNon-Goals
This local draft does not include an LLVM patch, LLVM test, full backend
benchmark, or implementation plan. It is intended for human review before any
external issue submission.
AliveProof : https://alive2.llvm.org/ce/z/FP8UQy
Compiler-explorer: https://compiler-explorer.com/z/TrcMvPr39