210 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			LLVM
		
	
	
	
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 | |
| ; RUN: opt -instcombine -S < %s | FileCheck %s
 | |
| 
 | |
| ; Function Attrs: noinline uwtable
 | |
| define i32 @foo(i32* nocapture writeonly %arg) {
 | |
| ; CHECK-LABEL: @foo(
 | |
| ; CHECK-NEXT:  bb:
 | |
| ; CHECK-NEXT:    [[VAR:%.*]] = call i32 @baz()
 | |
| ; CHECK-NEXT:    store i32 [[VAR]], i32* [[ARG:%.*]], align 4
 | |
| ; CHECK-NEXT:    [[VAR1:%.*]] = call i32 @baz()
 | |
| ; CHECK-NEXT:    ret i32 [[VAR1]]
 | |
| ;
 | |
| bb:
 | |
|   %var = call i32 @baz()
 | |
|   store i32 %var, i32* %arg, align 4
 | |
|   %var1 = call i32 @baz()
 | |
|   ret i32 %var1
 | |
| }
 | |
| declare i32 @baz()
 | |
| 
 | |
| ; Function Attrs: uwtable
 | |
| ; This is an equivalent IR for a c-style example with a large function (foo)
 | |
| ; with out-params which are unused in the caller(test8). Note that foo is
 | |
| ; marked noinline to prevent IPO transforms.
 | |
| ; int foo();
 | |
| ;
 | |
| ; extern int foo(int *out) __attribute__((noinline));
 | |
| ; int foo(int *out) {
 | |
| ;   *out = baz();
 | |
| ;   return baz();
 | |
| ; }
 | |
| ;
 | |
| ; int test() {
 | |
| ;
 | |
| ;   int notdead;
 | |
| ;   if (foo(¬dead))
 | |
| ;     return 0;
 | |
| ;
 | |
| ;   int dead;
 | |
| ;   int tmp = foo(&dead);
 | |
| ;   if (notdead)
 | |
| ;     return tmp;
 | |
| ;   return bar();
 | |
| ; }
 | |
| 
 | |
| ; TODO: We should be able to sink the second call @foo at bb5 down to bb_crit_edge
 | |
| define i32 @test() {
 | |
| ; CHECK-LABEL: @test(
 | |
| ; CHECK-NEXT:  bb:
 | |
| ; CHECK-NEXT:    [[VAR:%.*]] = alloca i32, align 4
 | |
| ; CHECK-NEXT:    [[VAR1:%.*]] = alloca i32, align 4
 | |
| ; CHECK-NEXT:    [[VAR2:%.*]] = bitcast i32* [[VAR]] to i8*
 | |
| ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull [[VAR2]])
 | |
| ; CHECK-NEXT:    [[VAR3:%.*]] = call i32 @foo(i32* nonnull writeonly [[VAR]])
 | |
| ; CHECK-NEXT:    [[VAR4:%.*]] = icmp eq i32 [[VAR3]], 0
 | |
| ; CHECK-NEXT:    br i1 [[VAR4]], label [[BB5:%.*]], label [[BB14:%.*]]
 | |
| ; CHECK:       bb5:
 | |
| ; CHECK-NEXT:    [[VAR6:%.*]] = bitcast i32* [[VAR1]] to i8*
 | |
| ; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull [[VAR6]])
 | |
| ; CHECK-NEXT:    [[VAR8:%.*]] = load i32, i32* [[VAR]], align 4
 | |
| ; CHECK-NEXT:    [[VAR9:%.*]] = icmp eq i32 [[VAR8]], 0
 | |
| ; CHECK-NEXT:    [[VAR7:%.*]] = call i32 @foo(i32* nonnull writeonly [[VAR1]])
 | |
| ; CHECK-NEXT:    br i1 [[VAR9]], label [[BB10:%.*]], label [[BB_CRIT_EDGE:%.*]]
 | |
| ; CHECK:       bb10:
 | |
| ; CHECK-NEXT:    [[VAR11:%.*]] = call i32 @bar()
 | |
| ; CHECK-NEXT:    br label [[BB12:%.*]]
 | |
| ; CHECK:       bb_crit_edge:
 | |
| ; CHECK-NEXT:    br label [[BB12]]
 | |
| ; CHECK:       bb12:
 | |
| ; CHECK-NEXT:    [[VAR13:%.*]] = phi i32 [ [[VAR11]], [[BB10]] ], [ [[VAR7]], [[BB_CRIT_EDGE]] ]
 | |
| ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[VAR6]])
 | |
| ; CHECK-NEXT:    br label [[BB14]]
 | |
| ; CHECK:       bb14:
 | |
| ; CHECK-NEXT:    [[VAR15:%.*]] = phi i32 [ [[VAR13]], [[BB12]] ], [ 0, [[BB:%.*]] ]
 | |
| ; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[VAR2]])
 | |
| ; CHECK-NEXT:    ret i32 [[VAR15]]
 | |
| ;
 | |
| bb:
 | |
|   %var = alloca i32, align 4
 | |
|   %var1 = alloca i32, align 4
 | |
|   %var2 = bitcast i32* %var to i8*
 | |
|   call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %var2) #4
 | |
|   %var3 = call i32 @foo(i32* nonnull writeonly %var)
 | |
|   %var4 = icmp eq i32 %var3, 0
 | |
|   br i1 %var4, label %bb5, label %bb14
 | |
| 
 | |
| bb5:                                              ; preds = %bb
 | |
|   %var6 = bitcast i32* %var1 to i8*
 | |
|   call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %var6) #4
 | |
|   %var8 = load i32, i32* %var, align 4
 | |
|   %var9 = icmp eq i32 %var8, 0
 | |
|   %var7 = call i32 @foo(i32* nonnull writeonly %var1)
 | |
|   br i1 %var9, label %bb10, label %bb_crit_edge
 | |
| 
 | |
| bb10:                                             ; preds = %bb5
 | |
|   %var11 = call i32 @bar()
 | |
|   br label %bb12
 | |
| 
 | |
| bb_crit_edge:
 | |
|   br label %bb12
 | |
| 
 | |
| bb12:                                             ; preds = %bb10, %bb5
 | |
|   %var13 = phi i32 [ %var11, %bb10 ], [ %var7, %bb_crit_edge ]
 | |
|   call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %var6) #4
 | |
|   br label %bb14
 | |
| 
 | |
| bb14:                                             ; preds = %bb12, %bb
 | |
|   %var15 = phi i32 [ %var13, %bb12 ], [ 0, %bb ]
 | |
|   call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %var2)
 | |
|   ret i32 %var15
 | |
| }
 | |
| 
 | |
| declare i32 @unknown(i32* %dest)
 | |
| 
 | |
| define i32 @sink_to_use(i1 %c) {
 | |
| ; CHECK-LABEL: @sink_to_use(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[VAR:%.*]] = alloca i32, align 4
 | |
| ; CHECK-NEXT:    [[VAR3:%.*]] = call i32 @unknown(i32* nonnull [[VAR]]) #[[ATTR1:[0-9]+]]
 | |
| ; CHECK-NEXT:    br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]
 | |
| ; CHECK:       early_return:
 | |
| ; CHECK-NEXT:    ret i32 0
 | |
| ; CHECK:       use_block:
 | |
| ; CHECK-NEXT:    ret i32 [[VAR3]]
 | |
| ;
 | |
| entry:
 | |
|   %var = alloca i32, align 4
 | |
|   %var3 = call i32 @unknown(i32* %var) argmemonly nounwind willreturn
 | |
|   br i1 %c, label %early_return, label %use_block
 | |
| 
 | |
| early_return:
 | |
|   ret i32 0
 | |
| 
 | |
| use_block:
 | |
|   ret i32 %var3
 | |
| }
 | |
| 
 | |
| define i32 @neg_infinite_loop(i1 %c) {
 | |
| ; CHECK-LABEL: @neg_infinite_loop(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[VAR:%.*]] = alloca i32, align 4
 | |
| ; CHECK-NEXT:    [[VAR3:%.*]] = call i32 @unknown(i32* nonnull [[VAR]]) #[[ATTR2:[0-9]+]]
 | |
| ; CHECK-NEXT:    br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]
 | |
| ; CHECK:       early_return:
 | |
| ; CHECK-NEXT:    ret i32 0
 | |
| ; CHECK:       use_block:
 | |
| ; CHECK-NEXT:    ret i32 [[VAR3]]
 | |
| ;
 | |
| entry:
 | |
|   %var = alloca i32, align 4
 | |
|   %var3 = call i32 @unknown(i32* %var) argmemonly nounwind
 | |
|   br i1 %c, label %early_return, label %use_block
 | |
| 
 | |
| early_return:
 | |
|   ret i32 0
 | |
| 
 | |
| use_block:
 | |
|   ret i32 %var3
 | |
| }
 | |
| 
 | |
| define i32 @neg_throw(i1 %c) {
 | |
| ; CHECK-LABEL: @neg_throw(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[VAR:%.*]] = alloca i32, align 4
 | |
| ; CHECK-NEXT:    [[VAR3:%.*]] = call i32 @unknown(i32* nonnull [[VAR]]) #[[ATTR3:[0-9]+]]
 | |
| ; CHECK-NEXT:    br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]
 | |
| ; CHECK:       early_return:
 | |
| ; CHECK-NEXT:    ret i32 0
 | |
| ; CHECK:       use_block:
 | |
| ; CHECK-NEXT:    ret i32 [[VAR3]]
 | |
| ;
 | |
| entry:
 | |
|   %var = alloca i32, align 4
 | |
|   %var3 = call i32 @unknown(i32* %var) argmemonly willreturn
 | |
|   br i1 %c, label %early_return, label %use_block
 | |
| 
 | |
| early_return:
 | |
|   ret i32 0
 | |
| 
 | |
| use_block:
 | |
|   ret i32 %var3
 | |
| }
 | |
| 
 | |
| define i32 @neg_unknown_write(i1 %c) {
 | |
| ; CHECK-LABEL: @neg_unknown_write(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[VAR:%.*]] = alloca i32, align 4
 | |
| ; CHECK-NEXT:    [[VAR3:%.*]] = call i32 @unknown(i32* nonnull [[VAR]]) #[[ATTR4:[0-9]+]]
 | |
| ; CHECK-NEXT:    br i1 [[C:%.*]], label [[EARLY_RETURN:%.*]], label [[USE_BLOCK:%.*]]
 | |
| ; CHECK:       early_return:
 | |
| ; CHECK-NEXT:    ret i32 0
 | |
| ; CHECK:       use_block:
 | |
| ; CHECK-NEXT:    ret i32 [[VAR3]]
 | |
| ;
 | |
| entry:
 | |
|   %var = alloca i32, align 4
 | |
|   %var3 = call i32 @unknown(i32* %var) nounwind willreturn
 | |
|   br i1 %c, label %early_return, label %use_block
 | |
| 
 | |
| early_return:
 | |
|   ret i32 0
 | |
| 
 | |
| use_block:
 | |
|   ret i32 %var3
 | |
| }
 | |
| 
 | |
| declare i32 @bar()
 | |
| declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
 | |
| declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
 |