72 lines · plain
1; Tests that CoroSplit can normalize a presplit coroutine whose body contains2; an indirectbr (a computed goto, e.g. glibc printf_positional's format3; dispatch) feeding a block with a multi-incoming PHI.4;5; Such an edge is a critical edge out of an indirectbr: the successor's address6; is taken, so the ordinary SplitEdge cannot split it and used to return null,7; which rewritePHIs then dereferenced via setName -> SIGSEGV in8; coro::normalizeCoroutine. normalizeCoroutine now runs9; SplitIndirectBrCriticalEdges first, which clones the PHI-only target so the10; indirectbr keeps a single un-split edge and the direct predecessors get their11; own clone, after which rewritePHIs succeeds.12;13; RUN: opt < %s -passes='cgscc(coro-split)' -S | FileCheck %s14 15define ptr @f(ptr %dst) presplitcoroutine {16entry:17 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)18 %hdl = call ptr @llvm.coro.begin(token %id, ptr null)19 call void @print(i32 0)20 %sp = call i8 @llvm.coro.suspend(token none, i1 false)21 switch i8 %sp, label %suspend [i8 0, label %resume22 i8 1, label %cleanup]23resume:24 ; computed-goto: an indirectbr with a runtime target so it is not25 ; constant-folded before CoroSplit normalizes the function.26 %addr = load ptr, ptr %dst27 indirectbr ptr %addr, [label %target, label %other]28 29other:30 br label %target31 32target:33 ; multi-incoming PHI; one predecessor (%resume) is the indirectbr, so the34 ; resume->target edge is a critical edge out of an indirectbr.35 %p = phi i32 [ 1, %resume ], [ 2, %other ]36 call void @print(i32 %p)37 br label %cleanup38 39cleanup:40 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)41 br label %suspend42 43suspend:44 call void @llvm.coro.end(ptr %hdl, i1 0, token none)45 ret ptr %hdl46}47 48; The coroutine must split cleanly (no crash). The indirectbr is preserved with49; both of its targets, and the indirectbr's PHI-only target is cloned for the50; direct predecessor so the values still merge correctly (1 via the indirectbr,51; 2 via %other).52 53; CHECK-LABEL: define ptr @f(54; CHECK: indirectbr ptr %addr, [label %target, label %other]55; CHECK: other:56; CHECK: br label %target.clone57; CHECK: target:58; CHECK: %ind = phi i32 [ 1, %resume ]59; CHECK: %merge = phi i3260; CHECK: target.clone:61; CHECK: %p.clone = phi i32 [ 2, %other ]62 63; The resume clone exists (i.e. the coroutine was actually split).64; CHECK-LABEL: define internal fastcc void @f.resume(65 66declare ptr @llvm.coro.free(token, ptr)67declare i8 @llvm.coro.suspend(token, i1)68declare token @llvm.coro.id(i32, ptr, ptr, ptr)69declare ptr @llvm.coro.begin(token, ptr)70declare void @llvm.coro.end(ptr, i1, token)71declare void @print(i32)72