Skip to content

Commit 6176e87

Browse files
celinvaloli-obk
authored andcommitted
Add a demo example to be used in the RW2024
1 parent 801f474 commit 6176e87

File tree

8 files changed

+136
-2
lines changed

8 files changed

+136
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ members = [
99
exclude = [
1010
"build",
1111
"target",
12+
"demo",
1213
]

demo/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "smir-demo"
3+
description = "A little demo tool on how to use StableMIR to analyze crates"
4+
version = "0.0.0"
5+
edition = "2021"
6+
7+
[dependencies]
8+
9+
[package.metadata.rust-analyzer]
10+
# This crate uses #[feature(rustc_private)].
11+
# See https://github.com/rust-analyzer/rust-analyzer/pull/7891
12+
rustc_private = true

demo/build.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use std::env;
2+
use std::path::PathBuf;
3+
4+
pub fn main() {
5+
// Add rustup to the rpath in order to properly link with the correct rustc version.
6+
let rustup_home = env::var("RUSTUP_HOME").unwrap();
7+
let toolchain = env::var("RUSTUP_TOOLCHAIN").unwrap();
8+
let rustc_lib: PathBuf = [&rustup_home, "toolchains", &toolchain, "lib"]
9+
.iter()
10+
.collect();
11+
println!(
12+
"cargo:rustc-link-arg-bin=smir-demo=-Wl,-rpath,{}",
13+
rustc_lib.display()
14+
);
15+
}

demo/run_demo.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
# Builds and run the demo driver against itself.
3+
# I.e.: This bootstrap itself.
4+
5+
REPO_DIR=$(git rev-parse --show-toplevel)
6+
DEMO_DIR="${REPO_DIR}/demo"
7+
8+
cd "${DEMO_DIR}"
9+
cargo run -- src/main.rs --crate-name demo --edition 2021 -C panic=abort
10+

demo/rust-toolchain.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[toolchain]
2+
channel = "nightly-2024-04-02"
3+
components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]

demo/src/main.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//! Small utility that print some information about a crate.
2+
3+
#![feature(rustc_private)]
4+
#![feature(assert_matches)]
5+
6+
extern crate rustc_driver;
7+
extern crate rustc_interface;
8+
#[macro_use]
9+
extern crate rustc_smir;
10+
extern crate stable_mir;
11+
12+
use std::collections::HashSet;
13+
use std::io::stdout;
14+
use rustc_smir::{run, rustc_internal};
15+
use stable_mir::{CompilerError, CrateDef};
16+
use std::ops::ControlFlow;
17+
use std::process::ExitCode;
18+
use stable_mir::mir::{LocalDecl, MirVisitor, Terminator, TerminatorKind};
19+
use stable_mir::mir::mono::Instance;
20+
use stable_mir::mir::visit::Location;
21+
use stable_mir::ty::{RigidTy, Ty, TyKind};
22+
23+
24+
/// This is a wrapper that can be used to replace rustc.
25+
fn main() -> ExitCode {
26+
let rustc_args = std::env::args().into_iter().collect();
27+
let result = run!(rustc_args, start_demo);
28+
match result {
29+
Ok(_) | Err(CompilerError::Skipped | CompilerError::Interrupted(_)) => ExitCode::SUCCESS,
30+
_ => ExitCode::FAILURE,
31+
}
32+
}
33+
34+
fn start_demo() -> ControlFlow<()> {
35+
let crate_name = stable_mir::local_crate().name;
36+
eprintln!("--- Analyzing crate: {crate_name}");
37+
38+
let crate_items = stable_mir::all_local_items();
39+
for item in crate_items {
40+
eprintln!(" - {} @{:?}", item.name(), item.span())
41+
}
42+
43+
let entry_fn = stable_mir::entry_fn().unwrap();
44+
let entry_instance = Instance::try_from(entry_fn).unwrap();
45+
analyze_instance(entry_instance);
46+
ControlFlow::Break(())
47+
}
48+
49+
fn analyze_instance(instance: Instance) {
50+
eprintln!("--- Analyzing instance: {}", instance.name());
51+
eprintln!(" - Mangled name: {}", instance.mangled_name());
52+
eprintln!(" - FnABI: {:?}", instance.fn_abi().unwrap());
53+
54+
let body = instance.body().unwrap();
55+
let mut visitor = Visitor {
56+
locals: body.locals(),
57+
tys: Default::default(),
58+
fn_calls: Default::default(),
59+
};
60+
visitor.visit_body(&body);
61+
visitor.tys.iter().for_each(|ty| eprintln!(" - Visited: {ty}"));
62+
visitor.fn_calls.iter().for_each(|instance| eprintln!(" - Call: {}", instance.name()));
63+
64+
body.dump(&mut stdout().lock(), &instance.name()).unwrap();
65+
}
66+
67+
struct Visitor<'a> {
68+
locals: &'a [LocalDecl],
69+
tys: HashSet<Ty>,
70+
fn_calls: HashSet<Instance>,
71+
}
72+
73+
impl<'a> MirVisitor for Visitor<'a> {
74+
fn visit_terminator(&mut self, term: &Terminator, _location: Location) {
75+
match term.kind {
76+
TerminatorKind::Call { ref func, .. } => {
77+
let op_ty = func.ty(self.locals).unwrap();
78+
let TyKind::RigidTy(RigidTy::FnDef(def, args)) = op_ty.kind() else { return; };
79+
self.fn_calls.insert(Instance::resolve(def, &args).unwrap());
80+
}
81+
_ => {}
82+
}
83+
}
84+
85+
fn visit_ty(&mut self, ty: &Ty, _location: Location) {
86+
self.tys.insert(*ty);
87+
}
88+
}

tools/test-drive/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ description = "A rustc wrapper that can be used to test stable-mir on a crate"
44
version = "0.0.0"
55
edition = "2021"
66

7-
[dependencies]
8-
97
[package.metadata.rust-analyzer]
108
# This crate uses #[feature(rustc_private)].
119
# See https://github.com/rust-analyzer/rust-analyzer/pull/7891

0 commit comments

Comments
 (0)