zkevm_assembly/assembly/instruction/
add.rs

1//!
2//! The arithmetic addition instruction.
3//!
4
5use super::*;
6use crate::assembly::operand::{FullOperand, RegisterOperand};
7use crate::error::InstructionReadError;
8use std::collections::HashMap;
9use std::convert::TryFrom;
10
11///
12/// The arithmetic addition instruction.
13///
14#[derive(Debug, Clone, PartialEq)]
15pub struct Add {
16    /// Condition for execution
17    pub condition: ConditionCase,
18    /// Whether we set flags or not
19    pub set_flags_option: SetFlags,
20    /// The first operand.
21    pub source_1: FullOperand,
22    /// The second operand.
23    pub source_2: RegisterOperand,
24    /// The destination operand.
25    pub destination: FullOperand,
26}
27
28impl Add {
29    // Total number of arguments in canonical form
30    pub const NUM_ARGUMENTS: usize = 3;
31
32    #[track_caller]
33    pub fn build_from_parts(
34        mut modifiers: HashSet<&str>,
35        operands: Vec<&str>,
36    ) -> Result<Self, InstructionReadError> {
37        let operands = if let Ok(operands) = parse_canonical_operands_sequence(
38            operands.clone(),
39            &[marker_full_operand(), marker_register_operand()],
40            &[marker_full_operand()],
41        ) {
42            operands
43        } else {
44            // try loading label
45            parse_canonical_operands_sequence(
46                operands,
47                &[OperandType::Label, marker_register_operand()],
48                &[marker_full_operand()],
49            )?
50        };
51
52        let src0 = operands[0].clone();
53        let src1 = operands[1].clone();
54        let dst0 = operands[2].clone();
55
56        let condition = pick_condition(&mut modifiers)?;
57        let set_flags_option = pick_setting_flags(&mut modifiers)?;
58
59        if !modifiers.is_empty() {
60            return Err(InstructionReadError::UnknownArgument(format!(
61                "Add instruction contains unknown modifiers: {:?}",
62                modifiers
63            )));
64        }
65
66        let new = Self {
67            condition,
68            source_1: src0,
69            source_2: src1.as_register_operand(1)?,
70            destination: dst0,
71            set_flags_option,
72        };
73
74        Ok(new)
75    }
76
77    #[track_caller]
78    pub(crate) fn link<const N: usize, E: VmEncodingMode<N>>(
79        &mut self,
80        function_labels_to_pc: &HashMap<String, usize>,
81        constant_labels_to_offset: &HashMap<String, usize>,
82        globals_to_offsets: &HashMap<String, usize>,
83    ) -> Result<(), AssemblyParseError> {
84        link_operand::<N, E>(
85            &mut self.source_1,
86            function_labels_to_pc,
87            constant_labels_to_offset,
88            globals_to_offsets,
89        )?;
90
91        link_operand::<N, E>(
92            &mut self.destination,
93            function_labels_to_pc,
94            constant_labels_to_offset,
95            globals_to_offsets,
96        )?;
97
98        Ok(())
99    }
100}
101
102impl<const N: usize, E: VmEncodingMode<N>> TryFrom<Add> for DecodedOpcode<N, E> {
103    type Error = InstructionReadError;
104
105    fn try_from(value: Add) -> Result<Self, Self::Error> {
106        let mut new = DecodedOpcode::default();
107        new.variant = OpcodeVariant {
108            opcode: Opcode::Add(AddOpcode::Add),
109            ..OpcodeVariant::default()
110        };
111        set_src0_or_dst0_full_operand(&value.source_1.as_generic_operand(0)?, &mut new, false);
112        set_register_operand(&value.source_2, &mut new, false);
113        set_src0_or_dst0_full_operand(&value.destination.as_generic_operand(2)?, &mut new, true);
114        new.condition = value.condition.0;
115        new.variant.flags[SET_FLAGS_FLAG_IDX] = value.set_flags_option.0;
116
117        Ok(new)
118    }
119}