neo_solidity/ir/expressions/
power.rs

1fn lower_power_expression(
2    left: &Expression,
3    right: &Expression,
4    ctx: &mut LoweringContext,
5    instructions: &mut Vec<Instruction>,
6) -> bool {
7    if let (Some(LiteralValue::Integer(base)), Some(LiteralValue::Integer(exp_lit))) = (
8        literal_from_expression(left),
9        literal_from_expression(right),
10    ) {
11        if let Some(exp) = exp_lit.to_u32() {
12            let mut result = BigInt::one();
13            for _ in 0..exp {
14                result *= &base;
15            }
16            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(result)));
17            return true;
18        }
19    }
20
21    let base_local = ctx.allocate_local("__pow_base".to_string(), None);
22    let exp_local = ctx.allocate_local("__pow_exp".to_string(), None);
23    let result_local = ctx.allocate_local("__pow_result".to_string(), None);
24
25    if !lower_expression(left, ctx, instructions) {
26        return false;
27    }
28    instructions.push(Instruction::StoreLocal(base_local));
29
30    if !lower_expression(right, ctx, instructions) {
31        return false;
32    }
33    instructions.push(Instruction::StoreLocal(exp_local));
34
35    instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::one())));
36    instructions.push(Instruction::StoreLocal(result_local));
37
38    let loop_label = ctx.next_label();
39    let end_label = ctx.next_label();
40    let skip_mul_label = ctx.next_label();
41
42    instructions.push(Instruction::Label(loop_label));
43    instructions.push(Instruction::LoadLocal(exp_local));
44    instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
45    instructions.push(Instruction::BinaryOp(BinaryOperator::Ne));
46    instructions.push(Instruction::JumpIf { target: end_label });
47
48    instructions.push(Instruction::LoadLocal(exp_local));
49    instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::one())));
50    instructions.push(Instruction::BinaryOp(BinaryOperator::BitAnd));
51    instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
52    instructions.push(Instruction::BinaryOp(BinaryOperator::Ne));
53    // JumpIf branches when the condition is false; skip multiply when exp is even.
54    instructions.push(Instruction::JumpIf {
55        target: skip_mul_label,
56    });
57    instructions.push(Instruction::LoadLocal(result_local));
58    instructions.push(Instruction::LoadLocal(base_local));
59    instructions.push(Instruction::BinaryOp(BinaryOperator::Mul));
60    instructions.push(Instruction::StoreLocal(result_local));
61
62    instructions.push(Instruction::Label(skip_mul_label));
63    instructions.push(Instruction::LoadLocal(base_local));
64    instructions.push(Instruction::LoadLocal(base_local));
65    instructions.push(Instruction::BinaryOp(BinaryOperator::Mul));
66    instructions.push(Instruction::StoreLocal(base_local));
67
68    instructions.push(Instruction::LoadLocal(exp_local));
69    instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::one())));
70    instructions.push(Instruction::BinaryOp(BinaryOperator::Shr));
71    instructions.push(Instruction::StoreLocal(exp_local));
72
73    instructions.push(Instruction::Jump { target: loop_label });
74    instructions.push(Instruction::Label(end_label));
75    instructions.push(Instruction::LoadLocal(result_local));
76    true
77}