From: Chuanqi Xu Date: Tue, 14 Feb 2023 07:19:20 +0000 (+0800) Subject: [Coroutines] Don't run optimizations for optnone functions X-Git-Tag: upstream/17.0.6~17614 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=af838c1b1c20c7b3b970e81039a1992857fe76bb;p=platform%2Fupstream%2Fllvm.git [Coroutines] Don't run optimizations for optnone functions Currently we will run two optimization (rematerialization and sink lifetime markers) unconditionally even if the coroutine is marked as optnone (O0). This looks not good. This patch disables these 2 optimizations for optnone functions. An internal change shows the change improve the compilation time for 3% in the debug build. --- diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 9f9b45c..5988ca27 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -2688,6 +2688,9 @@ static void sinkSpillUsesAfterCoroBegin(Function &F, /// hence minimizing the amount of data we end up putting on the frame. static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, SuspendCrossingInfo &Checker) { + if (F.hasOptNone()) + return; + DominatorTree DT(F); // Collect all possible basic blocks which may dominate all uses of allocas. @@ -2892,6 +2895,9 @@ void coro::salvageDebugInfo( static void doRematerializations( Function &F, SuspendCrossingInfo &Checker, const std::function &MaterializableCallback) { + if (F.hasOptNone()) + return; + SpillInfo Spills; // See if there are materializable instructions across suspend points diff --git a/llvm/test/Transforms/Coroutines/coro-materialize.ll b/llvm/test/Transforms/Coroutines/coro-materialize.ll index b45df16..7385337 100644 --- a/llvm/test/Transforms/Coroutines/coro-materialize.ll +++ b/llvm/test/Transforms/Coroutines/coro-materialize.ll @@ -3,11 +3,13 @@ ; See that we only spilled one value for f ; CHECK: %f.Frame = type { ptr, ptr, i32, i1 } +; CHECK: %f_optnone.Frame = type { ptr, ptr, i32, i32, i1 } ; Check other variants where different levels of materialization are achieved ; CHECK: %f_multiple_remat.Frame = type { ptr, ptr, i32, i1 } ; CHECK: %f_common_def.Frame = type { ptr, ptr, i32, i1 } ; CHECK: %f_common_def_multi_result.Frame = type { ptr, ptr, i32, i1 } ; CHECK-LABEL: @f( +; CHECK-LABEL: @f_optnone ; CHECK-LABEL: @f_multiple_remat( ; CHECK-LABEL: @f_common_def( ; CHECK-LABEL: @f_common_def_multi_result( @@ -43,6 +45,38 @@ suspend: ret ptr %hdl } +; Checks that we won't transform functions with optnone. +define ptr @f_optnone(i32 %n) presplitcoroutine optnone noinline { +entry: + %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) + %size = call i32 @llvm.coro.size.i32() + %alloc = call ptr @malloc(i32 %size) + %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc) + + %inc1 = add i32 %n, 1 + %sp1 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %sp1, label %suspend [i8 0, label %resume1 + i8 1, label %cleanup] +resume1: + %inc2 = add i32 %inc1, 1 + %sp2 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %sp1, label %suspend [i8 0, label %resume2 + i8 1, label %cleanup] + +resume2: + call void @print(i32 %inc1) + call void @print(i32 %inc2) + br label %cleanup + +cleanup: + %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) + call void @free(ptr %mem) + br label %suspend +suspend: + call i1 @llvm.coro.end(ptr %hdl, i1 0) + ret ptr %hdl +} + define ptr @f_multiple_remat(i32 %n) presplitcoroutine { entry: %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) diff --git a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll index f399429..d7978c9 100644 --- a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll +++ b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll @@ -2,6 +2,9 @@ ; sink them to the places after the suspend block. ; RUN: opt -opaque-pointers=0 < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s +; CHECK: %a.Frame = type { void (%a.Frame*)*, void (%a.Frame*)*, %"struct.lean_future::Awaiter", i1 } +; CHECK: %a_optnone.Frame = type { void (%a_optnone.Frame*)*, void (%a_optnone.Frame*)*, %"struct.lean_future::Awaiter", i8*, i32*, i32, i1 } + %"struct.std::coroutine_handle" = type { i8* } %"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" } %"struct.lean_future::Awaiter" = type { i32, %"struct.std::coroutine_handle.0" } @@ -53,6 +56,37 @@ exit: ; CHECK-NEXT: call void @print(i32 %val) ; CHECK-NEXT: ret void +define void @a_optnone() presplitcoroutine optnone noinline { +entry: + %ref.tmp7 = alloca %"struct.lean_future::Awaiter", align 8 + %testval = alloca i32 + %cast = bitcast i32* %testval to i8* + ; lifetime of %testval starts here, but not used until await.ready. + call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast) + %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %alloc = call i8* @malloc(i64 16) #3 + %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc) + + %save = call token @llvm.coro.save(i8* null) + %Result.i19 = getelementptr inbounds %"struct.lean_future::Awaiter", %"struct.lean_future::Awaiter"* %ref.tmp7, i64 0, i32 0 + %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) + switch i8 %suspend, label %exit [ + i8 0, label %await.ready + i8 1, label %exit + ] +await.ready: + %StrayCoroSave = call token @llvm.coro.save(i8* null) + %val = load i32, i32* %Result.i19 + %test = load i32, i32* %testval + call void @print(i32 %test) + call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast) + call void @print(i32 %val) + br label %exit +exit: + call i1 @llvm.coro.end(i8* null, i1 false) + ret void +} + declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) declare i1 @llvm.coro.alloc(token) #3 declare noalias nonnull i8* @"\01??2@YAPEAX_K@Z"(i64) local_unnamed_addr