forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			190 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -o - -emit-llvm -O1 \
 | |
| // RUN:     -fexceptions -fcxx-exceptions -mllvm -simplifycfg-sink-common=false | FileCheck %s
 | |
| //
 | |
| // We should emit lifetime.ends for these temporaries in both the 'exception'
 | |
| // and 'normal' paths in functions.
 | |
| //
 | |
| // -O1 is necessary to make lifetime markers appear.
 | |
| 
 | |
| struct Large {
 | |
|   int cs[32];
 | |
| };
 | |
| 
 | |
| Large getLarge();
 | |
| 
 | |
| // Used to ensure we emit invokes.
 | |
| struct NontrivialDtor {
 | |
|   int i;
 | |
|   ~NontrivialDtor();
 | |
| };
 | |
| 
 | |
| // CHECK-LABEL: define void @_Z33cleanupsAreEmittedWithoutTryCatchv
 | |
| void cleanupsAreEmittedWithoutTryCatch() {
 | |
| // CHECK: %[[CLEAN:[^ ]+]] = bitcast %struct.NontrivialDtor* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[CLEAN]])
 | |
| // CHECK: %[[T1:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CONT:[^ ]+]] unwind label %[[LPAD:[^ ]+]]
 | |
| //
 | |
| // CHECK: [[CONT]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK: %[[T2:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CONT2:[^ ]+]] unwind label %[[LPAD2:.+]]
 | |
| //
 | |
| // CHECK: [[CONT2]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[CLEAN]])
 | |
| // CHECK: ret void
 | |
| //
 | |
| // CHECK: [[LPAD]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK: br label %[[EHCLEANUP:.+]]
 | |
| //
 | |
| // CHECK: [[LPAD2]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK: br label %[[EHCLEANUP]]
 | |
| //
 | |
| // CHECK: [[EHCLEANUP]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[CLEAN]])
 | |
| 
 | |
|   NontrivialDtor clean;
 | |
| 
 | |
|   getLarge();
 | |
|   getLarge();
 | |
| }
 | |
| 
 | |
| // CHECK-LABEL: define void @_Z30cleanupsAreEmittedWithTryCatchv
 | |
| void cleanupsAreEmittedWithTryCatch() {
 | |
| // CHECK: %[[CLEAN:[^ ]+]] = bitcast %struct.NontrivialDtor* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[CLEAN]])
 | |
| // CHECK: %[[T1:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CONT:[^ ]+]] unwind label %[[LPAD:[^ ]+]]
 | |
| //
 | |
| // CHECK: [[CONT]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK: %[[T2:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CONT2:[^ ]+]] unwind label %[[LPAD2:.+]]
 | |
| //
 | |
| // CHECK: [[CONT2]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK: br label %[[TRY_CONT:.+]]
 | |
| //
 | |
| // CHECK: [[LPAD]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK: br label %[[CATCH:.+]]
 | |
| //
 | |
| // CHECK: [[LPAD2]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK: br label %[[CATCH]]
 | |
| //
 | |
| // CHECK: [[CATCH]]:
 | |
| // CHECK-NOT: call void @llvm.lifetime
 | |
| // CHECK: invoke void
 | |
| // CHECK-NEXT: to label %[[TRY_CONT]] unwind label %[[OUTER_LPAD:.+]]
 | |
| //
 | |
| // CHECK: [[TRY_CONT]]:
 | |
| // CHECK: %[[T_OUTER:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T_OUTER]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[OUTER_CONT:[^ ]+]] unwind label %[[OUTER_LPAD2:.+]]
 | |
| //
 | |
| // CHECK: [[OUTER_CONT]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T_OUTER]])
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[CLEAN]])
 | |
| // CHECK: ret void
 | |
| //
 | |
| // CHECK: [[OUTER_LPAD]]:
 | |
| // CHECK-NOT: call void @llvm.lifetime
 | |
| // CHECK: br label %[[EHCLEANUP:.+]]
 | |
| //
 | |
| // CHECK: [[OUTER_LPAD2]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T_OUTER]])
 | |
| // CHECK: br label %[[EHCLEANUP]]
 | |
| //
 | |
| // CHECK: [[EHCLEANUP]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[CLEAN]])
 | |
| 
 | |
|   NontrivialDtor clean;
 | |
| 
 | |
|   try {
 | |
|     getLarge();
 | |
|     getLarge();
 | |
|   } catch (...) {}
 | |
| 
 | |
|   getLarge();
 | |
| }
 | |
| 
 | |
| // CHECK-LABEL: define void @_Z39cleanupInTryHappensBeforeCleanupInCatchv
 | |
| void cleanupInTryHappensBeforeCleanupInCatch() {
 | |
| // CHECK: %[[T1:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CONT:[^ ]+]] unwind label %[[LPAD:[^ ]+]]
 | |
| //
 | |
| // CHECK: [[CONT]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK: br label %[[TRY_CONT]]
 | |
| //
 | |
| // CHECK: [[LPAD]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T1]])
 | |
| // CHECK: br i1 {{[^,]+}}, label %[[CATCH_INT_MATCH:[^,]+]], label %[[CATCH_ALL:.+]]
 | |
| //
 | |
| // CHECK: [[CATCH_INT_MATCH]]:
 | |
| // CHECK: %[[T2:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CATCH_INT_CONT:[^ ]+]] unwind label %[[CATCH_INT_LPAD:[^ ]+]]
 | |
| //
 | |
| // CHECK: [[CATCH_INT_CONT]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK: br label %[[TRY_CONT]]
 | |
| //
 | |
| // CHECK: [[TRY_CONT]]:
 | |
| // CHECK: ret void
 | |
| //
 | |
| // CHECK: [[CATCH_ALL]]:
 | |
| // CHECK: %[[T3:[^ ]+]] = bitcast %struct.Large* %{{[^ ]+}} to i8*
 | |
| // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* nonnull %[[T3]])
 | |
| // CHECK-NEXT: invoke void @_Z8getLargev
 | |
| // CHECK-NEXT:     to label %[[CATCH_ALL_CONT:[^ ]+]] unwind label %[[CATCH_ALL_LPAD:[^ ]+]]
 | |
| //
 | |
| // CHECK: [[CATCH_ALL_CONT]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T3]])
 | |
| // CHECK: br label %[[TRY_CONT]]
 | |
| //
 | |
| // CHECK: [[CATCH_ALL_LPAD]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T3]])
 | |
| //
 | |
| // CHECK: [[CATCH_INT_LPAD]]:
 | |
| // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* nonnull %[[T2]])
 | |
| // CHECK-NOT: call void @llvm.lifetime
 | |
| 
 | |
|   try {
 | |
|     getLarge();
 | |
|   } catch (const int &) {
 | |
|     getLarge();
 | |
|   } catch (...) {
 | |
|     getLarge();
 | |
|   }
 | |
| }
 | |
| 
 | |
| // FIXME: We don't currently emit lifetime markers for aggregate by-value
 | |
| // temporaries (e.g. given a function `Large combine(Large, Large);`
 | |
| // combine(getLarge(), getLarge()) "leaks" two `Large`s). We probably should. We
 | |
| // also don't emit markers for things like:
 | |
| //
 | |
| // {
 | |
| //   Large L = getLarge();
 | |
| //   combine(L, L);
 | |
| // }
 | |
| //
 | |
| // Though this arguably isn't as bad, since we pass a pointer to `L` as one of
 | |
| // the two args.
 |