Takashiidobe opened issue #14699:
Feature
Optimization of unsigned constant-remainder tests:
Take a look at: https://godbolt.org/z/MPfdhbc3q (divide x by constant, in this case 7, and then test it).
for signed/unsigned x, and for == and !=, rustc on llvm emits a short sequence, e.g. for the != case
is_multiple_of_7: imul eax, edi, -1227133513 cmp eax, 613566757 setae al retThe corresponding cranelift side is much longer:
is_multiple_of_7: mov rax, rdi mul dword ptr [rip + 0x2b] # 0x38 <is_multiple_of_7+0x38> mov r10, rdi sub r10d, edx shr r10d add r10d, edx shr r10d, 0x2 imul r11d, r10d, 0x7 sub edi, r11d test edi, edi setne al movzx rax, alBenefit
llvm-mca says this is 8 cycles for llvm or 20 for cranelift on a zen4. There is a similar disparity for arm64 and riscv64.
Implementation
Not sure. LLVM implements this in target independent SDAG, maybe there's a similar target independent ISLE fold that would be a good place for it?
extra note: make sure to handle signed vs unsigned, ne and eq, and odd and even numbers.
Alternatives
- We could leave this as is. I think this is a mildly popular pattern, like for byte aligning so I'd like to see it improved.
- Would need to look into cranelift more for other places to put this optimization. It could be target dependent but I assume this optimization should work the same for any target since it's a strength reduction.
alexcrichton added the cranelift label to Issue #14699.
alexcrichton added the performance label to Issue #14699.
alexcrichton added the cranelift:goal:optimize-speed label to Issue #14699.
alexcrichton removed the performance label from Issue #14699.
fitzgen commented on issue #14699:
It is possible that https://github.com/bytecodealliance/wasmtime/blob/ce2794bbf28c4ae1d2afb6620b2de17ab8e7b740/cranelift/codegen/src/opts/div_const.rs is missing some cases or that our cost function for egraph extraction is not weighing things correctly. Needs more investigation.
Last updated: Oct 31 2026 at 23:03 UTC