1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Helper class for splitting a coroutine into separate functions. For example
// the returned-continuation coroutine is split into separate continuation
// functions.
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
#define LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Transforms/Coroutines/ABI.h"
#include "llvm/Transforms/Coroutines/CoroInstr.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
namespace llvm {
namespace coro {
enum class CloneKind {
/// The shared resume function for a switch lowering.
SwitchResume,
/// The shared unwind function for a switch lowering.
SwitchUnwind,
/// The shared cleanup function for a switch lowering.
SwitchCleanup,
/// An individual continuation function.
Continuation,
/// An async resume function.
Async,
};
class BaseCloner {
protected:
Function &OrigF;
const Twine &Suffix;
coro::Shape &Shape;
CloneKind FKind;
IRBuilder<> Builder;
TargetTransformInfo &TTI;
// Common module-level metadata that's shared between all coroutine clones and
// doesn't need to be cloned itself.
const MetadataSetTy &CommonDebugInfo;
ValueToValueMapTy VMap;
Function *NewF = nullptr;
Value *NewFramePtr = nullptr;
/// The active suspend instruction; meaningful only for continuation and async
/// ABIs.
AnyCoroSuspendInst *ActiveSuspend = nullptr;
/// Create a cloner for a continuation lowering.
BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape,
Function *NewF, AnyCoroSuspendInst *ActiveSuspend,
TargetTransformInfo &TTI, const MetadataSetTy &CommonDebugInfo)
: OrigF(OrigF), Suffix(Suffix), Shape(Shape),
FKind(Shape.ABI == ABI::Async ? CloneKind::Async
: CloneKind::Continuation),
Builder(OrigF.getContext()), TTI(TTI), CommonDebugInfo(CommonDebugInfo),
NewF(NewF), ActiveSuspend(ActiveSuspend) {
assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce ||
Shape.ABI == ABI::Async);
assert(NewF && "need existing function for continuation");
assert(ActiveSuspend && "need active suspend point for continuation");
}
public:
BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape,
CloneKind FKind, TargetTransformInfo &TTI,
const MetadataSetTy &CommonDebugInfo)
: OrigF(OrigF), Suffix(Suffix), Shape(Shape), FKind(FKind),
Builder(OrigF.getContext()), TTI(TTI),
CommonDebugInfo(CommonDebugInfo) {}
virtual ~BaseCloner() {}
/// Create a clone for a continuation lowering.
static Function *createClone(Function &OrigF, const Twine &Suffix,
coro::Shape &Shape, Function *NewF,
AnyCoroSuspendInst *ActiveSuspend,
TargetTransformInfo &TTI,
const MetadataSetTy &CommonDebugInfo) {
assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce ||
Shape.ABI == ABI::Async);
TimeTraceScope FunctionScope("BaseCloner");
BaseCloner Cloner(OrigF, Suffix, Shape, NewF, ActiveSuspend, TTI,
CommonDebugInfo);
Cloner.create();
return Cloner.getFunction();
}
Function *getFunction() const {
assert(NewF != nullptr && "declaration not yet set");
return NewF;
}
virtual void create();
protected:
bool isSwitchDestroyFunction() {
switch (FKind) {
case CloneKind::Async:
case CloneKind::Continuation:
case CloneKind::SwitchResume:
return false;
case CloneKind::SwitchUnwind:
case CloneKind::SwitchCleanup:
return true;
}
llvm_unreachable("Unknown ClonerKind enum");
}
void replaceEntryBlock();
Value *deriveNewFramePointer();
void replaceRetconOrAsyncSuspendUses();
void replaceCoroSuspends();
void replaceCoroEnds();
void replaceSwiftErrorOps();
void salvageDebugInfo();
void handleFinalSuspend();
};
class SwitchCloner : public BaseCloner {
protected:
/// Create a cloner for a switch lowering.
SwitchCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape,
CloneKind FKind, TargetTransformInfo &TTI,
const MetadataSetTy &CommonDebugInfo)
: BaseCloner(OrigF, Suffix, Shape, FKind, TTI, CommonDebugInfo) {}
void create() override;
public:
/// Create a clone for a switch lowering.
static Function *createClone(Function &OrigF, const Twine &Suffix,
coro::Shape &Shape, CloneKind FKind,
TargetTransformInfo &TTI,
const MetadataSetTy &CommonDebugInfo) {
assert(Shape.ABI == ABI::Switch);
TimeTraceScope FunctionScope("SwitchCloner");
SwitchCloner Cloner(OrigF, Suffix, Shape, FKind, TTI, CommonDebugInfo);
Cloner.create();
return Cloner.getFunction();
}
};
} // end namespace coro
} // end namespace llvm
#endif // LLVM_LIB_TRANSFORMS_COROUTINES_COROCLONER_H
|