mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
170 lines
5.5 KiB
C++
170 lines
5.5 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.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Subsystems.h"
|
|
#include "swift/IRGen/Options.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "llvm/LLVMContext.h"
|
|
#include "llvm/Module.h"
|
|
#include "llvm/PassManager.h"
|
|
#include "llvm/Analysis/Verifier.h"
|
|
#include "llvm/Assembly/PrintModulePass.h"
|
|
#include "llvm/Bitcode/ReaderWriter.h"
|
|
#include "llvm/Target/TargetData.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
#include "IRGenModule.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
using namespace llvm;
|
|
|
|
static bool isBinaryOutput(OutputKind kind) {
|
|
switch (kind) {
|
|
case OutputKind::LLVMAssembly:
|
|
case OutputKind::NativeAssembly:
|
|
return false;
|
|
case OutputKind::LLVMBitcode:
|
|
case OutputKind::ObjectFile:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad output kind!");
|
|
}
|
|
|
|
void swift::performIRGeneration(TranslationUnitDecl *TU, ASTContext &Context,
|
|
Options &Opts) {
|
|
assert(!Context.hadError());
|
|
|
|
// Create the module.
|
|
LLVMContext LLVMContext;
|
|
Module Module(Opts.OutputFilename, LLVMContext);
|
|
Module.setTargetTriple(Opts.Triple);
|
|
|
|
std::string Error;
|
|
const Target *Target =
|
|
TargetRegistry::lookupTarget(Opts.Triple, Error);
|
|
if (!Target) {
|
|
errs() << "error loading LLVM target for triple '"
|
|
<< Opts.Triple << "': " << Error << "\n";
|
|
Context.setHadError();
|
|
return;
|
|
}
|
|
|
|
// Create a target machine.
|
|
// Things that maybe we should collect from the command line:
|
|
// - CPU
|
|
// - features
|
|
// - relocation model
|
|
// - code model
|
|
TargetMachine *TargetMachine
|
|
= Target->createTargetMachine(Opts.Triple, /*cpu*/ "", /*features*/ "");
|
|
if (!TargetMachine) {
|
|
errs() << "no LLVM target machine for triple '"
|
|
<< Opts.Triple << "'\n";
|
|
Context.setHadError();
|
|
return;
|
|
}
|
|
|
|
// Set the module's string representation.
|
|
const TargetData *TargetData = TargetMachine->getTargetData();
|
|
assert(TargetData && "target machine didn't set TargetData?");
|
|
Module.setDataLayout(TargetData->getStringRepresentation());
|
|
|
|
// Emit the translation unit.
|
|
IRGenModule IRM(Context, Opts, Module, *TargetData);
|
|
IRM.emitTranslationUnit(TU);
|
|
|
|
// Bail out if there are any errors.
|
|
if (Context.hadError()) return;
|
|
|
|
// Try to open the output file. Clobbering an existing file is fine.
|
|
// Open in binary mode if we're doing binary output.
|
|
unsigned OSFlags = 0;
|
|
if (isBinaryOutput(Opts.OutputKind))
|
|
OSFlags |= raw_fd_ostream::F_Binary;
|
|
raw_fd_ostream RawOS(Opts.OutputFilename.c_str(), Error, OSFlags);
|
|
if (RawOS.has_error()) {
|
|
errs() << "error opening '" << Opts.OutputFilename
|
|
<< "' for output: " << Error << "\n";
|
|
Context.setHadError();
|
|
return;
|
|
}
|
|
|
|
// Most output kinds want a formatted output stream. It's not clear
|
|
// why writing an object file does.
|
|
formatted_raw_ostream FormattedOS;
|
|
if (Opts.OutputKind != OutputKind::LLVMBitcode)
|
|
FormattedOS.setStream(RawOS, formatted_raw_ostream::PRESERVE_STREAM);
|
|
|
|
// Okay, set up a pipeline.
|
|
PassManagerBuilder PMBuilder;
|
|
PMBuilder.OptLevel = Opts.OptLevel;
|
|
|
|
// Configure the function passes.
|
|
FunctionPassManager FunctionPasses(&Module);
|
|
FunctionPasses.add(new llvm::TargetData(*TargetData));
|
|
if (Opts.Verify)
|
|
FunctionPasses.add(createVerifierPass());
|
|
PMBuilder.populateFunctionPassManager(FunctionPasses);
|
|
|
|
// Run the function passes.
|
|
FunctionPasses.doInitialization();
|
|
for (Module::iterator 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::TargetData(*TargetData));
|
|
PMBuilder.populateModulePassManager(ModulePasses);
|
|
|
|
// Set up the final emission passes.
|
|
switch (Opts.OutputKind) {
|
|
case OutputKind::LLVMAssembly:
|
|
ModulePasses.add(createPrintModulePass(&FormattedOS));
|
|
break;
|
|
case OutputKind::LLVMBitcode:
|
|
ModulePasses.add(createBitcodeWriterPass(RawOS));
|
|
break;
|
|
case OutputKind::NativeAssembly:
|
|
case OutputKind::ObjectFile: {
|
|
TargetMachine::CodeGenFileType FileType;
|
|
FileType = (Opts.OutputKind == OutputKind::NativeAssembly
|
|
? TargetMachine::CGFT_AssemblyFile
|
|
: TargetMachine::CGFT_ObjectFile);
|
|
|
|
CodeGenOpt::Level OptLevel = static_cast<CodeGenOpt::Level>(Opts.OptLevel);
|
|
if (TargetMachine->addPassesToEmitFile(ModulePasses, FormattedOS,
|
|
FileType, OptLevel,
|
|
!Opts.Verify)) {
|
|
errs() << "cannot initialize code generation passes for target\n";
|
|
Context.setHadError();
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Do it.
|
|
ModulePasses.run(Module);
|
|
}
|