From 51fbd187066fe4a0ba0deb1beb75106b088edd21 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Thu, 1 Jul 2021 10:59:57 +0800 Subject: [PATCH] [Coroutine] Recommit Add statistics for the number of elided coroutine Now we lack a benchmark to measure the performance change for each commit. Since coro elide is the main optimization in coroutine module, I wonder it may be an estimation to count the number of elided coroutine in private code bases. e.g., for a certain commit, if we found that the number of elided goes down, we could find it before the commit check-in. Reviewed By: lxfind Differential Revision: https://reviews.llvm.org/D105095 --- llvm/lib/Transforms/Coroutines/CoroElide.cpp | 4 + .../Transforms/Coroutines/coro-elide-count.ll | 148 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 llvm/test/Transforms/Coroutines/coro-elide-count.ll diff --git a/llvm/lib/Transforms/Coroutines/CoroElide.cpp b/llvm/lib/Transforms/Coroutines/CoroElide.cpp index 9f0adae58948ad..18bd56c45de19f 100644 --- a/llvm/lib/Transforms/Coroutines/CoroElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroElide.cpp @@ -9,6 +9,7 @@ #include "llvm/Transforms/Coroutines/CoroElide.h" #include "CoroInternal.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/IR/Dominators.h" @@ -21,6 +22,8 @@ using namespace llvm; #define DEBUG_TYPE "coro-elide" +STATISTIC(NumOfCoroElided, "The # of coroutine get elided."); + namespace { // Created on demand if the coro-elide pass has work to do. struct Lowerer : coro::LowererBase { @@ -344,6 +347,7 @@ bool Lowerer::processCoroId(CoroIdInst *CoroId, AAResults &AA, elideHeapAllocations(CoroId->getFunction(), FrameSizeAndAlign.first, FrameSizeAndAlign.second, AA); coro::replaceCoroFree(CoroId, /*Elide=*/true); + NumOfCoroElided++; } return true; diff --git a/llvm/test/Transforms/Coroutines/coro-elide-count.ll b/llvm/test/Transforms/Coroutines/coro-elide-count.ll new file mode 100644 index 00000000000000..ae40a74f41d5da --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-elide-count.ll @@ -0,0 +1,148 @@ +; Tests that the number elided coroutine is record correctly. +; REQUIRES: asserts +; +; RUN: opt < %s -S \ +; RUN: -passes='cgscc(repeat<2>(inline,function(coro-elide,dce)))' -stats 2>&1 \ +; RUN: | FileCheck %s + +; CHECK: 2 coro-elide - The # of coroutine get elided. + +declare void @print(i32) nounwind + +; resume part of the coroutine +define fastcc void @f.resume(i8*) { + tail call void @print(i32 0) + ret void +} + +; destroy part of the coroutine +define fastcc void @f.destroy(i8*) { + tail call void @print(i32 1) + ret void +} + +; cleanup part of the coroutine +define fastcc void @f.cleanup(i8*) { + tail call void @print(i32 2) + ret void +} + +@f.resumers = internal constant [3 x void (i8*)*] [void (i8*)* @f.resume, + void (i8*)* @f.destroy, + void (i8*)* @f.cleanup] + +; a coroutine start function +define i8* @f() { +entry: + %id = call token @llvm.coro.id(i32 0, i8* null, + i8* bitcast (i8*()* @f to i8*), + i8* bitcast ([3 x void (i8*)*]* @f.resumers to i8*)) + %alloc = call i1 @llvm.coro.alloc(token %id) + %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + ret i8* %hdl +} + +define void @callResume() { +entry: + %hdl = call i8* @f() + + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + call fastcc void %1(i8* %hdl) + + %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1) + %3 = bitcast i8* %2 to void (i8*)* + call fastcc void %3(i8* %hdl) + + ret void +} + +define void @callResumeMultiRet(i1 %b) { +entry: + %hdl = call i8* @f() + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + call fastcc void %1(i8* %hdl) + br i1 %b, label %destroy, label %ret + +destroy: + %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1) + %3 = bitcast i8* %2 to void (i8*)* + call fastcc void %3(i8* %hdl) + ret void + +ret: + ret void +} + +define void @callResumeMultiRetDommmed(i1 %b) { +entry: + %hdl = call i8* @f() + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + call fastcc void %1(i8* %hdl) + %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1) + %3 = bitcast i8* %2 to void (i8*)* + call fastcc void %3(i8* %hdl) + br i1 %b, label %destroy, label %ret + +destroy: + ret void + +ret: + ret void +} + +define void @eh() personality i8* null { +entry: + %hdl = call i8* @f() + + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + invoke void %1(i8* %hdl) + to label %cont unwind label %ehcleanup +cont: + ret void + +ehcleanup: + %tok = cleanuppad within none [] + cleanupret from %tok unwind to caller +} + +; no devirtualization here, since coro.begin info parameter is null +define void @no_devirt_info_null() { +entry: + %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + call fastcc void %1(i8* %hdl) + + %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1) + %3 = bitcast i8* %2 to void (i8*)* + call fastcc void %3(i8* %hdl) + + ret void +} + +; no devirtualization here, since coro.begin is not visible +define void @no_devirt_no_begin(i8* %hdl) { +entry: + + %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0) + %1 = bitcast i8* %0 to void (i8*)* + call fastcc void %1(i8* %hdl) + + %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1) + %3 = bitcast i8* %2 to void (i8*)* + call fastcc void %3(i8* %hdl) + + ret void +} + +declare token @llvm.coro.id(i32, i8*, i8*, i8*) +declare i8* @llvm.coro.begin(token, i8*) +declare i8* @llvm.coro.frame() +declare i8* @llvm.coro.subfn.addr(i8*, i8) +declare i1 @llvm.coro.alloc(token)