infer the assignment register when assigning the output of an instruction

This commit is contained in:
schaeff
2023-07-27 16:19:57 +02:00
parent 79f2077514
commit e965d7f0eb
7 changed files with 300 additions and 96 deletions

176
analysis/src/inference.rs Normal file
View File

@@ -0,0 +1,176 @@
use ast::asm_analysis::{AnalysisASMFile, Expression, FunctionStatement, Machine};
use number::FieldElement;
pub fn infer<T: FieldElement>(file: AnalysisASMFile<T>) -> Result<AnalysisASMFile<T>, Vec<String>> {
let mut errors = vec![];
let mut res = AnalysisASMFile::default();
for (name, m) in file.machines {
match infer_machine(m) {
Ok(m) => {
res.machines.insert(name, m);
}
Err(e) => {
errors.extend(e);
}
}
}
if !errors.is_empty() {
Err(errors)
} else {
Ok(res)
}
}
fn infer_machine<T: FieldElement>(mut machine: Machine<T>) -> Result<Machine<T>, Vec<String>> {
let mut errors = vec![];
for f in machine.functions.iter_mut() {
for s in f.body.statements.iter_mut() {
if let FunctionStatement::Assignment(a) = s {
let expr_reg = match &*a.rhs {
Expression::FunctionCall(c) => {
let instr = machine
.instructions
.iter()
.find(|i| i.name == c.id)
.unwrap();
let output = {
let outputs = instr.params.outputs.as_ref().unwrap();
assert!(outputs.params.len() == 1);
&outputs.params[0]
};
assert!(output.ty.is_none());
Some(output.name.clone())
}
_ => None,
};
match (&mut a.using_reg, expr_reg) {
(Some(using_reg), Some(expr_reg)) if *using_reg != expr_reg => {
errors.push(format!("Assignment register `{}` is incompatible with `{}`. Try replacing `<={}=` by `<==`.", using_reg, a.rhs, using_reg));
}
(Some(_), _) => {}
(None, Some(expr_reg)) => {
// infer the assignment register to that of the rhs
a.using_reg = Some(expr_reg);
}
(None, None) => {
errors.push(format!("Impossible to infer the assignment register for `{a}`. Try being more explicit."));
}
}
}
}
}
if !errors.is_empty() {
Err(errors)
} else {
Ok(machine)
}
}
#[cfg(test)]
mod tests {
use ast::asm_analysis::AssignmentStatement;
use number::Bn254Field;
use crate::test_util::infer_str;
use super::*;
#[test]
fn inferred() {
let file = r#"
machine Incompatible {
reg pc[@pc];
reg X[<=];
reg Y[<=];
reg A;
instr foo -> X {}
function main {
A <== foo();
}
}
"#;
let file = infer_str::<Bn254Field>(file).unwrap();
if let FunctionStatement::Assignment(AssignmentStatement { using_reg, .. }) =
&file.machines["Incompatible"].functions[0].body.statements[0]
{
assert_eq!(*using_reg, Some("X".to_string()));
} else {
panic!()
}
}
#[test]
fn compatible() {
let file = r#"
machine Incompatible {
reg pc[@pc];
reg X[<=];
reg Y[<=];
reg A;
instr foo -> X {}
function main {
A <=X= foo();
}
}
"#;
let file = infer_str::<Bn254Field>(file).unwrap();
if let FunctionStatement::Assignment(AssignmentStatement { using_reg, .. }) =
&file.machines["Incompatible"].functions[0].body.statements[0]
{
assert_eq!(*using_reg, Some("X".to_string()));
} else {
panic!()
}
}
#[test]
fn incompatible() {
let file = r#"
machine Incompatible {
reg pc[@pc];
reg X[<=];
reg Y[<=];
reg A;
instr foo -> X {}
function main {
A <=Y= foo();
}
}
"#;
assert_eq!(infer_str::<Bn254Field>(file).unwrap_err(), vec!["Assignment register `Y` is incompatible with `foo()`. Try replacing `<=Y=` by `<==`."]);
}
#[test]
fn unclear() {
let file = r#"
machine Incompatible {
reg pc[@pc];
reg X[<=];
reg Y[<=];
reg A;
function main {
A <== 1;
}
}
"#;
assert_eq!(infer_str::<Bn254Field>(file).unwrap_err(), vec!["Impossible to infer the assignment register for `A <== 1;`. Try being more explicit.".to_string()]);
}
}

View File

@@ -1,4 +1,5 @@
mod batcher;
mod inference;
mod macro_expansion;
mod romgen;
mod type_check;
@@ -12,7 +13,33 @@ use number::FieldElement;
pub fn analyze<T: FieldElement>(file: ASMFile<T>) -> Result<AnalysisASMFile<T>, Vec<String>> {
let expanded = macro_expansion::expand(file);
let checked = type_check::check(expanded)?;
let rommed = romgen::generate_rom(checked);
let inferred = inference::infer(checked)?;
let rommed = romgen::generate_rom(inferred);
let batched = batcher::batch(rommed);
Ok(batched)
}
#[cfg(test)]
mod test_util {
use ast::{asm_analysis::AnalysisASMFile, parsed::asm::ASMFile};
use number::FieldElement;
use parser::parse_asm;
use crate::{inference, macro_expansion, type_check};
/// A test utility to process a source file until after macro expansion
pub fn expand_str<T: FieldElement>(source: &str) -> ASMFile<T> {
let file = parse_asm(None, source).unwrap();
macro_expansion::expand(file)
}
/// A test utility to process a source file until after type checking
pub fn check_str<T: FieldElement>(source: &str) -> Result<AnalysisASMFile<T>, Vec<String>> {
type_check::check(expand_str(source))
}
/// A test utility to process a source file until after inference
pub fn infer_str<T: FieldElement>(source: &str) -> Result<AnalysisASMFile<T>, Vec<String>> {
inference::infer(check_str(source).unwrap())
}
}

View File

@@ -6,17 +6,19 @@ use num_bigint::BigUint;
use crate::parsed::{
asm::{InstructionBody, Params, RegisterFlag},
Expression, PilStatement,
PilStatement,
};
#[derive(Clone)]
pub use crate::parsed::Expression;
#[derive(Clone, Debug)]
pub struct RegisterDeclarationStatement {
pub start: usize,
pub name: String,
pub flag: Option<RegisterFlag>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct InstructionDefinitionStatement<T> {
pub start: usize,
pub name: String,
@@ -24,12 +26,12 @@ pub struct InstructionDefinitionStatement<T> {
pub body: InstructionBody<T>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct FunctionBody<T> {
pub statements: Vec<FunctionStatement<T>>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct FunctionDefinitionStatement<T> {
pub start: usize,
pub name: String,
@@ -37,12 +39,12 @@ pub struct FunctionDefinitionStatement<T> {
pub body: FunctionBody<T>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct DegreeStatement {
pub degree: BigUint,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum FunctionStatement<T> {
Assignment(AssignmentStatement<T>),
Instruction(InstructionStatement<T>),
@@ -74,7 +76,7 @@ impl<T> From<DebugDirective> for FunctionStatement<T> {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct AssignmentStatement<T> {
pub start: usize,
pub lhs: Vec<String>,
@@ -82,32 +84,32 @@ pub struct AssignmentStatement<T> {
pub rhs: Box<Expression<T>>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct InstructionStatement<T> {
pub start: usize,
pub instruction: String,
pub inputs: Vec<Expression<T>>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct LabelStatement {
pub start: usize,
pub name: String,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct DebugDirective {
pub start: usize,
pub directive: crate::parsed::asm::DebugDirective,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct PilBlock<T> {
pub start: usize,
pub statements: Vec<PilStatement<T>>,
}
#[derive(Clone, Default)]
#[derive(Clone, Default, Debug)]
pub struct Machine<T> {
pub degree: Option<DegreeStatement>,
pub registers: Vec<RegisterDeclarationStatement>,
@@ -130,12 +132,13 @@ impl<T> Machine<T> {
}
}
#[derive(Clone, Default)]
#[derive(Clone, Default, Debug)]
pub struct Rom<T> {
pub statements: Vec<FunctionStatement<T>>,
pub batches: Option<Vec<BatchMetadata>>,
}
#[derive(Default, Debug)]
pub struct AnalysisASMFile<T> {
pub machines: BTreeMap<String, Machine<T>>,
}

View File

@@ -38,8 +38,6 @@ One important requirement is for the assignment register of the assignment to be
{{#include ../../../test_data/asm/book/function.asm:square}}
```
> Specifying the assignment register of the assignment is currently required even in cases where it could be inferred. That restriction may be lifted in the future.
### Instructions
Instructions which do not return outputs can be used as statements.

View File

@@ -150,7 +150,7 @@ fn replace_dynamic_label_references(
load_dynamic s10, LABEL
which is then turned into
s10 <=X= load_label(LABEL)
s10 <== load_label(LABEL)
It gets more complicated by the fact that sometimes, labels
and debugging directives occur between the two statements
@@ -280,7 +280,7 @@ fn store_data_objects<'a>(
// code reference
// TODO should be possible without temporary
object_code.extend([
format!("tmp1 <=X= load_label({});", escape_label(sym)),
format!("tmp1 <== load_label({});", escape_label(sym)),
"mstore tmp1;".to_string(),
]);
}
@@ -876,7 +876,7 @@ fn only_if_no_write_to_zero_vec(statements: Vec<String>, reg: Register) -> Vec<S
}
static COPROCESSOR_SUBSTITUTIONS: &[(&str, &str)] =
&[("poseidon_coprocessor", "x10 <=X= poseidon(x10, x11);")];
&[("poseidon_coprocessor", "x10 <== poseidon(x10, x11);")];
fn try_coprocessor_substitution(label: &str) -> Option<&'static str> {
COPROCESSOR_SUBSTITUTIONS
@@ -909,27 +909,27 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// Arithmetic
"add" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= wrap({r1} + {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== wrap({r1} + {r2});"), rd)
}
"addi" => {
let (rd, rs, imm) = rri(args);
only_if_no_write_to_zero(format!("{rd} <=X= wrap({rs} + {imm});"), rd)
only_if_no_write_to_zero(format!("{rd} <== wrap({rs} + {imm});"), rd)
}
"sub" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= wrap_signed({r1} - {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== wrap_signed({r1} - {r2});"), rd)
}
"neg" => {
let (rd, r1) = rr(args);
only_if_no_write_to_zero(format!("{rd} <=X= wrap_signed(0 - {r1});"), rd)
only_if_no_write_to_zero(format!("{rd} <== wrap_signed(0 - {r1});"), rd)
}
"mul" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= mul({r1}, {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== mul({r1}, {r2});"), rd)
}
"mulhu" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= mulhu({r1}, {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== mulhu({r1}, {r2});"), rd)
}
"divu" => {
let (rd, r1, r2) = rrr(args);
@@ -939,31 +939,31 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// bitwise
"xor" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= xor({r1}, {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== xor({r1}, {r2});"), rd)
}
"xori" => {
let (rd, r1, imm) = rri(args);
only_if_no_write_to_zero(format!("{rd} <=X= xor({r1}, {imm});"), rd)
only_if_no_write_to_zero(format!("{rd} <== xor({r1}, {imm});"), rd)
}
"and" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= and({r1}, {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== and({r1}, {r2});"), rd)
}
"andi" => {
let (rd, r1, imm) = rri(args);
only_if_no_write_to_zero(format!("{rd} <=X= and({r1}, {imm});"), rd)
only_if_no_write_to_zero(format!("{rd} <== and({r1}, {imm});"), rd)
}
"or" => {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero(format!("{rd} <=X= or({r1}, {r2});"), rd)
only_if_no_write_to_zero(format!("{rd} <== or({r1}, {r2});"), rd)
}
"ori" => {
let (rd, r1, imm) = rri(args);
only_if_no_write_to_zero(format!("{rd} <=X= or({r1}, {imm});"), rd)
only_if_no_write_to_zero(format!("{rd} <== or({r1}, {imm});"), rd)
}
"not" => {
let (rd, rs) = rr(args);
only_if_no_write_to_zero(format!("{rd} <=X= wrap_signed(-{rs} - 1);"), rd)
only_if_no_write_to_zero(format!("{rd} <== wrap_signed(-{rs} - 1);"), rd)
}
// shift
@@ -972,11 +972,11 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
assert!(amount <= 31);
only_if_no_write_to_zero_vec(
if amount <= 16 {
vec![format!("{rd} <=X= wrap16({rs} * {});", 1 << amount)]
vec![format!("{rd} <== wrap16({rs} * {});", 1 << amount)]
} else {
vec![
format!("tmp1 <=X= wrap16({rs} * {});", 1 << 16),
format!("{rd} <=X= wrap16(tmp1 * {});", 1 << (amount - 16)),
format!("tmp1 <== wrap16({rs} * {});", 1 << 16),
format!("{rd} <== wrap16(tmp1 * {});", 1 << (amount - 16)),
]
},
rd,
@@ -986,8 +986,8 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero_vec(
vec![
format!("tmp1 <=X= and({r2}, 0x1f);"),
format!("{rd} <=X= shl({r1}, tmp1);"),
format!("tmp1 <== and({r2}, 0x1f);"),
format!("{rd} <== shl({r1}, tmp1);"),
],
rd,
)
@@ -996,15 +996,15 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// logical shift right
let (rd, rs, amount) = rri(args);
assert!(amount <= 31);
only_if_no_write_to_zero(format!("{rd} <=X= shr({rs}, {amount});"), rd)
only_if_no_write_to_zero(format!("{rd} <== shr({rs}, {amount});"), rd)
}
"srl" => {
// logical shift right
let (rd, r1, r2) = rrr(args);
only_if_no_write_to_zero_vec(
vec![
format!("tmp1 <=X= and({r2}, 0x1f);"),
format!("{rd} <=X= shr({r1}, tmp1);"),
format!("tmp1 <== and({r2}, 0x1f);"),
format!("{rd} <== shr({r1}, tmp1);"),
],
rd,
)
@@ -1018,14 +1018,14 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
assert!(amount <= 31);
only_if_no_write_to_zero_vec(
vec![
format!("tmp1 <=X= to_signed({rs});"),
format!("tmp1 <=Y= is_positive(0 - tmp1);"),
format!("tmp1 <== to_signed({rs});"),
format!("tmp1 <== is_positive(0 - tmp1);"),
format!("tmp1 <=X= tmp1 * 0xffffffff;"),
// Here, tmp1 is the full bit mask if rs is negative
// and zero otherwise.
format!("{rd} <=X= xor(tmp1, {rs});"),
format!("{rd} <=X= shr({rd}, {amount});"),
format!("{rd} <=X= xor(tmp1, {rd});"),
format!("{rd} <== xor(tmp1, {rs});"),
format!("{rd} <== shr({rd}, {amount});"),
format!("{rd} <== xor(tmp1, {rd});"),
],
rd,
)
@@ -1044,7 +1044,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
let (rd, rs, imm) = rri(args);
only_if_no_write_to_zero_vec(
vec![
format!("tmp1 <=X= to_signed({rs});"),
format!("tmp1 <== to_signed({rs});"),
format!("{rd} <=Y= is_positive({} - tmp1);", imm as i32),
],
rd,
@@ -1053,8 +1053,8 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
"slt" => {
let (rd, r1, r2) = rrr(args);
vec![
format!("tmp1 <=X= to_signed({r1});"),
format!("tmp2 <=X= to_signed({r2});"),
format!("tmp1 <== to_signed({r1});"),
format!("tmp2 <== to_signed({r2});"),
format!("{rd} <=Y= is_positive(tmp2 - tmp1);"),
]
}
@@ -1069,7 +1069,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
"sgtz" => {
let (rd, rs) = rr(args);
vec![
format!("tmp1 <=X= to_signed({rs});"),
format!("tmp1 <== to_signed({rs});"),
format!("{rd} <=Y= is_positive(tmp1);"),
]
}
@@ -1091,7 +1091,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
"bgez" => {
let (r1, label) = rl(args);
vec![
format!("tmp1 <=X= to_signed({r1});"),
format!("tmp1 <== to_signed({r1});"),
format!("branch_if_positive tmp1 + 1, {label};"),
]
}
@@ -1104,8 +1104,8 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// Branch if r1 < r2 (signed).
// TODO does this fulfill the input requirements for branch_if_positive?
vec![
format!("tmp1 <=X= to_signed({r1});"),
format!("tmp2 <=X= to_signed({r2});"),
format!("tmp1 <== to_signed({r1});"),
format!("tmp2 <== to_signed({r2});"),
format!("branch_if_positive tmp2 - tmp1, {label};"),
]
}
@@ -1114,8 +1114,8 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// Branch if r1 >= r2 (signed).
// TODO does this fulfill the input requirements for branch_if_positive?
vec![
format!("tmp1 <=X= to_signed({r1});"),
format!("tmp2 <=X= to_signed({r2});"),
format!("tmp1 <== to_signed({r1});"),
format!("tmp2 <== to_signed({r2});"),
format!("branch_if_positive tmp1 - tmp2 + 1, {label};"),
]
}
@@ -1129,7 +1129,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// branch less or equal zero
let (r1, label) = rl(args);
vec![
format!("tmp1 <=X= to_signed({r1});"),
format!("tmp1 <== to_signed({r1});"),
format!("branch_if_positive -tmp1 + 1, {label};"),
]
}
@@ -1137,7 +1137,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// branch if 0 < r1 < 2**31
let (r1, label) = rl(args);
vec![
format!("tmp1 <=X= to_signed({r1});"),
format!("tmp1 <== to_signed({r1});"),
format!("branch_if_positive tmp1, {label};"),
]
}
@@ -1226,8 +1226,8 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// TODO we need to consider misaligned loads / stores
only_if_no_write_to_zero_vec(
vec![
format!("addr <=X= wrap({rs} + {off});"),
format!("{rd} <=X= mload();"),
format!("addr <== wrap({rs} + {off});"),
format!("{rd} <== mload();"),
],
rd,
)
@@ -1237,12 +1237,12 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
let (rd, rs, off) = rro(args);
only_if_no_write_to_zero_vec(
vec![
format!("tmp1 <=X= wrap({rs} + {off});"),
"addr <=X= and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <=X= and(tmp1, 0x3);".to_string(),
format!("{rd} <=X= mload();"),
format!("{rd} <=X= shr({rd}, 8 * tmp2);"),
format!("{rd} <=X= sign_extend_byte({rd});"),
format!("tmp1 <== wrap({rs} + {off});"),
"addr <== and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <== and(tmp1, 0x3);".to_string(),
format!("{rd} <== mload();"),
format!("{rd} <== shr({rd}, 8 * tmp2);"),
format!("{rd} <== sign_extend_byte({rd});"),
],
rd,
)
@@ -1252,12 +1252,12 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
let (rd, rs, off) = rro(args);
only_if_no_write_to_zero_vec(
vec![
format!("tmp1 <=X= wrap({rs} + {off});"),
"addr <=X= and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <=X= and(tmp1, 0x3);".to_string(),
format!("{rd} <=X= mload();"),
format!("{rd} <=X= shr({rd}, 8 * tmp2);"),
format!("{rd} <=X= and({rd}, 0xff);"),
format!("tmp1 <== wrap({rs} + {off});"),
"addr <== and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <== and(tmp1, 0x3);".to_string(),
format!("{rd} <== mload();"),
format!("{rd} <== shr({rd}, 8 * tmp2);"),
format!("{rd} <== and({rd}, 0xff);"),
],
rd,
)
@@ -1265,7 +1265,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
"sw" => {
let (r1, r2, off) = rro(args);
vec![
format!("addr <=X= wrap({r2} + {off});"),
format!("addr <== wrap({r2} + {off});"),
format!("mstore {r1};"),
]
}
@@ -1276,16 +1276,16 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
let (rs, rd, off) = rro(args);
vec![
format!("tmp1 <=X= wrap({rd} + {off});"),
"addr <=X= and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <=X= and(tmp1, 0x3);".to_string(),
"tmp1 <=X= mload();".to_string(),
"tmp3 <=X= shl(0xffff, 8 * tmp2);".to_string(),
"tmp3 <=X= xor(tmp3, 0xffffffff);".to_string(),
"tmp1 <=X= and(tmp1, tmp3);".to_string(),
format!("tmp3 <=X= and({rs}, 0xffff);"),
"tmp3 <=X= shl(tmp3, 8 * tmp2);".to_string(),
"tmp1 <=X= or(tmp1, tmp3);".to_string(),
format!("tmp1 <== wrap({rd} + {off});"),
"addr <== and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <== and(tmp1, 0x3);".to_string(),
"tmp1 <== mload();".to_string(),
"tmp3 <== shl(0xffff, 8 * tmp2);".to_string(),
"tmp3 <== xor(tmp3, 0xffffffff);".to_string(),
"tmp1 <== and(tmp1, tmp3);".to_string(),
format!("tmp3 <== and({rs}, 0xffff);"),
"tmp3 <== shl(tmp3, 8 * tmp2);".to_string(),
"tmp1 <== or(tmp1, tmp3);".to_string(),
"mstore tmp1;".to_string(),
]
}
@@ -1293,16 +1293,16 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// store byte
let (rs, rd, off) = rro(args);
vec![
format!("tmp1 <=X= wrap({rd} + {off});"),
"addr <=X= and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <=X= and(tmp1, 0x3);".to_string(),
"tmp1 <=X= mload();".to_string(),
"tmp3 <=X= shl(0xff, 8 * tmp2);".to_string(),
"tmp3 <=X= xor(tmp3, 0xffffffff);".to_string(),
"tmp1 <=X= and(tmp1, tmp3);".to_string(),
format!("tmp3 <=X= and({rs}, 0xff);"),
"tmp3 <=X= shl(tmp3, 8 * tmp2);".to_string(),
"tmp1 <=X= or(tmp1, tmp3);".to_string(),
format!("tmp1 <== wrap({rd} + {off});"),
"addr <== and(tmp1, 0xfffffffc);".to_string(),
"tmp2 <== and(tmp1, 0x3);".to_string(),
"tmp1 <== mload();".to_string(),
"tmp3 <== shl(0xff, 8 * tmp2);".to_string(),
"tmp3 <== xor(tmp3, 0xffffffff);".to_string(),
"tmp1 <== and(tmp1, tmp3);".to_string(),
format!("tmp3 <== and({rs}, 0xff);"),
"tmp3 <== shl(tmp3, 8 * tmp2);".to_string(),
"tmp1 <== or(tmp1, tmp3);".to_string(),
"mstore tmp1;".to_string(),
]
}
@@ -1312,7 +1312,7 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec<String> {
// Special instruction that is inserted to allow dynamic label references
"load_dynamic" => {
let (rd, label) = rl(args);
only_if_no_write_to_zero(format!("{rd} <=X= load_label({label});"), rd)
only_if_no_write_to_zero(format!("{rd} <== load_label({label});"), rd)
}
_ => {

View File

@@ -50,7 +50,7 @@ machine Machine {
// ANCHOR_END: read_register
// square `A`
// ANCHOR: instruction
A <=Y= square(A);
A <== square(A);
// ANCHOR_END: instruction
// jump back to `start`
jmp start;

View File

@@ -33,8 +33,8 @@ machine HelloWorld {
// the main function assigns the first prover input to A, increments it, decrements it, and loops forever
function main {
A <=X= ${ ("input", 0) };
A <=Y= incr(A);
A <=Y= decr(A);
A <== incr(A);
A <== decr(A);
assert_zero A;
loop;
}