Skip to content

Commit

Permalink
Add a demo example to be used in the RW2024
Browse files Browse the repository at this point in the history
  • Loading branch information
celinval authored and oli-obk committed Apr 19, 2024
1 parent 801f474 commit 6176e87
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ members = [
exclude = [
"build",
"target",
"demo",
]
7 changes: 7 additions & 0 deletions demo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions demo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "smir-demo"
description = "A little demo tool on how to use StableMIR to analyze crates"
version = "0.0.0"
edition = "2021"

[dependencies]

[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)].
# See https://github.com/rust-analyzer/rust-analyzer/pull/7891
rustc_private = true
15 changes: 15 additions & 0 deletions demo/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::env;
use std::path::PathBuf;

pub fn main() {
// Add rustup to the rpath in order to properly link with the correct rustc version.
let rustup_home = env::var("RUSTUP_HOME").unwrap();
let toolchain = env::var("RUSTUP_TOOLCHAIN").unwrap();
let rustc_lib: PathBuf = [&rustup_home, "toolchains", &toolchain, "lib"]
.iter()
.collect();
println!(
"cargo:rustc-link-arg-bin=smir-demo=-Wl,-rpath,{}",
rustc_lib.display()
);
}
10 changes: 10 additions & 0 deletions demo/run_demo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Builds and run the demo driver against itself.
# I.e.: This bootstrap itself.

REPO_DIR=$(git rev-parse --show-toplevel)
DEMO_DIR="${REPO_DIR}/demo"

cd "${DEMO_DIR}"
cargo run -- src/main.rs --crate-name demo --edition 2021 -C panic=abort

3 changes: 3 additions & 0 deletions demo/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[toolchain]
channel = "nightly-2024-04-02"
components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]
88 changes: 88 additions & 0 deletions demo/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Small utility that print some information about a crate.

#![feature(rustc_private)]
#![feature(assert_matches)]

extern crate rustc_driver;
extern crate rustc_interface;
#[macro_use]
extern crate rustc_smir;
extern crate stable_mir;

use std::collections::HashSet;
use std::io::stdout;
use rustc_smir::{run, rustc_internal};
use stable_mir::{CompilerError, CrateDef};
use std::ops::ControlFlow;
use std::process::ExitCode;
use stable_mir::mir::{LocalDecl, MirVisitor, Terminator, TerminatorKind};
use stable_mir::mir::mono::Instance;
use stable_mir::mir::visit::Location;
use stable_mir::ty::{RigidTy, Ty, TyKind};


/// This is a wrapper that can be used to replace rustc.
fn main() -> ExitCode {
let rustc_args = std::env::args().into_iter().collect();
let result = run!(rustc_args, start_demo);
match result {
Ok(_) | Err(CompilerError::Skipped | CompilerError::Interrupted(_)) => ExitCode::SUCCESS,
_ => ExitCode::FAILURE,
}
}

fn start_demo() -> ControlFlow<()> {
let crate_name = stable_mir::local_crate().name;
eprintln!("--- Analyzing crate: {crate_name}");

let crate_items = stable_mir::all_local_items();
for item in crate_items {
eprintln!(" - {} @{:?}", item.name(), item.span())
}

let entry_fn = stable_mir::entry_fn().unwrap();
let entry_instance = Instance::try_from(entry_fn).unwrap();
analyze_instance(entry_instance);
ControlFlow::Break(())
}

fn analyze_instance(instance: Instance) {
eprintln!("--- Analyzing instance: {}", instance.name());
eprintln!(" - Mangled name: {}", instance.mangled_name());
eprintln!(" - FnABI: {:?}", instance.fn_abi().unwrap());

let body = instance.body().unwrap();
let mut visitor = Visitor {
locals: body.locals(),
tys: Default::default(),
fn_calls: Default::default(),
};
visitor.visit_body(&body);
visitor.tys.iter().for_each(|ty| eprintln!(" - Visited: {ty}"));
visitor.fn_calls.iter().for_each(|instance| eprintln!(" - Call: {}", instance.name()));

body.dump(&mut stdout().lock(), &instance.name()).unwrap();
}

struct Visitor<'a> {
locals: &'a [LocalDecl],
tys: HashSet<Ty>,
fn_calls: HashSet<Instance>,
}

impl<'a> MirVisitor for Visitor<'a> {
fn visit_terminator(&mut self, term: &Terminator, _location: Location) {
match term.kind {
TerminatorKind::Call { ref func, .. } => {
let op_ty = func.ty(self.locals).unwrap();
let TyKind::RigidTy(RigidTy::FnDef(def, args)) = op_ty.kind() else { return; };
self.fn_calls.insert(Instance::resolve(def, &args).unwrap());
}
_ => {}
}
}

fn visit_ty(&mut self, ty: &Ty, _location: Location) {
self.tys.insert(*ty);
}
}
2 changes: 0 additions & 2 deletions tools/test-drive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ description = "A rustc wrapper that can be used to test stable-mir on a crate"
version = "0.0.0"
edition = "2021"

[dependencies]

[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)].
# See https://github.com/rust-analyzer/rust-analyzer/pull/7891
Expand Down

0 comments on commit 6176e87

Please sign in to comment.