Files
swift-mirror/tools/driver/frontend_main.cpp
Erik Eckstein c16c510167 Set SILLinkage according to visibility.
Now the SILLinkage for functions and global variables is according to the swift visibility (private, internal or public).

In addition, the fact whether a function or global variable is considered as fragile, is kept in a separate flag at SIL level.
Previously the linkage was used for this (e.g. no inlining of less visible functions to more visible functions). But it had no effect,
because everything was public anyway.

For now this isFragile-flag is set for public transparent functions and for everything if a module is compiled with -sil-serialize-all,
i.e. for the stdlib.

For details see <rdar://problem/18201785> Set SILLinkage correctly and better handling of fragile functions.

The benefits of this change are:
*) Enable to eliminate unused private and internal functions
*) It should be possible now to use private in the stdlib
*) The symbol linkage is as one would expect (previously almost all symbols were public).

More details:

Specializations from fragile functions (e.g. from the stdlib) now get linkonce_odr,default
linkage instead of linkonce_odr,hidden, i.e. they have public visibility.
The reason is: if such a function is called from another fragile function (in the same module),
then it has to be visible from a third module, in case the fragile caller is inlined but not
the specialized function.

I had to update lots of test files, because many CHECK-LABEL lines include the linkage, which has changed.

The -sil-serialize-all option is now handled at SILGen and not at the Serializer.
This means that test files in sil format which are compiled with -sil-serialize-all
must have the [fragile] attribute set for all functions and globals.

The -disable-access-control option doesn't help anymore if the accessed module is not compiled
with -sil-serialize-all, because the linker will complain about unresolved symbols.

A final note: I tried to consider all the implications of this change, but it's not a low-risk change.
If you have any comments, please let me know.



Swift SVN r22215
2014-09-23 12:33:18 +00:00

429 lines
16 KiB
C++

//===-- frontend_main.cpp - Swift Compiler Frontend -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This is the entry point to the swift -frontend functionality, which
/// implements the core compiler functionality along with a number of additional
/// tools for demonstration and testing purposes.
///
//===----------------------------------------------------------------------===//
#include "swift/Subsystems.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/Mangle.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Frontend/DependencyFileGenerator.h"
#include "swift/Frontend/DiagnosticVerifier.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/Frontend/SerializedDiagnosticConsumer.h"
#include "swift/Immediate/Immediate.h"
#include "swift/Option/Options.h"
#include "swift/PrintAsObjC/PrintAsObjC.h"
#include "swift/Serialization/SerializationOptions.h"
#include "swift/SILPasses/Passes.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
using namespace swift;
static std::string displayName(StringRef MainExecutablePath) {
std::string Name = llvm::sys::path::stem(MainExecutablePath);
Name += " -frontend";
return Name;
}
static bool emitDependencies(DiagnosticEngine &Diags,
DependencyFileGenerator &DFG,
const FrontendOptions &opts) {
opts.forAllOutputPaths([&DFG](StringRef target) { DFG.addTarget(target); });
std::error_code EC;
llvm::raw_fd_ostream out(opts.DependenciesFilePath, EC,
llvm::sys::fs::F_None);
if (out.has_error() || EC) {
Diags.diagnose(SourceLoc(), diag::error_opening_output,
opts.DependenciesFilePath, EC.message());
out.clear_error();
return true;
}
DFG.writeToStream(out);
return false;
}
/// Writes SIL out to the given file.
static bool writeSIL(SILModule &SM, Module *M, bool EmitVerboseSIL,
std::string &OutputFilename, bool SortSIL) {
std::error_code EC;
llvm::raw_fd_ostream OS(OutputFilename, EC, llvm::sys::fs::F_None);
if (EC) {
M->Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_output,
OutputFilename, EC.message());
return true;
}
SM.print(OS, EmitVerboseSIL, M, SortSIL);
return false;
}
static bool printAsObjC(const std::string &path, Module *M,
StringRef bridgingHeader) {
std::error_code EC;
llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None);
if (out.has_error() || EC) {
M->getASTContext().Diags.diagnose(SourceLoc(), diag::error_opening_output,
path, EC.message());
out.clear_error();
return true;
}
auto requiredAccess = bridgingHeader.empty() ? Accessibility::Public
: Accessibility::Internal;
return printAsObjC(out, M, bridgingHeader, requiredAccess);
}
/// Performs the compile requested by the user.
/// \returns true on error
static bool performCompile(CompilerInstance &Instance,
CompilerInvocation &Invocation,
ArrayRef<const char *> Args) {
FrontendOptions opts = Invocation.getFrontendOptions();
FrontendOptions::ActionType Action = opts.RequestedAction;
if (Action == FrontendOptions::DumpParse)
Instance.performParseOnly();
else
Instance.performSema();
FrontendOptions::DebugCrashMode CrashMode = opts.CrashMode;
if (CrashMode == FrontendOptions::DebugCrashMode::AssertAfterParse)
// This assertion should always fail, per the user's request, and should
// not be converted to llvm_unreachable.
assert(0 && "This is an assertion!");
else if (CrashMode == FrontendOptions::DebugCrashMode::CrashAfterParse)
LLVM_BUILTIN_TRAP;
ASTContext &Context = Instance.getASTContext();
if (Action == FrontendOptions::REPL) {
REPLRunLoop(Instance, ProcessCmdLine(Args.begin(), Args.end()),
Invocation.getParseStdlib());
return false;
}
SourceFile *PrimarySourceFile = Instance.getPrimarySourceFile();
// We've been told to dump the AST (either after parsing or type-checking,
// which is already differentiated in CompilerInstance::performSema()),
// so dump or print the main source file and return.
if (Action == FrontendOptions::DumpParse ||
Action == FrontendOptions::DumpAST ||
Action == FrontendOptions::PrintAST) {
SourceFile *SF = PrimarySourceFile;
if (!SF) {
SourceFileKind Kind = Invocation.getInputKind();
SF = &Instance.getMainModule()->getMainSourceFile(Kind);
}
if (Action == FrontendOptions::PrintAST)
SF->print(llvm::outs(), PrintOptions::printEverything());
else
SF->dump();
return false;
}
if (Context.hadError())
return true;
// If we were asked to print Clang stats, do so.
if (opts.PrintClangStats && Context.getClangModuleLoader())
Context.getClangModuleLoader()->printStatistics();
if (DependencyTracker *DT = Instance.getDependencyTracker()) {
auto &DFG = *static_cast<DependencyFileGenerator*>(DT);
(void)emitDependencies(Context.Diags, DFG, opts);
}
// We've just been told to perform a parse, so we can return now.
if (Action == FrontendOptions::Parse) {
if (!opts.ObjCHeaderOutputPath.empty())
return printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(),
opts.ImplicitObjCHeaderPath);
return false;
}
assert(Action >= FrontendOptions::EmitSILGen &&
"All actions not requiring SILGen must have been handled!");
std::unique_ptr<SILModule> SM = Instance.takeSILModule();
if (!SM) {
if (PrimarySourceFile)
SM = performSILGeneration(*PrimarySourceFile, Nothing,
opts.SILSerializeAll);
else
SM = performSILGeneration(Instance.getMainModule(), opts.SILSerializeAll);
}
// We've been told to emit SIL after SILGen, so write it now.
if (Action == FrontendOptions::EmitSILGen) {
// If we are asked to link all, link all.
if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll)
performSILLinking(SM.get(), true);
return writeSIL(*SM, Instance.getMainModule(), opts.EmitVerboseSIL,
opts.OutputFilename, opts.EmitSortedSIL);
}
// Perform "stable" optimizations that are invariant across compiler versions.
if (!Invocation.getDiagnosticOptions().SkipDiagnosticPasses &&
runSILDiagnosticPasses(*SM, Invocation.getSILOptions()))
return true;
// Now if we are asked to link all, link all.
if (Invocation.getSILOptions().LinkMode == SILOptions::LinkAll)
performSILLinking(SM.get(), true);
SM->verify();
// Perform SIL optimization passes if optimizations haven't been disabled.
// These may change across compiler versions.
IRGenOptions &IRGenOpts = Invocation.getIRGenOptions();
if (IRGenOpts.Optimize) {
runSILOptimizationPasses(*SM, Invocation.getSILOptions());
SM->verify();
}
// Get the main source file's private discriminator and attach it to
// the compile unit's flags.
if (PrimarySourceFile) {
Identifier PD = PrimarySourceFile->getPrivateDiscriminator();
if (!PD.empty())
IRGenOpts.DWARFDebugFlags += (" -private-discriminator "+PD.str()).str();
}
if (!opts.ObjCHeaderOutputPath.empty()) {
(void)printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(),
opts.ImplicitObjCHeaderPath);
}
if (!opts.ModuleOutputPath.empty() || !opts.ModuleDocOutputPath.empty()) {
auto DC = PrimarySourceFile ? ModuleOrSourceFile(PrimarySourceFile) :
Instance.getMainModule();
if (!opts.ModuleOutputPath.empty()) {
SerializationOptions serializationOpts;
serializationOpts.OutputPath = opts.ModuleOutputPath.c_str();
serializationOpts.DocOutputPath = opts.ModuleDocOutputPath.c_str();
serializationOpts.SerializeAllSIL = opts.SILSerializeAll;
serializationOpts.InputFilenames = opts.InputFilenames;
if (opts.SerializeBridgingHeader)
serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath;
serializationOpts.ModuleLinkName = opts.ModuleLinkName;
if (!IRGenOpts.ForceLoadSymbolName.empty())
serializationOpts.AutolinkForceLoad = true;
serializationOpts.HasUnderlyingModule = opts.ImportUnderlyingModule;
serialize(DC, serializationOpts, SM.get());
}
if (Action == FrontendOptions::EmitModuleOnly)
return false;
}
assert(Action >= FrontendOptions::EmitSIL &&
"All actions not requiring SILPasses must have been handled!");
// We've been told to write canonical SIL, so write it now.
if (Action == FrontendOptions::EmitSIL) {
return writeSIL(*SM, Instance.getMainModule(), opts.EmitVerboseSIL,
opts.OutputFilename, opts.EmitSortedSIL);
}
assert(Action >= FrontendOptions::Immediate &&
"All actions not requiring IRGen must have been handled!");
assert(Action != FrontendOptions::REPL &&
"REPL mode must be handled immediately after Instance.performSema()");
// Check if we had any errors; if we did, don't proceed to IRGen.
if (Context.hadError())
return true;
// Cleanup instructions/builtin calls not suitable for IRGen.
performSILCleanup(SM.get());
// TODO: remove once the frontend understands what action it should perform
switch (Action) {
case FrontendOptions::EmitIR:
IRGenOpts.OutputKind = IRGenOutputKind::LLVMAssembly;
break;
case FrontendOptions::EmitBC:
IRGenOpts.OutputKind = IRGenOutputKind::LLVMBitcode;
break;
case FrontendOptions::EmitAssembly:
IRGenOpts.OutputKind = IRGenOutputKind::NativeAssembly;
break;
case FrontendOptions::EmitObject:
IRGenOpts.OutputKind = IRGenOutputKind::ObjectFile;
break;
case FrontendOptions::Immediate: {
assert(!PrimarySourceFile && "-i doesn't work in -primary-file mode");
IRGenOpts.Triple = llvm::sys::getDefaultTargetTriple();
IRGenOpts.OutputKind = IRGenOutputKind::Module;
IRGenOpts.UseJIT = true;
// FIXME: Debug info is temporarily disabled, because
// JITCodeEmitter doesn't support it. This can be fixed by
// migrating to MCJIT.
IRGenOpts.DebugInfo = false;
const ProcessCmdLine &CmdLine = ProcessCmdLine(opts.ImmediateArgv.begin(),
opts.ImmediateArgv.end());
Instance.setSILModule(std::move(SM));
RunImmediately(Instance, CmdLine, IRGenOpts, Invocation.getSILOptions());
return false;
}
default:
llvm_unreachable("Unknown ActionType which requires IRGen");
return true;
}
// FIXME: We shouldn't need to use the global context here, but
// something is persisting across calls to performIRGeneration.
auto &LLVMContext = llvm::getGlobalContext();
if (PrimarySourceFile) {
performIRGeneration(IRGenOpts, *PrimarySourceFile, SM.get(),
opts.OutputFilename, LLVMContext);
} else {
performIRGeneration(IRGenOpts, Instance.getMainModule(), SM.get(),
opts.OutputFilename, LLVMContext);
}
return false;
}
int frontend_main(ArrayRef<const char *>Args,
const char *Argv0, void *MainAddr) {
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
CompilerInstance Instance;
PrintingDiagnosticConsumer PDC;
Instance.addDiagnosticConsumer(&PDC);
if (Args.empty()) {
Instance.getDiags().diagnose(SourceLoc(), diag::error_no_frontend_args);
return 1;
}
CompilerInvocation Invocation;
std::string MainExecutablePath = llvm::sys::fs::getMainExecutable(Argv0,
MainAddr);
Invocation.setMainExecutablePath(MainExecutablePath);
// Parse arguments.
if (Invocation.parseArgs(Args, Instance.getDiags())) {
return 1;
}
if (Invocation.getFrontendOptions().RequestedAction ==
FrontendOptions::NoneAction) {
Instance.getDiags().diagnose(SourceLoc(),
diag::error_missing_frontend_action);
return 1;
}
if (Invocation.getLangOptions().UsePrivateDiscriminators)
Mangle::Mangler::UsePrivateDiscriminators = true;
// TODO: reorder, if possible, so that diagnostics emitted during
// CompilerInvocation::parseArgs are included in the serialized file.
std::unique_ptr<DiagnosticConsumer> SerializedConsumer;
{
const std::string &SerializedDiagnosticsPath =
Invocation.getFrontendOptions().SerializedDiagnosticsPath;
if (!SerializedDiagnosticsPath.empty()) {
std::error_code EC;
std::unique_ptr<llvm::raw_fd_ostream> OS;
OS.reset(new llvm::raw_fd_ostream(SerializedDiagnosticsPath,
EC,
llvm::sys::fs::F_None));
if (EC) {
Instance.getDiags().diagnose(SourceLoc(),
diag::cannot_open_serialized_file,
SerializedDiagnosticsPath, EC.message());
return 1;
}
SerializedConsumer.reset(
serialized_diagnostics::createConsumer(std::move(OS)));
Instance.addDiagnosticConsumer(SerializedConsumer.get());
}
}
if (Invocation.getDiagnosticOptions().UseColor)
PDC.forceColors();
if (Invocation.getFrontendOptions().PrintHelp ||
Invocation.getFrontendOptions().PrintHelpHidden) {
unsigned IncludedFlagsBitmask = options::FrontendOption;
unsigned ExcludedFlagsBitmask =
Invocation.getFrontendOptions().PrintHelpHidden ? 0 :
llvm::opt::HelpHidden;
std::unique_ptr<llvm::opt::OptTable> Options(createSwiftOptTable());
Options->PrintHelp(llvm::outs(), displayName(MainExecutablePath).c_str(),
"Swift frontend", IncludedFlagsBitmask,
ExcludedFlagsBitmask);
return 0;
}
if (Invocation.getFrontendOptions().PrintStats) {
llvm::EnableStatistics();
}
if (Invocation.getDiagnosticOptions().VerifyDiagnostics) {
enableDiagnosticVerifier(Instance.getSourceMgr());
}
DependencyFileGenerator DFG;
if (!Invocation.getFrontendOptions().DependenciesFilePath.empty())
Instance.setDependencyTracker(&DFG);
if (Instance.setup(Invocation)) {
return 1;
}
bool HadError = performCompile(Instance, Invocation, Args) ||
Instance.getASTContext().hadError();
if (Invocation.getDiagnosticOptions().VerifyDiagnostics) {
HadError = verifyDiagnostics(Instance.getSourceMgr(),
Instance.getInputBufferIDs());
DiagnosticEngine &diags = Instance.getDiags();
if (diags.hasFatalErrorOccurred() &&
!Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) {
diags.resetHadAnyError();
diags.diagnose(SourceLoc(), diag::verify_encountered_fatal);
HadError = true;
}
}
return HadError;
}