llvm-project/clang/test/CodeGen/switch-dce.c

248 lines
3.8 KiB
C

// RUN: %clang_cc1 -triple i386-unknown-unknown -O0 %s -emit-llvm -o - | FileCheck %s
// PR9322 and rdar://6970405
// CHECK: @test1
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32 {{.*}}, 1
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
int i;
void dead();
void test1() {
switch (1)
case 1:
++i;
switch (0)
case 1:
dead();
}
// CHECK: @test2
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32 {{.*}}, 2
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test2() {
switch (4) {
case 1:
dead();
break;
case 4:
i += 2;
// Fall off the end of the switch.
}
}
// CHECK: @test3
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32 {{.*}}, 2
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test3() {
switch (4) {
case 1:
dead();
break;
case 4: {
i += 2;
break;
}
}
}
// CHECK: @test4
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32 {{.*}}, 2
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test4() {
switch (4) {
case 1:
dead();
break;
default: {
i += 2;
break;
}
}
}
// This shouldn't crash codegen, but we don't have to optimize out the switch
// in this case.
void test5() {
switch (1) {
int x; // eliding var decl?
case 1:
x = 4;
i = x;
break;
}
}
// CHECK: @test6
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test6() {
// Neither case is reachable.
switch (40) {
case 1:
dead();
break;
case 4: {
dead();
break;
}
}
}
// CHECK: @test7
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test7() {
switch (4) {
case 1:
dead();
break;
{
case 4: // crazy brace scenario
++i;
}
break;
}
}
// CHECK: @test8
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test8() {
switch (4) {
case 1:
dead();
break;
case 4:
++i;
// Fall off the end of the switch.
}
}
// CHECK: @test9
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: add nsw i32
// CHECK: add nsw i32
// CHECK-NOT: switch
// CHECK-NOT: @dead
// CHECK: ret void
void test9(int i) {
switch (1) {
case 5:
dead();
case 1:
++i;
// Fall through is fine.
case 4:
++i;
break;
}
}
// CHECK: @test10
// CHECK-NOT: switch
// CHECK: ret i32
int test10(void) {
switch(8) {
case 8:
break;
case 4:
break;
default:
dead();
}
return 0;
}
// CHECK: @test11
// CHECK-NOT: switch
// CHECK: ret void
void test11() {
switch (1) {
case 1:
break;
case 42: ;
int x; // eliding var decl?
x = 4;
break;
}
}
// CHECK: @test12
// CHECK-NOT: switch
// CHECK: ret void
void test12() {
switch (1) {
case 2: {
int a; // Ok to skip this vardecl.
a = 42;
}
case 1:
break;
case 42: ;
int x; // eliding var decl?
x = 4;
break;
}
}
// rdar://9289524 - Check that the empty cases don't produce an empty block.
// CHECK: @test13
// CHECK: switch
// CHECK: i32 42, label [[EPILOG:%[0-9.a-z]+]]
// CHECK: i32 11, label [[EPILOG]]
void test13(int x) {
switch (x) {
case 42: break; // No empty block please.
case 11: break; // No empty block please.
default: test13(42); break;
}
}
// Verify that case 42 only calls test14 once.
// CHECK: @test14
// CHECK: call void @test14(i32 97)
// CHECK-NEXT: br label [[EPILOG2:%[0-9.a-z]+]]
// CHECK: call void @test14(i32 42)
// CHECK-NEXT: br label [[EPILOG2]]
void test14(int x) {
switch (x) {
case 42: test14(97); // fallthrough
case 11: break;
default: test14(42); break;
}
}