#[test]
fn removes_trivial_jump_to_next_label() {
let module = Module {
functions: vec![Function {
name: "trivialjump".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::Jump { target: 1 },
Instruction::Label(1),
Instruction::ReturnVoid,
],
}],
local_count: 0,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert!(
!matches!(instrs[0], Instruction::Jump { .. }),
"trivial jump should be removed"
);
assert!(matches!(instrs[0], Instruction::Label(1)));
assert!(matches!(instrs[1], Instruction::ReturnVoid));
}
#[test]
fn neovm_peephole_removes_push_drop() {
use neo_devpack_solidity::ir::LiteralValue;
use num_bigint::BigInt;
let module = Module {
functions: vec![Function {
name: "peephole".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::PushLiteral(LiteralValue::Integer(BigInt::from(42))),
Instruction::Drop(ValueType::Integer {
signed: false,
bits: 256,
}),
Instruction::ReturnVoid,
],
}],
local_count: 0,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 1);
assert!(matches!(instrs[0], Instruction::ReturnVoid));
}
#[test]
fn neovm_peephole_removes_load_local_drop() {
let module = Module {
functions: vec![Function {
name: "peephole_local".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::LoadLocal(0),
Instruction::Drop(ValueType::Integer {
signed: false,
bits: 256,
}),
Instruction::ReturnVoid,
],
}],
local_count: 1,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 1);
assert!(matches!(instrs[0], Instruction::ReturnVoid));
}
#[test]
fn neovm_simplify_removes_add_zero() {
use neo_devpack_solidity::ir::{BinaryOperator, LiteralValue};
use num_bigint::BigInt;
let module = Module {
functions: vec![Function {
name: "identity_add".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::LoadLocal(0),
Instruction::PushLiteral(LiteralValue::Integer(BigInt::from(0))),
Instruction::BinaryOp(BinaryOperator::Add),
Instruction::Return,
],
}],
local_count: 1,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 2);
assert!(matches!(instrs[0], Instruction::LoadLocal(0)));
assert!(matches!(instrs[1], Instruction::Return));
}
#[test]
fn neovm_simplify_removes_mul_one() {
use neo_devpack_solidity::ir::{BinaryOperator, LiteralValue};
use num_bigint::BigInt;
let module = Module {
functions: vec![Function {
name: "identity_mul".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::LoadLocal(0),
Instruction::PushLiteral(LiteralValue::Integer(BigInt::from(1))),
Instruction::BinaryOp(BinaryOperator::Mul),
Instruction::Return,
],
}],
local_count: 1,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 2);
assert!(matches!(instrs[0], Instruction::LoadLocal(0)));
assert!(matches!(instrs[1], Instruction::Return));
}
#[test]
fn neovm_bool_keeps_eq_true_for_safety() {
use neo_devpack_solidity::ir::{BinaryOperator, LiteralValue};
let module = Module {
functions: vec![Function {
name: "bool_eq_true".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::LoadLocal(0),
Instruction::PushLiteral(LiteralValue::Boolean(true)),
Instruction::BinaryOp(BinaryOperator::Eq),
Instruction::Return,
],
}],
local_count: 1,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 4, "PUSH true; EQ must be preserved (M-BC2)");
assert!(matches!(instrs[0], Instruction::LoadLocal(0)));
assert!(matches!(
instrs[1],
Instruction::PushLiteral(LiteralValue::Boolean(true))
));
assert!(matches!(
instrs[2],
Instruction::BinaryOp(BinaryOperator::Eq)
));
assert!(matches!(instrs[3], Instruction::Return));
}
#[test]
fn neovm_bool_removes_ne_false() {
use neo_devpack_solidity::ir::{BinaryOperator, LiteralValue};
let module = Module {
functions: vec![Function {
name: "bool_ne_false".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::LoadLocal(0),
Instruction::PushLiteral(LiteralValue::Boolean(false)),
Instruction::BinaryOp(BinaryOperator::Ne),
Instruction::Return,
],
}],
local_count: 1,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 2);
assert!(matches!(instrs[0], Instruction::LoadLocal(0)));
assert!(matches!(instrs[1], Instruction::Return));
}
#[test]
fn neovm_double_bitwise_not_removed() {
let module = Module {
functions: vec![Function {
name: "double_not".to_string(),
kind: IrFunctionKind::Regular,
parameters: vec![],
returns: vec![],
basic_blocks: vec![BasicBlock {
instructions: vec![
Instruction::LoadLocal(0),
Instruction::BitwiseNot,
Instruction::BitwiseNot,
Instruction::Return,
],
}],
local_count: 1,
}],
state_variables: vec![],
events: vec![],
};
let optimized = optimize_ir(module, 3);
let instrs = &optimized.functions[0].basic_blocks[0].instructions;
assert_eq!(instrs.len(), 2);
assert!(matches!(instrs[0], Instruction::LoadLocal(0)));
assert!(matches!(instrs[1], Instruction::Return));
}