brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.8 KiB · 37aec85 Raw
67 lines · plain
1; Tests that CoroSplit does not place a dynamically sized alloca (a VLA) on the2; coroutine frame when it does not actually live across a suspend point, even if3; its address escapes to a call.4;5; This is the glibc _nl_load_locale shape on the wasm32 coro arm: a VLA path6; buffer is filled and handed by pointer to a (non-capturing) syscall wrapper,7; all before the first suspend, and is never used afterwards. The generic8; "escaped => must live on frame" heuristic used to collect such an alloca onto9; the frame; FrameTypeBuilder::addFieldForAllocas then sorted the frame allocas10; by AllocaInst::getAllocationSize(), which is std::nullopt for a VLA, and (with11; assertions disabled, as in the shipped toolchain) dereferenced the empty12; optional. That made the sort comparator non-deterministic and corrupted the13; frame layout -> SIGSEGV while splitting the coroutine. With assertions it hit14; "Coroutines cannot handle non static allocas yet".15;16; A VLA whose uses do not cross a suspend does not belong on the frame at all --17; it stays a normal stack alloca in the ramp function -- so the coroutine now18; splits cleanly. reuse-storage selects OptimizeFrame, matching clang at -O2.19;20; RUN: opt < %s -passes='cgscc(coro-split<reuse-storage>)' -S | FileCheck %s21 22define ptr @f(i32 %n) presplitcoroutine {23entry:24  %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)25  %size = call i32 @llvm.coro.size.i32()26  %alloc = call ptr @malloc(i32 %size)27  %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc)28  ; A dynamically sized alloca whose address escapes (no nocapture) to a call,29  ; all before the suspend, and which is dead afterwards.30  %vla = alloca i8, i32 %n, align 1631  call void @use(ptr %vla)32  %sp = call i8 @llvm.coro.suspend(token none, i1 false)33  switch i8 %sp, label %suspend [i8 0, label %resume34                                 i8 1, label %cleanup]35resume:36  br label %cleanup37 38cleanup:39  %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)40  call void @free(ptr %mem)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 splits cleanly (no crash). The VLA stays a normal dynamic alloca49; in the ramp function rather than being materialized as a frame field.50 51; CHECK-LABEL: define ptr @f(52; CHECK:         %vla = alloca i8, i32 %n53; CHECK:         call void @use(ptr %vla)54 55; The resume clone exists (i.e. the coroutine was actually split).56; CHECK-LABEL: define internal fastcc void @f.resume(57 58declare token @llvm.coro.id(i32, ptr, ptr, ptr)59declare i32 @llvm.coro.size.i32()60declare ptr @llvm.coro.begin(token, ptr)61declare i8 @llvm.coro.suspend(token, i1)62declare ptr @llvm.coro.free(token, ptr)63declare void @llvm.coro.end(ptr, i1, token)64declare ptr @malloc(i32)65declare void @free(ptr)66declare void @use(ptr)67