neo_solidity/ir/expressions/
power.rs1fn 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 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}