Skip to content

Rework the integrated REPL to use separate modules for every line #19485

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 8 commits into from
Sep 26, 2018
6 changes: 2 additions & 4 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,9 @@ class SILModule {
/// should contain source files.
///
/// If a source file is provided, SIL will only be emitted for decls in that
/// source file, starting from the specified element number.
/// source file.
static std::unique_ptr<SILModule>
constructSIL(ModuleDecl *M, SILOptions &Options, FileUnit *sf = nullptr,
Optional<unsigned> startElem = None,
bool isWholeModule = false);
constructSIL(ModuleDecl *M, SILOptions &Options, FileUnit *sf = nullptr);

/// \brief Create and return an empty SIL module that we can
/// later parse SIL bodies directly into, without converting from an AST.
Expand Down
16 changes: 4 additions & 12 deletions include/swift/Subsystems.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,21 +237,14 @@ namespace swift {

/// Turn the given module into SIL IR.
///
/// The module must contain source files.
///
/// if \p wholeModuleCompilation is true, the optimizer assumes that the SIL
/// of all files in the module is present in the SILModule.
/// The module must contain source files. The optimizer will assume that the
/// SIL of all files in the module is present in the SILModule.
std::unique_ptr<SILModule>
performSILGeneration(ModuleDecl *M, SILOptions &options,
bool wholeModuleCompilation = false);
performSILGeneration(ModuleDecl *M, SILOptions &options);

/// Turn a source file into SIL IR.
///
/// If \p StartElem is provided, the module is assumed to be only part of the
/// SourceFile, and any optimizations should take that into account.
std::unique_ptr<SILModule>
performSILGeneration(FileUnit &SF, SILOptions &options,
Optional<unsigned> StartElem = None);
performSILGeneration(FileUnit &SF, SILOptions &options);

using ModuleOrSourceFile = PointerUnion<ModuleDecl *, SourceFile *>;

Expand Down Expand Up @@ -283,7 +276,6 @@ namespace swift {
std::unique_ptr<SILModule> SILMod,
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
llvm::LLVMContext &LLVMContext,
unsigned StartElem = 0,
llvm::GlobalVariable **outModuleHash = nullptr);

/// Given an already created LLVM module, construct a pass pipeline and run
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,12 @@ SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const
if (next->getName() == getParentModule()->getName())
return true;

// Hack: Assume other REPL files already have their libraries linked.
if (!next->getFiles().empty())
if (auto *nextSource = dyn_cast<SourceFile>(next->getFiles().front()))
if (nextSource->Kind == SourceFileKind::REPL)
return true;

next->collectLinkLibraries(callback);
return true;
});
Expand Down
8 changes: 4 additions & 4 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ generateSILModules(CompilerInvocation &Invocation, CompilerInstance &Instance) {
if (!opts.InputsAndOutputs.hasPrimaryInputs()) {
// If there are no primary inputs the compiler is in WMO mode and builds one
// SILModule for the entire module.
auto SM = performSILGeneration(mod, SILOpts, true);
auto SM = performSILGeneration(mod, SILOpts);
std::deque<PostSILGenInputs> PSGIs;
const PrimarySpecificPaths PSPs =
Instance.getPrimarySpecificPathsForWholeModuleOptimizationMode();
Expand All @@ -832,7 +832,7 @@ generateSILModules(CompilerInvocation &Invocation, CompilerInstance &Instance) {
// once for each such input.
std::deque<PostSILGenInputs> PSGIs;
for (auto *PrimaryFile : Instance.getPrimarySourceFiles()) {
auto SM = performSILGeneration(*PrimaryFile, SILOpts, None);
auto SM = performSILGeneration(*PrimaryFile, SILOpts);
const PrimarySpecificPaths PSPs =
Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile);
PSGIs.push_back(PostSILGenInputs{std::move(SM), true, PrimaryFile, PSPs});
Expand All @@ -846,7 +846,7 @@ generateSILModules(CompilerInvocation &Invocation, CompilerInstance &Instance) {
if (Invocation.getFrontendOptions().InputsAndOutputs.isInputPrimary(
SASTF->getFilename())) {
assert(PSGIs.empty() && "Can only handle one primary AST input");
auto SM = performSILGeneration(*SASTF, SILOpts, None);
auto SM = performSILGeneration(*SASTF, SILOpts);
const PrimarySpecificPaths &PSPs =
Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename());
PSGIs.push_back(
Expand Down Expand Up @@ -1130,7 +1130,7 @@ static void generateIR(IRGenOptions &IRGenOpts, std::unique_ptr<SILModule> SM,
IRModule = MSF.is<SourceFile *>()
? performIRGeneration(IRGenOpts, *MSF.get<SourceFile *>(),
std::move(SM), OutputFilename, PSPs,
LLVMContext, 0, &HashGlobal)
LLVMContext, &HashGlobal)
: performIRGeneration(IRGenOpts, MSF.get<ModuleDecl *>(),
std::move(SM), OutputFilename, PSPs,
LLVMContext, parallelOutputFilenames,
Expand Down
15 changes: 4 additions & 11 deletions lib/IDE/REPLCodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID,
CodeCompletionCallbacksFactory *CompletionCallbacksFactory) {
// Temporarily disable printing the diagnostics.
ASTContext &Ctx = SF.getASTContext();
auto DiagnosticConsumers = Ctx.Diags.takeConsumers();
DiagnosticTransaction DelayedDiags(Ctx.Diags);

std::string AugmentedCode = EnteredCode.str();
AugmentedCode += '\0';
Expand All @@ -206,30 +206,23 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID,
// Parse, typecheck and temporarily insert the incomplete code into the AST.
const unsigned OriginalDeclCount = SF.Decls.size();

unsigned CurElem = OriginalDeclCount;
PersistentParserState PersistentState(Ctx);
std::unique_ptr<DelayedParsingCallbacks> DelayedCB(
new CodeCompleteDelayedCallbacks(Ctx.SourceMgr.getCodeCompletionLoc()));
bool Done;
do {
parseIntoSourceFile(SF, *BufferID, &Done, nullptr, &PersistentState,
DelayedCB.get());
performTypeChecking(SF, PersistentState.getTopLevelContext(), None,
CurElem);
CurElem = SF.Decls.size();
} while (!Done);
performTypeChecking(SF, PersistentState.getTopLevelContext(), None,
OriginalDeclCount);

performDelayedParsing(&SF, PersistentState, CompletionCallbacksFactory);

// Now we are done with code completion. Remove the declarations we
// temporarily inserted.
SF.Decls.resize(OriginalDeclCount);

// Add the diagnostic consumers back.
for (auto DC : DiagnosticConsumers)
Ctx.Diags.addConsumer(*DC);

Ctx.Diags.resetHadAnyError();
DelayedDiags.abort();
}

void REPLCompletions::populate(SourceFile &SF, StringRef EnteredCode) {
Expand Down
6 changes: 3 additions & 3 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,13 +467,13 @@ class PrettySourceFileEmission : public llvm::PrettyStackTraceEntry {
} // end anonymous namespace

/// Emit all the top-level code in the source file.
void IRGenModule::emitSourceFile(SourceFile &SF, unsigned StartElem) {
void IRGenModule::emitSourceFile(SourceFile &SF) {
PrettySourceFileEmission StackEntry(SF);
llvm::SaveAndRestore<SourceFile *> SetCurSourceFile(CurSourceFile, &SF);

// Emit types and other global decls.
for (unsigned i = StartElem, e = SF.Decls.size(); i != e; ++i)
emitGlobalDecl(SF.Decls[i]);
for (auto *decl : SF.Decls)
emitGlobalDecl(decl);
for (auto *localDecl : SF.LocalTypeDecls)
emitGlobalDecl(localDecl);

Expand Down
30 changes: 12 additions & 18 deletions lib/IRGen/IRGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -762,15 +762,12 @@ static void runIRGenPreparePasses(SILModule &Module,

/// Generates LLVM IR, runs the LLVM passes and produces the output file.
/// All this is done in a single thread.
static std::unique_ptr<llvm::Module> performIRGeneration(IRGenOptions &Opts,
swift::ModuleDecl *M,
std::unique_ptr<SILModule> SILMod,
StringRef ModuleName,
const PrimarySpecificPaths &PSPs,
llvm::LLVMContext &LLVMContext,
SourceFile *SF = nullptr,
llvm::GlobalVariable **outModuleHash = nullptr,
unsigned StartElem = 0) {
static std::unique_ptr<llvm::Module>
performIRGeneration(IRGenOptions &Opts, ModuleDecl *M,
std::unique_ptr<SILModule> SILMod, StringRef ModuleName,
const PrimarySpecificPaths &PSPs,
llvm::LLVMContext &LLVMContext, SourceFile *SF = nullptr,
llvm::GlobalVariable **outModuleHash = nullptr) {
auto &Ctx = M->getASTContext();
assert(!Ctx.hadError());

Expand All @@ -795,13 +792,12 @@ static std::unique_ptr<llvm::Module> performIRGeneration(IRGenOptions &Opts,
irgen.emitGlobalTopLevel();

if (SF) {
IGM.emitSourceFile(*SF, StartElem);
IGM.emitSourceFile(*SF);
} else {
assert(StartElem == 0 && "no explicit source file provided");
for (auto *File : M->getFiles()) {
if (auto *nextSF = dyn_cast<SourceFile>(File)) {
if (nextSF->ASTStage >= SourceFile::TypeChecked)
IGM.emitSourceFile(*nextSF, 0);
IGM.emitSourceFile(*nextSF);
} else {
File->collectLinkLibraries([&IGM](LinkLibrary LinkLib) {
IGM.addLinkLibrary(LinkLib);
Expand Down Expand Up @@ -972,7 +968,7 @@ static void performParallelIRGeneration(
for (auto *File : M->getFiles()) {
if (auto *SF = dyn_cast<SourceFile>(File)) {
IRGenModule *IGM = irgen.getGenModule(SF);
IGM->emitSourceFile(*SF, 0);
IGM->emitSourceFile(*SF);
} else {
File->collectLinkLibraries([&](LinkLibrary LinkLib) {
irgen.getPrimaryIGM()->addLinkLibrary(LinkLib);
Expand Down Expand Up @@ -1116,12 +1112,10 @@ performIRGeneration(IRGenOptions &Opts, SourceFile &SF,
std::unique_ptr<SILModule> SILMod,
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
llvm::LLVMContext &LLVMContext,
unsigned StartElem,
llvm::GlobalVariable **outModuleHash) {
return ::performIRGeneration(Opts, SF.getParentModule(),
std::move(SILMod), ModuleName,
PSPs,
LLVMContext, &SF, outModuleHash, StartElem);
return ::performIRGeneration(Opts, SF.getParentModule(), std::move(SILMod),
ModuleName, PSPs, LLVMContext, &SF,
outModuleHash);
}

void
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ private: \

llvm::LLVMContext &getLLVMContext() const { return LLVMContext; }

void emitSourceFile(SourceFile &SF, unsigned StartElem);
void emitSourceFile(SourceFile &SF);
void addLinkLibrary(const LinkLibrary &linkLib);

/// Attempt to finalize the module.
Expand Down
73 changes: 6 additions & 67 deletions lib/Immediate/Immediate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,8 @@ bool swift::immediate::linkLLVMModules(llvm::Module *Module,
return !Failed;
}

bool swift::immediate::IRGenImportedModules(
CompilerInstance &CI, llvm::Module &Module,
llvm::SmallPtrSetImpl<swift::ModuleDecl *> &ImportedModules,
SmallVectorImpl<llvm::Function *> &InitFns, IRGenOptions &IRGenOpts,
const SILOptions &SILOpts) {
swift::ModuleDecl *M = CI.getMainModule();

bool swift::immediate::autolinkImportedModules(ModuleDecl *M,
IRGenOptions &IRGenOpts) {
// Perform autolinking.
SmallVector<LinkLibrary, 4> AllLinkLibraries(IRGenOpts.LinkLibraries);
auto addLinkLibrary = [&](LinkLibrary linkLib) {
Expand All @@ -219,63 +214,9 @@ bool swift::immediate::IRGenImportedModules(

M->collectLinkLibraries(addLinkLibrary);

tryLoadLibraries(AllLinkLibraries, CI.getASTContext().SearchPathOpts,
CI.getDiags());

ImportedModules.insert(M);
if (!CI.hasSourceImport())
return false;

// IRGen the modules this module depends on. This is only really necessary
// for imported source, but that's a very convenient thing to do in -i mode.
// FIXME: Crawling all loaded modules is a hack.
// FIXME: And re-doing SILGen, SIL-linking, SIL diagnostics, and IRGen is
// expensive, because it's not properly being limited to new things right now.
bool hadError = false;
for (auto &entry : CI.getASTContext().LoadedModules) {
swift::ModuleDecl *import = entry.second;
if (!ImportedModules.insert(import).second)
continue;

std::unique_ptr<SILModule> SILMod = performSILGeneration(import,
CI.getSILOptions());
if (runSILDiagnosticPasses(*SILMod)) {
hadError = true;
break;
}
runSILLoweringPasses(*SILMod);

const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
// FIXME: We shouldn't need to use the global context here, but
// something is persisting across calls to performIRGeneration.
auto SubModule = performIRGeneration(
IRGenOpts, import, std::move(SILMod), import->getName().str(), PSPs,
getGlobalLLVMContext(), ArrayRef<std::string>());

if (CI.getASTContext().hadError()) {
hadError = true;
break;
}

if (!linkLLVMModules(&Module, std::move(SubModule)
// TODO: reactivate the linker mode if it is
// supported in llvm again. Otherwise remove the
// commented code completely.
/*, llvm::Linker::DestroySource */)) {
hadError = true;
break;
}

// FIXME: This is an ugly hack; need to figure out how this should
// actually work.
SmallVector<char, 20> NameBuf;
StringRef InitFnName = (import->getName().str() + ".init").toStringRef(NameBuf);
llvm::Function *InitFn = Module.getFunction(InitFnName);
if (InitFn)
InitFns.push_back(InitFn);
}

return hadError;
tryLoadLibraries(AllLinkLibraries, M->getASTContext().SearchPathOpts,
M->getASTContext().Diags);
return false;
}

int swift::RunImmediately(CompilerInstance &CI, const ProcessCmdLine &CmdLine,
Expand Down Expand Up @@ -330,9 +271,7 @@ int swift::RunImmediately(CompilerInstance &CI, const ProcessCmdLine &CmdLine,
(*emplaceProcessArgs)(argBuf.data(), CmdLine.size());

SmallVector<llvm::Function*, 8> InitFns;
llvm::SmallPtrSet<swift::ModuleDecl *, 8> ImportedModules;
if (IRGenImportedModules(CI, *Module, ImportedModules, InitFns,
IRGenOpts, SILOpts))
if (autolinkImportedModules(swiftModule, IRGenOpts))
return -1;

llvm::PassManagerBuilder PMBuilder;
Expand Down
6 changes: 1 addition & 5 deletions lib/Immediate/ImmediateImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,7 @@ bool tryLoadLibraries(ArrayRef<LinkLibrary> LinkLibraries,
DiagnosticEngine &Diags);
bool linkLLVMModules(llvm::Module *Module,
std::unique_ptr<llvm::Module> SubModule);
bool IRGenImportedModules(
CompilerInstance &CI, llvm::Module &Module,
llvm::SmallPtrSetImpl<swift::ModuleDecl *> &ImportedModules,
SmallVectorImpl<llvm::Function *> &InitFns, IRGenOptions &IRGenOpts,
const SILOptions &SILOpts);
bool autolinkImportedModules(ModuleDecl *M, IRGenOptions &IRGenOpts);

} // end namespace immediate
} // end namespace swift
Expand Down
Loading