Skip to content

Commit

Permalink
chore(avm): operands reordering (#10182)
Browse files Browse the repository at this point in the history
Resolves #10136
  • Loading branch information
jeanmon authored Nov 25, 2024
1 parent 4418ef2 commit 69bdf4f
Show file tree
Hide file tree
Showing 23 changed files with 896 additions and 894 deletions.
16 changes: 0 additions & 16 deletions avm-transpiler/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion avm-transpiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ license = "MIT OR Apache-2.0"
# local
acvm = { path = "../noir/noir-repo/acvm-repo/acvm", features = ["bn254"] }
noirc_errors = { path = "../noir/noir-repo/compiler/noirc_errors" }
fxhash = "0.2.1"

# external
base64 = "0.21"
Expand Down
41 changes: 40 additions & 1 deletion avm-transpiler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,50 @@ This component transpiles Aztec public contracts code from Noir's Brillig byteco
## Build

```
./boostrap.sh
./bootstrap.sh
```

## Run

```
cargo run <aztec-contract-artifact-json> <transpiled-output-json>
```

## Testing Transpiler Changes

After bootstrap in `avm-transpiler`, go to `noir-contracts` and only compile avm_test_contract with:

```
nargo compile --package avm_test_contract --inliner-aggressiveness=0 --silence-warnings
```

Important: use the right nargo binary located in
`aztec-packages/noir/noir-repo/target/release/nargo`
If required, build nargo by going in `noir/noir-repo` and run
`cargo build --release`.

Then, transpile it:

```
scripts/transpile.sh
```

Go to yarn-project/simulator and run:

```
yarn build:fast
```

This takes in the TS generated by the compilation and transpilation.

Finally, run

```
yarn test src/avm/avm_simulator.test.ts
```

To test against some .cpp changes, compile the bb binary and run bb prover test:

```
yarn test src/avm_proving.test.ts
```
35 changes: 25 additions & 10 deletions avm-transpiler/src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ pub struct AvmInstruction {
/// Its usage will depend on the instruction.
pub tag: Option<AvmTypeTag>,

/// Different instructions have different numbers of operands
/// Different instructions have different numbers of operands. These operands contain
/// memory addresses.
pub operands: Vec<AvmOperand>,

// Operands which are immediate, i.e., contain hardcoded constants.
pub immediates: Vec<AvmOperand>,
}

impl Display for AvmInstruction {
Expand All @@ -32,35 +36,46 @@ impl Display for AvmInstruction {
if let Some(indirect) = &self.indirect {
write!(f, ", indirect: {}", indirect)?;
}
// This will be either inTag or dstTag depending on the operation
if let Some(dst_tag) = self.tag {
write!(f, ", tag: {}", dst_tag as u8)?;
}
if !self.operands.is_empty() {
write!(f, ", operands: [")?;
for operand in &self.operands {
write!(f, "{operand}, ")?;
}
write!(f, "]")?;
};
// This will be either inTag or dstTag depending on the operation
if let Some(dst_tag) = self.tag {
write!(f, ", tag: {}", dst_tag as u8)?;
}
if !self.immediates.is_empty() {
write!(f, ", immediates: [")?;
for immediate in &self.immediates {
write!(f, "{immediate}, ")?;
}
write!(f, "]")?;
};
Ok(())
}
}

impl AvmInstruction {
/// Bytes representation for generating AVM bytecode
/// Order: INDIRECT, OPERANDS, TAG, IMMEDIATES
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.push(self.opcode as u8);
if let Some(indirect) = &self.indirect {
bytes.extend_from_slice(&indirect.to_be_bytes());
}
for operand in &self.operands {
bytes.extend_from_slice(&operand.to_be_bytes());
}
// This will be either inTag or dstTag depending on the operation
if let Some(tag) = self.tag {
bytes.extend_from_slice(&(tag as u8).to_be_bytes());
}
for operand in &self.operands {
bytes.extend_from_slice(&operand.to_be_bytes());
for immediate in &self.immediates {
bytes.extend_from_slice(&immediate.to_be_bytes());
}
bytes
}
Expand All @@ -84,6 +99,7 @@ impl Default for AvmInstruction {
indirect: None,
tag: None,
operands: vec![],
immediates: vec![],
}
}
}
Expand All @@ -102,9 +118,8 @@ pub enum AvmTypeTag {
INVALID,
}

/// Operands are usually 32 bits (offsets or jump destinations)
/// Constants (as used by the SET instruction) can have size
/// different from 32 bits
/// Operands are usually 8, 16 and 32 bits (offsets)
/// Immediates (as used by the SET instruction) can have different sizes
#[allow(non_camel_case_types)]
pub enum AvmOperand {
U8 { value: u8 },
Expand Down
44 changes: 20 additions & 24 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use acvm::acir::brillig::{BitSize, IntegerBitSize, Opcode as BrilligOpcode};
use fxhash::FxHashMap as HashMap;
use std::collections::BTreeMap;

use acvm::acir::circuit::BrilligOpcodeLocation;
Expand Down Expand Up @@ -90,12 +89,12 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
.direct_operand(destination)
.build(),
),
tag: None,
operands: vec![
make_operand(bits_needed, &lhs.to_usize()),
make_operand(bits_needed, &rhs.to_usize()),
make_operand(bits_needed, &destination.to_usize()),
],
..Default::default()
});
}
BrilligOpcode::BinaryIntOp { destination, op, lhs, rhs, .. } => {
Expand Down Expand Up @@ -178,12 +177,12 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
.direct_operand(destination)
.build(),
),
tag: None,
operands: vec![
make_operand(bits_needed, &lhs.to_usize()),
make_operand(bits_needed, &rhs.to_usize()),
make_operand(bits_needed, &destination.to_usize()),
],
..Default::default()
});
}
BrilligOpcode::Not { destination, source, .. } => {
Expand All @@ -207,7 +206,7 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
make_operand(bits_needed, &source.to_usize()),
make_operand(bits_needed, &destination.to_usize()),
],
tag: None,
..Default::default()
});
}
BrilligOpcode::CalldataCopy { destination_address, size_address, offset_address } => {
Expand Down Expand Up @@ -236,7 +235,7 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
assert!(location.num_bits() <= 32);
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::JUMP_32,
operands: vec![AvmOperand::BRILLIG_LOCATION { brillig_pc: *location as u32 }],
immediates: vec![AvmOperand::BRILLIG_LOCATION { brillig_pc: *location as u32 }],
..Default::default()
});
}
Expand All @@ -247,10 +246,8 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
indirect: Some(
AddressingModeBuilder::default().direct_operand(condition).build(),
),
operands: vec![
AvmOperand::BRILLIG_LOCATION { brillig_pc: *location as u32 },
make_operand(16, &condition.to_usize()),
],
operands: vec![make_operand(16, &condition.to_usize())],
immediates: vec![AvmOperand::BRILLIG_LOCATION { brillig_pc: *location as u32 }],
..Default::default()
});
}
Expand Down Expand Up @@ -300,7 +297,7 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
assert!(location.num_bits() <= 32);
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::INTERNALCALL,
operands: vec![AvmOperand::BRILLIG_LOCATION { brillig_pc: *location as u32 }],
immediates: vec![AvmOperand::BRILLIG_LOCATION { brillig_pc: *location as u32 }],
..Default::default()
});
}
Expand Down Expand Up @@ -353,8 +350,8 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
.into_iter()
.map(|i| match i.opcode {
AvmOpcode::JUMP_32 | AvmOpcode::JUMPI_32 | AvmOpcode::INTERNALCALL => {
let new_operands = i
.operands
let new_immediates = i
.immediates
.into_iter()
.map(|o| match o {
AvmOperand::BRILLIG_LOCATION { brillig_pc } => {
Expand All @@ -365,7 +362,7 @@ pub fn brillig_to_avm(brillig_bytecode: &[BrilligOpcode<FieldElement>]) -> (Vec<
_ => o,
})
.collect::<Vec<AvmOperand>>();
AvmInstruction { operands: new_operands, ..i }
AvmInstruction { immediates: new_immediates, ..i }
}
_ => i,
})
Expand Down Expand Up @@ -832,10 +829,8 @@ fn handle_getter_instruction(
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::GETENVVAR_16,
indirect: Some(AddressingModeBuilder::default().direct_operand(&dest_offset).build()),
operands: vec![
AvmOperand::U8 { value: var_idx as u8 },
AvmOperand::U16 { value: dest_offset.to_usize() as u16 },
],
operands: vec![AvmOperand::U16 { value: dest_offset.to_usize() as u16 }],
immediates: vec![AvmOperand::U8 { value: var_idx as u8 }],
..Default::default()
});
}
Expand Down Expand Up @@ -882,10 +877,8 @@ fn generate_set_instruction(
Some(AddressingModeBuilder::default().direct_operand(dest).build())
},
tag: Some(tag),
operands: vec![
make_operand(bits_needed_opcode, value),
make_operand(bits_needed_mem, &(dest.to_usize())),
],
operands: vec![make_operand(bits_needed_mem, &(dest.to_usize()))],
immediates: vec![make_operand(bits_needed_opcode, value)],
}
}

Expand Down Expand Up @@ -924,6 +917,7 @@ fn generate_cast_instruction(
make_operand(bits_needed, &(source.to_usize())),
make_operand(bits_needed, &(destination.to_usize())),
],
..Default::default()
}
}

Expand Down Expand Up @@ -1087,14 +1081,16 @@ fn handle_black_box_function(avm_instrs: &mut Vec<AvmInstruction>, operation: &B
.direct_operand(radix)
.build(),
),
tag: None,
operands: vec![
AvmOperand::U16 { value: input_offset as u16 },
AvmOperand::U16 { value: output_offset as u16 },
AvmOperand::U16 { value: radix_offset as u16 },
],
immediates: vec![
AvmOperand::U16 { value: num_limbs as u16 },
AvmOperand::U8 { value: *output_bits as u8 },
],
..Default::default()
});
}
// This will be changed to utilise relative memory offsets
Expand Down Expand Up @@ -1202,10 +1198,10 @@ fn handle_debug_log(
),
operands: vec![
AvmOperand::U16 { value: message_offset.to_usize() as u16 },
AvmOperand::U16 { value: message_size as u16 },
AvmOperand::U16 { value: fields_offset_ptr.to_usize() as u16 },
AvmOperand::U16 { value: fields_size_ptr.to_usize() as u16 },
],
immediates: vec![AvmOperand::U16 { value: message_size as u16 }],
..Default::default()
});
}
Expand Down Expand Up @@ -1462,11 +1458,11 @@ fn handle_get_contract_instance(
.build(),
),
operands: vec![
AvmOperand::U8 { value: member_idx as u8 },
AvmOperand::U16 { value: address_offset.to_usize() as u16 },
AvmOperand::U16 { value: dest_offset.to_usize() as u16 },
AvmOperand::U16 { value: exists_offset.to_usize() as u16 },
],
immediates: vec![AvmOperand::U8 { value: member_idx as u8 }],
..Default::default()
});
}
Expand Down
Loading

1 comment on commit 69bdf4f

@AztecBot
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'C++ Benchmark'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.05.

Benchmark suite Current: 69bdf4f Previous: 4418ef2 Ratio
nativeClientIVCBench/Full/6 30281.088646 ms/iter 27295.253331999986 ms/iter 1.11
nativeconstruct_proof_ultrahonk_power_of_2/20 5165.641212000011 ms/iter 4592.153176000011 ms/iter 1.12
wasmClientIVCBench/Full/6 95685.394308 ms/iter 86860.485455 ms/iter 1.10
wasmconstruct_proof_ultrahonk_power_of_2/20 18117.187870999995 ms/iter 16630.894746 ms/iter 1.09
commit(t) 3330448468 ns/iter 3016161929 ns/iter 1.10

This comment was automatically generated by workflow using github-action-benchmark.

CC: @ludamad @codygunton

Please sign in to comment.