//! This is just a helpful place to do random tests and stuff use anyhow::Context; use dpc::common::function::{ CallInterface, FunctionAnnotations, FunctionInterface, FunctionSignature, }; use dpc::common::mc::block::{BlockData, BlockProperties, SetBlockData, SetBlockMode}; use dpc::common::mc::entity::{SelectorType, TargetSelector}; use dpc::common::mc::instr::MinecraftInstr; use dpc::common::mc::pos::Coordinates; use dpc::common::mc::{EntityTarget, XPValue}; use dpc::common::val::{MutableValue, Value}; use dpc::common::{DeclareBinding, IRType, Identifier}; use dpc::ir::{Block, IRFunction, InstrKind, Instruction, IR}; use dpc::lower::ir_to_mir::lower_ir; use dpc::lower::mir_to_lir::lower_mir; use dpc::output::link; use dpc::project::ProjectSettings; use dpc::{def_compound, push_instrs}; use dpc::common::ty::{ create_nbyte_array, DataType, DataTypeContents, NBTArrayType, NBTType, NBTTypeContents, ScoreType, ScoreTypeContents, }; use dpc::passes::{run_ir_passes, run_lir_passes, run_mir_passes}; use rand::Rng; fn main() { fuzz(); } #[allow(dead_code)] fn known() { let mut ir = IR::new(); let mut block = Block::new(); push_instrs! { block, InstrKind::Call { call: CallInterface { function: "foo:bar".into(), args: Vec::new(), ret: Vec::new(), }, }; } let mut annotations = FunctionAnnotations::new(); annotations.preserve = true; ir.functions.insert( "foo_baz".into(), IRFunction { interface: FunctionInterface::with_all( "foo:baz".into(), FunctionSignature::new(), annotations, ), block, }, ); let mut block = Block::new(); let reg_id = Identifier::from("foo"); let reg2_id = Identifier::from("bar"); let reg3_id = Identifier::from("baz"); let reg4_id = Identifier::from("hello"); let reg5_id = Identifier::from("there"); let reg6_id = Identifier::from("swapl"); let reg7_id = Identifier::from("swapr"); let reg8_id = Identifier::from("arr"); let reg10_id = Identifier::from("data"); let cmp1 = def_compound! { foo: NBTType::Int, bar: NBTType::Bool, }; let cmp2 = def_compound! { foo: NBTType::Compound(cmp1.clone()), bar: NBTType::Short, }; let cmp2_cont = def_compound! { foo: NBTTypeContents::Compound(cmp1.clone(), def_compound! { foo: NBTTypeContents::Int(5), bar: NBTTypeContents::Bool(false), }.into()), bar: NBTTypeContents::Short(123), }; push_instrs! { block, InstrKind::Declare { left: reg_id.clone(), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Value(Value::Constant(DataTypeContents::Score( ScoreTypeContents::Score(15), ))), }; InstrKind::Assign { left: MutableValue::Reg(reg_id.clone()), right: Value::Constant(DataTypeContents::Score(ScoreTypeContents::Score(93))), }; InstrKind::Declare { left: reg2_id.clone(), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Value(Value::Constant(DataTypeContents::Score( ScoreTypeContents::Score(-2139), ))), }; InstrKind::Add { left: MutableValue::Reg(reg_id.clone()), right: Value::Mutable(MutableValue::Reg(reg2_id.clone())), }; InstrKind::Add { left: MutableValue::Reg(reg_id.clone()), right: Value::Constant(DataTypeContents::Score(ScoreTypeContents::Score(7))), }; InstrKind::Add { left: MutableValue::Reg(reg_id.clone()), right: Value::Constant(DataTypeContents::Score(ScoreTypeContents::Score(-15))), }; InstrKind::Sub { left: MutableValue::Reg(reg_id.clone()), right: Value::Constant(DataTypeContents::Score(ScoreTypeContents::Score(-1290))), }; InstrKind::Declare { left: reg3_id.clone(), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Value(Value::Constant(DataTypeContents::Score( ScoreTypeContents::Score(0), ))), }; InstrKind::Declare { left: reg4_id.clone(), ty: DataType::NBT(NBTType::Long), right: DeclareBinding::Value(Value::Constant(DataTypeContents::NBT( NBTTypeContents::Long(-9219209999023734623), ))), }; InstrKind::Assign { left: MutableValue::Reg(reg4_id.clone()), right: Value::Constant(DataTypeContents::NBT(NBTTypeContents::Long(1289))), }; InstrKind::Abs { val: MutableValue::Reg(reg2_id.clone()), }; InstrKind::Div { left: MutableValue::Reg(reg_id.clone()), right: Value::Constant(DataTypeContents::Score(ScoreTypeContents::Bool(true))), }; InstrKind::Declare { left: reg5_id.clone(), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Cast( DataType::Score(ScoreType::Score), MutableValue::Reg(reg4_id.clone()), ), }; InstrKind::Mul { left: MutableValue::Reg(reg2_id.clone()), right: Value::Constant(DataTypeContents::Score(ScoreTypeContents::Score(2))), }; InstrKind::Swap { left: MutableValue::Reg(reg5_id.clone()), right: MutableValue::Reg(reg2_id.clone()), }; InstrKind::Declare { left: reg6_id.clone(), ty: DataType::NBT(NBTType::Int), right: DeclareBinding::Value(Value::Constant(DataTypeContents::NBT( NBTTypeContents::Int(-9046), ))), }; InstrKind::Declare { left: reg7_id.clone(), ty: DataType::NBT(NBTType::Int), right: DeclareBinding::Value(Value::Constant(DataTypeContents::NBT( NBTTypeContents::Int(1), ))), }; InstrKind::Swap { left: MutableValue::Reg(reg6_id.clone()), right: MutableValue::Reg(reg7_id.clone()), }; InstrKind::Declare { left: reg8_id.clone(), ty: DataType::NBT(NBTType::Arr(NBTArrayType::Byte(6))), right: DeclareBinding::Value(Value::Constant(DataTypeContents::NBT( NBTTypeContents::Arr(create_nbyte_array(vec![5, 9, -2, 8, -121, 86])), ))), }; InstrKind::Call { call: CallInterface { function: "foo:baz".into(), args: Vec::new(), ret: Vec::new(), }, }; InstrKind::Declare { left: reg10_id.clone(), ty: DataType::NBT(NBTType::Compound(cmp2.clone())), right: DeclareBinding::Value(Value::Constant(DataTypeContents::NBT( NBTTypeContents::Compound(cmp2, cmp2_cont.into()), ))), }; } ir.functions.insert( "foo:bar".into(), IRFunction { interface: FunctionInterface::new("foo:bar".into()), block, }, ); let mut block = Block::new(); push_instrs! { block, InstrKind::Declare { left: reg2_id.clone(), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Value(Value::Constant(DataTypeContents::Score( ScoreTypeContents::Score(7), ))), }; InstrKind::Use { val: MutableValue::Reg(reg2_id.clone()), }; InstrKind::Call { call: CallInterface { function: "foo:bar".into(), args: Vec::new(), ret: Vec::new(), }, }; } ir.functions.insert( "foo:main".into(), IRFunction { interface: FunctionInterface::with_all( "foo:main".into(), FunctionSignature::new(), FunctionAnnotations::new(), ), block, }, ); let res = run(ir, true); if let Err(e) = res { eprintln!("{e:?}"); } } #[allow(dead_code)] fn fuzz() { let instr_count = 35; let fn_count = 1000; let debug = false; let mut rng = rand::thread_rng(); let mut ir = IR::new(); for fn_i in 0..fn_count { let instr_count = rng.gen_range(0..instr_count); let mut reg_count = 0; let mut block = Block::new(); let new_reg = reg_count; reg_count += 1; let kind = InstrKind::Declare { left: Identifier::from(format!("reg{new_reg}")), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Value(Value::Constant(DataTypeContents::Score( ScoreTypeContents::Score(0), ))), }; block.contents.push(Instruction::new(kind)); for _ in 0..instr_count { let left_reg = rng.gen_range(0..reg_count); let left_reg = Identifier::from(format!("reg{left_reg}")); let right_val = match rng.gen_range(0..2) { 0 => { let reg = rng.gen_range(0..reg_count); let reg = Identifier::from(format!("reg{reg}")); Value::Mutable(MutableValue::Reg(reg)) } 1 => { let val = rng.gen_range(-128..128); Value::Constant(DataTypeContents::Score(ScoreTypeContents::Score(val))) } _ => continue, }; let instr = rng.gen_range(0..13); let kind = match instr { 0 => { let new_reg = reg_count; reg_count += 1; InstrKind::Declare { left: Identifier::from(format!("reg{new_reg}")), ty: DataType::Score(ScoreType::Score), right: DeclareBinding::Value(right_val), } } 1 => InstrKind::Assign { left: MutableValue::Reg(left_reg), right: right_val, }, 2 => InstrKind::Add { left: MutableValue::Reg(left_reg), right: right_val, }, 3 => InstrKind::Sub { left: MutableValue::Reg(left_reg), right: right_val, }, 4 => InstrKind::Mul { left: MutableValue::Reg(left_reg), right: right_val, }, 5 => InstrKind::Div { left: MutableValue::Reg(left_reg), right: right_val, }, 6 => InstrKind::Mod { left: MutableValue::Reg(left_reg), right: right_val, }, 7 => InstrKind::Min { left: MutableValue::Reg(left_reg), right: right_val, }, 8 => InstrKind::Max { left: MutableValue::Reg(left_reg), right: right_val, }, 9 => InstrKind::Abs { val: MutableValue::Reg(left_reg), }, 10 => { let amount = rng.gen_range(0..1024); InstrKind::MC(MinecraftInstr::SetXP { target: EntityTarget::Selector(TargetSelector::new(SelectorType::This)), amount, value: XPValue::Points, }) } 11 => { let func = rng.gen_range(0..fn_count); if func == fn_i { continue; } InstrKind::Call { call: CallInterface { function: format!("foo:{func}").into(), args: Vec::new(), ret: Vec::new(), }, } } 12 => InstrKind::MC(MinecraftInstr::SetBlock { data: SetBlockData { pos: Coordinates::here(), block: BlockData::new("stone".into(), BlockProperties::new()), mode: SetBlockMode::Replace, }, }), _ => continue, }; block.contents.push(Instruction::new(kind)); } let func_id = format!("foo:{fn_i}"); let mut annotations = FunctionAnnotations::new(); annotations.preserve = true; let func = if fn_i == 0 { FunctionInterface::with_all( func_id.clone().into(), FunctionSignature::new(), annotations, ) } else { FunctionInterface::new(func_id.clone().into()) }; ir.functions.insert( func_id.into(), IRFunction { interface: func, block, }, ); } let res = run(ir, debug); if let Err(e) = res { eprintln!("{e:?}"); } } fn run(mut ir: IR, debug: bool) -> anyhow::Result<()> { let proj = ProjectSettings::new("dpc".into()); if debug { println!("IR:"); dbg!(&ir.functions); } run_ir_passes(&mut ir, &proj, debug).context("IR passes failed")?; let mut mir = lower_ir(ir).context("Failed to lower IR")?; let init_count = mir.instr_count(); if debug { println!("MIR:"); dbg!(&mir.functions); } run_mir_passes(&mut mir, &proj, debug).context("MIR passes failed")?; if debug { println!("Optimized MIR:"); dbg!(&mir.functions); } let final_count = mir.instr_count(); let pct = if init_count == 0 { 0.0 } else { (1.0 - (final_count as f32 / init_count as f32)) * 100.0 }; println!("Removed percent: {pct}%"); let mut lir = lower_mir(mir).context("Failed to lower MIR")?; let init_count = lir.instr_count(); if debug { println!("LIR:"); dbg!(&lir.functions); } run_lir_passes(&mut lir, &proj, debug).context("LIR passes failed")?; if debug { println!("Optimized LIR:"); dbg!(&lir.functions); } let final_count = lir.instr_count(); let pct = if init_count == 0 { 0.0 } else { (1.0 - (final_count as f32 / init_count as f32)) * 100.0 }; println!("Removed percent: {pct}%"); println!("Doing codegen..."); let datapack = link(lir, &proj).context("Failed to link datapack")?; if debug { dbg!(datapack); } Ok(()) }