rust/src/librustc
bors 2819eca69c Auto merge of #36296 - nagisa:pass-timing, r=eddyb
Count and report time taken by MIR passes

There’s some desire for deeper introspectability into what MIR passes cost us.

-Z time-passes after this PR:

```
   Compiling test_shim v0.1.0 (file:///home/nagisa/Documents/rust/rust/src/rustc/test_shim)
time: 0.000; rss: 29MB	parsing
time: 0.000; rss: 29MB	configuration
time: 0.000; rss: 29MB	recursion limit
time: 0.000; rss: 29MB	crate injection
time: 0.000; rss: 29MB	plugin loading
time: 0.000; rss: 29MB	plugin registration
time: 0.032; rss: 54MB	expansion
time: 0.000; rss: 54MB	maybe building test harness
time: 0.000; rss: 54MB	assigning node ids
time: 0.000; rss: 54MB	checking for inline asm in case the target doesn't support it
time: 0.000; rss: 54MB	complete gated feature checking
time: 0.000; rss: 54MB	collecting defs
time: 0.004; rss: 54MB	external crate/lib resolution
time: 0.000; rss: 54MB	early lint checks
time: 0.000; rss: 54MB	AST validation
time: 0.001; rss: 54MB	name resolution
time: 0.000; rss: 54MB	lowering ast -> hir
time: 0.000; rss: 56MB	indexing hir
time: 0.000; rss: 56MB	attribute checking
time: 0.000; rss: 56MB	language item collection
time: 0.000; rss: 56MB	lifetime resolution
time: 0.000; rss: 56MB	looking for entry point
time: 0.000; rss: 56MB	looking for plugin registrar
time: 0.000; rss: 56MB	region resolution
time: 0.000; rss: 56MB	loop checking
time: 0.000; rss: 56MB	static item recursion checking
time: 0.000; rss: 56MB	compute_incremental_hashes_map
time: 0.000; rss: 56MB	load_dep_graph
time: 0.000; rss: 56MB	type collecting
time: 0.000; rss: 56MB	variance inference
time: 0.011; rss: 59MB	coherence checking
time: 0.000; rss: 59MB	wf checking
time: 0.000; rss: 59MB	item-types checking
time: 0.000; rss: 59MB	item-bodies checking
time: 0.000; rss: 59MB	drop-impl checking
time: 0.000; rss: 59MB	const checking
time: 0.000; rss: 59MB	privacy checking
time: 0.000; rss: 59MB	stability index
time: 0.000; rss: 59MB	intrinsic checking
time: 0.000; rss: 59MB	effect checking
time: 0.000; rss: 59MB	match checking
time: 0.000; rss: 59MB	liveness checking
time: 0.000; rss: 59MB	rvalue checking
time: 0.000; rss: 59MB	MIR dump
  time: 0.000; rss: 59MB	SimplifyCfg
  time: 0.000; rss: 59MB	QualifyAndPromoteConstants
  time: 0.000; rss: 59MB	TypeckMir
  time: 0.000; rss: 59MB	SimplifyBranches
  time: 0.000; rss: 59MB	SimplifyCfg
time: 0.000; rss: 59MB	MIR passes
time: 0.000; rss: 59MB	borrow checking
time: 0.000; rss: 59MB	reachability checking
time: 0.000; rss: 59MB	death checking
time: 0.000; rss: 59MB	stability checking
time: 0.000; rss: 59MB	unused lib feature checking
time: 0.000; rss: 59MB	lint checking
time: 0.000; rss: 59MB	resolving dependency formats
  time: 0.000; rss: 59MB	NoLandingPads
  time: 0.000; rss: 59MB	SimplifyCfg
  time: 0.000; rss: 59MB	EraseRegions
  time: 0.000; rss: 59MB	AddCallGuards
  time: 0.000; rss: 59MB	ElaborateDrops
  time: 0.000; rss: 59MB	NoLandingPads
  time: 0.000; rss: 59MB	SimplifyCfg
  time: 0.000; rss: 59MB	Deaggregator
  time: 0.000; rss: 59MB	AddCallGuards
  time: 0.000; rss: 59MB	PreTrans
time: 0.000; rss: 59MB	Prepare MIR codegen passes
  time: 0.000; rss: 59MB	write metadata
  time: 0.000; rss: 61MB	translation item collection
  time: 0.000; rss: 61MB	codegen unit partitioning
  time: 0.000; rss: 61MB	internalize symbols
time: 0.007; rss: 61MB	translation
time: 0.000; rss: 61MB	assert dep graph
time: 0.000; rss: 61MB	serialize dep graph
time: 0.000; rss: 61MB	llvm function passes [2]
time: 0.000; rss: 61MB	llvm function passes [3]
time: 0.000; rss: 61MB	llvm function passes [1]
time: 0.000; rss: 61MB	llvm function passes [0]
time: 0.000; rss: 61MB	llvm module passes [2]
time: 0.000; rss: 61MB	llvm module passes [1]
time: 0.000; rss: 61MB	llvm module passes [0]
time: 0.000; rss: 61MB	llvm module passes [3]
time: 0.001; rss: 62MB	codegen passes [1]
time: 0.001; rss: 62MB	codegen passes [2]
time: 0.001; rss: 62MB	codegen passes [0]
time: 0.001; rss: 62MB	codegen passes [3]
time: 0.001; rss: 63MB	codegen passes [1]
time: 0.005; rss: 63MB	LLVM passes
time: 0.000; rss: 63MB	serialize work products
time: 0.001; rss: 63MB	linking
```

r? @eddyb or @nikomatsakis

cc @nrc, @Mark-Simulacrum
2016-09-07 02:47:35 -07:00
..
cfg Replace _, _ with .. 2016-09-04 12:30:33 +03:00
dep_graph simplify DepNode for trait selection 2016-08-31 15:23:50 -04:00
hir E0518 Update error format #36111 2016-09-06 00:21:04 +10:00
infer Replace _, _ with .. 2016-09-04 12:30:33 +03:00
lint turn the RFC1592 warnings into hard errors 2016-09-01 13:34:56 +03:00
middle Auto merge of #36252 - joshtriplett:union-field-never-used, r=sanxiyn 2016-09-06 20:06:34 -07:00
mir Count and report time taken by MIR passes 2016-09-06 17:19:36 +03:00
session Auto merge of #36025 - michaelwoerister:incr-comp-hash-spans, r=nikomatsakis 2016-09-06 13:22:35 -07:00
traits Replace _, _ with .. 2016-09-04 12:30:33 +03:00
ty Fix issue #36036. 2016-09-05 12:57:00 +02:00
util Auto merge of #36025 - michaelwoerister:incr-comp-hash-spans, r=nikomatsakis 2016-09-06 13:22:35 -07:00
Cargo.toml Fix Cargo.tomls 2016-06-27 18:30:46 +00:00
diagnostics.rs Warn about multiple conflicting #[repr] hints 2016-08-31 18:54:19 +12:00
lib.rs Replace _, _, _ with .. 2016-09-04 12:27:01 +03:00
macros.rs use diagnostic-mutating style for note_type_err too 2016-07-22 22:47:38 +03:00
README.md Integrate overview section with existing docs 2016-01-24 10:52:51 +00:00

An informal guide to reading and working on the rustc compiler.

If you wish to expand on this document, or have a more experienced Rust contributor add anything else to it, please get in touch:

or file a bug:

https://github.com/rust-lang/rust/issues

Your concerns are probably the same as someone else's.

The crates of rustc

Rustc consists of a number of crates, including libsyntax, librustc, librustc_back, librustc_trans, and librustc_driver (the names and divisions are not set in stone and may change; in general, a finer-grained division of crates is preferable):

  • libsyntax contains those things concerned purely with syntax that is, the AST, parser, pretty-printer, lexer, macro expander, and utilities for traversing ASTs are in a separate crate called "syntax", whose files are in ./../libsyntax, where . is the current directory (that is, the parent directory of front/, middle/, back/, and so on).

  • librustc (the current directory) contains the high-level analysis passes, such as the type checker, borrow checker, and so forth. It is the heart of the compiler.

  • librustc_back contains some very low-level details that are specific to different LLVM targets and so forth.

  • librustc_trans contains the code to convert from Rust IR into LLVM IR, and then from LLVM IR into machine code, as well as the main driver that orchestrates all the other passes and various other bits of miscellany. In general it contains code that runs towards the end of the compilation process.

  • librustc_driver invokes the compiler from libsyntax, then the analysis phases from librustc, and finally the lowering and codegen passes from librustc_trans.

Roughly speaking the "order" of the three crates is as follows:

          librustc_driver
                  |
+-----------------+-------------------+
|                                     |
libsyntax -> librustc -> librustc_trans

The compiler process:

The Rust compiler is comprised of six main compilation phases.

  1. Parsing input
  2. Configuration & expanding (cfg rules & syntax extension expansion)
  3. Running analysis passes
  4. Translation to LLVM
  5. LLVM passes
  6. Linking

Phase one is responsible for parsing & lexing the input to the compiler. The output of this phase is an abstract syntax tree (AST). The AST at this point includes all macro uses & attributes. This means code which will be later expanded and/or removed due to cfg attributes is still present in this version of the AST. Parsing abstracts away details about individual files which have been read into the AST.

Phase two handles configuration and macro expansion. You can think of this phase as a function acting on the AST from the previous phase. The input for this phase is the unexpanded AST from phase one, and the output is an expanded version of the same AST. This phase will expand all macros & syntax extensions and will evaluate all cfg attributes, potentially removing some code. The resulting AST will not contain any macros or macro_use statements.

The code for these first two phases is in libsyntax.

After this phase, the compiler allocates IDs to each node in the AST (technically not every node, but most of them). If we are writing out dependencies, that happens now.

The third phase is analysis. This is the most complex phase in the compiler, and makes up much of the code. This phase included name resolution, type checking, borrow checking, type & lifetime inference, trait selection, method selection, linting and so on. Most of the error detection in the compiler comes from this phase (with the exception of parse errors which arise during parsing). The "output" of this phase is a set of side tables containing semantic information about the source program. The analysis code is in librustc and some other crates with the librustc_ prefix.

The fourth phase is translation. This phase translates the AST (and the side tables from the previous phase) into LLVM IR (intermediate representation). This is achieved by calling into the LLVM libraries. The code for this is in librustc_trans.

Phase five runs the LLVM backend. This runs LLVM's optimization passes on the generated IR and generates machine code resulting in object files. This phase is not really part of the Rust compiler, as LLVM carries out all the work. The interface between LLVM and Rust is in librustc_llvm.

The final phase, phase six, links the object files into an executable. This is again outsourced to other tools and not performed by the Rust compiler directly. The interface is in librustc_back (which also contains some things used primarily during translation).

A module called the driver coordinates all these phases. It handles all the highest level coordination of compilation from parsing command line arguments all the way to invoking the linker to produce an executable.

Modules in the librustc crate

The librustc crate itself consists of the following submodules (mostly, but not entirely, in their own directories):

  • session: options and data that pertain to the compilation session as a whole
  • middle: middle-end: name resolution, typechecking, LLVM code generation
  • metadata: encoder and decoder for data required by separate compilation
  • plugin: infrastructure for compiler plugins
  • lint: infrastructure for compiler warnings
  • util: ubiquitous types and helper functions
  • lib: bindings to LLVM

The entry-point for the compiler is main() in the librustc_driver crate.

The 3 central data structures:

  1. ./../libsyntax/ast.rs defines the AST. The AST is treated as immutable after parsing, but it depends on mutable context data structures (mainly hash maps) to give it meaning.

    • Many though not all nodes within this data structure are wrapped in the type spanned<T>, meaning that the front-end has marked the input coordinates of that node. The member node is the data itself, the member span is the input location (file, line, column; both low and high).

    • Many other nodes within this data structure carry a def_id. These nodes represent the 'target' of some name reference elsewhere in the tree. When the AST is resolved, by middle/resolve.rs, all names wind up acquiring a def that they point to. So anything that can be pointed-to by a name winds up with a def_id.

  2. middle/ty.rs defines the datatype sty. This is the type that represents types after they have been resolved and normalized by the middle-end. The typeck phase converts every ast type to a ty::sty, and the latter is used to drive later phases of compilation. Most variants in the ast::ty tag have a corresponding variant in the ty::sty tag.

  3. ./../librustc_llvm/lib.rs defines the exported types ValueRef, TypeRef, BasicBlockRef, and several others. Each of these is an opaque pointer to an LLVM type, manipulated through the lib::llvm interface.