blob: 796dd0a6a11de5fa2e5801a9e0b3b666347ab2b2 [file] [log] [blame]
//===--- IRGenRequests.h - IRGen Requests -----------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines IRGen requests.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGen_REQUESTS_H
#define SWIFT_IRGen_REQUESTS_H
#include "swift/AST/ASTTypeIDs.h"
#include "swift/AST/EvaluatorDependencies.h"
#include "swift/AST/SimpleRequest.h"
#include "swift/Basic/PrimarySpecificPaths.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Target/TargetMachine.h"
namespace swift {
class SourceFile;
class IRGenOptions;
class SILModule;
class SILOptions;
struct TBDGenOptions;
class TBDGenDescriptor;
namespace irgen {
class IRGenModule;
};
}; // namespace swift
namespace llvm {
class GlobalVariable;
class LLVMContext;
class Module;
class TargetMachine;
namespace orc {
class ThreadSafeModule;
}; // namespace orc
}; // namespace llvm
namespace swift {
/// A pair consisting of an \c LLVMContext and an \c llvm::Module that enforces
/// exclusive ownership of those resources, and ensures that they are
/// deallocated or transferred together.
///
/// Note that the underlying module and context are either both valid pointers
/// or both null. This class forbids the remaining cases by construction.
class GeneratedModule final {
private:
std::unique_ptr<llvm::LLVMContext> Context;
std::unique_ptr<llvm::Module> Module;
std::unique_ptr<llvm::TargetMachine> Target;
GeneratedModule() : Context(nullptr), Module(nullptr), Target(nullptr) {}
GeneratedModule(GeneratedModule const &) = delete;
GeneratedModule &operator=(GeneratedModule const &) = delete;
public:
/// Construct a \c GeneratedModule that owns a given module and context.
///
/// The given pointers must not be null. If a null \c GeneratedModule is
/// needed, use \c GeneratedModule::null() instead.
explicit GeneratedModule(std::unique_ptr<llvm::LLVMContext> &&Context,
std::unique_ptr<llvm::Module> &&Module,
std::unique_ptr<llvm::TargetMachine> &&Target)
: Context(std::move(Context)), Module(std::move(Module)),
Target(std::move(Target)) {
assert(getModule() && "Use GeneratedModule::null() instead");
assert(getContext() && "Use GeneratedModule::null() instead");
assert(getTargetMachine() && "Use GeneratedModule::null() instead");
}
GeneratedModule(GeneratedModule &&) = default;
GeneratedModule& operator=(GeneratedModule &&) = default;
public:
/// Construct a \c GeneratedModule that does not own any resources.
static GeneratedModule null() {
return GeneratedModule{};
}
public:
explicit operator bool() const {
return Module != nullptr && Context != nullptr;
}
public:
const llvm::Module *getModule() const { return Module.get(); }
llvm::Module *getModule() { return Module.get(); }
const llvm::LLVMContext *getContext() const { return Context.get(); }
llvm::LLVMContext *getContext() { return Context.get(); }
const llvm::TargetMachine *getTargetMachine() const { return Target.get(); }
llvm::TargetMachine *getTargetMachine() { return Target.get(); }
public:
/// Release ownership of the context and module to the caller, consuming
/// this value in the process.
///
/// The REPL is the only caller that needs this. New uses of this function
/// should be avoided at all costs.
std::pair<llvm::LLVMContext *, llvm::Module *> release() && {
return { Context.release(), Module.release() };
}
public:
/// Transfers ownership of the underlying module and context to an
/// ORC-compatible context.
llvm::orc::ThreadSafeModule intoThreadSafeContext() &&;
};
struct IRGenDescriptor {
llvm::PointerUnion<FileUnit *, ModuleDecl *> Ctx;
using SymsToEmit = Optional<llvm::SmallVector<std::string, 1>>;
SymsToEmit SymbolsToEmit;
const IRGenOptions &Opts;
const TBDGenOptions &TBDOpts;
const SILOptions &SILOpts;
Lowering::TypeConverter &Conv;
/// The SILModule to emit. If \c nullptr, a fresh SILModule will be requested
/// during IRGen (which will eventually become the default behavior).
SILModule *SILMod;
StringRef ModuleName;
const PrimarySpecificPaths &PSPs;
StringRef PrivateDiscriminator;
ArrayRef<std::string> parallelOutputFilenames;
llvm::GlobalVariable **outModuleHash;
friend llvm::hash_code hash_value(const IRGenDescriptor &owner) {
return llvm::hash_combine(owner.Ctx, owner.SymbolsToEmit, owner.SILMod);
}
friend bool operator==(const IRGenDescriptor &lhs,
const IRGenDescriptor &rhs) {
return lhs.Ctx == rhs.Ctx && lhs.SymbolsToEmit == rhs.SymbolsToEmit &&
lhs.SILMod == rhs.SILMod;
}
friend bool operator!=(const IRGenDescriptor &lhs,
const IRGenDescriptor &rhs) {
return !(lhs == rhs);
}
public:
static IRGenDescriptor
forFile(FileUnit *file, const IRGenOptions &Opts,
const TBDGenOptions &TBDOpts, const SILOptions &SILOpts,
Lowering::TypeConverter &Conv, std::unique_ptr<SILModule> &&SILMod,
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
StringRef PrivateDiscriminator, SymsToEmit symsToEmit = None,
llvm::GlobalVariable **outModuleHash = nullptr) {
return IRGenDescriptor{file,
symsToEmit,
Opts,
TBDOpts,
SILOpts,
Conv,
SILMod.release(),
ModuleName,
PSPs,
PrivateDiscriminator,
{},
outModuleHash};
}
static IRGenDescriptor
forWholeModule(ModuleDecl *M, const IRGenOptions &Opts,
const TBDGenOptions &TBDOpts, const SILOptions &SILOpts,
Lowering::TypeConverter &Conv,
std::unique_ptr<SILModule> &&SILMod, StringRef ModuleName,
const PrimarySpecificPaths &PSPs, SymsToEmit symsToEmit = None,
ArrayRef<std::string> parallelOutputFilenames = {},
llvm::GlobalVariable **outModuleHash = nullptr) {
return IRGenDescriptor{M,
symsToEmit,
Opts,
TBDOpts,
SILOpts,
Conv,
SILMod.release(),
ModuleName,
PSPs,
"",
parallelOutputFilenames,
outModuleHash};
}
/// Retrieves the files to perform IR generation for. If the descriptor is
/// configured only to emit a specific set of symbols, this will be empty.
TinyPtrVector<FileUnit *> getFilesToEmit() const;
/// For a single file, returns its parent module, otherwise returns the module
/// itself.
ModuleDecl *getParentModule() const;
/// Retrieve a descriptor suitable for generating TBD for the file or module.
TBDGenDescriptor getTBDGenDescriptor() const;
/// Compute the linker directives to emit.
std::vector<std::string> getLinkerDirectives() const;
};
/// Report that a request of the given kind is being evaluated, so it
/// can be recorded by the stats reporter.
template<typename Request>
void reportEvaluatedRequest(UnifiedStatsReporter &stats,
const Request &request);
class IRGenRequest
: public SimpleRequest<IRGenRequest, GeneratedModule(IRGenDescriptor),
RequestFlags::Uncached |
RequestFlags::DependencySource> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
GeneratedModule
evaluate(Evaluator &evaluator, IRGenDescriptor desc) const;
public:
// Incremental dependencies.
evaluator::DependencySource
readDependencySource(const evaluator::DependencyRecorder &) const;
};
void simple_display(llvm::raw_ostream &out, const IRGenDescriptor &d);
SourceLoc extractNearestSourceLoc(const IRGenDescriptor &desc);
/// Returns the optimized IR for a given file or module. Note this runs the
/// entire compiler pipeline and ignores the passed SILModule.
class OptimizedIRRequest
: public SimpleRequest<OptimizedIRRequest, GeneratedModule(IRGenDescriptor),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
GeneratedModule evaluate(Evaluator &evaluator, IRGenDescriptor desc) const;
};
using SymbolsToEmit = SmallVector<std::string, 1>;
/// Return the object code for a specific set of symbols in a file or module.
class SymbolObjectCodeRequest : public SimpleRequest<SymbolObjectCodeRequest,
StringRef(IRGenDescriptor),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
StringRef evaluate(Evaluator &evaluator, IRGenDescriptor desc) const;
public:
// Caching.
bool isCached() const { return true; }
};
/// The zone number for IRGen.
#define SWIFT_TYPEID_ZONE IRGen
#define SWIFT_TYPEID_HEADER "swift/AST/IRGenTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER
// Set up reporting of evaluated requests.
#define SWIFT_REQUEST(Zone, RequestType, Sig, Caching, LocOptions) \
template<> \
inline void reportEvaluatedRequest(UnifiedStatsReporter &stats, \
const RequestType &request) { \
++stats.getFrontendCounters().RequestType; \
}
#include "swift/AST/IRGenTypeIDZone.def"
#undef SWIFT_REQUEST
} // end namespace swift
#endif // SWIFT_IRGen_REQUESTS_H