Skip to content

Commit 8d229c6

Browse files
Implement LLVM bits
1 parent d38f060 commit 8d229c6

23 files changed

+382
-33
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: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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/IR/Analysis.h"
15+
#include "llvm/IR/IRBuilder.h"
16+
#include "llvm/IR/InstIterator.h"
17+
#include "llvm/IR/Instruction.h"
18+
#include "llvm/IR/Module.h"
19+
20+
#include <cassert>
21+
22+
using namespace llvm;
23+
24+
#define DEBUG_TYPE "coro-annotation-elide"
25+
26+
#define CORO_MUST_ELIDE_ANNOTATION "coro_must_elide"
27+
28+
static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
29+
for (Instruction &I : F->getEntryBlock())
30+
if (!isa<AllocaInst>(&I))
31+
return &I;
32+
llvm_unreachable("no terminator in the entry block");
33+
}
34+
35+
static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
36+
Align FrameAlign) {
37+
LLVMContext &C = Caller->getContext();
38+
BasicBlock::iterator InsertPt =
39+
getFirstNonAllocaInTheEntryBlock(Caller)->getIterator();
40+
const DataLayout &DL = Caller->getDataLayout();
41+
auto FrameTy = ArrayType::get(Type::getInt8Ty(C), FrameSize);
42+
auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt);
43+
Frame->setAlignment(FrameAlign);
44+
return new BitCastInst(Frame, PointerType::getUnqual(C), "vFrame", InsertPt);
45+
}
46+
47+
static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
48+
uint64_t FrameSize, Align FrameAlign) {
49+
auto *FramePtr = allocateFrameInCaller(Caller, FrameSize, FrameAlign);
50+
CB->setCalledFunction(NewCallee->getFunctionType(), NewCallee);
51+
auto NewCBInsertPt = CB->getIterator();
52+
llvm::CallBase *NewCB = nullptr;
53+
SmallVector<Value *, 4> NewArgs;
54+
NewArgs.append(CB->arg_begin(), CB->arg_end());
55+
NewArgs.push_back(FramePtr);
56+
57+
// TODO: See CallBase::Create(CallBase*, ...)
58+
if (auto *CI = dyn_cast<CallInst>(CB)) {
59+
auto *NewCI = CallInst::Create(NewCallee->getFunctionType(), NewCallee,
60+
NewArgs, "", NewCBInsertPt);
61+
NewCI->setTailCallKind(CI->getTailCallKind());
62+
NewCB = NewCI;
63+
} else if (auto *II = dyn_cast<InvokeInst>(CB)) {
64+
NewCB = InvokeInst::Create(NewCallee->getFunctionType(), NewCallee,
65+
II->getNormalDest(), II->getUnwindDest(),
66+
NewArgs, std::nullopt, "", NewCBInsertPt);
67+
} else {
68+
llvm_unreachable("CallBase should either be Call or Invoke!");
69+
}
70+
71+
NewCB->setCallingConv(CB->getCallingConv());
72+
NewCB->setAttributes(CB->getAttributes());
73+
NewCB->setDebugLoc(CB->getDebugLoc());
74+
std::copy(CB->bundle_op_info_begin(), CB->bundle_op_info_end(),
75+
NewCB->bundle_op_info_begin());
76+
77+
CB->replaceAllUsesWith(NewCB);
78+
CB->eraseFromParent();
79+
}
80+
81+
PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
82+
CGSCCAnalysisManager &AM,
83+
LazyCallGraph &CG,
84+
CGSCCUpdateResult &UR) {
85+
bool Changed = false;
86+
87+
for (LazyCallGraph::Node &N : C) {
88+
Function *Callee = &N.getFunction();
89+
Function *NewCallee = Callee->getParent()->getFunction(
90+
(Callee->getName() + ".noalloc").str());
91+
if (!NewCallee) {
92+
continue;
93+
}
94+
95+
auto FramePtrArgPosition = NewCallee->arg_size() - 1;
96+
auto FrameSize =
97+
NewCallee->getParamDereferenceableBytes(FramePtrArgPosition);
98+
auto FrameAlign =
99+
NewCallee->getParamAlign(FramePtrArgPosition).valueOrOne();
100+
101+
SmallVector<CallBase *, 4> Users;
102+
for (auto *U : Callee->users()) {
103+
if (auto *CB = dyn_cast<CallBase>(U)) {
104+
Users.push_back(CB);
105+
}
106+
}
107+
108+
for (auto *CB : Users) {
109+
auto *Caller = CB->getFunction();
110+
if (Caller && Caller->isPresplitCoroutine() &&
111+
CB->hasFnAttr(llvm::Attribute::CoroMustElide)) {
112+
processCall(CB, Caller, NewCallee, FrameSize, FrameAlign);
113+
C.getOuterRefSCC().replaceNodeFunction(N, *NewCallee);
114+
Changed = true;
115+
}
116+
}
117+
}
118+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
119+
}

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)