Skip to content

Commit

Permalink
Initial set of changes to add a new 'swift_driver' executable.
Browse files Browse the repository at this point in the history
- Added a couple of new targets:
  - libswiftDriver, which contains most of the driver implementation
  - swift_driver, which produces the actual executable

- Added centralized version information into libswiftBasic.

- Added a new "Driver Design & Internals" document, which currently describes
  the high-level design of the Swift driver.

- Implemented an early version of the functionality of the driver, including
  versions of the Parse, Pipeline, Bind, Translate, and Execute driver stages.
  Parse, Pipeline, and Bind are largely implemented; Translate and Execute are
  early placeholders. (Translate produces "swift_driver --version" and "ld -v"
  commands, while Execute performs all subtasks sequentially, rather than in
  parallel.)

This is just the starting point for the Swift driver. Tests for the existing
behavior are forthcoming.

Swift SVN r10933
  • Loading branch information
cwakamo committed Dec 6, 2013
1 parent 8fcb7c4 commit ed20385
Show file tree
Hide file tree
Showing 46 changed files with 2,789 additions and 6 deletions.
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,13 @@ macro(add_swift_library name)
list( GET split_path -1 dir)
file( GLOB_RECURSE SWIFTLIB_HEADERS
${SWIFT_SOURCE_DIR}/include/swift${dir}/*.h
${SWIFT_SOURCE_DIR}/include/swift${dir}/*.td
${SWIFT_SOURCE_DIR}/include/swift${dir}/*.def)
set(SWIFTLIB_SOURCES ${SWIFTLIB_SOURCES} ${SWIFTLIB_HEADERS})

file( GLOB_RECURSE SWIFTLIB_TDS
${SWIFT_SOURCE_DIR}/include/swift${dir}/*.td)
source_group("TableGen descriptions" FILES ${SWIFTLIB_TDS})

set(SWIFTLIB_SOURCES ${SWIFTLIB_SOURCES} ${SWIFTLIB_HEADERS} ${SWIFTLIB_TDS})
endif(MSVC_IDE OR XCODE)

if (MODULE)
Expand Down Expand Up @@ -674,6 +678,7 @@ include_directories(BEFORE

# Add all of the subdirectories, where we actually do work.
if (SWIFT_BUILD_TOOLS)
add_subdirectory(include)
add_subdirectory(lib)
add_subdirectory(tools)
endif (SWIFT_BUILD_TOOLS)
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ifndef SWIFT_LEVEL
IS_TOP_LEVEL := 1
SWIFT_LEVEL := .

DIRS := lib tools # include docs
DIRS := include lib tools # docs
PARALLEL_DIRS :=

# See compiler-rt/Makefile for a description of the problems with building
Expand Down
Binary file added docs/DriverDesign.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
164 changes: 164 additions & 0 deletions docs/DriverInternals.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
=========================
Driver Design & Internals
=========================

.. contents::
:local:

Introduction
============

This document serves to describe the high-level design of the Swift 1.0 compiler
driver (which includes what the driver is intended to do, and the approach it
takes to do that), as well as the internals of the driver (which is meant to
provide a brief overview of and rationale for how the high-level design is
implemented).

The Swift 1.0 driver is not intended to be GCC/Clang compatible, as it does not
need to serve as a drop-in replacement for either driver. However, the design
of the driver is inspired by Clang's design (though it is "smarter" than Clang,
since it performs some limited dependency analysis), and will only diverge if it
produces a better design, or if it needs to implement something which Clang
does not.

High-Level Driver Design
========================

The compiler driver for Swift will roughly follow the same design as Clang's
compiler driver: it will parse command-line arguments into Arg objects; use
those to generate a pipeline of Actions; bind Tools to each Action, which will
then translate an Action into a Job; execute Jobs; and return a result code.
However, since Swift source files must be compiled on a per-module basis,
external build systems cannot easily detect while files in a module must be
recompiled to accurately produce an executable. As a result, the Swift compiler
driver must perform dependency tracking on its own, which means that all Jobs
will not be executed. Instead, Jobs will be logically grouped, and each
Job will have the opportunity to influence whether other Jobs in the same
logical group will be executed.

.. contents::
:local:

Overview
--------

The diagram below, taken from Clang's "Driver Design & Internals" document,
shows the high-level design of the Swift compiler driver.

.. admonition:: TODO

Update diagram to show conditional Job execution

.. image:: DriverDesign.png
:align: center
:alt: Driver Design Diagram

1. Parse input strings into an ArgList of Args.

2. Establish a pipeline of Action groups, such as the following:

- A0: Input, "a.swift"

- A1: Input, "b.swift"

- B0: Compile, {A0}, "a.o"

- B1: Compile, {A1}, "b.o"

- C0: Link, {B0, B1}, "a.out"

4. Bind the appropriate Tool to each Action.

5. Using the bound Tools, translate each Action into a Job, creating a graph.

6. Execute each top-level Job by performing the following:

1. Ask each Job which is an input to the current Job if it needs to
execute. This will have the side-effect of loading dependency
information from the last build (if present). If a Job already
knows that it needs to execute, schedule it for execution.

2. Execute each Job which is scheduled for execution. This will have the
side-effect of creating new dependency information for that Job.

3. After each Job finishes execution, load the new dependency information
and reevaluate every Job which is a peer to that Job.

7. After all top-level Jobs been processed, the build artifacts should be
present on disk, either from a new execution or from a previous execution.
Return a result code.

Driver Stages
-------------

The Swift compiler driver is conceptually broken into five stages: Parse
(transforming input strings to ArgList/Args), Pipeline (transforming Args into
groups of Actions), Bind (assigning Tools and other build information to
Actions), Translate (using Tools to translate Actions into Jobs), and Execute.
From a high level, these look like Clang's driver stages, and functionally
they're similar. However, unlike Clang, Translate and Execute will, optimally,
only be performed on a subset of Actions, and the execution of one Action will
influence whether or not another Action is executed.

Parse: Option parsing
^^^^^^^^^^^^^^^^^^^^^

This is a fairly straightforward port of the Clang driver's Parse stage. The
command line arguments are parsed as options and inputs into Arg instances.

Pipeline: Converting Args into Actions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This is also a fairly straightforward port of the Clang driver's Pipeline stage.
At this stage, the driver will take the input Args and input files and establish
a graph of Actions.

Bind: Tool and Filename Selection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This stage, like the Clang driver's Bind stage, selects an appropriate Tool to
use for each Action in a pipeline. This is achieved by asking the Toolchain for
the right Tool for a given Action. Once every Action in the pipeline has a Tool,
this stage will determine how to pass output from one Action to the next.

For Actions which do not already have output filenames but require one, this
stage will also assign unique output filenames.

Translate: Translating Actions into Jobs using Tools
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This stage, like the Clang driver's Translate stage, uses the Tool bound to each
Action to translate the Args in ArgList into tool-specific arguments. Unlike
Clang's Translate stage, though, the Swift driver will translate the graph of
Actions into a graph of Jobs, instead of putting it into a serial queue.

This stage must result in a graph of Jobs instead of a queue of Jobs so that
Jobs can remain logically grouped. All Jobs which are an input to a particular
Job will be given the opportunity to impact whether other Jobs in that logical
group need to be executed; this permits us to perform partial rebuilds when
safe.

Execute
^^^^^^^

This stage, like the Clang driver's Execute stage, executes the Jobs which are
created by Translate. Unlike Clang's Execute stage, Swift's will support
concurrency: at the most basic level, this will be something like ``make -jn``,
where the compiler executes up to n Jobs concurrently. This could be enhanced to
include things like intelligently scaling back the number of Jobs if the system
is under pressure, but that may not be necessary for Swift 1.0. (Another
possible enhancement would be to let an external build system update the value
of n as the build continues, but that will definitely not be necessary for 1.0.)

Jobs will be scheduled onto a single work queue. Multiple Jobs may execute
simultaneously, but Job termination will be handled on a single thread. When a
Job terminates, the driver will evaluate the other Jobs in that Job's group
to determine if any additional Jobs need to be scheduled. Once all outstanding
Jobs in the same group have terminated, any unprocessed Jobs will be evaluated
before executing the downstream Job for which all of the Jobs in that group are
an input.

Driver Internals
================

TBD
1 change: 1 addition & 0 deletions docs/contents.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Contents
StoredAndComputedVariables
SIL
TypeChecker
DriverInternals



1 change: 1 addition & 0 deletions include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(swift)
16 changes: 16 additions & 0 deletions include/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
##===- include/Makefile ------------------------------------*- Makefile -*-===##
#
# 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
#
##===----------------------------------------------------------------------===##

SWIFT_LEVEL := ..
DIRS := swift

include $(SWIFT_LEVEL)/Makefile
35 changes: 35 additions & 0 deletions include/swift/Basic/Version.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===- Version.h - Swift Version Number -------------------------*- C++ -*-===//
//
// 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 Defines version macros and version-related utility functions
/// for Swift.
///
//===----------------------------------------------------------------------===//

#ifndef SWIFT_BASIC_VERSION_H
#define SWIFT_BASIC_VERSION_H

#include <string>

namespace swift {
namespace version {

/// \brief Retrieves a string representing the complete Swift version, which
/// includes the Swift version number, the repository version, and the vendor
/// tag.
std::string getSwiftFullVersion();

} // end namespace version
} // end namespace swift

#endif
1 change: 1 addition & 0 deletions include/swift/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(Driver)
136 changes: 136 additions & 0 deletions include/swift/Driver/Action.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//===--- Action.h - Abstract compilation steps ------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_DRIVER_ACTION_H
#define SWIFT_DRIVER_ACTION_H

#include "swift/Basic/LLVM.h"
#include "swift/Driver/Types.h"
#include "swift/Driver/Util.h"
#include "llvm/ADT/ArrayRef.h"

namespace llvm {
namespace opt {
class Arg;
}
}

namespace swift {
namespace driver {
class Action;

class Action {
public:
typedef ActionList::size_type size_type;
typedef ActionList::iterator iterator;
typedef ActionList::const_iterator const_iterator;

enum ActionClass {
Input = 0,
CompileJob,
LinkJob,

JobFirst=CompileJob,
JobLast=LinkJob
};

static const char *getClassName(ActionClass AC);

private:
ActionClass Kind;
types::ID Type;

ActionList Inputs;

unsigned OwnsInputs : 1;

protected:
Action(ActionClass Kind, types::ID Type)
: Kind(Kind), Type(Type), OwnsInputs(true) {}
Action(ActionClass Kind, ArrayRef<Action *> Inputs, types::ID Type)
: Kind(Kind), Type(Type), Inputs(Inputs.begin(), Inputs.end()),
OwnsInputs(true) {}

public:
virtual ~Action();

const char *getClassName() const { return Action::getClassName(getKind()); }

bool getOwnsInputs() const { return OwnsInputs; }
void setOwnsInputs(bool Value) { OwnsInputs = Value; }

ActionClass getKind() const { return Kind; }
types::ID getType() const { return Type; }

ArrayRef<Action *> getInputs() const { return Inputs; }

size_type size() const { return Inputs.size(); }

iterator begin() { return Inputs.begin(); }
iterator end() { return Inputs.end(); }
const_iterator begin() const { return Inputs.begin(); }
const_iterator end() const { return Inputs.end(); }
};

class InputAction : public Action {
virtual void anchor();
const llvm::opt::Arg &Input;

public:
InputAction(const llvm::opt::Arg &Input, types::ID Type)
: Action(Action::Input, Type), Input(Input) {}
const llvm::opt::Arg &getInputArg() const { return Input; }

static bool classof(const Action *A) {
return A->getKind() == Action::Input;
}
};

class JobAction : public Action {
virtual void anchor();
protected:
JobAction(ActionClass Kind, ArrayRef<Action *> Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {}

public:
static bool classof(const Action *A) {
return (A->getKind() >= ActionClass::JobFirst &&
A->getKind() <= ActionClass::JobLast);
}
};

class CompileJobAction : public JobAction {
virtual void anchor();
public:
CompileJobAction(Action *Input, types::ID OutputType)
: JobAction(Action::CompileJob, Input, OutputType) {}

static bool classof(const Action *A) {
return A->getKind() == Action::CompileJob;
}
};

class LinkJobAction : public JobAction {
virtual void anchor();
public:
LinkJobAction(ArrayRef<Action *> Inputs)
: JobAction(Action::LinkJob, Inputs, types::TY_Image) {}

static bool classof(const Action *A) {
return A->getKind() == Action::LinkJob;
}
};

} // end namespace driver
} // end namespace swift

#endif
Loading

0 comments on commit ed20385

Please sign in to comment.