Skip to content

Commit

Permalink
feat!: Acir call opcode (#4773)
Browse files Browse the repository at this point in the history
  • Loading branch information
vezenovm authored Mar 18, 2024
1 parent 5ab07fb commit 0b15db2
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 76 deletions.
142 changes: 67 additions & 75 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,18 +1063,7 @@ struct Directive {
static ToLeRadix bincodeDeserialize(std::vector<uint8_t>);
};

struct PermutationSort {
std::vector<std::vector<Circuit::Expression>> inputs;
uint32_t tuple;
std::vector<Circuit::Witness> bits;
std::vector<uint32_t> sort_by;

friend bool operator==(const PermutationSort&, const PermutationSort&);
std::vector<uint8_t> bincodeSerialize() const;
static PermutationSort bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<ToLeRadix, PermutationSort> value;
std::variant<ToLeRadix> value;

friend bool operator==(const Directive&, const Directive&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -1144,7 +1133,17 @@ struct Opcode {
static MemoryInit bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<AssertZero, BlackBoxFuncCall, Directive, Brillig, MemoryOp, MemoryInit> value;
struct Call {
uint32_t id;
std::vector<Circuit::Witness> inputs;
std::vector<Circuit::Witness> outputs;

friend bool operator==(const Call&, const Call&);
std::vector<uint8_t> bincodeSerialize() const;
static Call bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<AssertZero, BlackBoxFuncCall, Directive, Brillig, MemoryOp, MemoryInit, Call> value;

friend bool operator==(const Opcode&, const Opcode&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -6450,68 +6449,6 @@ Circuit::Directive::ToLeRadix serde::Deserializable<Circuit::Directive::ToLeRadi

namespace Circuit {

inline bool operator==(const Directive::PermutationSort& lhs, const Directive::PermutationSort& rhs)
{
if (!(lhs.inputs == rhs.inputs)) {
return false;
}
if (!(lhs.tuple == rhs.tuple)) {
return false;
}
if (!(lhs.bits == rhs.bits)) {
return false;
}
if (!(lhs.sort_by == rhs.sort_by)) {
return false;
}
return true;
}

inline std::vector<uint8_t> Directive::PermutationSort::bincodeSerialize() const
{
auto serializer = serde::BincodeSerializer();
serde::Serializable<Directive::PermutationSort>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline Directive::PermutationSort Directive::PermutationSort::bincodeDeserialize(std::vector<uint8_t> input)
{
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<Directive::PermutationSort>::deserialize(deserializer);
if (deserializer.get_buffer_offset() < input.size()) {
throw_or_abort("Some input bytes were not read");
}
return value;
}

} // end of namespace Circuit

template <>
template <typename Serializer>
void serde::Serializable<Circuit::Directive::PermutationSort>::serialize(const Circuit::Directive::PermutationSort& obj,
Serializer& serializer)
{
serde::Serializable<decltype(obj.inputs)>::serialize(obj.inputs, serializer);
serde::Serializable<decltype(obj.tuple)>::serialize(obj.tuple, serializer);
serde::Serializable<decltype(obj.bits)>::serialize(obj.bits, serializer);
serde::Serializable<decltype(obj.sort_by)>::serialize(obj.sort_by, serializer);
}

template <>
template <typename Deserializer>
Circuit::Directive::PermutationSort serde::Deserializable<Circuit::Directive::PermutationSort>::deserialize(
Deserializer& deserializer)
{
Circuit::Directive::PermutationSort obj;
obj.inputs = serde::Deserializable<decltype(obj.inputs)>::deserialize(deserializer);
obj.tuple = serde::Deserializable<decltype(obj.tuple)>::deserialize(deserializer);
obj.bits = serde::Deserializable<decltype(obj.bits)>::deserialize(deserializer);
obj.sort_by = serde::Deserializable<decltype(obj.sort_by)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const Expression& lhs, const Expression& rhs)
{
if (!(lhs.mul_terms == rhs.mul_terms)) {
Expand Down Expand Up @@ -7509,6 +7446,61 @@ Circuit::Opcode::MemoryInit serde::Deserializable<Circuit::Opcode::MemoryInit>::

namespace Circuit {

inline bool operator==(const Opcode::Call& lhs, const Opcode::Call& rhs)
{
if (!(lhs.id == rhs.id)) {
return false;
}
if (!(lhs.inputs == rhs.inputs)) {
return false;
}
if (!(lhs.outputs == rhs.outputs)) {
return false;
}
return true;
}

inline std::vector<uint8_t> Opcode::Call::bincodeSerialize() const
{
auto serializer = serde::BincodeSerializer();
serde::Serializable<Opcode::Call>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline Opcode::Call Opcode::Call::bincodeDeserialize(std::vector<uint8_t> input)
{
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<Opcode::Call>::deserialize(deserializer);
if (deserializer.get_buffer_offset() < input.size()) {
throw_or_abort("Some input bytes were not read");
}
return value;
}

} // end of namespace Circuit

template <>
template <typename Serializer>
void serde::Serializable<Circuit::Opcode::Call>::serialize(const Circuit::Opcode::Call& obj, Serializer& serializer)
{
serde::Serializable<decltype(obj.id)>::serialize(obj.id, serializer);
serde::Serializable<decltype(obj.inputs)>::serialize(obj.inputs, serializer);
serde::Serializable<decltype(obj.outputs)>::serialize(obj.outputs, serializer);
}

template <>
template <typename Deserializer>
Circuit::Opcode::Call serde::Deserializable<Circuit::Opcode::Call>::deserialize(Deserializer& deserializer)
{
Circuit::Opcode::Call obj;
obj.id = serde::Deserializable<decltype(obj.id)>::deserialize(deserializer);
obj.inputs = serde::Deserializable<decltype(obj.inputs)>::deserialize(deserializer);
obj.outputs = serde::Deserializable<decltype(obj.outputs)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const OpcodeLocation& lhs, const OpcodeLocation& rhs)
{
if (!(lhs.value == rhs.value)) {
Expand Down
1 change: 1 addition & 0 deletions build_manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ noir-packages-tests:
rebuildPatterns: .rebuild_patterns_packages
dependencies:
- noir
- noir-packages

# Builds the brillig to avm transpiler.
avm-transpiler:
Expand Down
3 changes: 3 additions & 0 deletions noir/Dockerfile.packages-test
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
FROM aztecprotocol/noir AS noir
FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages

FROM node:20 AS builder
COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages

COPY --from=noir /usr/src/noir/noir-repo/target/release /usr/src/noir/noir-repo/target/release
ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
Expand Down
56 changes: 55 additions & 1 deletion noir/noir-repo/acvm-repo/acir/codegen/acir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,17 @@ namespace Circuit {
static MemoryInit bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<AssertZero, BlackBoxFuncCall, Directive, Brillig, MemoryOp, MemoryInit> value;
struct Call {
uint32_t id;
std::vector<Circuit::Witness> inputs;
std::vector<Circuit::Witness> outputs;

friend bool operator==(const Call&, const Call&);
std::vector<uint8_t> bincodeSerialize() const;
static Call bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<AssertZero, BlackBoxFuncCall, Directive, Brillig, MemoryOp, MemoryInit, Call> value;

friend bool operator==(const Opcode&, const Opcode&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -6135,6 +6145,50 @@ Circuit::Opcode::MemoryInit serde::Deserializable<Circuit::Opcode::MemoryInit>::
return obj;
}

namespace Circuit {

inline bool operator==(const Opcode::Call &lhs, const Opcode::Call &rhs) {
if (!(lhs.id == rhs.id)) { return false; }
if (!(lhs.inputs == rhs.inputs)) { return false; }
if (!(lhs.outputs == rhs.outputs)) { return false; }
return true;
}

inline std::vector<uint8_t> Opcode::Call::bincodeSerialize() const {
auto serializer = serde::BincodeSerializer();
serde::Serializable<Opcode::Call>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline Opcode::Call Opcode::Call::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<Opcode::Call>::deserialize(deserializer);
if (deserializer.get_buffer_offset() < input.size()) {
throw serde::deserialization_error("Some input bytes were not read");
}
return value;
}

} // end of namespace Circuit

template <>
template <typename Serializer>
void serde::Serializable<Circuit::Opcode::Call>::serialize(const Circuit::Opcode::Call &obj, Serializer &serializer) {
serde::Serializable<decltype(obj.id)>::serialize(obj.id, serializer);
serde::Serializable<decltype(obj.inputs)>::serialize(obj.inputs, serializer);
serde::Serializable<decltype(obj.outputs)>::serialize(obj.outputs, serializer);
}

template <>
template <typename Deserializer>
Circuit::Opcode::Call serde::Deserializable<Circuit::Opcode::Call>::deserialize(Deserializer &deserializer) {
Circuit::Opcode::Call obj;
obj.id = serde::Deserializable<decltype(obj.id)>::deserialize(deserializer);
obj.inputs = serde::Deserializable<decltype(obj.inputs)>::deserialize(deserializer);
obj.outputs = serde::Deserializable<decltype(obj.outputs)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const OpcodeLocation &lhs, const OpcodeLocation &rhs) {
Expand Down
16 changes: 16 additions & 0 deletions noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ pub enum Opcode {
block_id: BlockId,
init: Vec<Witness>,
},
/// Calls to functions represented as a separate circuit. A call opcode allows us
/// to build a call stack when executing the outer-most circuit.
Call {
/// Id for the function being called. It is the responsibility of the executor
/// to fetch the appropriate circuit from this id.
id: u32,
/// Inputs to the function call
inputs: Vec<Witness>,
/// Outputs of the function call
outputs: Vec<Witness>,
},
}

impl std::fmt::Display for Opcode {
Expand Down Expand Up @@ -86,6 +97,11 @@ impl std::fmt::Display for Opcode {
write!(f, "INIT ")?;
write!(f, "(id: {}, len: {}) ", block_id.0, init.len())
}
Opcode::Call { id, inputs, outputs } => {
write!(f, "CALL func {}: ", id)?;
writeln!(f, "inputs: {:?}", inputs)?;
writeln!(f, "outputs: {:?}", outputs)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pub(super) fn transform_internal(
new_acir_opcode_positions.push(acir_opcode_positions[index]);
transformed_opcodes.push(opcode);
}
Opcode::Call { .. } => todo!("Handle Call opcodes in the ACVM"),
}
}

Expand Down
1 change: 1 addition & 0 deletions noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call),
res => res.map(|_| ()),
},
Opcode::Call { .. } => todo!("Handle Call opcodes in the ACVM"),
};
self.handle_opcode_resolution(resolution)
}
Expand Down

0 comments on commit 0b15db2

Please sign in to comment.