From 544b06d455a067ab54a850e34bdc7794f23c6734 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 Nov 2015 06:33:59 -0500 Subject: [PATCH] Add a MIR visitor --- src/librustc_mir/lib.rs | 1 + src/librustc_mir/visit.rs | 239 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 src/librustc_mir/visit.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 5c52dfe2bd6..ed5df21d911 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -35,4 +35,5 @@ mod hair; pub mod repr; mod graphviz; pub mod tcx; +pub mod visit; diff --git a/src/librustc_mir/visit.rs b/src/librustc_mir/visit.rs new file mode 100644 index 00000000000..b4d6075d0ad --- /dev/null +++ b/src/librustc_mir/visit.rs @@ -0,0 +1,239 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::middle::ty::Region; +use repr::*; + +pub trait Visitor<'tcx> { + // Override these, and call `self.super_xxx` to revert back to the + // default behavior. + + fn visit_mir(&mut self, mir: &Mir<'tcx>) { + self.super_mir(mir); + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { + self.super_basic_block_data(block, data); + } + + fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) { + self.super_statement(block, statement); + } + + fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) { + self.super_assign(block, lvalue, rvalue); + } + + fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) { + self.super_terminator(block, terminator); + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + self.super_rvalue(rvalue); + } + + fn visit_operand(&mut self, operand: &Operand<'tcx>) { + self.super_operand(operand); + } + + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) { + self.super_lvalue(lvalue, context); + } + + fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) { + self.super_branch(source, target); + } + + fn visit_constant(&mut self, constant: &Constant<'tcx>) { + self.super_constant(constant); + } + + // The `super_xxx` methods comprise the default behavior and are + // not meant to be overidden. + + fn super_mir(&mut self, mir: &Mir<'tcx>) { + for block in mir.all_basic_blocks() { + let data = mir.basic_block_data(block); + self.visit_basic_block_data(block, data); + } + } + + fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { + for statement in &data.statements { + self.visit_statement(block, statement); + } + self.visit_terminator(block, &data.terminator); + } + + fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) { + match statement.kind { + StatementKind::Assign(ref lvalue, ref rvalue) => { + self.visit_assign(block, lvalue, rvalue); + } + StatementKind::Drop(_, ref lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Drop); + } + } + } + + fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) { + self.visit_lvalue(lvalue, LvalueContext::Store); + self.visit_rvalue(rvalue); + } + + fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) { + match *terminator { + Terminator::Goto { target } | + Terminator::Panic { target } => { + self.visit_branch(block, target); + } + + Terminator::If { ref cond, ref targets } => { + self.visit_operand(cond); + for &target in &targets[..] { + self.visit_branch(block, target); + } + } + + Terminator::Switch { ref discr, adt_def: _, ref targets } => { + self.visit_lvalue(discr, LvalueContext::Inspect); + for &target in targets { + self.visit_branch(block, target); + } + } + + Terminator::Diverge | + Terminator::Return => { + } + + Terminator::Call { ref data, ref targets } => { + self.visit_lvalue(&data.destination, LvalueContext::Store); + self.visit_operand(&data.func); + for arg in &data.args { + self.visit_operand(arg); + } + for &target in &targets[..] { + self.visit_branch(block, target); + } + } + } + } + + fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + match *rvalue { + Rvalue::Use(ref operand) => { + self.visit_operand(operand); + } + + Rvalue::Repeat(ref value, ref len) => { + self.visit_operand(value); + self.visit_operand(len); + } + + Rvalue::Ref(r, bk, ref path) => { + self.visit_lvalue(path, LvalueContext::Borrow { + region: r, + kind: bk + }); + } + + Rvalue::Len(ref path) => { + self.visit_lvalue(path, LvalueContext::Inspect); + } + + Rvalue::Cast(_, ref operand, _) => { + self.visit_operand(operand); + } + + Rvalue::BinaryOp(_, ref lhs, ref rhs) => { + self.visit_operand(lhs); + self.visit_operand(rhs); + } + + Rvalue::UnaryOp(_, ref op) => { + self.visit_operand(op); + } + + Rvalue::Box(_) => { + } + + Rvalue::Aggregate(_, ref operands) => { + for operand in operands { + self.visit_operand(operand); + } + } + + Rvalue::Slice { ref input, from_start, from_end } => { + self.visit_lvalue(input, LvalueContext::Slice { + from_start: from_start, + from_end: from_end, + }); + } + + Rvalue::InlineAsm(_) => { + } + } + } + + fn super_operand(&mut self, operand: &Operand<'tcx>) { + match *operand { + Operand::Consume(ref lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Consume); + } + Operand::Constant(ref constant) => { + self.visit_constant(constant); + } + } + } + + fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) { + match *lvalue { + Lvalue::Var(_) | + Lvalue::Temp(_) | + Lvalue::Arg(_) | + Lvalue::Static(_) | + Lvalue::ReturnPointer => { + } + Lvalue::Projection(ref proj) => { + self.visit_lvalue(&proj.base, LvalueContext::Projection); + } + } + } + + fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) { + } + + fn super_constant(&mut self, _constant: &Constant<'tcx>) { + } +} + +#[derive(Copy, Clone, Debug)] +pub enum LvalueContext { + // Appears as LHS of an assignment or as dest of a call + Store, + + // Being dropped + Drop, + + // Being inspected in some way, like loading a len + Inspect, + + // Being borrowed + Borrow { region: Region, kind: BorrowKind }, + + // Being sliced -- this should be same as being borrowed, probably + Slice { from_start: usize, from_end: usize }, + + // Used as base for another lvalue, e.g. `x` in `x.y` + Projection, + + // Consumed as part of an operand + Consume, +}