Extend switch condition in optimizeSwitchPhiConst when free

In a case like:

    switch((i32)x) { case 42: phi((i64)42, ...); }

replace `(i64)42` with `zext(x)` when we can do so for free.

This fixes a part of https://github.com/llvm/llvm-project/issues/55153

Differential Revision: https://reviews.llvm.org/D124897
This commit is contained in:
Matthias Braun 2022-05-03 10:01:54 -07:00
parent 6cc741bcbf
commit 8d03c49f49
3 changed files with 112 additions and 24 deletions

View File

@ -7048,12 +7048,29 @@ bool CodeGenPrepare::optimizeSwitchPhiConstants(SwitchInst *SI) {
bool CheckedForSinglePred = false;
for (PHINode &PHI : CaseBB->phis()) {
Type *PHIType = PHI.getType();
if (PHIType == ConditionType) {
// If ZExt is free then we can also catch patterns like this:
// switch((i32)x) { case 42: phi((i64)42, ...); }
// and replace `(i64)42` with `zext i32 %x to i64`.
bool TryZExt =
PHIType->isIntegerTy() &&
PHIType->getIntegerBitWidth() > ConditionType->getIntegerBitWidth() &&
TLI->isZExtFree(ConditionType, PHIType);
if (PHIType == ConditionType || TryZExt) {
// Set to true to skip this case because of multiple preds.
bool SkipCase = false;
Value *Replacement = nullptr;
for (unsigned I = 0, E = PHI.getNumIncomingValues(); I != E; I++) {
if (PHI.getIncomingValue(I) != CaseValue ||
PHI.getIncomingBlock(I) != SwitchBB)
Value *PHIValue = PHI.getIncomingValue(I);
if (PHIValue != CaseValue) {
if (!TryZExt)
continue;
ConstantInt *PHIValueInt = dyn_cast<ConstantInt>(PHIValue);
if (!PHIValueInt ||
PHIValueInt->getValue() !=
CaseValue->getValue().zext(PHIType->getIntegerBitWidth()))
continue;
}
if (PHI.getIncomingBlock(I) != SwitchBB)
continue;
// We cannot optimize if there are multiple case labels jumping to
// this block. This check may get expensive when there are many
@ -7066,7 +7083,15 @@ bool CodeGenPrepare::optimizeSwitchPhiConstants(SwitchInst *SI) {
}
}
PHI.setIncomingValue(I, Condition);
if (Replacement == nullptr) {
if (PHIValue == CaseValue) {
Replacement = Condition;
} else {
IRBuilder<> Builder(SI);
Replacement = Builder.CreateZExt(Condition, PHIType);
}
}
PHI.setIncomingValue(I, Replacement);
Changed = true;
}
if (SkipCase)

View File

@ -91,38 +91,33 @@ default:
define void @switch_trunc_phi_const(i32 %x) {
; CHECK-LABEL: switch_trunc_phi_const:
; CHECK: # %bb.0: # %bb0
; CHECK-NEXT: movzbl %dil, %r8d
; CHECK-NEXT: movl $3895, %ecx # imm = 0xF37
; CHECK-NEXT: movl $42, %esi
; CHECK-NEXT: movl $13, %edx
; CHECK-NEXT: movl $5, %edi
; CHECK-NEXT: movl $1, %eax
; CHECK-NEXT: decl %r8d
; CHECK-NEXT: cmpl $54, %r8d
; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
; CHECK-NEXT: movzbl %dil, %ecx
; CHECK-NEXT: movzbl %dil, %eax
; CHECK-NEXT: movl $3895, %edx # imm = 0xF37
; CHECK-NEXT: decl %ecx
; CHECK-NEXT: cmpl $54, %ecx
; CHECK-NEXT: ja .LBB1_8
; CHECK-NEXT: # %bb.1: # %bb0
; CHECK-NEXT: jmpq *.LJTI1_0(,%r8,8)
; CHECK-NEXT: jmpq *.LJTI1_0(,%rcx,8)
; CHECK-NEXT: .LBB1_8: # %default
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB1_2: # %case_1_loop
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx
; CHECK-NEXT: movq $1, (%rcx)
; CHECK-NEXT: movq %rax, %rdi
; CHECK-NEXT: .LBB1_3: # %case_5
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rax
; CHECK-NEXT: movq $5, (%rax)
; CHECK-NEXT: movq %rdi, %rdx
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx
; CHECK-NEXT: movq $5, (%rcx)
; CHECK-NEXT: .LBB1_4: # %case_13
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rax
; CHECK-NEXT: movq $13, (%rax)
; CHECK-NEXT: movq %rdx, %rsi
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx
; CHECK-NEXT: movq $13, (%rcx)
; CHECK-NEXT: .LBB1_5: # %case_42
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rax
; CHECK-NEXT: movq %rsi, (%rax)
; CHECK-NEXT: movl $55, %ecx
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rcx
; CHECK-NEXT: movq %rax, (%rcx)
; CHECK-NEXT: movl $55, %edx
; CHECK-NEXT: .LBB1_6: # %case_55
; CHECK-NEXT: movq effect64@GOTPCREL(%rip), %rax
; CHECK-NEXT: movq %rcx, (%rax)
; CHECK-NEXT: movq %rdx, (%rax)
; CHECK-NEXT: .LBB1_7: # %case_7
; CHECK-NEXT: movq g64@GOTPCREL(%rip), %rax
; CHECK-NEXT: movq (%rax), %rax

View File

@ -155,3 +155,71 @@ case_42:
unreachable:
unreachable
}
@g64 = global i64 0
@effect64 = global i64 0
define void @switch_trunc_phi_const(i32 %x) {
; CHECK-LABEL: @switch_trunc_phi_const(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[X:%.*]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[X]] to i64
; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT:%.*]] [
; CHECK-NEXT: i32 13, label [[CASE_13:%.*]]
; CHECK-NEXT: i32 42, label [[CASE_42:%.*]]
; CHECK-NEXT: i32 55, label [[CASE_55:%.*]]
; CHECK-NEXT: i32 7, label [[CASE_7:%.*]]
; CHECK-NEXT: ]
; CHECK: case_13:
; CHECK-NEXT: [[X0:%.*]] = phi i64 [ [[TMP0]], [[BB0:%.*]] ], [ [[X7:%.*]], [[CASE_7]] ]
; CHECK-NEXT: store i64 13, i64* @effect64, align 4
; CHECK-NEXT: br label [[CASE_42]]
; CHECK: case_42:
; CHECK-NEXT: [[X1:%.*]] = phi i64 [ [[TMP1]], [[BB0]] ], [ [[X0]], [[CASE_13]] ]
; CHECK-NEXT: store i64 [[X1]], i64* @effect64, align 4
; CHECK-NEXT: br label [[CASE_55]]
; CHECK: case_55:
; CHECK-NEXT: [[X2:%.*]] = phi i64 [ 3895, [[BB0]] ], [ 55, [[CASE_42]] ]
; CHECK-NEXT: store i64 [[X2]], i64* @effect64, align 4
; CHECK-NEXT: br label [[DEFAULT]]
; CHECK: case_7:
; CHECK-NEXT: [[X7]] = load i64, i64* @g64, align 4
; CHECK-NEXT: store i64 7, i64* @effect64, align 4
; CHECK-NEXT: br label [[CASE_13]]
; CHECK: default:
; CHECK-NEXT: ret void
;
bb0:
switch i32 %x, label %default [
i32 13, label %case_13
i32 42, label %case_42
i32 55, label %case_55
i32 7, label %case_7
]
case_13:
; We should replace 13 with zext %x to i64
%x0 = phi i64 [ 13, %bb0 ], [ %x7, %case_7 ]
store i64 13, i64* @effect64, align 4
br label %case_42
case_42:
; We should replace 42 with zext i32 %x to i64
%x1 = phi i64 [ 42, %bb0 ], [ %x0, %case_13 ]
store i64 %x1, i64* @effect64, align 4
br label %case_55
case_55:
; We must not replace any of the PHI arguments! (3898 == 0xf00 + 55)
%x2 = phi i64 [ 3895, %bb0 ], [ 55, %case_42 ]
store i64 %x2, i64* @effect64, align 4
br label %default
case_7:
%x7 = load i64, i64* @g64, align 4
store i64 7, i64* @effect64, align 4
br label %case_13
default:
ret void
}