We already do this during initial worklist population. Doing this as part of primary combining allows us to remove instructions in blocks that were rendered dead by condition folding within the same instcombine iteration.
147 lines
3.0 KiB
LLVM
147 lines
3.0 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
|
; RUN: opt -S -passes=instcombine -instcombine-infinite-loop-threshold=2 < %s | FileCheck %s
|
|
|
|
declare void @dummy()
|
|
|
|
define void @br_true(i1 %x) {
|
|
; CHECK-LABEL: define void @br_true
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 true, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: else:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = or i1 %x, true
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
else:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @br_false(i1 %x) {
|
|
; CHECK-LABEL: define void @br_false
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 false, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: else:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = and i1 %x, false
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
else:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @br_undef(i1 %x) {
|
|
; CHECK-LABEL: define void @br_undef
|
|
; CHECK-SAME: (i1 [[X:%.*]]) {
|
|
; CHECK-NEXT: br i1 undef, label [[IF:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: if:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: else:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%c = xor i1 %x, undef
|
|
br i1 %c, label %if, label %else
|
|
|
|
if:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
else:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @switch_case(i32 %x) {
|
|
; CHECK-LABEL: define void @switch_case
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: switch i32 0, label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case0:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: default:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%v = and i32 %x, 0
|
|
switch i32 %v, label %default [
|
|
i32 0, label %case0
|
|
]
|
|
|
|
case0:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
default:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @switch_default(i32 %x) {
|
|
; CHECK-LABEL: define void @switch_default
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: switch i32 -1, label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case0:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: default:
|
|
; CHECK-NEXT: call void @dummy()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%v = or i32 %x, -1
|
|
switch i32 %v, label %default [
|
|
i32 0, label %case0
|
|
]
|
|
|
|
case0:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
default:
|
|
call void @dummy()
|
|
ret void
|
|
}
|
|
|
|
define void @switch_undef(i32 %x) {
|
|
; CHECK-LABEL: define void @switch_undef
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: switch i32 undef, label [[DEFAULT:%.*]] [
|
|
; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case0:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: default:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%v = xor i32 %x, undef
|
|
switch i32 %v, label %default [
|
|
i32 0, label %case0
|
|
]
|
|
|
|
case0:
|
|
call void @dummy()
|
|
ret void
|
|
|
|
default:
|
|
call void @dummy()
|
|
ret void
|
|
}
|