switch-dce.c 3.46 KB
// RUN: %clang_cc1 -triple i386-unknown-unknown %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;
  }
}

// Verify that case 42 only calls test14 once.
// CHECK: @test13
// CHECK: call void @test13(i32 97)
// CHECK-NEXT: br label %[[EPILOG2:[0-9.a-z]+]]
// CHECK: [[EPILOG2]]
// CHECK-NEXT: br label [[EPILOG:%[0-9.a-z]+]]
// CHECK: call void @test13(i32 42)
// CHECK-NEXT: br label [[EPILOG]]
void test13(int x) {
  switch (x) {
    case 42: test13(97);  // fallthrough
    case 11: break;
    default: test13(42); break;
  }
}