Skip to content

Introduce SymbolObjectCodeRequest #33954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions include/swift/AST/IRGenRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class IRGenOptions;
class SILModule;
class SILOptions;
struct TBDGenOptions;
class TBDGenDescriptor;

namespace irgen {
class IRGenModule;
Expand Down Expand Up @@ -126,6 +127,9 @@ class GeneratedModule final {
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;
Expand All @@ -143,12 +147,13 @@ struct IRGenDescriptor {
llvm::GlobalVariable **outModuleHash;

friend llvm::hash_code hash_value(const IRGenDescriptor &owner) {
return llvm::hash_combine(owner.Ctx);
return llvm::hash_combine(owner.Ctx, owner.SymbolsToEmit, owner.SILMod);
}

friend bool operator==(const IRGenDescriptor &lhs,
const IRGenDescriptor &rhs) {
return lhs.Ctx == rhs.Ctx;
return lhs.Ctx == rhs.Ctx && lhs.SymbolsToEmit == rhs.SymbolsToEmit &&
lhs.SILMod == rhs.SILMod;
}

friend bool operator!=(const IRGenDescriptor &lhs,
Expand All @@ -162,9 +167,10 @@ struct IRGenDescriptor {
const TBDGenOptions &TBDOpts, const SILOptions &SILOpts,
Lowering::TypeConverter &Conv, std::unique_ptr<SILModule> &&SILMod,
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
StringRef PrivateDiscriminator,
StringRef PrivateDiscriminator, SymsToEmit symsToEmit = None,
llvm::GlobalVariable **outModuleHash = nullptr) {
return IRGenDescriptor{file,
symsToEmit,
Opts,
TBDOpts,
SILOpts,
Expand All @@ -182,10 +188,11 @@ struct IRGenDescriptor {
const TBDGenOptions &TBDOpts, const SILOptions &SILOpts,
Lowering::TypeConverter &Conv,
std::unique_ptr<SILModule> &&SILMod, StringRef ModuleName,
const PrimarySpecificPaths &PSPs,
const PrimarySpecificPaths &PSPs, SymsToEmit symsToEmit = None,
ArrayRef<std::string> parallelOutputFilenames = {},
llvm::GlobalVariable **outModuleHash = nullptr) {
return IRGenDescriptor{M,
symsToEmit,
Opts,
TBDOpts,
SILOpts,
Expand All @@ -198,13 +205,17 @@ struct IRGenDescriptor {
outModuleHash};
}

/// Retrieves the files to perform IR generation for.
TinyPtrVector<FileUnit *> getFiles() const;
/// 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;
};
Expand Down Expand Up @@ -254,6 +265,26 @@ class OptimizedIRRequest
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"
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/IRGenTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ SWIFT_REQUEST(IRGen, IRGenRequest,
SWIFT_REQUEST(IRGen, OptimizedIRRequest,
GeneratedModule(IRGenDescriptor),
Uncached, NoLocationInfo)
SWIFT_REQUEST(IRGen, SymbolObjectCodeRequest,
StringRef(SymbolsToEmit, IRGenDescriptor),
Cached, NoLocationInfo)
33 changes: 22 additions & 11 deletions include/swift/AST/SILGenRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/AST/ASTTypeIDs.h"
#include "swift/AST/EvaluatorDependencies.h"
#include "swift/AST/SimpleRequest.h"
#include "swift/SIL/SILDeclRef.h"

namespace swift {

Expand All @@ -40,22 +41,30 @@ template<typename Request>
void reportEvaluatedRequest(UnifiedStatsReporter &stats,
const Request &request);

using SILRefsToEmit = llvm::SmallVector<SILDeclRef, 1>;

/// Describes a file or module to be lowered to SIL.
struct ASTLoweringDescriptor {
llvm::PointerUnion<FileUnit *, ModuleDecl *> context;
Lowering::TypeConverter &conv;
const SILOptions &opts;

/// A specific set of SILDeclRefs to emit. If set, only these refs will be
/// emitted. Otherwise the entire \c context will be emitted.
Optional<SILRefsToEmit> refsToEmit;

friend llvm::hash_code hash_value(const ASTLoweringDescriptor &owner) {
return llvm::hash_combine(owner.context, (void *)&owner.conv,
(void *)&owner.opts);
(void *)&owner.opts,
owner.refsToEmit);
}

friend bool operator==(const ASTLoweringDescriptor &lhs,
const ASTLoweringDescriptor &rhs) {
return lhs.context == rhs.context &&
&lhs.conv == &rhs.conv &&
&lhs.opts == &rhs.opts;
&lhs.opts == &rhs.opts &&
lhs.refsToEmit == rhs.refsToEmit;
}

friend bool operator!=(const ASTLoweringDescriptor &lhs,
Expand All @@ -65,19 +74,21 @@ struct ASTLoweringDescriptor {

public:
static ASTLoweringDescriptor
forFile(FileUnit &sf, Lowering::TypeConverter &conv, const SILOptions &opts) {
return ASTLoweringDescriptor{&sf, conv, opts};
forFile(FileUnit &sf, Lowering::TypeConverter &conv, const SILOptions &opts,
Optional<SILRefsToEmit> refsToEmit = None) {
return ASTLoweringDescriptor{&sf, conv, opts, refsToEmit};
}

static ASTLoweringDescriptor forWholeModule(ModuleDecl *mod,
Lowering::TypeConverter &conv,
const SILOptions &opts) {
return ASTLoweringDescriptor{mod, conv, opts};
static ASTLoweringDescriptor
forWholeModule(ModuleDecl *mod, Lowering::TypeConverter &conv,
const SILOptions &opts,
Optional<SILRefsToEmit> refsToEmit = None) {
return ASTLoweringDescriptor{mod, conv, opts, refsToEmit};
}

/// For a single file input, returns a single element array containing that
/// file. Otherwise returns an array of each file in the module.
ArrayRef<FileUnit *> getFiles() const;
/// Retrieves the files to generate SIL for. If the descriptor is configured
/// only to emit a specific set of SILDeclRefs, this will be empty.
ArrayRef<FileUnit *> getFilesToEmit() const;

/// If the module or file contains SIL that needs parsing, returns the file
/// to be parsed, or \c nullptr if parsing isn't required.
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Basic/AnyValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ namespace llvm {
hash_code hash_value(const llvm::PointerUnion<PT1, PT2> &ptr) {
return hash_value(ptr.getOpaqueValue());
}

// FIXME: Belongs in LLVM itself
template<typename T>
hash_code hash_value(const llvm::Optional<T> &opt) {
if (!opt)
return 1;
return hash_value(*opt);
}
}

namespace swift {
Expand Down
8 changes: 4 additions & 4 deletions include/swift/SIL/SILDeclRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,10 @@ struct SILDeclRef {
SILLinkage getLinkage(ForDefinition_t forDefinition) const;

/// Return the hash code for the SIL declaration.
llvm::hash_code getHashCode() const {
return llvm::hash_combine(loc.getOpaqueValue(),
static_cast<int>(kind),
isForeign, defaultArgIndex);
friend llvm::hash_code hash_value(const SILDeclRef &ref) {
return llvm::hash_combine(ref.loc.getOpaqueValue(),
static_cast<int>(ref.kind),
ref.isForeign, ref.defaultArgIndex);
}

bool operator==(SILDeclRef rhs) const {
Expand Down
6 changes: 5 additions & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "swift/SIL/FormalLinkage.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILModule.h"
#include "swift/Subsystems.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/GlobalDecl.h"
Expand Down Expand Up @@ -443,7 +444,10 @@ class PrettySynthesizedFileUnitEmission : public llvm::PrettyStackTraceEntry {

/// Emit all the top-level code in the source file.
void IRGenModule::emitSourceFile(SourceFile &SF) {
assert(SF.ASTStage == SourceFile::TypeChecked);
// Type-check the file if we haven't already (this may be necessary for .sil
// files, which don't get fully type-checked by parsing).
performTypeChecking(SF);

PrettySourceFileEmission StackEntry(SF);

// Emit types and other global decls.
Expand Down
91 changes: 80 additions & 11 deletions lib/IRGen/IRGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SILGenRequests.h"
#include "swift/AST/SILOptimizerRequests.h"
#include "swift/AST/TBDGenRequests.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Dwarf.h"
#include "swift/Basic/Platform.h"
Expand All @@ -40,6 +41,7 @@
#include "swift/SILOptimizer/PassManager/PassPipeline.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/Subsystems.h"
#include "swift/TBDGen/TBDGen.h"
#include "../Serialization/ModuleFormat.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
Expand Down Expand Up @@ -907,6 +909,52 @@ static void runIRGenPreparePasses(SILModule &Module,
executePassPipelinePlan(&Module, plan, /*isMandatory*/ true, &IRModule);
}

namespace {
using IREntitiesToEmit = SmallVector<LinkEntity, 1>;

struct SymbolSourcesToEmit {
SILRefsToEmit silRefsToEmit;
IREntitiesToEmit irEntitiesToEmit;
};

static Optional<SymbolSourcesToEmit>
getSymbolSourcesToEmit(const IRGenDescriptor &desc) {
if (!desc.SymbolsToEmit)
return None;

assert(!desc.SILMod && "Already emitted SIL?");

// First retrieve the symbol source map to figure out what we need to build,
// making sure to include non-public symbols.
auto &ctx = desc.getParentModule()->getASTContext();
auto tbdDesc = desc.getTBDGenDescriptor();
tbdDesc.getOptions().PublicSymbolsOnly = false;
auto symbolMap =
llvm::cantFail(ctx.evaluator(SymbolSourceMapRequest{std::move(tbdDesc)}));

// Then split up the symbols so they can be emitted by the appropriate part
// of the pipeline.
SILRefsToEmit silRefsToEmit;
IREntitiesToEmit irEntitiesToEmit;
for (const auto &symbol : *desc.SymbolsToEmit) {
auto source = symbolMap.find(symbol);
assert(source && "Couldn't find symbol");
switch (source->kind) {
case SymbolSource::Kind::SIL:
silRefsToEmit.push_back(source->getSILDeclRef());
break;
case SymbolSource::Kind::IR:
irEntitiesToEmit.push_back(source->getIRLinkEntity());
break;
case SymbolSource::Kind::LinkerDirective:
case SymbolSource::Kind::Unknown:
llvm_unreachable("Not supported");
}
}
return SymbolSourcesToEmit{silRefsToEmit, irEntitiesToEmit};
}
} // end of anonymous namespace

/// Generates LLVM IR, runs the LLVM passes and produces the output file.
/// All this is done in a single thread.
GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
Expand All @@ -917,20 +965,25 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
auto &Ctx = M->getASTContext();
assert(!Ctx.hadError());

auto symsToEmit = getSymbolSourcesToEmit(desc);
assert(!symsToEmit || symsToEmit->irEntitiesToEmit.empty() &&
"IR symbol emission not implemented yet");

// If we've been provided a SILModule, use it. Otherwise request the lowered
// SIL for the file or module.
auto SILMod = std::unique_ptr<SILModule>(desc.SILMod);
if (!SILMod) {
auto loweringDesc =
ASTLoweringDescriptor{desc.Ctx, desc.Conv, desc.SILOpts};
auto loweringDesc = ASTLoweringDescriptor{
desc.Ctx, desc.Conv, desc.SILOpts,
symsToEmit.map([](const auto &x) { return x.silRefsToEmit; })};
SILMod = llvm::cantFail(Ctx.evaluator(LoweredSILRequest{loweringDesc}));

// If there was an error, bail.
if (Ctx.hadError())
return GeneratedModule::null();
}

auto filesToEmit = desc.getFiles();
auto filesToEmit = desc.getFilesToEmit();
auto *primaryFile =
dyn_cast_or_null<SourceFile>(desc.Ctx.dyn_cast<FileUnit *>());

Expand Down Expand Up @@ -1334,7 +1387,8 @@ GeneratedModule swift::performIRGeneration(
const auto &SILOpts = SILModPtr->getOptions();
auto desc = IRGenDescriptor::forWholeModule(
M, Opts, TBDOpts, SILOpts, SILModPtr->Types, std::move(SILMod),
ModuleName, PSPs, parallelOutputFilenames, outModuleHash);
ModuleName, PSPs, /*symsToEmit*/ None, parallelOutputFilenames,
outModuleHash);

if (Opts.shouldPerformIRGenerationInParallel() &&
!parallelOutputFilenames.empty()) {
Expand All @@ -1358,7 +1412,8 @@ performIRGeneration(FileUnit *file, const IRGenOptions &Opts,
const auto &SILOpts = SILModPtr->getOptions();
auto desc = IRGenDescriptor::forFile(
file, Opts, TBDOpts, SILOpts, SILModPtr->Types, std::move(SILMod),
ModuleName, PSPs, PrivateDiscriminator, outModuleHash);
ModuleName, PSPs, PrivateDiscriminator, /*symsToEmit*/ None,
outModuleHash);
return llvm::cantFail(file->getASTContext().evaluator(IRGenRequest{desc}));
}

Expand Down Expand Up @@ -1447,12 +1502,6 @@ GeneratedModule OptimizedIRRequest::evaluate(Evaluator &evaluator,

bindExtensions(*parentMod);

// Type-check the files that need emitting.
for (auto *file : desc.getFiles()) {
if (auto *SF = dyn_cast<SourceFile>(file))
performTypeChecking(*SF);
}

if (ctx.hadError())
return GeneratedModule::null();

Expand All @@ -1464,3 +1513,23 @@ GeneratedModule OptimizedIRRequest::evaluate(Evaluator &evaluator,
irMod.getTargetMachine());
return irMod;
}

StringRef SymbolObjectCodeRequest::evaluate(Evaluator &evaluator,
IRGenDescriptor desc) const {
auto &ctx = desc.getParentModule()->getASTContext();
auto mod = cantFail(evaluator(OptimizedIRRequest{desc}));
auto *targetMachine = mod.getTargetMachine();

// Add the passes to emit the LLVM module as object code.
// TODO: Use compileAndWriteLLVM.
legacy::PassManager emitPasses;
emitPasses.add(createTargetTransformInfoWrapperPass(
targetMachine->getTargetIRAnalysis()));

SmallString<0> output;
raw_svector_ostream os(output);
targetMachine->addPassesToEmitFile(emitPasses, os, nullptr, CGFT_ObjectFile);
emitPasses.run(*mod.getModule());
os << '\0';
return ctx.AllocateCopy(output.str());
}
Loading