[missed-opt] [instcombine] fshl/fshr not pushed into constant-argument phi
Rust reproducer because I don't remember how to trigger funnel shifts with C intrinsics.
#[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.
Should be handled by foldOpIntoPhi(). At a guess, it may have trouble with multiple uses of the same phi in the instruction.
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.