mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
classes, UseJIT will also be set, so we don't need to check. And there's an important case where we *don't* need to register classes: testcases, which break if we do try to register classes, with the following assertion: Assertion failed: (registered == c && "objc_readClassPair failed to instantiate the class in-place"), function swift_instantiateObjCClass, file /Volumes/Excelion/swift/lldb-work/llvm/tools/swift/stdlib/runtime/SwiftObject.mm, line 594. So only register classes if UseJIT is enabled, and ignore the playground flag. Swift SVN r20655
332 lines
12 KiB
C++
332 lines
12 KiB
C++
//===--- IRGen.cpp - Swift LLVM IR Generation -----------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the entrypoints into IR generation.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "irgen"
|
|
#include "swift/Subsystems.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/AST/DiagnosticsIRGen.h"
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/AST/LinkLibrary.h"
|
|
#include "swift/Basic/Platform.h"
|
|
#include "swift/ClangImporter/ClangImporter.h"
|
|
#include "swift/OptimizeARC/PassesFwd.h"
|
|
#include "llvm/Bitcode/BitcodeWriterPass.h"
|
|
#include "llvm/Bitcode/ReaderWriter.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/IRPrintingPasses.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Verifier.h"
|
|
#include "llvm/Linker/Linker.h"
|
|
#include "llvm/MC/SubtargetFeature.h"
|
|
#include "llvm/PassManager.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Transforms/IPO.h"
|
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
|
#include "IRGenModule.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
using namespace llvm;
|
|
|
|
static void addSwiftARCOptPass(const PassManagerBuilder &Builder,
|
|
PassManagerBase &PM) {
|
|
if (Builder.OptLevel > 0)
|
|
PM.add(createSwiftARCOptPass());
|
|
}
|
|
|
|
static void addSwiftExpandPass(const PassManagerBuilder &Builder,
|
|
PassManagerBase &PM) {
|
|
if (Builder.OptLevel > 0)
|
|
PM.add(createSwiftARCExpandPass());
|
|
}
|
|
|
|
// FIXME: Copied from clang/lib/CodeGen/CGObjCMac.cpp.
|
|
// These should be moved to a single definition shared by clang and swift.
|
|
enum ImageInfoFlags {
|
|
eImageInfo_FixAndContinue = (1 << 0),
|
|
eImageInfo_GarbageCollected = (1 << 1),
|
|
eImageInfo_GCOnly = (1 << 2),
|
|
eImageInfo_OptimizedByDyld = (1 << 3),
|
|
eImageInfo_CorrectedSynthesize = (1 << 4),
|
|
eImageInfo_ImageIsSimulated = (1 << 5)
|
|
};
|
|
|
|
static std::unique_ptr<llvm::Module> performIRGeneration(IRGenOptions &Opts,
|
|
swift::Module *M,
|
|
SILModule *SILMod,
|
|
StringRef ModuleName,
|
|
llvm::LLVMContext &LLVMContext,
|
|
SourceFile *SF = nullptr,
|
|
unsigned StartElem = 0) {
|
|
assert(!M->Ctx.hadError());
|
|
|
|
std::string Error;
|
|
const Target *Target =
|
|
TargetRegistry::lookupTarget(Opts.Triple, Error);
|
|
if (!Target) {
|
|
M->Ctx.Diags.diagnose(SourceLoc(), diag::no_llvm_target,
|
|
Opts.Triple, Error);
|
|
return nullptr;
|
|
}
|
|
|
|
CodeGenOpt::Level OptLevel = Opts.Optimize ? CodeGenOpt::Aggressive
|
|
: CodeGenOpt::None;
|
|
|
|
// Set up TargetOptions.
|
|
// Things that maybe we should collect from the command line:
|
|
// - relocation model
|
|
// - code model
|
|
TargetOptions TargetOpts;
|
|
TargetOpts.NoFramePointerElim = Opts.DisableFPElim;
|
|
|
|
// Create the target features string.
|
|
std::string targetFeatures;
|
|
if (!Opts.TargetFeatures.empty()) {
|
|
llvm::SubtargetFeatures features;
|
|
for (std::string &feature : Opts.TargetFeatures)
|
|
features.AddFeature(feature);
|
|
targetFeatures = features.getString();
|
|
}
|
|
|
|
// Create a target machine.
|
|
llvm::TargetMachine *TargetMachine
|
|
= Target->createTargetMachine(Opts.Triple, Opts.TargetCPU,
|
|
std::move(targetFeatures),
|
|
TargetOpts, Reloc::PIC_,
|
|
CodeModel::Default, OptLevel);
|
|
if (!TargetMachine) {
|
|
M->Ctx.Diags.diagnose(SourceLoc(), diag::no_llvm_target,
|
|
Opts.Triple, "no LLVM target machine");
|
|
return nullptr;
|
|
}
|
|
|
|
const llvm::DataLayout *DataLayout = TargetMachine->getDataLayout();
|
|
assert(DataLayout && "target machine didn't set DataLayout?");
|
|
|
|
// Create the IR emitter.
|
|
IRGenModule IGM(M->Ctx, LLVMContext, Opts, ModuleName, *DataLayout, SILMod);
|
|
|
|
auto *Module = IGM.getModule();
|
|
assert(Module && "Expected llvm:Module for IR generation!");
|
|
|
|
Module->setTargetTriple(Opts.Triple);
|
|
// Set the dwarf version to 3, which is what the Xcode 5.0 tool chain
|
|
// understands. FIXME: Increase this to 4 once we have a build
|
|
// train that includes the ToT version of ld64.
|
|
Module->addModuleFlag(llvm::Module::Warning, "Dwarf Version", 3);
|
|
// Set the debug info metadata version to the one generated by the LLVM backend.
|
|
Module->addModuleFlag(llvm::Module::Error, "Debug Info Version",
|
|
llvm::DEBUG_METADATA_VERSION);
|
|
|
|
// Set the module's string representation.
|
|
Module->setDataLayout(DataLayout->getStringRepresentation());
|
|
|
|
// Emit the module contents.
|
|
IGM.prepare();
|
|
IGM.emitGlobalTopLevel();
|
|
|
|
if (SF) {
|
|
IGM.emitSourceFile(*SF, StartElem);
|
|
} else {
|
|
assert(StartElem == 0 && "no explicit source file provided");
|
|
for (auto *File : M->getFiles()) {
|
|
auto nextSF = dyn_cast<SourceFile>(File);
|
|
if (!nextSF || nextSF->ASTStage < SourceFile::TypeChecked)
|
|
continue;
|
|
IGM.emitSourceFile(*nextSF, 0);
|
|
}
|
|
}
|
|
|
|
// Okay, emit any definitions that we suddenly need.
|
|
IGM.emitLazyDefinitions();
|
|
|
|
// Emit intializers for debugger functions if needed
|
|
if (IGM.ObjCInterop && Opts.UseJIT) {
|
|
IGM.emitDebuggerInitializers();
|
|
}
|
|
|
|
std::for_each(Opts.LinkLibraries.begin(), Opts.LinkLibraries.end(),
|
|
[&](LinkLibrary linkLib) {
|
|
IGM.addLinkLibrary(linkLib);
|
|
});
|
|
|
|
// Hack to handle thunks eagerly synthesized by the Clang importer.
|
|
swift::Module *prev = nullptr;
|
|
for (auto external : M->Ctx.ExternalDefinitions) {
|
|
swift::Module *next = external->getModuleContext();
|
|
if (next == prev)
|
|
continue;
|
|
prev = next;
|
|
|
|
if (Opts.HasUnderlyingModule && next->Name == M->Name)
|
|
continue;
|
|
|
|
next->collectLinkLibraries([&](LinkLibrary linkLib) {
|
|
IGM.addLinkLibrary(linkLib);
|
|
});
|
|
}
|
|
|
|
IGM.finalize();
|
|
|
|
// Objective-C image information.
|
|
// Generate module-level named metadata to convey this information to the
|
|
// linker and code-gen.
|
|
unsigned version = 0; // Version is unused?
|
|
const char *section = "__DATA, __objc_imageinfo, regular, no_dead_strip";
|
|
|
|
// Add the ObjC ABI version to the module flags.
|
|
Module->addModuleFlag(llvm::Module::Error, "Objective-C Version", 2);
|
|
Module->addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
|
|
version);
|
|
Module->addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
|
|
llvm::MDString::get(Module->getContext(), section));
|
|
|
|
Module->addModuleFlag(llvm::Module::Override,
|
|
"Objective-C Garbage Collection", (uint32_t)0);
|
|
|
|
// Mark iOS simulator images.
|
|
if (tripleIsiOSSimulator(llvm::Triple(Opts.Triple)))
|
|
Module->addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
|
|
eImageInfo_ImageIsSimulated);
|
|
|
|
DEBUG(llvm::dbgs() << "module before passes:\n";
|
|
IGM.Module.dump());
|
|
|
|
// Bail out if there are any errors.
|
|
if (M->Ctx.hadError()) return nullptr;
|
|
|
|
std::unique_ptr<raw_fd_ostream> RawOS;
|
|
formatted_raw_ostream FormattedOS;
|
|
if (!Opts.OutputFilename.empty()) {
|
|
// Try to open the output file. Clobbering an existing file is fine.
|
|
// Open in binary mode if we're doing binary output.
|
|
llvm::sys::fs::OpenFlags OSFlags = llvm::sys::fs::F_None;
|
|
RawOS.reset(new raw_fd_ostream(Opts.OutputFilename.c_str(),
|
|
Error, OSFlags));
|
|
if (RawOS->has_error() || !Error.empty()) {
|
|
M->Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_output,
|
|
Opts.OutputFilename, Error);
|
|
RawOS->clear_error();
|
|
return nullptr;
|
|
}
|
|
|
|
// Most output kinds want a formatted output stream. It's not clear
|
|
// why writing an object file does.
|
|
if (Opts.OutputKind != IRGenOutputKind::LLVMBitcode)
|
|
FormattedOS.setStream(*RawOS, formatted_raw_ostream::PRESERVE_STREAM);
|
|
}
|
|
|
|
// Set up a pipeline.
|
|
PassManagerBuilder PMBuilder;
|
|
|
|
if (Opts.Optimize && !Opts.DisableLLVMOptzns) {
|
|
PMBuilder.OptLevel = 3;
|
|
PMBuilder.Inliner = llvm::createFunctionInliningPass(200);
|
|
PMBuilder.SLPVectorize = true;
|
|
PMBuilder.LoopVectorize = true;
|
|
} else {
|
|
PMBuilder.OptLevel = 0;
|
|
}
|
|
|
|
// If the optimizer is enabled, we run the ARCOpt pass in the scalar optimizer
|
|
// and the Expand pass as late as possible.
|
|
if (!Opts.DisableLLVMARCOpts) {
|
|
PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
|
|
addSwiftARCOptPass);
|
|
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
|
|
addSwiftExpandPass);
|
|
}
|
|
|
|
// Configure the function passes.
|
|
FunctionPassManager FunctionPasses(Module);
|
|
FunctionPasses.add(new llvm::DataLayoutPass(*DataLayout));
|
|
TargetMachine->addAnalysisPasses(FunctionPasses);
|
|
if (Opts.Verify)
|
|
FunctionPasses.add(createVerifierPass());
|
|
PMBuilder.populateFunctionPassManager(FunctionPasses);
|
|
|
|
// Run the function passes.
|
|
FunctionPasses.doInitialization();
|
|
for (auto I = Module->begin(), E = Module->end(); I != E; ++I)
|
|
if (!I->isDeclaration())
|
|
FunctionPasses.run(*I);
|
|
FunctionPasses.doFinalization();
|
|
|
|
// Configure the module passes.
|
|
PassManager ModulePasses;
|
|
ModulePasses.add(new llvm::DataLayoutPass(*DataLayout));
|
|
TargetMachine->addAnalysisPasses(ModulePasses);
|
|
PMBuilder.populateModulePassManager(ModulePasses);
|
|
if (Opts.Verify)
|
|
ModulePasses.add(createVerifierPass());
|
|
|
|
// Do it.
|
|
ModulePasses.run(*Module);
|
|
|
|
PassManager EmitPasses;
|
|
|
|
// Set up the final emission passes.
|
|
switch (Opts.OutputKind) {
|
|
case IRGenOutputKind::Module:
|
|
break;
|
|
case IRGenOutputKind::LLVMAssembly:
|
|
EmitPasses.add(createPrintModulePass(FormattedOS));
|
|
break;
|
|
case IRGenOutputKind::LLVMBitcode:
|
|
EmitPasses.add(createBitcodeWriterPass(*RawOS));
|
|
break;
|
|
case IRGenOutputKind::NativeAssembly:
|
|
case IRGenOutputKind::ObjectFile: {
|
|
llvm::TargetMachine::CodeGenFileType FileType;
|
|
FileType = (Opts.OutputKind == IRGenOutputKind::NativeAssembly
|
|
? llvm::TargetMachine::CGFT_AssemblyFile
|
|
: llvm::TargetMachine::CGFT_ObjectFile);
|
|
|
|
TargetMachine->addAnalysisPasses(EmitPasses);
|
|
bool fail = TargetMachine->addPassesToEmitFile(EmitPasses, FormattedOS,
|
|
FileType, !Opts.Verify);
|
|
if (fail) {
|
|
M->Ctx.Diags.diagnose(SourceLoc(), diag::error_codegen_init_fail);
|
|
return nullptr;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
EmitPasses.run(*Module);
|
|
return std::unique_ptr<llvm::Module>(IGM.releaseModule());
|
|
}
|
|
|
|
std::unique_ptr<llvm::Module> swift::
|
|
performIRGeneration(IRGenOptions &Opts, swift::Module *M, SILModule *SILMod,
|
|
StringRef ModuleName, llvm::LLVMContext &LLVMContext) {
|
|
return ::performIRGeneration(Opts, M, SILMod, ModuleName, LLVMContext);
|
|
}
|
|
|
|
std::unique_ptr<llvm::Module> swift::
|
|
performIRGeneration(IRGenOptions &Opts, SourceFile &SF, SILModule *SILMod,
|
|
StringRef ModuleName, llvm::LLVMContext &LLVMContext,
|
|
unsigned StartElem) {
|
|
return ::performIRGeneration(Opts, SF.getParentModule(), SILMod, ModuleName,
|
|
LLVMContext, &SF, StartElem);
|
|
}
|