237 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			LLVM
		
	
	
	
| ; RUN: opt < %s -S -loop-simplify | FileCheck %s
 | |
| ; RUN: opt < %s -S -passes=loop-simplify | FileCheck %s
 | |
| 
 | |
| ; This function should get a preheader inserted before bb3, that is jumped
 | |
| ; to by bb1 & bb2
 | |
| define void @test() {
 | |
| ; CHECK-LABEL: define void @test(
 | |
| entry:
 | |
|   br i1 true, label %bb1, label %bb2
 | |
| 
 | |
| bb1:
 | |
|   br label %bb3
 | |
| ; CHECK:      bb1:
 | |
| ; CHECK-NEXT:   br label %[[PH:.*]]
 | |
| 
 | |
| bb2:
 | |
|   br label %bb3
 | |
| ; CHECK:      bb2:
 | |
| ; CHECK-NEXT:   br label %[[PH]]
 | |
| 
 | |
| bb3:
 | |
|   br label %bb3
 | |
| ; CHECK:      [[PH]]:
 | |
| ; CHECK-NEXT:   br label %bb3
 | |
| ;
 | |
| ; CHECK:      bb3:
 | |
| ; CHECK-NEXT:   br label %bb3
 | |
| }
 | |
| 
 | |
| ; Test a case where we have multiple exit blocks as successors of a single loop
 | |
| ; block that need to be made dedicated exit blocks. We also have multiple
 | |
| ; exiting edges to one of the exit blocks that all should be rewritten.
 | |
| define void @test_multiple_exits_from_single_block(i8 %a, i8* %b.ptr) {
 | |
| ; CHECK-LABEL: define void @test_multiple_exits_from_single_block(
 | |
| entry:
 | |
|   switch i8 %a, label %loop [
 | |
|     i8 0, label %exit.a
 | |
|     i8 1, label %exit.b
 | |
|   ]
 | |
| ; CHECK:      entry:
 | |
| ; CHECK-NEXT:   switch i8 %a, label %[[PH:.*]] [
 | |
| ; CHECK-NEXT:     i8 0, label %exit.a
 | |
| ; CHECK-NEXT:     i8 1, label %exit.b
 | |
| ; CHECK-NEXT:   ]
 | |
| 
 | |
| loop:
 | |
|   %b = load volatile i8, i8* %b.ptr
 | |
|   switch i8 %b, label %loop [
 | |
|     i8 0, label %exit.a
 | |
|     i8 1, label %exit.b
 | |
|     i8 2, label %loop
 | |
|     i8 3, label %exit.a
 | |
|     i8 4, label %loop
 | |
|     i8 5, label %exit.a
 | |
|     i8 6, label %loop
 | |
|   ]
 | |
| ; CHECK:      [[PH]]:
 | |
| ; CHECK-NEXT:   br label %loop
 | |
| ;
 | |
| ; CHECK:      loop:
 | |
| ; CHECK-NEXT:   %[[B:.*]] = load volatile i8, i8* %b.ptr
 | |
| ; CHECK-NEXT:   switch i8 %[[B]], label %[[BACKEDGE:.*]] [
 | |
| ; CHECK-NEXT:     i8 0, label %[[LOOPEXIT_A:.*]]
 | |
| ; CHECK-NEXT:     i8 1, label %[[LOOPEXIT_B:.*]]
 | |
| ; CHECK-NEXT:     i8 2, label %[[BACKEDGE]]
 | |
| ; CHECK-NEXT:     i8 3, label %[[LOOPEXIT_A]]
 | |
| ; CHECK-NEXT:     i8 4, label %[[BACKEDGE]]
 | |
| ; CHECK-NEXT:     i8 5, label %[[LOOPEXIT_A]]
 | |
| ; CHECK-NEXT:     i8 6, label %[[BACKEDGE]]
 | |
| ; CHECK-NEXT:   ]
 | |
| ;
 | |
| ; CHECK:      [[BACKEDGE]]:
 | |
| ; CHECK-NEXT:   br label %loop
 | |
| 
 | |
| exit.a:
 | |
|   ret void
 | |
| ; CHECK:      [[LOOPEXIT_A]]:
 | |
| ; CHECK-NEXT:   br label %exit.a
 | |
| ;
 | |
| ; CHECK:      exit.a:
 | |
| ; CHECK-NEXT:   ret void
 | |
| 
 | |
| exit.b:
 | |
|   ret void
 | |
| ; CHECK:      [[LOOPEXIT_B]]:
 | |
| ; CHECK-NEXT:   br label %exit.b
 | |
| ;
 | |
| ; CHECK:      exit.b:
 | |
| ; CHECK-NEXT:   ret void
 | |
| }
 | |
| 
 | |
| ; Check that we leave already dedicated exits alone when forming dedicated exit
 | |
| ; blocks.
 | |
| define void @test_pre_existing_dedicated_exits(i1 %a, i1* %ptr) {
 | |
| ; CHECK-LABEL: define void @test_pre_existing_dedicated_exits(
 | |
| entry:
 | |
|   br i1 %a, label %loop.ph, label %non_dedicated_exit
 | |
| ; CHECK:      entry:
 | |
| ; CHECK-NEXT:   br i1 %a, label %loop.ph, label %non_dedicated_exit
 | |
| 
 | |
| loop.ph:
 | |
|   br label %loop.header
 | |
| ; CHECK:      loop.ph:
 | |
| ; CHECK-NEXT:   br label %loop.header
 | |
| 
 | |
| loop.header:
 | |
|   %c1 = load volatile i1, i1* %ptr
 | |
|   br i1 %c1, label %loop.body1, label %dedicated_exit1
 | |
| ; CHECK:      loop.header:
 | |
| ; CHECK-NEXT:   %[[C1:.*]] = load volatile i1, i1* %ptr
 | |
| ; CHECK-NEXT:   br i1 %[[C1]], label %loop.body1, label %dedicated_exit1
 | |
| 
 | |
| loop.body1:
 | |
|   %c2 = load volatile i1, i1* %ptr
 | |
|   br i1 %c2, label %loop.body2, label %non_dedicated_exit
 | |
| ; CHECK:      loop.body1:
 | |
| ; CHECK-NEXT:   %[[C2:.*]] = load volatile i1, i1* %ptr
 | |
| ; CHECK-NEXT:   br i1 %[[C2]], label %loop.body2, label %[[LOOPEXIT:.*]]
 | |
| 
 | |
| loop.body2:
 | |
|   %c3 = load volatile i1, i1* %ptr
 | |
|   br i1 %c3, label %loop.backedge, label %dedicated_exit2
 | |
| ; CHECK:      loop.body2:
 | |
| ; CHECK-NEXT:   %[[C3:.*]] = load volatile i1, i1* %ptr
 | |
| ; CHECK-NEXT:   br i1 %[[C3]], label %loop.backedge, label %dedicated_exit2
 | |
| 
 | |
| loop.backedge:
 | |
|   br label %loop.header
 | |
| ; CHECK:      loop.backedge:
 | |
| ; CHECK-NEXT:   br label %loop.header
 | |
| 
 | |
| dedicated_exit1:
 | |
|   ret void
 | |
| ; Check that there isn't a split loop exit.
 | |
| ; CHECK-NOT:    br label %dedicated_exit1
 | |
| ;
 | |
| ; CHECK:      dedicated_exit1:
 | |
| ; CHECK-NEXT:   ret void
 | |
| 
 | |
| dedicated_exit2:
 | |
|   ret void
 | |
| ; Check that there isn't a split loop exit.
 | |
| ; CHECK-NOT:    br label %dedicated_exit2
 | |
| ;
 | |
| ; CHECK:      dedicated_exit2:
 | |
| ; CHECK-NEXT:   ret void
 | |
| 
 | |
| non_dedicated_exit:
 | |
|   ret void
 | |
| ; CHECK:      [[LOOPEXIT]]:
 | |
| ; CHECK-NEXT:   br label %non_dedicated_exit
 | |
| ;
 | |
| ; CHECK:      non_dedicated_exit:
 | |
| ; CHECK-NEXT:   ret void
 | |
| }
 | |
| 
 | |
| ; Check that we form what dedicated exits we can even when some exits are
 | |
| ; reached via indirectbr which precludes forming dedicated exits.
 | |
| define void @test_form_some_dedicated_exits_despite_indirectbr(i8 %a, i8* %ptr, i8** %addr.ptr) {
 | |
| ; CHECK-LABEL: define void @test_form_some_dedicated_exits_despite_indirectbr(
 | |
| entry:
 | |
|   switch i8 %a, label %loop.ph [
 | |
|     i8 0, label %exit.a
 | |
|     i8 1, label %exit.b
 | |
|     i8 2, label %exit.c
 | |
|   ]
 | |
| ; CHECK:      entry:
 | |
| ; CHECK-NEXT:   switch i8 %a, label %loop.ph [
 | |
| ; CHECK-NEXT:     i8 0, label %exit.a
 | |
| ; CHECK-NEXT:     i8 1, label %exit.b
 | |
| ; CHECK-NEXT:     i8 2, label %exit.c
 | |
| ; CHECK-NEXT:   ]
 | |
| 
 | |
| loop.ph:
 | |
|   br label %loop.header
 | |
| ; CHECK:      loop.ph:
 | |
| ; CHECK-NEXT:   br label %loop.header
 | |
| 
 | |
| loop.header:
 | |
|   %addr1 = load volatile i8*, i8** %addr.ptr
 | |
|   indirectbr i8* %addr1, [label %loop.body1, label %exit.a]
 | |
| ; CHECK:      loop.header:
 | |
| ; CHECK-NEXT:   %[[ADDR1:.*]] = load volatile i8*, i8** %addr.ptr
 | |
| ; CHECK-NEXT:   indirectbr i8* %[[ADDR1]], [label %loop.body1, label %exit.a]
 | |
| 
 | |
| loop.body1:
 | |
|   %b = load volatile i8, i8* %ptr
 | |
|   switch i8 %b, label %loop.body2 [
 | |
|     i8 0, label %exit.a
 | |
|     i8 1, label %exit.b
 | |
|     i8 2, label %exit.c
 | |
|   ]
 | |
| ; CHECK:      loop.body1:
 | |
| ; CHECK-NEXT:   %[[B:.*]] = load volatile i8, i8* %ptr
 | |
| ; CHECK-NEXT:   switch i8 %[[B]], label %loop.body2 [
 | |
| ; CHECK-NEXT:     i8 0, label %exit.a
 | |
| ; CHECK-NEXT:     i8 1, label %[[LOOPEXIT:.*]]
 | |
| ; CHECK-NEXT:     i8 2, label %exit.c
 | |
| ; CHECK-NEXT:   ]
 | |
| 
 | |
| loop.body2:
 | |
|   %addr2 = load volatile i8*, i8** %addr.ptr
 | |
|   indirectbr i8* %addr2, [label %loop.backedge, label %exit.c]
 | |
| ; CHECK:      loop.body2:
 | |
| ; CHECK-NEXT:   %[[ADDR2:.*]] = load volatile i8*, i8** %addr.ptr
 | |
| ; CHECK-NEXT:   indirectbr i8* %[[ADDR2]], [label %loop.backedge, label %exit.c]
 | |
| 
 | |
| loop.backedge:
 | |
|   br label %loop.header
 | |
| ; CHECK:      loop.backedge:
 | |
| ; CHECK-NEXT:   br label %loop.header
 | |
| 
 | |
| exit.a:
 | |
|   ret void
 | |
| ; Check that there isn't a split loop exit.
 | |
| ; CHECK-NOT:    br label %exit.a
 | |
| ;
 | |
| ; CHECK:      exit.a:
 | |
| ; CHECK-NEXT:   ret void
 | |
| 
 | |
| exit.b:
 | |
|   ret void
 | |
| ; CHECK:      [[LOOPEXIT]]:
 | |
| ; CHECK-NEXT:   br label %exit.b
 | |
| ;
 | |
| ; CHECK:      exit.b:
 | |
| ; CHECK-NEXT:   ret void
 | |
| 
 | |
| exit.c:
 | |
|   ret void
 | |
| ; Check that there isn't a split loop exit.
 | |
| ; CHECK-NOT:    br label %exit.c
 | |
| ;
 | |
| ; CHECK:      exit.c:
 | |
| ; CHECK-NEXT:   ret void
 | |
| }
 |