mirror of
https://github.com/RPCS3/llvm.git
synced 2025-03-04 00:29:28 +00:00

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293494 91177308-0d34-0410-b5e6-96231b3b80d8
324 lines
11 KiB
C++
324 lines
11 KiB
C++
//===-- CoroInstr.h - Coroutine Intrinsics Instruction Wrappers -*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// This file defines classes that make it really easy to deal with intrinsic
|
|
// functions with the isa/dyncast family of functions. In particular, this
|
|
// allows you to do things like:
|
|
//
|
|
// if (auto *SF = dyn_cast<CoroSubFnInst>(Inst))
|
|
// ... SF->getFrame() ...
|
|
//
|
|
// All intrinsic function calls are instances of the call instruction, so these
|
|
// are all subclasses of the CallInst class. Note that none of these classes
|
|
// has state or virtual methods, which is an important part of this gross/neat
|
|
// hack working.
|
|
//
|
|
// The helpful comment above is borrowed from llvm/IntrinsicInst.h, we keep
|
|
// coroutine intrinsic wrappers here since they are only used by the passes in
|
|
// the Coroutine library.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H
|
|
#define LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
|
|
namespace llvm {
|
|
|
|
/// This class represents the llvm.coro.subfn.addr instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroSubFnInst : public IntrinsicInst {
|
|
enum { FrameArg, IndexArg };
|
|
|
|
public:
|
|
enum ResumeKind {
|
|
RestartTrigger = -1,
|
|
ResumeIndex,
|
|
DestroyIndex,
|
|
CleanupIndex,
|
|
IndexLast,
|
|
IndexFirst = RestartTrigger
|
|
};
|
|
|
|
Value *getFrame() const { return getArgOperand(FrameArg); }
|
|
ResumeKind getIndex() const {
|
|
int64_t Index = getRawIndex()->getValue().getSExtValue();
|
|
assert(Index >= IndexFirst && Index < IndexLast &&
|
|
"unexpected CoroSubFnInst index argument");
|
|
return static_cast<ResumeKind>(Index);
|
|
}
|
|
|
|
ConstantInt *getRawIndex() const {
|
|
return cast<ConstantInt>(getArgOperand(IndexArg));
|
|
}
|
|
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_subfn_addr;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.alloc instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroAllocInst : public IntrinsicInst {
|
|
public:
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_alloc;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.alloc instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroIdInst : public IntrinsicInst {
|
|
enum { AlignArg, PromiseArg, CoroutineArg, InfoArg };
|
|
|
|
public:
|
|
CoroAllocInst *getCoroAlloc() {
|
|
for (User *U : users())
|
|
if (auto *CA = dyn_cast<CoroAllocInst>(U))
|
|
return CA;
|
|
return nullptr;
|
|
}
|
|
|
|
IntrinsicInst *getCoroBegin() {
|
|
for (User *U : users())
|
|
if (auto *II = dyn_cast<IntrinsicInst>(U))
|
|
if (II->getIntrinsicID() == Intrinsic::coro_begin)
|
|
return II;
|
|
llvm_unreachable("no coro.begin associated with coro.id");
|
|
}
|
|
|
|
AllocaInst *getPromise() const {
|
|
Value *Arg = getArgOperand(PromiseArg);
|
|
return isa<ConstantPointerNull>(Arg)
|
|
? nullptr
|
|
: cast<AllocaInst>(Arg->stripPointerCasts());
|
|
}
|
|
|
|
void clearPromise() {
|
|
Value *Arg = getArgOperand(PromiseArg);
|
|
setArgOperand(PromiseArg,
|
|
ConstantPointerNull::get(Type::getInt8PtrTy(getContext())));
|
|
if (isa<AllocaInst>(Arg))
|
|
return;
|
|
assert((isa<BitCastInst>(Arg) || isa<GetElementPtrInst>(Arg)) &&
|
|
"unexpected instruction designating the promise");
|
|
// TODO: Add a check that any remaining users of Inst are after coro.begin
|
|
// or add code to move the users after coro.begin.
|
|
auto *Inst = cast<Instruction>(Arg);
|
|
if (Inst->use_empty()) {
|
|
Inst->eraseFromParent();
|
|
return;
|
|
}
|
|
Inst->moveBefore(getCoroBegin()->getNextNode());
|
|
}
|
|
|
|
// Info argument of coro.id is
|
|
// fresh out of the frontend: null ;
|
|
// outlined : {Init, Return, Susp1, Susp2, ...} ;
|
|
// postsplit : [resume, destroy, cleanup] ;
|
|
//
|
|
// If parts of the coroutine were outlined to protect against undesirable
|
|
// code motion, these functions will be stored in a struct literal referred to
|
|
// by the Info parameter. Note: this is only needed before coroutine is split.
|
|
//
|
|
// After coroutine is split, resume functions are stored in an array
|
|
// referred to by this parameter.
|
|
|
|
struct Info {
|
|
ConstantStruct *OutlinedParts = nullptr;
|
|
ConstantArray *Resumers = nullptr;
|
|
|
|
bool hasOutlinedParts() const { return OutlinedParts != nullptr; }
|
|
bool isPostSplit() const { return Resumers != nullptr; }
|
|
bool isPreSplit() const { return !isPostSplit(); }
|
|
};
|
|
Info getInfo() const {
|
|
Info Result;
|
|
auto *GV = dyn_cast<GlobalVariable>(getRawInfo());
|
|
if (!GV)
|
|
return Result;
|
|
|
|
assert(GV->isConstant() && GV->hasDefinitiveInitializer());
|
|
Constant *Initializer = GV->getInitializer();
|
|
if ((Result.OutlinedParts = dyn_cast<ConstantStruct>(Initializer)))
|
|
return Result;
|
|
|
|
Result.Resumers = cast<ConstantArray>(Initializer);
|
|
return Result;
|
|
}
|
|
Constant *getRawInfo() const {
|
|
return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts());
|
|
}
|
|
|
|
void setInfo(Constant *C) { setArgOperand(InfoArg, C); }
|
|
|
|
Function *getCoroutine() const {
|
|
return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts());
|
|
}
|
|
void setCoroutineSelf() {
|
|
assert(isa<ConstantPointerNull>(getArgOperand(CoroutineArg)) &&
|
|
"Coroutine argument is already assigned");
|
|
auto *const Int8PtrTy = Type::getInt8PtrTy(getContext());
|
|
setArgOperand(CoroutineArg,
|
|
ConstantExpr::getBitCast(getFunction(), Int8PtrTy));
|
|
}
|
|
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_id;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.frame instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst {
|
|
public:
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_frame;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.free instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst {
|
|
enum { IdArg, FrameArg };
|
|
|
|
public:
|
|
Value *getFrame() const { return getArgOperand(FrameArg); }
|
|
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_free;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This class represents the llvm.coro.begin instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst {
|
|
enum { IdArg, MemArg };
|
|
|
|
public:
|
|
CoroIdInst *getId() const { return cast<CoroIdInst>(getArgOperand(IdArg)); }
|
|
|
|
Value *getMem() const { return getArgOperand(MemArg); }
|
|
|
|
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_begin;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.save instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst {
|
|
public:
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_save;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.promise instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst {
|
|
enum { FrameArg, AlignArg, FromArg };
|
|
|
|
public:
|
|
bool isFromPromise() const {
|
|
return cast<Constant>(getArgOperand(FromArg))->isOneValue();
|
|
}
|
|
unsigned getAlignment() const {
|
|
return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue();
|
|
}
|
|
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_promise;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.suspend instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public IntrinsicInst {
|
|
enum { SaveArg, FinalArg };
|
|
|
|
public:
|
|
CoroSaveInst *getCoroSave() const {
|
|
Value *Arg = getArgOperand(SaveArg);
|
|
if (auto *SI = dyn_cast<CoroSaveInst>(Arg))
|
|
return SI;
|
|
assert(isa<ConstantTokenNone>(Arg));
|
|
return nullptr;
|
|
}
|
|
bool isFinal() const {
|
|
return cast<Constant>(getArgOperand(FinalArg))->isOneValue();
|
|
}
|
|
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_suspend;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.size instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst {
|
|
public:
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_size;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
/// This represents the llvm.coro.end instruction.
|
|
class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst {
|
|
enum { FrameArg, UnwindArg };
|
|
|
|
public:
|
|
bool isFallthrough() const { return !isUnwind(); }
|
|
bool isUnwind() const {
|
|
return cast<Constant>(getArgOperand(UnwindArg))->isOneValue();
|
|
}
|
|
|
|
// Methods to support type inquiry through isa, cast, and dyn_cast:
|
|
static inline bool classof(const IntrinsicInst *I) {
|
|
return I->getIntrinsicID() == Intrinsic::coro_end;
|
|
}
|
|
static inline bool classof(const Value *V) {
|
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
|
}
|
|
};
|
|
|
|
} // End namespace llvm.
|
|
|
|
#endif
|