139 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			LLVM
		
	
	
	
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 | |
| ; RUN: opt -S -loop-guard-widening -enable-new-pm=0 < %s | FileCheck %s
 | |
| ; RUN: opt -S -passes="loop(guard-widening)" < %s | FileCheck %s
 | |
| 
 | |
| declare void @llvm.experimental.guard(i1,...)
 | |
| 
 | |
| @G = external global i32
 | |
| 
 | |
| ; Show that we can widen into early checks within a loop, and in the process
 | |
| ; expose optimization oppurtunities.
 | |
| define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 | |
| ; CHECK-LABEL: @widen_within_loop(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    br label [[LOOP:%.*]]
 | |
| ; CHECK:       loop:
 | |
| ; CHECK-NEXT:    store i32 0, i32* @G
 | |
| ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
 | |
| ; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
 | |
| ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
 | |
| ; CHECK-NEXT:    store i32 1, i32* @G
 | |
| ; CHECK-NEXT:    store i32 2, i32* @G
 | |
| ; CHECK-NEXT:    store i32 3, i32* @G
 | |
| ; CHECK-NEXT:    br label [[LOOP]]
 | |
| ;
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   store i32 0, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
 | |
|   store i32 1, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
 | |
|   store i32 2, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
 | |
|   store i32 3, i32* @G
 | |
|   br label %loop
 | |
| }
 | |
| 
 | |
| define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 | |
| ; CHECK-LABEL: @widen_into_preheader(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    store i32 0, i32* @G
 | |
| ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
 | |
| ; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
 | |
| ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
 | |
| ; CHECK-NEXT:    br label [[LOOP:%.*]]
 | |
| ; CHECK:       loop:
 | |
| ; CHECK-NEXT:    store i32 1, i32* @G
 | |
| ; CHECK-NEXT:    store i32 2, i32* @G
 | |
| ; CHECK-NEXT:    store i32 3, i32* @G
 | |
| ; CHECK-NEXT:    br label [[LOOP]]
 | |
| ;
 | |
| entry:
 | |
|   store i32 0, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   store i32 1, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
 | |
|   store i32 2, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
 | |
|   store i32 3, i32* @G
 | |
|   br label %loop
 | |
| }
 | |
| 
 | |
| define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 | |
| ; CHECK-LABEL: @dont_widen_over_common_exit(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    br label [[LOOP:%.*]]
 | |
| ; CHECK:       loop:
 | |
| ; CHECK-NEXT:    store i32 0, i32* @G
 | |
| ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ]
 | |
| ; CHECK-NEXT:    store i32 1, i32* @G
 | |
| ; CHECK-NEXT:    br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
 | |
| ; CHECK:       backedge:
 | |
| ; CHECK-NEXT:    store i32 2, i32* @G
 | |
| ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ]
 | |
| ; CHECK-NEXT:    store i32 3, i32* @G
 | |
| ; CHECK-NEXT:    br label [[LOOP]]
 | |
| ; CHECK:       exit:
 | |
| ; CHECK-NEXT:    ret void
 | |
| ;
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   store i32 0, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
 | |
|   store i32 1, i32* @G
 | |
|   br i1 %cond_1, label %backedge, label %exit
 | |
| 
 | |
| backedge:
 | |
|   store i32 2, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
 | |
|   store i32 3, i32* @G
 | |
|   br label %loop
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 | |
| ; CHECK-LABEL: @widen_over_common_exit_to_ph(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    store i32 0, i32* @G
 | |
| ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]]
 | |
| ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ]
 | |
| ; CHECK-NEXT:    br label [[LOOP:%.*]]
 | |
| ; CHECK:       loop:
 | |
| ; CHECK-NEXT:    store i32 1, i32* @G
 | |
| ; CHECK-NEXT:    br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
 | |
| ; CHECK:       backedge:
 | |
| ; CHECK-NEXT:    store i32 2, i32* @G
 | |
| ; CHECK-NEXT:    store i32 3, i32* @G
 | |
| ; CHECK-NEXT:    br label [[LOOP]]
 | |
| ; CHECK:       exit:
 | |
| ; CHECK-NEXT:    ret void
 | |
| ;
 | |
| entry:
 | |
|   store i32 0, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   store i32 1, i32* @G
 | |
|   br i1 %cond_1, label %backedge, label %exit
 | |
| 
 | |
| backedge:
 | |
|   store i32 2, i32* @G
 | |
|   call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
 | |
|   store i32 3, i32* @G
 | |
|   br label %loop
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 |