diff --git a/Cargo.lock b/Cargo.lock index d24a4271aa166..724587a4a71c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4093,6 +4093,7 @@ dependencies = [ name = "rustc_smir" version = "0.0.0" dependencies = [ + "rustc_hir", "rustc_middle", "rustc_span", "tracing", diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index fb97ee5bebe6e..80360a3c73f8d 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] +rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 09cb6fd22d5e6..241cd182059ba 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -93,10 +93,10 @@ fn rustc_statement_to_statement( } } -fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Operand { +fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Rvalue { use rustc_middle::mir::Rvalue::*; match rvalue { - Use(op) => rustc_op_to_op(op), + Use(op) => stable_mir::mir::Rvalue::Use(rustc_op_to_op(op)), Repeat(_, _) => todo!(), Ref(_, _, _) => todo!(), ThreadLocalRef(_) => todo!(), @@ -104,9 +104,15 @@ fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir: Len(_) => todo!(), Cast(_, _, _) => todo!(), BinaryOp(_, _) => todo!(), - CheckedBinaryOp(_, _) => todo!(), + CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp( + rustc_bin_op_to_bin_op(bin_op), + rustc_op_to_op(&ops.0), + rustc_op_to_op(&ops.1), + ), NullaryOp(_, _) => todo!(), - UnaryOp(_, _) => todo!(), + UnaryOp(un_op, op) => { + stable_mir::mir::Rvalue::UnaryOp(rustc_un_op_to_un_op(un_op), rustc_op_to_op(op)) + } Discriminant(_) => todo!(), Aggregate(_, _) => todo!(), ShallowInitBox(_, _) => todo!(), @@ -124,8 +130,10 @@ fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Opera } fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place { - assert_eq!(&place.projection[..], &[]); - stable_mir::mir::Place { local: place.local.as_usize() } + stable_mir::mir::Place { + local: place.local.as_usize(), + projection: format!("{:?}", place.projection), + } } fn rustc_unwind_to_unwind( @@ -140,6 +148,96 @@ fn rustc_unwind_to_unwind( } } +fn rustc_assert_msg_to_msg<'tcx>( + assert_message: &rustc_middle::mir::AssertMessage<'tcx>, +) -> stable_mir::mir::AssertMessage { + use rustc_middle::mir::AssertKind; + match assert_message { + AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck { + len: rustc_op_to_op(len), + index: rustc_op_to_op(index), + }, + AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow( + rustc_bin_op_to_bin_op(bin_op), + rustc_op_to_op(op1), + rustc_op_to_op(op2), + ), + AssertKind::OverflowNeg(op) => { + stable_mir::mir::AssertMessage::OverflowNeg(rustc_op_to_op(op)) + } + AssertKind::DivisionByZero(op) => { + stable_mir::mir::AssertMessage::DivisionByZero(rustc_op_to_op(op)) + } + AssertKind::RemainderByZero(op) => { + stable_mir::mir::AssertMessage::RemainderByZero(rustc_op_to_op(op)) + } + AssertKind::ResumedAfterReturn(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterReturn(rustc_generator_to_generator( + generator, + )) + } + AssertKind::ResumedAfterPanic(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterPanic(rustc_generator_to_generator( + generator, + )) + } + AssertKind::MisalignedPointerDereference { required, found } => { + stable_mir::mir::AssertMessage::MisalignedPointerDereference { + required: rustc_op_to_op(required), + found: rustc_op_to_op(found), + } + } + } +} + +fn rustc_bin_op_to_bin_op(bin_op: &rustc_middle::mir::BinOp) -> stable_mir::mir::BinOp { + use rustc_middle::mir::BinOp; + match bin_op { + BinOp::Add => stable_mir::mir::BinOp::Add, + BinOp::Sub => stable_mir::mir::BinOp::Sub, + BinOp::Mul => stable_mir::mir::BinOp::Mul, + BinOp::Div => stable_mir::mir::BinOp::Div, + BinOp::Rem => stable_mir::mir::BinOp::Rem, + BinOp::BitXor => stable_mir::mir::BinOp::BitXor, + BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd, + BinOp::BitOr => stable_mir::mir::BinOp::BitOr, + BinOp::Shl => stable_mir::mir::BinOp::Shl, + BinOp::Shr => stable_mir::mir::BinOp::Shr, + BinOp::Eq => stable_mir::mir::BinOp::Eq, + BinOp::Lt => stable_mir::mir::BinOp::Lt, + BinOp::Le => stable_mir::mir::BinOp::Le, + BinOp::Ne => stable_mir::mir::BinOp::Ne, + BinOp::Ge => stable_mir::mir::BinOp::Ge, + BinOp::Gt => stable_mir::mir::BinOp::Gt, + BinOp::Offset => stable_mir::mir::BinOp::Offset, + } +} + +fn rustc_un_op_to_un_op(unary_op: &rustc_middle::mir::UnOp) -> stable_mir::mir::UnOp { + use rustc_middle::mir::UnOp; + match unary_op { + UnOp::Not => stable_mir::mir::UnOp::Not, + UnOp::Neg => stable_mir::mir::UnOp::Neg, + } +} + +fn rustc_generator_to_generator( + generator: &rustc_hir::GeneratorKind, +) -> stable_mir::mir::GeneratorKind { + use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; + match generator { + GeneratorKind::Async(async_gen) => { + let async_gen = match async_gen { + AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block, + AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure, + AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn, + }; + stable_mir::mir::GeneratorKind::Async(async_gen) + } + GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen, + } +} + fn rustc_terminator_to_terminator( terminator: &rustc_middle::mir::Terminator<'_>, ) -> stable_mir::mir::Terminator { @@ -162,7 +260,11 @@ fn rustc_terminator_to_terminator( Terminate => Terminator::Abort, Return => Terminator::Return, Unreachable => Terminator::Unreachable, - Drop { .. } => todo!(), + Drop { place, target, unwind } => Terminator::Drop { + place: rustc_place_to_place(place), + target: target.as_usize(), + unwind: rustc_unwind_to_unwind(unwind), + }, Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => { Terminator::Call { func: rustc_op_to_op(func), @@ -172,9 +274,15 @@ fn rustc_terminator_to_terminator( unwind: rustc_unwind_to_unwind(unwind), } } - Assert { .. } => todo!(), + Assert { cond, expected, msg, target, unwind } => Terminator::Assert { + cond: rustc_op_to_op(cond), + expected: *expected, + msg: rustc_assert_msg_to_msg(msg), + target: target.as_usize(), + unwind: rustc_unwind_to_unwind(unwind), + }, Yield { .. } => todo!(), - GeneratorDrop => todo!(), + GeneratorDrop => Terminator::GeneratorDrop, FalseEdge { .. } => todo!(), FalseUnwind { .. } => todo!(), InlineAsm { .. } => todo!(), diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index bd5e6b68a12fa..4baf3f1f75eac 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -26,7 +26,7 @@ pub enum Terminator { Drop { place: Place, target: usize, - unwind: Option, + unwind: UnwindAction, }, Call { func: Operand, @@ -38,10 +38,11 @@ pub enum Terminator { Assert { cond: Operand, expected: bool, - msg: String, + msg: AssertMessage, target: usize, - cleanup: Option, + unwind: UnwindAction, }, + GeneratorDrop, } #[derive(Clone, Debug)] @@ -52,12 +53,72 @@ pub enum UnwindAction { Cleanup(usize), } +#[derive(Clone, Debug)] +pub enum AssertMessage { + BoundsCheck { len: Operand, index: Operand }, + Overflow(BinOp, Operand, Operand), + OverflowNeg(Operand), + DivisionByZero(Operand), + RemainderByZero(Operand), + ResumedAfterReturn(GeneratorKind), + ResumedAfterPanic(GeneratorKind), + MisalignedPointerDereference { required: Operand, found: Operand }, +} + +#[derive(Clone, Debug)] +pub enum BinOp { + Add, + Sub, + Mul, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt, + Offset, +} + +#[derive(Clone, Debug)] +pub enum UnOp { + Not, + Neg, +} + +#[derive(Clone, Debug)] +pub enum GeneratorKind { + Async(AsyncGeneratorKind), + Gen, +} + +#[derive(Clone, Debug)] +pub enum AsyncGeneratorKind { + Block, + Closure, + Fn, +} + #[derive(Clone, Debug)] pub enum Statement { - Assign(Place, Operand), + Assign(Place, Rvalue), Nop, } +// FIXME this is incomplete +#[derive(Clone, Debug)] +pub enum Rvalue { + Use(Operand), + CheckedBinaryOp(BinOp, Operand, Operand), + UnaryOp(UnOp, Operand), +} + #[derive(Clone, Debug)] pub enum Operand { Copy(Place), @@ -68,6 +129,7 @@ pub enum Operand { #[derive(Clone, Debug)] pub struct Place { pub local: usize, + pub projection: String, } #[derive(Clone, Debug)] diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 95f27efa7715c..1454d6dde6c97 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -60,6 +60,24 @@ fn test_stable_mir(tcx: TyCtxt<'_>) { stable_mir::mir::Terminator::Call { .. } => {} other => panic!("{other:?}"), } + + let drop = get_item(tcx, &items, (DefKind::Fn, "drop")).unwrap(); + let body = drop.body(); + assert_eq!(body.blocks.len(), 2); + let block = &body.blocks[0]; + match &block.terminator { + stable_mir::mir::Terminator::Drop { .. } => {} + other => panic!("{other:?}"), + } + + let assert = get_item(tcx, &items, (DefKind::Fn, "assert")).unwrap(); + let body = assert.body(); + assert_eq!(body.blocks.len(), 2); + let block = &body.blocks[0]; + match &block.terminator { + stable_mir::mir::Terminator::Assert { .. } => {} + other => panic!("{other:?}"), + } } // Use internal API to find a function in a crate. @@ -131,6 +149,12 @@ fn generate_input(path: &str) -> std::io::Result<()> { let x_64 = foo::bar(x); let y_64 = foo::bar(y); x_64.wrapping_add(y_64) + }} + + pub fn drop(_: String) {{}} + + pub fn assert(x: i32) -> i32 {{ + x + 1 }}"# )?; Ok(())