; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Verifies that we insert spills of PHI instruction _after) all PHI Nodes ; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s ; Verifies that the both phis are stored correctly in the coroutine frame ; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i32, i32, i1 } define i8* @f(i1 %n) presplitcoroutine { ; CHECK-LABEL: @f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* bitcast ([3 x void (%f.Frame*)*]* @f.resumers to i8*)) ; CHECK-NEXT: [[ALLOC:%.*]] = call i8* @malloc(i32 32) ; CHECK-NEXT: [[HDL:%.*]] = call noalias nonnull i8* @llvm.coro.begin(token [[ID]], i8* [[ALLOC]]) ; CHECK-NEXT: [[FRAMEPTR:%.*]] = bitcast i8* [[HDL]] to %f.Frame* ; CHECK-NEXT: [[RESUME_ADDR:%.*]] = getelementptr inbounds [[F_FRAME:%.*]], %f.Frame* [[FRAMEPTR]], i32 0, i32 0 ; CHECK-NEXT: store void (%f.Frame*)* @f.resume, void (%f.Frame*)** [[RESUME_ADDR]], align 8 ; CHECK-NEXT: [[DESTROY_ADDR:%.*]] = getelementptr inbounds [[F_FRAME]], %f.Frame* [[FRAMEPTR]], i32 0, i32 1 ; CHECK-NEXT: store void (%f.Frame*)* @f.destroy, void (%f.Frame*)** [[DESTROY_ADDR]], align 8 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[N:%.*]], i32 0, i32 2 ; CHECK-NEXT: [[SPEC_SELECT5:%.*]] = select i1 [[N]], i32 1, i32 3 ; CHECK-NEXT: [[PHI2_SPILL_ADDR:%.*]] = getelementptr inbounds [[F_FRAME]], %f.Frame* [[FRAMEPTR]], i32 0, i32 3 ; CHECK-NEXT: store i32 [[SPEC_SELECT5]], i32* [[PHI2_SPILL_ADDR]], align 4 ; CHECK-NEXT: [[PHI1_SPILL_ADDR:%.*]] = getelementptr inbounds [[F_FRAME]], %f.Frame* [[FRAMEPTR]], i32 0, i32 2 ; CHECK-NEXT: store i32 [[SPEC_SELECT]], i32* [[PHI1_SPILL_ADDR]], align 4 ; CHECK-NEXT: [[INDEX_ADDR4:%.*]] = getelementptr inbounds [[F_FRAME]], %f.Frame* [[FRAMEPTR]], i32 0, i32 4 ; CHECK-NEXT: store i1 false, i1* [[INDEX_ADDR4]], align 1 ; CHECK-NEXT: ret i8* [[HDL]] ; entry: %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) %size = call i32 @llvm.coro.size.i32() %alloc = call i8* @malloc(i32 %size) %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc) br i1 %n, label %begin, label %alt alt: br label %begin begin: %phi1 = phi i32 [ 0, %entry ], [ 2, %alt ] %phi2 = phi i32 [ 1, %entry ], [ 3, %alt ] %sp1 = call i8 @llvm.coro.suspend(token none, i1 false) switch i8 %sp1, label %suspend [i8 0, label %resume i8 1, label %cleanup] resume: call i32 @print(i32 %phi1) call i32 @print(i32 %phi2) br label %cleanup cleanup: %mem = call i8* @llvm.coro.free(token %id, i8* %hdl) call void @free(i8* %mem) br label %suspend suspend: call i1 @llvm.coro.end(i8* %hdl, i1 0) ret i8* %hdl } declare i8* @llvm.coro.free(token, i8*) declare i32 @llvm.coro.size.i32() declare i8 @llvm.coro.suspend(token, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) declare token @llvm.coro.id(i32, i8*, i8*, i8*) declare i1 @llvm.coro.alloc(token) declare i8* @llvm.coro.begin(token, i8*) declare i1 @llvm.coro.end(i8*, i1) declare noalias i8* @malloc(i32) declare i32 @print(i32) declare void @free(i8*)