Skip to main content

zkevm_assembly/assembly/instruction/
bitwise.rs

1use super::*;
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct Bitwise {
5    /// Condition for execution
6    pub condition: ConditionCase,
7    /// Whether we set flags or not
8    pub set_flags_option: SetFlags,
9    /// The first operand.
10    pub source_1: FullOperand,
11    /// The second operand.
12    pub source_2: RegisterOperand,
13    /// The destination register.
14    pub destination: FullOperand,
15    /// And, Or or Xor
16    pub op_type: BinopOpcode,
17}
18
19impl Bitwise {
20    pub const ALL_CANONICAL_MODIFIERS: [&'static str; 3] = ["xor", "and", "or"];
21
22    #[track_caller]
23    pub fn build_from_parts(
24        mut modifiers: HashSet<&str>,
25        operands: Vec<&str>,
26    ) -> Result<Self, InstructionReadError> {
27        let operands = parse_canonical_operands_sequence(
28            operands,
29            &[marker_full_operand(), marker_register_operand()],
30            &[marker_full_operand()],
31        )?;
32
33        let src0 = operands[0].clone();
34        let src1 = operands[1].clone();
35        let dst0 = operands[2].clone();
36
37        if modifiers.is_empty() {
38            return Err(InstructionReadError::InvalidArgument {
39                index: 0,
40                expected: "Binop opcode must contain a modifier",
41                found: "no modifiers".to_owned(),
42            });
43        }
44
45        let mut result = None;
46        for (idx, modifier) in Self::ALL_CANONICAL_MODIFIERS.iter().enumerate() {
47            if modifiers.contains(modifier) {
48                if result.is_some() {
49                    return Err(InstructionReadError::UnknownArgument(format!(
50                        "duplicate variant in modifiers: already have {:?}, got {}",
51                        result.unwrap(),
52                        modifier
53                    )));
54                } else {
55                    modifiers.remove(modifier);
56                    let variant = match idx {
57                        0 => BinopOpcode::Xor,
58                        1 => BinopOpcode::And,
59                        2 => BinopOpcode::Or,
60                        _ => {
61                            unreachable!()
62                        }
63                    };
64                    result = Some(variant);
65                }
66            }
67        }
68
69        let variant = result.ok_or(InstructionReadError::UnknownArgument(
70            "Binop instruction contains no modifier".to_owned(),
71        ))?;
72
73        let condition = pick_condition(&mut modifiers)?;
74        let set_flags_option = pick_setting_flags(&mut modifiers)?;
75
76        if !modifiers.is_empty() {
77            return Err(InstructionReadError::UnknownArgument(format!(
78                "Binop instruction contains unknown modifiers: {:?}",
79                modifiers
80            )));
81        }
82
83        let new = Self {
84            condition,
85            source_1: src0,
86            source_2: src1.as_register_operand(1)?,
87            destination: dst0,
88            op_type: variant,
89            set_flags_option,
90        };
91
92        Ok(new)
93    }
94
95    #[track_caller]
96    pub(crate) fn link<const N: usize, E: VmEncodingMode<N>>(
97        &mut self,
98        function_labels_to_pc: &HashMap<String, usize>,
99        constant_labels_to_offset: &HashMap<String, usize>,
100        globals_to_offsets: &HashMap<String, usize>,
101    ) -> Result<(), AssemblyParseError> {
102        link_operand::<N, E>(
103            &mut self.source_1,
104            function_labels_to_pc,
105            constant_labels_to_offset,
106            globals_to_offsets,
107        )?;
108
109        link_operand::<N, E>(
110            &mut self.destination,
111            function_labels_to_pc,
112            constant_labels_to_offset,
113            globals_to_offsets,
114        )?;
115
116        Ok(())
117    }
118}
119
120impl<const N: usize, E: VmEncodingMode<N>> TryFrom<Bitwise> for DecodedOpcode<N, E> {
121    type Error = InstructionReadError;
122
123    fn try_from(value: Bitwise) -> Result<Self, Self::Error> {
124        let mut new = DecodedOpcode::default();
125        new.variant = OpcodeVariant {
126            opcode: Opcode::Binop(value.op_type),
127            ..OpcodeVariant::default()
128        };
129        set_src0_or_dst0_full_operand(&value.source_1.as_generic_operand(0)?, &mut new, false);
130        set_register_operand(&value.source_2, &mut new, false);
131        set_src0_or_dst0_full_operand(&value.destination.as_generic_operand(2)?, &mut new, true);
132        new.condition = value.condition.0;
133        new.variant.flags[SET_FLAGS_FLAG_IDX] = value.set_flags_option.0;
134
135        Ok(new)
136    }
137}