Skip to content

Unnecessary and x,C introduced due to assume on trunc+zext #143778

@dzaima

Description

@dzaima

The code:

#include<stdint.h>

uint64_t foo(uint64_t a) {
    uint32_t b = a;
    if (b >= 100) __builtin_unreachable();
    return b;
}

with -O3 compiles to:

foo:
        mov rax, rdi
        and eax, 127
        ret

but it could be:

foo:
        mov eax, edi
        ret

compiler explorer on the instcombine pass that introduces the and; namely, it transforms:

define dso_local range(i64 0, 4294967296) i64 @foo(i64 noundef %a) local_unnamed_addr {
entry:
  %conv = trunc i64 %a to i32
  %cmp = icmp uge i32 %conv, 100
  %0 = xor i1 %cmp, true
  call void @llvm.assume(i1 %0)
  %conv2 = zext i32 %conv to i64
  ret i64 %conv2
}

to:

define dso_local range(i64 0, 4294967296) i64 @foo(i64 noundef %a) local_unnamed_addr {
entry:
  %conv = trunc i64 %a to i32
  %cmp = icmp ult i32 %conv, 100
  call void @llvm.assume(i1 %cmp)
  %conv2 = and i64 %a, 127
  ret i64 %conv2
}

reduced from this Rust code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions