Skip to content

Commit 8de1f2a

Browse files
authored
feat(avm)!: variants for binary operations (#8473)
Gets us another ~30% bytecode size gain. I still have to remove tags.
1 parent 26706e9 commit 8de1f2a

27 files changed

+904
-638
lines changed

avm-transpiler/src/instructions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl Debug for AvmInstruction {
8080
impl Default for AvmInstruction {
8181
fn default() -> Self {
8282
AvmInstruction {
83-
opcode: AvmOpcode::ADD,
83+
opcode: AvmOpcode::ADD_8,
8484
// TODO(4266): default to Some(0), since all instructions have indirect flag except jumps
8585
indirect: None,
8686
tag: None,

avm-transpiler/src/opcodes.rs

+52-26
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,33 @@
44
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
55
pub enum AvmOpcode {
66
// Compute
7-
ADD,
8-
SUB,
9-
MUL,
10-
DIV,
11-
FDIV,
12-
EQ,
13-
LT,
14-
LTE,
15-
AND,
16-
OR,
17-
XOR,
7+
ADD_8,
8+
ADD_16,
9+
SUB_8,
10+
SUB_16,
11+
MUL_8,
12+
MUL_16,
13+
DIV_8,
14+
DIV_16,
15+
FDIV_8,
16+
FDIV_16,
17+
EQ_8,
18+
EQ_16,
19+
LT_8,
20+
LT_16,
21+
LTE_8,
22+
LTE_16,
23+
AND_8,
24+
AND_16,
25+
OR_8,
26+
OR_16,
27+
XOR_8,
28+
XOR_16,
1829
NOT,
19-
SHL,
20-
SHR,
30+
SHL_8,
31+
SHL_16,
32+
SHR_8,
33+
SHR_16,
2134
CAST,
2235
// Execution environment
2336
ADDRESS,
@@ -89,22 +102,35 @@ impl AvmOpcode {
89102
match self {
90103
// Compute
91104
// Compute - Arithmetic
92-
AvmOpcode::ADD => "ADD",
93-
AvmOpcode::SUB => "SUB",
94-
AvmOpcode::MUL => "MUL",
95-
AvmOpcode::DIV => "DIV",
96-
AvmOpcode::FDIV => "FDIV",
105+
AvmOpcode::ADD_8 => "ADD_8",
106+
AvmOpcode::ADD_16 => "ADD_16",
107+
AvmOpcode::SUB_8 => "SUB_8",
108+
AvmOpcode::SUB_16 => "SUB_16",
109+
AvmOpcode::MUL_8 => "MUL_8",
110+
AvmOpcode::MUL_16 => "MUL_16",
111+
AvmOpcode::DIV_8 => "DIV_8",
112+
AvmOpcode::DIV_16 => "DIV_16",
113+
AvmOpcode::FDIV_8 => "FDIV_8",
114+
AvmOpcode::FDIV_16 => "FDIV_16",
97115
// Compute - Comparators
98-
AvmOpcode::EQ => "EQ",
99-
AvmOpcode::LT => "LT",
100-
AvmOpcode::LTE => "LTE",
116+
AvmOpcode::EQ_8 => "EQ_8",
117+
AvmOpcode::EQ_16 => "EQ_16",
118+
AvmOpcode::LT_8 => "LT_8",
119+
AvmOpcode::LT_16 => "LT_16",
120+
AvmOpcode::LTE_8 => "LTE_8",
121+
AvmOpcode::LTE_16 => "LTE_16",
101122
// Compute - Bitwise
102-
AvmOpcode::AND => "AND",
103-
AvmOpcode::OR => "OR",
104-
AvmOpcode::XOR => "XOR",
123+
AvmOpcode::AND_8 => "AND_8",
124+
AvmOpcode::AND_16 => "AND_16",
125+
AvmOpcode::OR_8 => "OR_8",
126+
AvmOpcode::OR_16 => "OR_16",
127+
AvmOpcode::XOR_8 => "XOR_8",
128+
AvmOpcode::XOR_16 => "XOR_16",
105129
AvmOpcode::NOT => "NOT",
106-
AvmOpcode::SHL => "SHL",
107-
AvmOpcode::SHR => "SHR",
130+
AvmOpcode::SHL_8 => "SHL_8",
131+
AvmOpcode::SHL_16 => "SHL_16",
132+
AvmOpcode::SHR_8 => "SHR_8",
133+
AvmOpcode::SHR_16 => "SHR_16",
108134
// Compute - Type Conversions
109135
AvmOpcode::CAST => "CAST",
110136

avm-transpiler/src/transpile.rs

+126-29
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,65 @@ pub fn brillig_to_avm(
3030
for brillig_instr in brillig_bytecode {
3131
match brillig_instr {
3232
BrilligOpcode::BinaryFieldOp { destination, op, lhs, rhs } => {
33+
let bits_needed =
34+
[lhs.0, rhs.0, destination.0].iter().map(bits_needed_for).max().unwrap();
35+
36+
assert!(
37+
bits_needed == 8 || bits_needed == 16,
38+
"BinaryFieldOp only support 8 or 16 bit encodings, got: {}",
39+
bits_needed
40+
);
41+
3342
let avm_opcode = match op {
34-
BinaryFieldOp::Add => AvmOpcode::ADD,
35-
BinaryFieldOp::Sub => AvmOpcode::SUB,
36-
BinaryFieldOp::Mul => AvmOpcode::MUL,
37-
BinaryFieldOp::Div => AvmOpcode::FDIV,
38-
BinaryFieldOp::IntegerDiv => AvmOpcode::DIV,
39-
BinaryFieldOp::Equals => AvmOpcode::EQ,
40-
BinaryFieldOp::LessThan => AvmOpcode::LT,
41-
BinaryFieldOp::LessThanEquals => AvmOpcode::LTE,
43+
BinaryFieldOp::Add => match bits_needed {
44+
8 => AvmOpcode::ADD_8,
45+
16 => AvmOpcode::ADD_16,
46+
_ => unreachable!(),
47+
},
48+
BinaryFieldOp::Sub => match bits_needed {
49+
8 => AvmOpcode::SUB_8,
50+
16 => AvmOpcode::SUB_16,
51+
_ => unreachable!(),
52+
},
53+
BinaryFieldOp::Mul => match bits_needed {
54+
8 => AvmOpcode::MUL_8,
55+
16 => AvmOpcode::MUL_16,
56+
_ => unreachable!(),
57+
},
58+
BinaryFieldOp::Div => match bits_needed {
59+
8 => AvmOpcode::FDIV_8,
60+
16 => AvmOpcode::FDIV_16,
61+
_ => unreachable!(),
62+
},
63+
BinaryFieldOp::IntegerDiv => match bits_needed {
64+
8 => AvmOpcode::DIV_8,
65+
16 => AvmOpcode::DIV_16,
66+
_ => unreachable!(),
67+
},
68+
BinaryFieldOp::Equals => match bits_needed {
69+
8 => AvmOpcode::EQ_8,
70+
16 => AvmOpcode::EQ_16,
71+
_ => unreachable!(),
72+
},
73+
BinaryFieldOp::LessThan => match bits_needed {
74+
8 => AvmOpcode::LT_8,
75+
16 => AvmOpcode::LT_16,
76+
_ => unreachable!(),
77+
},
78+
BinaryFieldOp::LessThanEquals => match bits_needed {
79+
8 => AvmOpcode::LTE_8,
80+
16 => AvmOpcode::LTE_16,
81+
_ => unreachable!(),
82+
},
4283
};
4384
avm_instrs.push(AvmInstruction {
4485
opcode: avm_opcode,
4586
indirect: Some(ALL_DIRECT),
46-
tag: if avm_opcode == AvmOpcode::FDIV { None } else { Some(AvmTypeTag::FIELD) },
87+
tag: Some(AvmTypeTag::FIELD),
4788
operands: vec![
48-
AvmOperand::U32 { value: lhs.to_usize() as u32 },
49-
AvmOperand::U32 { value: rhs.to_usize() as u32 },
50-
AvmOperand::U32 { value: destination.to_usize() as u32 },
89+
make_operand(bits_needed, &lhs.0),
90+
make_operand(bits_needed, &rhs.0),
91+
make_operand(bits_needed, &destination.0),
5192
],
5293
});
5394
}
@@ -57,28 +98,84 @@ pub fn brillig_to_avm(
5798
"BinaryIntOp bit size should be integral: {:?}",
5899
brillig_instr
59100
);
101+
let bits_needed =
102+
[lhs.0, rhs.0, destination.0].iter().map(bits_needed_for).max().unwrap();
103+
assert!(
104+
bits_needed == 8 || bits_needed == 16,
105+
"BinaryIntOp only support 8 or 16 bit encodings, got: {}",
106+
bits_needed
107+
);
108+
60109
let avm_opcode = match op {
61-
BinaryIntOp::Add => AvmOpcode::ADD,
62-
BinaryIntOp::Sub => AvmOpcode::SUB,
63-
BinaryIntOp::Mul => AvmOpcode::MUL,
64-
BinaryIntOp::Div => AvmOpcode::DIV,
65-
BinaryIntOp::Equals => AvmOpcode::EQ,
66-
BinaryIntOp::LessThan => AvmOpcode::LT,
67-
BinaryIntOp::LessThanEquals => AvmOpcode::LTE,
68-
BinaryIntOp::And => AvmOpcode::AND,
69-
BinaryIntOp::Or => AvmOpcode::OR,
70-
BinaryIntOp::Xor => AvmOpcode::XOR,
71-
BinaryIntOp::Shl => AvmOpcode::SHL,
72-
BinaryIntOp::Shr => AvmOpcode::SHR,
110+
BinaryIntOp::Add => match bits_needed {
111+
8 => AvmOpcode::ADD_8,
112+
16 => AvmOpcode::ADD_16,
113+
_ => unreachable!(),
114+
},
115+
BinaryIntOp::Sub => match bits_needed {
116+
8 => AvmOpcode::SUB_8,
117+
16 => AvmOpcode::SUB_16,
118+
_ => unreachable!(),
119+
},
120+
BinaryIntOp::Mul => match bits_needed {
121+
8 => AvmOpcode::MUL_8,
122+
16 => AvmOpcode::MUL_16,
123+
_ => unreachable!(),
124+
},
125+
BinaryIntOp::Div => match bits_needed {
126+
8 => AvmOpcode::DIV_8,
127+
16 => AvmOpcode::DIV_16,
128+
_ => unreachable!(),
129+
},
130+
BinaryIntOp::And => match bits_needed {
131+
8 => AvmOpcode::AND_8,
132+
16 => AvmOpcode::AND_16,
133+
_ => unreachable!(),
134+
},
135+
BinaryIntOp::Or => match bits_needed {
136+
8 => AvmOpcode::OR_8,
137+
16 => AvmOpcode::OR_16,
138+
_ => unreachable!(),
139+
},
140+
BinaryIntOp::Xor => match bits_needed {
141+
8 => AvmOpcode::XOR_8,
142+
16 => AvmOpcode::XOR_16,
143+
_ => unreachable!(),
144+
},
145+
BinaryIntOp::Shl => match bits_needed {
146+
8 => AvmOpcode::SHL_8,
147+
16 => AvmOpcode::SHL_16,
148+
_ => unreachable!(),
149+
},
150+
BinaryIntOp::Shr => match bits_needed {
151+
8 => AvmOpcode::SHR_8,
152+
16 => AvmOpcode::SHR_16,
153+
_ => unreachable!(),
154+
},
155+
BinaryIntOp::Equals => match bits_needed {
156+
8 => AvmOpcode::EQ_8,
157+
16 => AvmOpcode::EQ_16,
158+
_ => unreachable!(),
159+
},
160+
BinaryIntOp::LessThan => match bits_needed {
161+
8 => AvmOpcode::LT_8,
162+
16 => AvmOpcode::LT_16,
163+
_ => unreachable!(),
164+
},
165+
BinaryIntOp::LessThanEquals => match bits_needed {
166+
8 => AvmOpcode::LTE_8,
167+
16 => AvmOpcode::LTE_16,
168+
_ => unreachable!(),
169+
},
73170
};
74171
avm_instrs.push(AvmInstruction {
75172
opcode: avm_opcode,
76173
indirect: Some(ALL_DIRECT),
77174
tag: Some(tag_from_bit_size(BitSize::Integer(*bit_size))),
78175
operands: vec![
79-
AvmOperand::U32 { value: lhs.to_usize() as u32 },
80-
AvmOperand::U32 { value: rhs.to_usize() as u32 },
81-
AvmOperand::U32 { value: destination.to_usize() as u32 },
176+
make_operand(bits_needed, &lhs.0),
177+
make_operand(bits_needed, &rhs.0),
178+
make_operand(bits_needed, &destination.0),
82179
],
83180
});
84181
}
@@ -214,9 +311,9 @@ pub fn brillig_to_avm(
214311
// We are adding a MOV instruction that moves a value to itself.
215312
// This should therefore not affect the program's execution.
216313
avm_instrs.push(AvmInstruction {
217-
opcode: AvmOpcode::MOV_8,
314+
opcode: AvmOpcode::MOV_16,
218315
indirect: Some(ALL_DIRECT),
219-
operands: vec![AvmOperand::U32 { value: 0x18ca }, AvmOperand::U32 { value: 0x18ca }],
316+
operands: vec![AvmOperand::U16 { value: 0x18ca }, AvmOperand::U16 { value: 0x18ca }],
220317
..Default::default()
221318
});
222319

0 commit comments

Comments
 (0)