Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smir demo #74

Merged
merged 2 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Run a job to ensure formatting is OK
name: Run demo
on:
pull_request:
paths:
- demo/**

push:
paths:
- demo/**

jobs:
check_demo:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Run Demo
run: ./demo/run_demo.sh
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()
);
Comment on lines +5 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something all users need to do? Can we do anything on the rustc side to make this simpler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think users have to do this if they want to be able to invoke their binaries directly. If you run the program under cargo or rustup run, it should configure the environment correctly for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I.e.: if you remove this build file, the following still works:

$ cargo run -- --help

But if you run the binary directly:

$ ./target/debug/smir-demo --help
./target/debug/smir-demo: error while loading shared libraries: librustc_driver-a03ea465d8e03db1.so: cannot open shared object file: No such file or directory

}
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
Loading