Skip to content

Commit

Permalink
feat(acir)!: BrilligCall opcode (#5709)
Browse files Browse the repository at this point in the history
This starts work towards noir-lang/noir#3907
but is only the breaking serialization change.

Codegen and evaluation will come in a follow-up. This PR is purely
additive and does not remove the current way we do Brillig gen during
ACIR gen. Codegen for normal Brillig functions is working in my
follow-up, however, removing the existing Brillig opcode will most
likely have to come once we settle on how to [handle the brillig std
lib](noir-lang/acvm#471) as we are currently
generating code such as calculating a quotient during ACIR gen.

---------

Co-authored-by: Tom French <[email protected]>
  • Loading branch information
vezenovm and TomAFrench authored Apr 16, 2024
1 parent 9a9eab6 commit f06f64c
Show file tree
Hide file tree
Showing 19 changed files with 426 additions and 117 deletions.
140 changes: 139 additions & 1 deletion barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,17 @@ struct Opcode {
static MemoryInit bincodeDeserialize(std::vector<uint8_t>);
};

struct BrilligCall {
uint32_t id;
std::vector<Program::BrilligInputs> inputs;
std::vector<Program::BrilligOutputs> outputs;
std::optional<Program::Expression> predicate;

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

struct Call {
uint32_t id;
std::vector<Program::Witness> inputs;
Expand All @@ -1134,7 +1145,7 @@ struct Opcode {
static Call bincodeDeserialize(std::vector<uint8_t>);
};

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

friend bool operator==(const Opcode&, const Opcode&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -1213,8 +1224,17 @@ struct Circuit {
static Circuit bincodeDeserialize(std::vector<uint8_t>);
};

struct BrilligBytecode {
std::vector<Program::BrilligOpcode> bytecode;

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

struct Program {
std::vector<Circuit> functions;
std::vector<BrilligBytecode> unconstrained_functions;

friend bool operator==(const Program&, const Program&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -4878,6 +4898,56 @@ Program::Brillig serde::Deserializable<Program::Brillig>::deserialize(Deserializ

namespace Program {

inline bool operator==(const BrilligBytecode& lhs, const BrilligBytecode& rhs)
{
if (!(lhs.bytecode == rhs.bytecode)) {
return false;
}
return true;
}

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

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

} // end of namespace Program

template <>
template <typename Serializer>
void serde::Serializable<Program::BrilligBytecode>::serialize(const Program::BrilligBytecode& obj,
Serializer& serializer)
{
serializer.increase_container_depth();
serde::Serializable<decltype(obj.bytecode)>::serialize(obj.bytecode, serializer);
serializer.decrease_container_depth();
}

template <>
template <typename Deserializer>
Program::BrilligBytecode serde::Deserializable<Program::BrilligBytecode>::deserialize(Deserializer& deserializer)
{
deserializer.increase_container_depth();
Program::BrilligBytecode obj;
obj.bytecode = serde::Deserializable<decltype(obj.bytecode)>::deserialize(deserializer);
deserializer.decrease_container_depth();
return obj;
}

namespace Program {

inline bool operator==(const BrilligInputs& lhs, const BrilligInputs& rhs)
{
if (!(lhs.value == rhs.value)) {
Expand Down Expand Up @@ -7417,6 +7487,68 @@ Program::Opcode::MemoryInit serde::Deserializable<Program::Opcode::MemoryInit>::

namespace Program {

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

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

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

} // end of namespace Program

template <>
template <typename Serializer>
void serde::Serializable<Program::Opcode::BrilligCall>::serialize(const Program::Opcode::BrilligCall& 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);
serde::Serializable<decltype(obj.predicate)>::serialize(obj.predicate, serializer);
}

template <>
template <typename Deserializer>
Program::Opcode::BrilligCall serde::Deserializable<Program::Opcode::BrilligCall>::deserialize(
Deserializer& deserializer)
{
Program::Opcode::BrilligCall 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);
obj.predicate = serde::Deserializable<decltype(obj.predicate)>::deserialize(deserializer);
return obj;
}

namespace Program {

inline bool operator==(const Opcode::Call& lhs, const Opcode::Call& rhs)
{
if (!(lhs.id == rhs.id)) {
Expand Down Expand Up @@ -7630,6 +7762,9 @@ inline bool operator==(const Program& lhs, const Program& rhs)
if (!(lhs.functions == rhs.functions)) {
return false;
}
if (!(lhs.unconstrained_functions == rhs.unconstrained_functions)) {
return false;
}
return true;
}

Expand Down Expand Up @@ -7658,6 +7793,7 @@ void serde::Serializable<Program::Program>::serialize(const Program::Program& ob
{
serializer.increase_container_depth();
serde::Serializable<decltype(obj.functions)>::serialize(obj.functions, serializer);
serde::Serializable<decltype(obj.unconstrained_functions)>::serialize(obj.unconstrained_functions, serializer);
serializer.decrease_container_depth();
}

Expand All @@ -7668,6 +7804,8 @@ Program::Program serde::Deserializable<Program::Program>::deserialize(Deserializ
deserializer.increase_container_depth();
Program::Program obj;
obj.functions = serde::Deserializable<decltype(obj.functions)>::deserialize(deserializer);
obj.unconstrained_functions =
serde::Deserializable<decltype(obj.unconstrained_functions)>::deserialize(deserializer);
deserializer.decrease_container_depth();
return obj;
}
Expand Down
114 changes: 113 additions & 1 deletion noir/noir-repo/acvm-repo/acir/codegen/acir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,17 @@ namespace Program {
static MemoryInit bincodeDeserialize(std::vector<uint8_t>);
};

struct BrilligCall {
uint32_t id;
std::vector<Program::BrilligInputs> inputs;
std::vector<Program::BrilligOutputs> outputs;
std::optional<Program::Expression> predicate;

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

struct Call {
uint32_t id;
std::vector<Program::Witness> inputs;
Expand All @@ -1072,7 +1083,7 @@ namespace Program {
static Call bincodeDeserialize(std::vector<uint8_t>);
};

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

friend bool operator==(const Opcode&, const Opcode&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -1151,8 +1162,17 @@ namespace Program {
static Circuit bincodeDeserialize(std::vector<uint8_t>);
};

struct BrilligBytecode {
std::vector<Program::BrilligOpcode> bytecode;

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

struct Program {
std::vector<Program::Circuit> functions;
std::vector<Program::BrilligBytecode> unconstrained_functions;

friend bool operator==(const Program&, const Program&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -4071,6 +4091,48 @@ Program::Brillig serde::Deserializable<Program::Brillig>::deserialize(Deserializ
return obj;
}

namespace Program {

inline bool operator==(const BrilligBytecode &lhs, const BrilligBytecode &rhs) {
if (!(lhs.bytecode == rhs.bytecode)) { return false; }
return true;
}

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

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

} // end of namespace Program

template <>
template <typename Serializer>
void serde::Serializable<Program::BrilligBytecode>::serialize(const Program::BrilligBytecode &obj, Serializer &serializer) {
serializer.increase_container_depth();
serde::Serializable<decltype(obj.bytecode)>::serialize(obj.bytecode, serializer);
serializer.decrease_container_depth();
}

template <>
template <typename Deserializer>
Program::BrilligBytecode serde::Deserializable<Program::BrilligBytecode>::deserialize(Deserializer &deserializer) {
deserializer.increase_container_depth();
Program::BrilligBytecode obj;
obj.bytecode = serde::Deserializable<decltype(obj.bytecode)>::deserialize(deserializer);
deserializer.decrease_container_depth();
return obj;
}

namespace Program {

inline bool operator==(const BrilligInputs &lhs, const BrilligInputs &rhs) {
Expand Down Expand Up @@ -6118,6 +6180,53 @@ Program::Opcode::MemoryInit serde::Deserializable<Program::Opcode::MemoryInit>::
return obj;
}

namespace Program {

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

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

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

} // end of namespace Program

template <>
template <typename Serializer>
void serde::Serializable<Program::Opcode::BrilligCall>::serialize(const Program::Opcode::BrilligCall &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);
serde::Serializable<decltype(obj.predicate)>::serialize(obj.predicate, serializer);
}

template <>
template <typename Deserializer>
Program::Opcode::BrilligCall serde::Deserializable<Program::Opcode::BrilligCall>::deserialize(Deserializer &deserializer) {
Program::Opcode::BrilligCall 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);
obj.predicate = serde::Deserializable<decltype(obj.predicate)>::deserialize(deserializer);
return obj;
}

namespace Program {

inline bool operator==(const Opcode::Call &lhs, const Opcode::Call &rhs) {
Expand Down Expand Up @@ -6290,6 +6399,7 @@ namespace Program {

inline bool operator==(const Program &lhs, const Program &rhs) {
if (!(lhs.functions == rhs.functions)) { return false; }
if (!(lhs.unconstrained_functions == rhs.unconstrained_functions)) { return false; }
return true;
}

Expand All @@ -6315,6 +6425,7 @@ template <typename Serializer>
void serde::Serializable<Program::Program>::serialize(const Program::Program &obj, Serializer &serializer) {
serializer.increase_container_depth();
serde::Serializable<decltype(obj.functions)>::serialize(obj.functions, serializer);
serde::Serializable<decltype(obj.unconstrained_functions)>::serialize(obj.unconstrained_functions, serializer);
serializer.decrease_container_depth();
}

Expand All @@ -6324,6 +6435,7 @@ Program::Program serde::Deserializable<Program::Program>::deserialize(Deserializ
deserializer.increase_container_depth();
Program::Program obj;
obj.functions = serde::Deserializable<decltype(obj.functions)>::deserialize(deserializer);
obj.unconstrained_functions = serde::Deserializable<decltype(obj.unconstrained_functions)>::deserialize(deserializer);
deserializer.decrease_container_depth();
return obj;
}
Expand Down
8 changes: 8 additions & 0 deletions noir/noir-repo/acvm-repo/acir/src/circuit/brillig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,11 @@ pub struct Brillig {
/// Predicate of the Brillig execution - indicates if it should be skipped
pub predicate: Option<Expression>,
}

/// This is purely a wrapper struct around a list of Brillig opcode's which represents
/// a full Brillig function to be executed by the Brillig VM.
/// This is stored separately on a program and accessed through a [BrilligPointer].
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct BrilligBytecode {
pub bytecode: Vec<BrilligOpcode>,
}
Loading

0 comments on commit f06f64c

Please sign in to comment.