Skip to content
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

Excessive overflow checks that can be proven unnecessary #114386

Open
ProgramCrafter opened this issue Aug 2, 2023 · 7 comments
Open

Excessive overflow checks that can be proven unnecessary #114386

ProgramCrafter opened this issue Aug 2, 2023 · 7 comments
Assignees
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. I-slow Issue: Problems and improvements with respect to performance of generated code. llvm-fixed-upstream Issue expected to be fixed by the next major LLVM upgrade, or backported fixes T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@ProgramCrafter
Copy link

ProgramCrafter commented Aug 2, 2023

I tried this code:

#[inline(never)]
fn overflow_check(triple_lim: usize) -> bool {
    let lim: usize = triple_lim / 3;
    lim * 3 >= lim
}

fn main() {
    let n = std::hint::black_box(30);
    println!("{}", overflow_check(n));
}

The check lim * 3 >= lim is trivially true, since lim is obtained by dividing usize by 3 so there can be no overflow. I expected to see it optimized out in ASM, like here (obtained via std::hint::black_box-ing true):

playground::overflow_check:
	movb	$1, -1(%rsp)
	leaq	-1(%rsp), %rax
	#APP
	#NO_APP
	movzbl	-1(%rsp), %eax
	retq

Instead, this happened:

playground::overflow_check:
	movq	%rdi, %rax
	movabsq	$-6148914691236517205, %rcx
	mulq	%rcx
	shrq	%rdx
	leaq	(%rdx,%rdx,2), %rax
	cmpq	%rdx, %rax
	setae	%al
	retq

Meta

https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=17cc61a317c18d7ea86d7d98b6a43510

triple_lim >= triple_lim / 3 in a similar test is actually optimized away.

Source

Optimized down from https://rust.godbolt.org/z/jsh6zhPYa (utility function for converting BGR to RGBA arrays).

@ProgramCrafter ProgramCrafter added the C-bug Category: This is a bug. label Aug 2, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 2, 2023
@Noratrieb Noratrieb added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. I-slow Issue: Problems and improvements with respect to performance of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Aug 3, 2023
@AaronKutch
Copy link
Contributor

AaronKutch commented Aug 4, 2023

It's worrying about wrap around overflow inlim * 3 >= lim by itself in case lim is something like usize::MAX, I'm guessing the problem is that the numerical bounds of what leads to lim could be are not being tracked with respect to division by a constant.

@erikdesjardins
Copy link
Contributor

nuw already gets inferred on the mul: https://rust.godbolt.org/z/99r9no3MP

So LLVM just needs this transform: https://alive2.llvm.org/ce/z/4a6RLR

declare void @llvm.assume(i1)

define i1 @src(i16 %x, i16 %c) {
  %c_nonzero = icmp ne i16 %c, 0
  call void @llvm.assume(i1 %c_nonzero)

  %x3 = mul nuw i16 %x, %c
  %cmp = icmp uge i16 %x3, %x
  ret i1 %cmp
}

define i1 @tgt(i16 %x, i16 %c) {
  ret i1 true
}

@veera-sivarajan
Copy link
Contributor

@rustbot claim

@dianqk
Copy link
Member

dianqk commented Feb 25, 2025

@rustbot ping

@rustbot
Copy link
Collaborator

rustbot commented Feb 25, 2025

Error: Parsing ping command in comment failed: ...' ping' | error: no team specified at >| ''...

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #t-infra on Zulip.

@dianqk
Copy link
Member

dianqk commented Feb 25, 2025

@rustbot claim
Testing the bot

@dianqk dianqk assigned veera-sivarajan and unassigned dianqk Feb 25, 2025
veera-sivarajan added a commit to llvm/llvm-project that referenced this issue Mar 1, 2025
Proof: https://alive2.llvm.org/ce/z/T_ocLy

Discovered in: rust-lang/rust#114386

This PR folds `X * C >= X` to `true` when `C` is known to be non-zero
and `mul` is `nuw`.

Folds for other math operators exist already:
https://llvm-ir.godbolt.org/z/GKcYEf5Kb
@veera-sivarajan
Copy link
Contributor

@rustbot label llvm-fixed-upstream

@rustbot rustbot added the llvm-fixed-upstream Issue expected to be fixed by the next major LLVM upgrade, or backported fixes label Mar 1, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this issue Mar 1, 2025
Proof: https://alive2.llvm.org/ce/z/T_ocLy

Discovered in: rust-lang/rust#114386

This PR folds `X * C >= X` to `true` when `C` is known to be non-zero
and `mul` is `nuw`.

Folds for other math operators exist already:
https://llvm-ir.godbolt.org/z/GKcYEf5Kb
jph-13 pushed a commit to jph-13/llvm-project that referenced this issue Mar 21, 2025
Proof: https://alive2.llvm.org/ce/z/T_ocLy

Discovered in: rust-lang/rust#114386

This PR folds `X * C >= X` to `true` when `C` is known to be non-zero
and `mul` is `nuw`.

Folds for other math operators exist already:
https://llvm-ir.godbolt.org/z/GKcYEf5Kb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. I-slow Issue: Problems and improvements with respect to performance of generated code. llvm-fixed-upstream Issue expected to be fixed by the next major LLVM upgrade, or backported fixes T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants