Skip to content

Commit 8aca8e3

Browse files
Implement LLVM bits
1 parent d38f060 commit 8aca8e3

23 files changed

+399
-34
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===- CoroAnnotationElide.h - Optimizing a coro_must_elide call ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// \file
10+
// This pass transforms all Call or Invoke instructions that are annotated
11+
// "coro_must_elide" to call the `.noalloc` variant of coroutine instead.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_TRANSFORMS_COROUTINES_COROANNOTATIONELIDE_H
16+
#define LLVM_TRANSFORMS_COROUTINES_COROANNOTATIONELIDE_H
17+
18+
#include "llvm/Analysis/CGSCCPassManager.h"
19+
#include "llvm/Analysis/LazyCallGraph.h"
20+
#include "llvm/IR/PassManager.h"
21+
22+
namespace llvm {
23+
24+
struct CoroAnnotationElidePass : PassInfoMixin<CoroAnnotationElidePass> {
25+
CoroAnnotationElidePass() {}
26+
27+
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
28+
LazyCallGraph &CG, CGSCCUpdateResult &UR);
29+
30+
static bool isRequired() { return false; }
31+
};
32+
} // end namespace llvm
33+
34+
#endif // LLVM_TRANSFORMS_COROUTINES_COROANNOTATIONELIDE_H

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#include "llvm/Target/TargetMachine.h"
135135
#include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h"
136136
#include "llvm/Transforms/CFGuard.h"
137+
#include "llvm/Transforms/Coroutines/CoroAnnotationElide.h"
137138
#include "llvm/Transforms/Coroutines/CoroCleanup.h"
138139
#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h"
139140
#include "llvm/Transforms/Coroutines/CoroEarly.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "llvm/Support/VirtualFileSystem.h"
3333
#include "llvm/Target/TargetMachine.h"
3434
#include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h"
35+
#include "llvm/Transforms/Coroutines/CoroAnnotationElide.h"
3536
#include "llvm/Transforms/Coroutines/CoroCleanup.h"
3637
#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h"
3738
#include "llvm/Transforms/Coroutines/CoroEarly.h"
@@ -968,8 +969,8 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
968969
// it's been modified since.
969970
MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor(
970971
RequireAnalysisPass<ShouldNotRunFunctionPassesAnalysis, Function>()));
971-
972972
MainCGPipeline.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
973+
MainCGPipeline.addPass(CoroAnnotationElidePass());
973974

974975
// Make sure we don't affect potential future NoRerun CGSCC adaptors.
975976
MIWP.addLateModulePass(createModuleToFunctionPassAdaptor(

llvm/lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ CGSCC_PASS("attributor-light-cgscc", AttributorLightCGSCCPass())
234234
CGSCC_PASS("invalidate<all>", InvalidateAllAnalysesPass())
235235
CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
236236
CGSCC_PASS("openmp-opt-cgscc", OpenMPOptCGSCCPass())
237+
CGSCC_PASS("coro-annotation-elide", CoroAnnotationElidePass())
237238
#undef CGSCC_PASS
238239

239240
#ifndef CGSCC_PASS_WITH_PARAMS

llvm/lib/Transforms/Coroutines/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_llvm_component_library(LLVMCoroutines
22
Coroutines.cpp
3+
CoroAnnotationElide.cpp
34
CoroCleanup.cpp
45
CoroConditionalWrapper.cpp
56
CoroEarly.cpp
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//===- CoroSplit.cpp - Converts a coroutine into a state machine ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
//===----------------------------------------------------------------------===//
10+
11+
#include "llvm/Transforms/Coroutines/CoroAnnotationElide.h"
12+
13+
#include "llvm/Analysis/LazyCallGraph.h"
14+
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
15+
#include "llvm/IR/Analysis.h"
16+
#include "llvm/IR/IRBuilder.h"
17+
#include "llvm/IR/InstIterator.h"
18+
#include "llvm/IR/Instruction.h"
19+
#include "llvm/IR/Module.h"
20+
#include "llvm/IR/PassManager.h"
21+
#include "llvm/Transforms/Utils/CallGraphUpdater.h"
22+
23+
#include <cassert>
24+
25+
using namespace llvm;
26+
27+
#define DEBUG_TYPE "coro-annotation-elide"
28+
29+
#define CORO_MUST_ELIDE_ANNOTATION "coro_must_elide"
30+
31+
static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
32+
for (Instruction &I : F->getEntryBlock())
33+
if (!isa<AllocaInst>(&I))
34+
return &I;
35+
llvm_unreachable("no terminator in the entry block");
36+
}
37+
38+
static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
39+
Align FrameAlign) {
40+
LLVMContext &C = Caller->getContext();
41+
BasicBlock::iterator InsertPt =
42+
getFirstNonAllocaInTheEntryBlock(Caller)->getIterator();
43+
const DataLayout &DL = Caller->getDataLayout();
44+
auto FrameTy = ArrayType::get(Type::getInt8Ty(C), FrameSize);
45+
auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt);
46+
Frame->setAlignment(FrameAlign);
47+
return new BitCastInst(Frame, PointerType::getUnqual(C), "vFrame", InsertPt);
48+
}
49+
50+
static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
51+
uint64_t FrameSize, Align FrameAlign) {
52+
auto *FramePtr = allocateFrameInCaller(Caller, FrameSize, FrameAlign);
53+
auto NewCBInsertPt = CB->getIterator();
54+
llvm::CallBase *NewCB = nullptr;
55+
SmallVector<Value *, 4> NewArgs;
56+
NewArgs.append(CB->arg_begin(), CB->arg_end());
57+
NewArgs.push_back(FramePtr);
58+
59+
if (auto *CI = dyn_cast<CallInst>(CB)) {
60+
auto *NewCI = CallInst::Create(NewCallee->getFunctionType(), NewCallee,
61+
NewArgs, "", NewCBInsertPt);
62+
NewCI->setTailCallKind(CI->getTailCallKind());
63+
NewCB = NewCI;
64+
} else if (auto *II = dyn_cast<InvokeInst>(CB)) {
65+
NewCB = InvokeInst::Create(NewCallee->getFunctionType(), NewCallee,
66+
II->getNormalDest(), II->getUnwindDest(),
67+
NewArgs, std::nullopt, "", NewCBInsertPt);
68+
} else {
69+
llvm_unreachable("CallBase should either be Call or Invoke!");
70+
}
71+
72+
NewCB->setCalledFunction(NewCallee->getFunctionType(), NewCallee);
73+
NewCB->setCallingConv(CB->getCallingConv());
74+
NewCB->setAttributes(CB->getAttributes());
75+
NewCB->setDebugLoc(CB->getDebugLoc());
76+
std::copy(CB->bundle_op_info_begin(), CB->bundle_op_info_end(),
77+
NewCB->bundle_op_info_begin());
78+
79+
NewCB->removeFnAttr(llvm::Attribute::CoroMustElide);
80+
CB->replaceAllUsesWith(NewCB);
81+
CB->eraseFromParent();
82+
}
83+
84+
PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
85+
CGSCCAnalysisManager &AM,
86+
LazyCallGraph &CG,
87+
CGSCCUpdateResult &UR) {
88+
bool Changed = false;
89+
CallGraphUpdater CGUpdater;
90+
CGUpdater.initialize(CG, C, AM, UR);
91+
92+
auto &FAM =
93+
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
94+
95+
for (LazyCallGraph::Node &N : C) {
96+
Function *Callee = &N.getFunction();
97+
Function *NewCallee = Callee->getParent()->getFunction(
98+
(Callee->getName() + ".noalloc").str());
99+
if (!NewCallee) {
100+
continue;
101+
}
102+
103+
auto FramePtrArgPosition = NewCallee->arg_size() - 1;
104+
auto FrameSize =
105+
NewCallee->getParamDereferenceableBytes(FramePtrArgPosition);
106+
auto FrameAlign =
107+
NewCallee->getParamAlign(FramePtrArgPosition).valueOrOne();
108+
109+
SmallVector<CallBase *, 4> Users;
110+
for (auto *U : Callee->users()) {
111+
if (auto *CB = dyn_cast<CallBase>(U)) {
112+
Users.push_back(CB);
113+
}
114+
}
115+
116+
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*Callee);
117+
118+
for (auto *CB : Users) {
119+
auto *Caller = CB->getFunction();
120+
if (Caller && Caller->isPresplitCoroutine() &&
121+
CB->hasFnAttr(llvm::Attribute::CoroMustElide)) {
122+
processCall(CB, Caller, NewCallee, FrameSize, FrameAlign);
123+
CGUpdater.reanalyzeFunction(*Caller);
124+
125+
ORE.emit([&]() {
126+
return OptimizationRemark(DEBUG_TYPE, "CoroAnnotationElide", Caller)
127+
<< "'" << ore::NV("callee", Callee->getName())
128+
<< "' elided in '" << ore::NV("caller", Caller->getName());
129+
});
130+
Changed = true;
131+
}
132+
}
133+
}
134+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
135+
}

llvm/lib/Transforms/Coroutines/CoroInternal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ bool declaresIntrinsics(const Module &M,
2626
const std::initializer_list<StringRef>);
2727
void replaceCoroFree(CoroIdInst *CoroId, bool Elide);
2828

29+
void suppressCoroAllocs(CoroIdInst *CoroId);
30+
void suppressCoroAllocs(LLVMContext &Context,
31+
ArrayRef<CoroAllocInst *> CoroAllocs);
32+
2933
/// Attempts to rewrite the location operand of debug intrinsics in terms of
3034
/// the coroutine frame pointer, folding pointer offsets into the DIExpression
3135
/// of the intrinsic.

0 commit comments

Comments
 (0)