zkevm_assembly/assembly/instruction/
bitwise.rs1use super::*;
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct Bitwise {
5 pub condition: ConditionCase,
7 pub set_flags_option: SetFlags,
9 pub source_1: FullOperand,
11 pub source_2: RegisterOperand,
13 pub destination: FullOperand,
15 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}