llvm-project icon indicating copy to clipboard operation
llvm-project copied to clipboard

[missed-opt] [instcombine] fshl/fshr not pushed into constant-argument phi

Open purplesyringa opened this issue 3 weeks ago • 2 comments

Rust reproducer because I don't remember how to trigger funnel shifts with C intrinsics.

Godbolt

#[unsafe(no_mangle)]
pub fn fshl(cond: bool) -> u32 {
    if cond { 0xd2c31701u32 } else { 0xfd46843fu32 }.rotate_left(3)
}

#[unsafe(no_mangle)]
pub fn fshr(cond: bool) -> u32 {
    if cond { 0xd2c31701u32 } else { 0xfd46843fu32 }.rotate_right(3)
}
fshl:
        test    edi, edi
        mov     ecx, -758966527
        mov     eax, -45710273
        cmovne  eax, ecx
        rol     eax, 3
        ret

fshr:
        test    edi, edi
        mov     ecx, -758966527
        mov     eax, -45710273
        cmovne  eax, ecx
        rol     eax, 29
        ret

I would like the rol to be absent and inlined into the constants.

IR:

define noundef i32 @fshl(i1 noundef zeroext %0) unnamed_addr {
  br i1 %0, label %3, label %2

2:                                                ; preds = %1
  br label %4

3:                                                ; preds = %1
  br label %4

4:                                                ; preds = %3, %2
  %5 = phi i32 [ -758966527, %3 ], [ -45710273, %2 ]
  %6 = call i32 @llvm.fshl.i32(i32 %5, i32 %5, i32 3)
  ret i32 %6
}

define noundef i32 @fshr(i1 noundef zeroext %0) unnamed_addr {
  br i1 %0, label %3, label %2

2:                                                ; preds = %1
  br label %4

3:                                                ; preds = %1
  br label %4

4:                                                ; preds = %3, %2
  %5 = phi i32 [ -758966527, %3 ], [ -45710273, %2 ]
  %6 = call i32 @llvm.fshr.i32(i32 %5, i32 %5, i32 3)
  ret i32 %6
}

This applies specifically to funnel shifts, not normal shifts.

purplesyringa avatar Dec 13 '25 20:12 purplesyringa

Should be handled by foldOpIntoPhi(). At a guess, it may have trouble with multiple uses of the same phi in the instruction.

nikic avatar Dec 13 '25 20:12 nikic

It seems that opt on trunk actually can push these funnel shifts into the phi. However, the reason we still get the rol in the final binary is because the SimplifyCFGPass turns the phi into a select, and FoldOpIntoSelect has trouble with the multiple uses.

I'll submit a patch for this soon.

sivakusayan avatar Dec 17 '25 13:12 sivakusayan