rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
95.17k stars 12.27k forks source link

Strange `jmp 0` emitted in size-optimized x86-64 assembly #127375

Open dead-claudia opened 2 weeks ago

dead-claudia commented 2 weeks ago

Godbolt link (includes this and another buggy example)+%7B%0A++++++++(Some(next),+Some(v+@+0..%3D9))+%3D%3E+next.checkedadd(v+as+u32),%0A+++++++++%3D%3E+None,%0A++++%7D%0A%7D%0A%0A%23%5Bno_mangle%5D%0Apub+fn+parse_u32_digit_2(acc:+u32,+byte:+u8)+-%3E+Option%3Cu32%3E+%7B%0A++++//+Not+sure+why+this+order+is+required+for+ensuring+proper+branch%0A++++let+max+%3D+if+acc+%3D%3D+429496729+%7B+5+%7D+else+%7B+9+%7D%3B%0A++++if+acc+%3C%3D+429496729+%7B%0A++++++++let+v+%3D+(byte+as+u32).wrapping_sub(b!'0!'+as+u32)%3B%0A++++++++if+v+%3C%3D+max+%7B%0A++++++++++++return+Some(acc.wrapping_mul(10).wrapping_add(v))%3B%0A++++++++%7D%0A++++%7D%0A++++None%0A%7D'),l:'5',n:'1',o:'Rust+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:r1790,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:rust,libs:!(),options:'-C+opt-level%3Ds',overrides:!(),selection:(endColumn:12,endLineNumber:20,positionColumn:1,positionLineNumber:1,selectionStartColumn:12,selectionStartLineNumber:20,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+rustc+1.79.0+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4)

I tried this code:

pub fn parse_u32_digit(acc: u32, byte: u8) -> Option<u32> {
    match (acc.checked_mul(10), byte.checked_sub(b'0')) {
        (Some(next), Some(v @ 0..=9)) => next.checked_add(v as u32),
        _ => None,
    }
}

I expected to see this happen: assembly that looks something like this:

parse_u32_digit:
        mov     eax, edi
        xor     ecx, ecx
        mov     edx, 10
        mul     edx
        jo      .LBB0_1
        mov     edx, eax
        lea     eax, [rsi - 58]
        cmp     al, -10
        jb      .LBB0_4
        add     sil, -48
        movzx   eax, sil
        xor     ecx, ecx
        add     edx, eax
        setae   cl
.LBB0_1:
.LBB0_4:
        mov     eax, ecx
        ret

Instead, this happened: the following assembly:

parse_u32_digit:
        mov     eax, edi
        xor     ecx, ecx
        mov     edx, 10
        mul     edx
        jo      .LBB0_1
        mov     edx, eax
        lea     eax, [rsi - 58]
        cmp     al, -10
        jb      .LBB0_4
        add     sil, -48
        movzx   eax, sil
        xor     ecx, ecx
        add     edx, eax
        setae   cl
        jmp     .LBB0_4
.LBB0_1:
.LBB0_4:
        mov     eax, ecx
        ret

Meta

rustc --version --verbose:

rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: x86_64-unknown-linux-gnu
release: 1.79.0
LLVM version: 18.1.7
Compiler returned: 0
workingjubilee commented 2 weeks ago

@rustbot label: +C-optimization -C-bug +I-heavy +A-LLVM +A-codegen

the8472 commented 2 weeks ago

126585 looks somewhat similar

DianQK commented 1 week ago

126585 looks somewhat similar

Yes. But it's not exactly duplicated. This should be in the plan I mentioned at https://github.com/llvm/llvm-project/pull/95932#issuecomment-2180664558.

@rustbot claim