Skip to content
This repository has been archived by the owner on Jan 7, 2022. It is now read-only.

Commit

Permalink
Add the Yorick software tracing MIR pass and associated functionality.
Browse files Browse the repository at this point in the history
This change:

 - Adds a MIR pass which adds, for each MIR block, a call to a tracing
   (language item) function. The arguments to this function uniquely
   identify a location in the MIR. A collection of such locations will
   form a trace.

 - Adds a "no_trace" attribute, which informs the compiler to not apply
   the above MIR pass to an item or crate. This is needed for tests, but
   also to prevent infinite recursion on the tracing function itself.
  • Loading branch information
vext01 committed Dec 31, 2018
1 parent 7df215d commit 3504c9c
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ mod nonzero;
mod tuple;
mod unit;

mod yk_swt;

// Pull in the `coresimd` crate directly into libcore. This is where all the
// architecture-specific (and vendor-specific) intrinsics are defined. AKA
// things like SIMD and such. Note that the actual source for all this lies in a
Expand Down
26 changes: 26 additions & 0 deletions src/libcore/yk_swt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2018 King's College London.
// Created by the Software Development Team <http://soft-dev.org/>.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The software trace recorder function.
/// This is a weak language item, it actually resides in libstd. It has to be weak to allow libcore
/// to call up to libstd (libstd is not a dependency of libcore).
extern "Rust" {
#[cfg_attr(not(stage0), lang="yk_swt_rec_loc")]
fn yk_swt_rec_loc(crate_hash: u64, def_idx: u32, bb: u32);
}

/// Wrapper lang item to call the above wrapper function.
/// This has to be a lang item too, as a MIR terminator cannot call a weak language item directly.
#[allow(dead_code)] // Used only indirectly in a MIR pass.
#[cfg_attr(not(stage0), lang="yk_swt_rec_loc_wrap")]
#[cfg_attr(not(stage0), no_trace)]
fn yk_swt_rec_loc_wrap(crate_hash: u64, def_idx: u32, bb: u32) {
unsafe { yk_swt_rec_loc(crate_hash, def_idx, bb) };
}

3 changes: 3 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ language_item_table! {
I128ShroFnLangItem, "i128_shro", i128_shro_fn, Target::Fn;
U128ShroFnLangItem, "u128_shro", u128_shro_fn, Target::Fn;

YkSwtRecLocLangItem, "yk_swt_rec_loc", yk_swt_rec_loc, Target::Fn;
YkSwtRecLocWrapLangItem, "yk_swt_rec_loc_wrap",yk_swt_rec_loc_wrap, Target::Fn;

// Align offset for stride != 1, must not panic.
AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn;

Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,5 @@ weak_lang_items! {
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
oom, OomLangItem, rust_oom;
yk_swt_rec_loc, YkSwtRecLocLangItem, rust_yk_swt_rec_loc;
}
10 changes: 10 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,16 @@ impl<'tcx> Const<'tcx> {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
}

#[inline]
pub fn from_u32(tcx: TyCtxt<'_, '_, 'tcx>, n: u32) -> &'tcx Self {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.u32))
}

#[inline]
pub fn from_u64(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.u64))
}

#[inline]
pub fn to_bits(
&self,
Expand Down
170 changes: 170 additions & 0 deletions src/librustc_mir/transform/add_yk_swt_calls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Copyright 2018 King's College London.
// Created by the Software Development Team <http://soft-dev.org/>.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::ty::{self, TyCtxt, List};
use rustc::mir::{Operand, LocalDecl, Place, SourceInfo, BasicBlock, Local, BasicBlockData,
TerminatorKind, Terminator, OUTERMOST_SOURCE_SCOPE, Constant, Mir};
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::DUMMY_SP;
use syntax::attr;
use transform::{MirPass, MirSource};
use rustc::hir;
use rustc::hir::def_id::{DefIndex, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode;

/// A MIR pass which, for each basic block, inserts a call to the software trace recorder.
/// The call arguments passed uniquely identify the MIR location.
pub struct AddYkSWTCalls(pub DefIndex);

impl MirPass for AddYkSWTCalls {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource,
mir: &mut Mir<'tcx>) {
if !should_annotate(tcx, src) {
return;
}

// Find the recorder function to call.
let rec_fn_defid = tcx.get_lang_items(LOCAL_CRATE).yk_swt_rec_loc_wrap()
.expect("couldn't find software trace recorder function");

// Types.
let unit_ty = tcx.mk_unit();
let u32_ty = tcx.types.u32;
let u64_ty = tcx.types.u64;

// Each block is replaced by a new block whose terminator calls the recorder function.
let mut replace_blocks = Vec::new();

// The original blocks are copied and the recorder function returns to a copy.
let mut copied_blocks = Vec::new();

// New local decls are required to accomodate the (unit) return value of the recorder func.
let mut new_local_decls = Vec::new();

let num_orig_blocks = mir.basic_blocks().len();
let num_orig_local_decls = mir.local_decls.len();
let local_crate_hash = tcx.crate_hash(LOCAL_CRATE).as_u64();

for (bb, bb_data) in mir.basic_blocks_mut().iter_enumerated() {
// Copy the original block and compute what its index will be once we have pushed onto
// the end of the MIR's basic block vector.
let new_blk = bb_data.clone();
let new_blk_idx = BasicBlock::new(num_orig_blocks + copied_blocks.len());
copied_blocks.push(new_blk);

// Prepare to call the recorder function.
let ret_val = LocalDecl::new_temp(unit_ty, DUMMY_SP);
let ret_place = Place::Local(Local::new(num_orig_local_decls + new_local_decls.len()));
new_local_decls.push(ret_val);

let crate_hash_oper = Operand::Constant(box Constant {
span: DUMMY_SP,
ty: u64_ty,
user_ty: None,
literal: ty::Const::from_u64(tcx, local_crate_hash),
});

let def_idx_oper = Operand::Constant(box Constant {
span: DUMMY_SP,
ty: u32_ty,
user_ty: None,
literal: ty::Const::from_u32(tcx, self.0.as_raw_u32()),
});

let bb_oper = Operand::Constant(box Constant {
span: DUMMY_SP,
ty: u32_ty,
user_ty: None,
literal: ty::Const::from_u32(tcx, bb.index() as u32),
});

let rec_fn_oper = Operand::function_handle(tcx, rec_fn_defid,
List::empty(), DUMMY_SP);

let term_kind = TerminatorKind::Call {
func: rec_fn_oper,
args: vec![crate_hash_oper, def_idx_oper, bb_oper],
destination: Some((ret_place, new_blk_idx)),
cleanup: None,
from_hir_call: false,
};

// Construct a new block to replace the original one.
let source_info = bb_data.terminator.clone().map(|t| t.source_info)
.or(Some(SourceInfo { span: DUMMY_SP, scope: OUTERMOST_SOURCE_SCOPE })).unwrap();
let replace_block = BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
source_info,
kind: term_kind
}),
is_cleanup: false
};
replace_blocks.push(replace_block);
}

// Finally, commit our transformations.
mir.basic_blocks_mut().extend(copied_blocks);
mir.local_decls.extend(new_local_decls);
for (bb, bb_data) in replace_blocks.drain(..).enumerate() {
mir.basic_blocks_mut()[BasicBlock::new(bb)] = bb_data;
}
}
}

/// Given a `MirSource`, decides if we should annotate the correpsonding MIR.
fn should_annotate(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource) -> bool {
// Never annotate any MIR-like thing marked `#[no_trace]` or `#[naked]`. The trace record and
// wrapper are also marked `#[no_trace]` to prevent infinite recursion.
for attr in tcx.get_attrs(src.def_id).iter() {
if attr.check_name("no_trace") {
return false;
}
if attr.check_name("naked") {
return false;
}
}

// If there is a crate level `#![no_trace]` attribute, honour that.
for attr in tcx.hir.krate_attrs() {
if attr.check_name("no_trace") {
return false;
}
}

// We can't call the software tracing function if there is no libcore.
if attr::contains_name(tcx.hir.krate_attrs(), "no_core") {
return false;
}

// The libcompiler_builtins crate is special and we can't annotate it.
if tcx.is_compiler_builtins(LOCAL_CRATE) {
return false;
}

// We can't add calls to promoted items.
if let Some(_) = src.promoted {
return false;
}

// We can't add calls to constant functions.
let node_id = tcx.hir.as_local_node_id(src.def_id)
.expect("Failed to get node id");
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
if fn_like.constness() == hir::Constness::Const {
return false;
}
} else {
return false;
}

true
}
2 changes: 2 additions & 0 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub mod generator;
pub mod inline;
pub mod lower_128bit;
pub mod uniform_array_move_out;
pub mod add_yk_swt_calls;

pub(crate) fn provide(providers: &mut Providers) {
self::qualify_consts::provide(providers);
Expand Down Expand Up @@ -302,6 +303,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
&simplify::SimplifyLocals,

&add_call_guards::CriticalCallEdges,
&add_yk_swt_calls::AddYkSWTCalls(def_id.index),
&dump_mir::Marker("PreCodegen"),
]);
tcx.alloc_mir(mir)
Expand Down
4 changes: 4 additions & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,10 @@ mod coresimd {
#[cfg(all(not(stage0), not(test)))]
pub use stdsimd::arch;

/// Yorick software tracing.
#[unstable(feature = "yk_swt", issue = "0")]
pub mod yk_swt;

// Include a number of private modules that exist solely to provide
// the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level.
Expand Down
19 changes: 19 additions & 0 deletions src/libstd/yk_swt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2018 King's College London.
// Created by the Software Development Team <http://soft-dev.org/>.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The software trace recorder function.
/// The `AddYkSWTCalls` MIR pass injects a call this for every MIR block. The call is done
/// indirectly via a wrapper in libcore.
#[cfg_attr(not(stage0), lang="yk_swt_rec_loc")]
#[allow(unused_variables,dead_code)]
#[cfg_attr(not(stage0), no_trace)]
#[cfg(not(test))]
fn rec_loc(crate_hash: u64, def_idx: u32, bb_idx: u32) {
// Not implemented.
}
2 changes: 2 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,8 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
("abi", Normal, Ungated),
("automatically_derived", Normal, Ungated),
("no_mangle", Normal, Ungated),
// Don't trace this. Disables the `AddYkSWTCalls` MIR transform.
("no_trace", Whitelisted, Ungated),
("no_link", Normal, Ungated),
("derive", Normal, Ungated),
("should_panic", Normal, Ungated),
Expand Down

0 comments on commit 3504c9c

Please sign in to comment.