rust-lang / rust-lang/rust

interesting codegen difference between idiomatic check and pattern matching discriminant checks

Open
#161,851 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-codegen A-enum A-patterns C-optimization T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

https://godbolt.org/z/ebPdcdcfo

both functions have the same input Option type, one does the idiomatic if is_none() { init() } and the other does the check by pattern matching if let None = opt { init() }.

assembly

aaa generates an extra ret and compares a qword while bbb only compares a dword and has a single ret.

aaa:
        cmp     qword ptr [rdi], 0
        je      .LBB0_1
        ret
.LBB0_1:
        ; init
        ret

bbb:
        cmp     dword ptr [rdi], 1
        je      .LBB1_2
        ; init
.LBB1_2:
        ret

when compiled with -Cno-prepopulate-passes, the differences between the two functions disappear in terms of assembly.

LLVM-IR

we can see that LLVM resorted to swapping the labels in the branch for bbb. another note is that one does a compare to 0 (icmp) and branch on the result, the other truncates the load and branches on the truncated value.

define void @aaa(... %opt) {
start:
  %_4 = load i64, ptr %opt, align 8
  %_3.not = icmp eq i64 %_4, 0
  br i1 %_3.not, label %bb1, label %bb2

bb2:
  ret void

bb1:
  ; init
  br label %bb2
}

define void @bbb(... %opt) {
start:
  %_2 = load i64, ptr %opt, align 8
  %0 = trunc nuw i64 %_2 to i1
  br i1 %0, label %bb2, label %bb1

bb2:
  ret void

bb1:
  ; init
  br label %bb2
}

even with -Cno-prepopulate-passes, the trunc vs icmp difference remains.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example from the linked Compiler Explorer case with and without -Cno-prepopulate-passes. Compare the generated assembly and LLVM IR for the two Rust functions, focusing on the branch-label ordering and icmp versus trunc. Done means identifying the compiler stage responsible and either explaining the difference as expected or providing a verified correction.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.