Skip to content

Commit

Permalink
feat: support explicit nops, allow either branch of if.true to be e…
Browse files Browse the repository at this point in the history
…mpty
  • Loading branch information
bobbinth authored Jun 24, 2024
2 parents 107142d + 72c93cb commit ddf536c
Show file tree
Hide file tree
Showing 17 changed files with 229 additions and 55 deletions.
12 changes: 9 additions & 3 deletions .github/workflows/book.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,26 @@ jobs:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
toolchain: nightly
override: true

- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
with:
mdbook-version: 'latest'
mdbook-version: "latest"

- name: Install mdbook-katex
uses: actions-rs/cargo@v1
with:
command: install
args: mdbook-katex

- name: Install mdbook-alerts
uses: actions-rs/cargo@v1
with:
command: install
args: mdbook-alerts

- name: Install mdbook-linkcheck
uses: actions-rs/cargo@v1
with:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
- Change MAST to a table-based representation (#1349)
- Adjusted prover's metal acceleration code to work with 0.9 versions of the crates (#1357)
- Added support for immediate values for `u32lt`, `u32lte`, `u32gt`, `u32gte`, `u32min` and `u32max` comparison instructions (#1358).
- Added support for the `nop` instruction, which corresponds to the VM opcode of the same name, and has the same semantics. This is implemented for use by compilers primarily.
- Added support for the `if.false` instruction, which can be used in the same manner as `if.true`
- Relaxed the parser to allow one branch of an `if.(true|false)` to be empty

#### Changed

- When using `if.(true|false) .. end`, the parser used to emit an empty block for the branch that was elided. The parser now emits a block containing a single `nop` instruction instead, which is equivalent to the code emitted by the assembler when lowering to MAST.

## 0.9.2 (2024-05-22) - `stdlib` crate only
- Skip writing MASM documentation to file when building on docs.rs (#1341).
Expand Down
1 change: 1 addition & 0 deletions assembly/src/assembler/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl Assembler {
use Operation::*;

match instruction {
Instruction::Nop => span_builder.push_op(Noop),
Instruction::Assert => span_builder.push_op(Assert(0)),
Instruction::AssertWithError(err_code) => {
span_builder.push_op(Assert(err_code.expect_value()))
Expand Down
10 changes: 2 additions & 8 deletions assembly/src/assembler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,14 +774,8 @@ impl Assembler {

let then_blk =
self.compile_body(then_blk.iter(), context, None, mast_forest)?;
// else is an exception because it is optional; hence, will have to be replaced
// by noop span
let else_blk = if else_blk.is_empty() {
let basic_block_node = MastNode::new_basic_block(vec![Operation::Noop]);
mast_forest.ensure_node(basic_block_node)
} else {
self.compile_body(else_blk.iter(), context, None, mast_forest)?
};
let else_blk =
self.compile_body(else_blk.iter(), context, None, mast_forest)?;

let split_node_id = {
let split_node = MastNode::new_split(then_blk, else_blk, mast_forest);
Expand Down
11 changes: 10 additions & 1 deletion assembly/src/ast/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,17 @@ impl fmt::Debug for Block {
impl crate::prettier::PrettyPrint for Block {
fn render(&self) -> crate::prettier::Document {
use crate::prettier::*;
use crate::{ast::Instruction, Span};

// If a block is empty, pretty-print it with a `nop` instruction
let default_body = [Op::Inst(Span::new(self.span, Instruction::Nop))];
let body = match self.body.as_slice() {
[] => default_body.as_slice().iter(),
body => body.iter(),
}
.map(PrettyPrint::render)
.reduce(|acc, doc| acc + nl() + doc);

let body = self.body.iter().map(PrettyPrint::render).reduce(|acc, doc| acc + nl() + doc);
body.map(|body| indent(4, body)).unwrap_or(Document::Empty)
}
}
Expand Down
1 change: 1 addition & 0 deletions assembly/src/ast/instruction/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ impl Deserializable for Instruction {
let opcode = OpCode::read_from(source)?;

match opcode {
OpCode::Nop => Ok(Self::Nop),
OpCode::Assert => Ok(Self::Assert),
OpCode::AssertWithError => Ok(Self::AssertWithError(source.read_u32()?.into())),
OpCode::AssertEq => Ok(Self::AssertEq),
Expand Down
1 change: 1 addition & 0 deletions assembly/src/ast/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
/// NOTE: For control flow instructions, see [crate::ast::Op].
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Instruction {
Nop,
Assert,
AssertWithError(ErrorCode),
AssertEq,
Expand Down
3 changes: 2 additions & 1 deletion assembly/src/ast/instruction/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use alloc::string::ToString;
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OpCode {
Assert = 0,
Nop = 0,
Assert,
AssertWithError,
AssertEq,
AssertEqWithError,
Expand Down
1 change: 1 addition & 0 deletions assembly/src/ast/instruction/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl PrettyPrint for Instruction {
use crate::prettier::*;

match self {
Self::Nop => const_text("nop"),
Self::Assert => const_text("assert"),
Self::AssertWithError(err_code) => {
flatten(const_text("assert.err") + const_text("=") + display(err_code))
Expand Down
1 change: 1 addition & 0 deletions assembly/src/ast/instruction/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
impl Serializable for Instruction {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
match self {
Self::Nop => OpCode::Nop.write_into(target),
Self::Assert => OpCode::Assert.write_into(target),
Self::AssertWithError(err_code) => {
OpCode::AssertWithError.write_into(target);
Expand Down
23 changes: 13 additions & 10 deletions assembly/src/ast/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,14 +513,17 @@ fn test_ast_parsing_module_nested_if() -> Result<(), Report> {
0,
block!(
inst!(PushU8(1)),
if_true!(block!(
inst!(PushU8(0)),
inst!(PushU8(1)),
if_true!(
block!(inst!(PushU8(0)), inst!(Sub)),
block!(inst!(PushU8(1)), inst!(Sub))
)
))
if_true!(
block!(
inst!(PushU8(0)),
inst!(PushU8(1)),
if_true!(
block!(inst!(PushU8(0)), inst!(Sub)),
block!(inst!(PushU8(1)), inst!(Sub))
)
),
block!(inst!(Nop))
)
)
));
assert_eq!(context.parse_forms(source)?, forms);
Expand Down Expand Up @@ -553,7 +556,7 @@ fn test_ast_parsing_module_sequential_if() -> Result<(), Report> {
0,
block!(
inst!(PushU8(1)),
if_true!(block!(inst!(PushU8(5)), inst!(PushU8(1)))),
if_true!(block!(inst!(PushU8(5)), inst!(PushU8(1))), block!(inst!(Nop))),
if_true!(block!(inst!(PushU8(0)), inst!(Sub)), block!(inst!(PushU8(1)), inst!(Sub)))
)
));
Expand Down Expand Up @@ -585,7 +588,7 @@ fn parsed_while_if_body() {
inst!(PushU8(1)),
while_true!(block!(inst!(Mul))),
inst!(Add),
if_true!(block!(inst!(Div))),
if_true!(block!(inst!(Div)), block!(inst!(Nop))),
inst!(Mul)
));

Expand Down
20 changes: 10 additions & 10 deletions assembly/src/ast/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,11 @@ where
SysCall(ref target) => visitor.visit_syscall(target),
ProcRef(ref target) => visitor.visit_procref(target),
Debug(ref options) => visitor.visit_debug_options(Span::new(span, options)),
Assert | AssertEq | AssertEqw | Assertz | Add | Sub | Mul | Div | Neg | ILog2 | Inv
| Incr | Pow2 | Exp | ExpBitLength(_) | Not | And | Or | Xor | Eq | Neq | Eqw | Lt
| Lte | Gt | Gte | IsOdd | Ext2Add | Ext2Sub | Ext2Mul | Ext2Div | Ext2Neg | Ext2Inv
| U32Test | U32TestW | U32Assert | U32Assert2 | U32AssertW | U32Split | U32Cast
| U32WrappingAdd | U32OverflowingAdd | U32OverflowingAdd3 | U32WrappingAdd3
Nop | Assert | AssertEq | AssertEqw | Assertz | Add | Sub | Mul | Div | Neg | ILog2
| Inv | Incr | Pow2 | Exp | ExpBitLength(_) | Not | And | Or | Xor | Eq | Neq | Eqw
| Lt | Lte | Gt | Gte | IsOdd | Ext2Add | Ext2Sub | Ext2Mul | Ext2Div | Ext2Neg
| Ext2Inv | U32Test | U32TestW | U32Assert | U32Assert2 | U32AssertW | U32Split
| U32Cast | U32WrappingAdd | U32OverflowingAdd | U32OverflowingAdd3 | U32WrappingAdd3
| U32WrappingSub | U32OverflowingSub | U32WrappingMul | U32OverflowingMul
| U32OverflowingMadd | U32WrappingMadd | U32Div | U32Mod | U32DivMod | U32And | U32Or
| U32Xor | U32Not | U32Shr | U32Shl | U32Rotr | U32Rotl | U32Popcnt | U32Clz | U32Ctz
Expand Down Expand Up @@ -775,11 +775,11 @@ where
SysCall(ref mut target) => visitor.visit_mut_syscall(target),
ProcRef(ref mut target) => visitor.visit_mut_procref(target),
Debug(ref mut options) => visitor.visit_mut_debug_options(Span::new(span, options)),
Assert | AssertEq | AssertEqw | Assertz | Add | Sub | Mul | Div | Neg | ILog2 | Inv
| Incr | Pow2 | Exp | ExpBitLength(_) | Not | And | Or | Xor | Eq | Neq | Eqw | Lt
| Lte | Gt | Gte | IsOdd | Ext2Add | Ext2Sub | Ext2Mul | Ext2Div | Ext2Neg | Ext2Inv
| U32Test | U32TestW | U32Assert | U32Assert2 | U32AssertW | U32Split | U32Cast
| U32WrappingAdd | U32OverflowingAdd | U32OverflowingAdd3 | U32WrappingAdd3
Nop | Assert | AssertEq | AssertEqw | Assertz | Add | Sub | Mul | Div | Neg | ILog2
| Inv | Incr | Pow2 | Exp | ExpBitLength(_) | Not | And | Or | Xor | Eq | Neq | Eqw
| Lt | Lte | Gt | Gte | IsOdd | Ext2Add | Ext2Sub | Ext2Mul | Ext2Div | Ext2Neg
| Ext2Inv | U32Test | U32TestW | U32Assert | U32Assert2 | U32AssertW | U32Split
| U32Cast | U32WrappingAdd | U32OverflowingAdd | U32OverflowingAdd3 | U32WrappingAdd3
| U32WrappingSub | U32OverflowingSub | U32WrappingMul | U32OverflowingMul
| U32OverflowingMadd | U32WrappingMadd | U32Div | U32Mod | U32DivMod | U32And | U32Or
| U32Xor | U32Not | U32Shr | U32Shl | U32Rotr | U32Rotl | U32Popcnt | U32Clz | U32Ctz
Expand Down
45 changes: 40 additions & 5 deletions assembly/src/parser/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ extern {
"exp" => Token::Exp,
"exp.u" => Token::ExpU,
"export" => Token::Export,
"false" => Token::False,
"fri_ext2fold4" => Token::FriExt2Fold4,
"gt" => Token::Gt,
"gte" => Token::Gte,
Expand Down Expand Up @@ -129,6 +130,7 @@ extern {
"neg" => Token::Neg,
"neq" => Token::Neq,
"not" => Token::Not,
"nop" => Token::Nop,
"or" => Token::Or,
"padw" => Token::Padw,
"pow2" => Token::Pow2,
Expand Down Expand Up @@ -347,19 +349,51 @@ Op: SmallOpsVec = {
}

IfElse: Op = {
<l:@L> "if" "." "true" <then_blk:Block> "else" <else_blk:Block> "end" <r:@R> => {
Op::If { span: span!(l, r), then_blk, else_blk }
// Handles the edge case of a code generator emitting an empty "then" block
<l:@L> "if" "." <cond:Condition> "else" <else_blk:Block> "end" <r:@R> => {
let span = span!(l, r);
let then_blk = Block::new(span, vec![Op::Inst(Span::new(span, Instruction::Nop))]);
// If false-conditioned, swap the blocks
if cond {
Op::If { span, then_blk, else_blk }
} else {
Op::If { span, then_blk: else_blk, else_blk: then_blk }
}
},

<l:@L> "if" "." <cond:Condition> <then_blk:Block> "else" <else_blk:Block?> "end" <r:@R> => {
let span = span!(l, r);
let else_blk = else_blk.unwrap_or_else(|| Block::new(span, vec![Op::Inst(Span::new(span, Instruction::Nop))]));
// If false-conditioned, swap the blocks
if cond {
Op::If { span, then_blk, else_blk }
} else {
Op::If { span, then_blk: else_blk, else_blk: then_blk }
}
},

<l:@L> "if" "." "true" <then_blk:Block> "end" <r:@R> => {
Op::If { span: span!(l, r), then_blk, else_blk: Default::default() }
<l:@L> "if" "." <cond:Condition> <then_blk:Block> "end" <r:@R> => {
let span = span!(l, r);
let else_blk = Block::new(span, vec![Op::Inst(Span::new(span, Instruction::Nop))]);
// If false-conditioned, swap the blocks
if cond {
Op::If { span, then_blk, else_blk }
} else {
Op::If { span, then_blk: else_blk, else_blk: then_blk }
}
}
}

#[inline]
Condition: bool = {
"true" => true,
"false" => false,
}

While: Op = {
<l:@L> "while" "." "true" <body:Block> "end" <r:@R> => {
Op::While { span: span!(l, r), body }
}
},
}

Repeat: Op = {
Expand Down Expand Up @@ -439,6 +473,7 @@ Inst: Instruction = {
"mtree_set" => Instruction::MTreeSet,
"neg" => Instruction::Neg,
"not" => Instruction::Not,
"nop" => Instruction::Nop,
"or" => Instruction::Or,
"padw" => Instruction::PadW,
"pow2" => Instruction::Pow2,
Expand Down
7 changes: 7 additions & 0 deletions assembly/src/parser/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub enum Token<'input> {
Export,
Exp,
ExpU,
False,
FriExt2Fold4,
Gt,
Gte,
Expand Down Expand Up @@ -148,6 +149,7 @@ pub enum Token<'input> {
Neg,
Neq,
Not,
Nop,
Or,
Padw,
Pow2,
Expand Down Expand Up @@ -288,6 +290,7 @@ impl<'input> fmt::Display for Token<'input> {
Token::Exp => write!(f, "exp"),
Token::ExpU => write!(f, "exp.u"),
Token::Export => write!(f, "export"),
Token::False => write!(f, "false"),
Token::FriExt2Fold4 => write!(f, "fri_ext2fold4"),
Token::Gt => write!(f, "gt"),
Token::Gte => write!(f, "gte"),
Expand Down Expand Up @@ -324,6 +327,7 @@ impl<'input> fmt::Display for Token<'input> {
Token::Neg => write!(f, "neg"),
Token::Neq => write!(f, "neq"),
Token::Not => write!(f, "not"),
Token::Nop => write!(f, "nop"),
Token::Or => write!(f, "or"),
Token::Padw => write!(f, "padw"),
Token::Pow2 => write!(f, "pow2"),
Expand Down Expand Up @@ -501,6 +505,7 @@ impl<'input> Token<'input> {
| Token::Neg
| Token::Neq
| Token::Not
| Token::Nop
| Token::Or
| Token::Padw
| Token::Pow2
Expand Down Expand Up @@ -615,6 +620,7 @@ impl<'input> Token<'input> {
("exp", Token::Exp),
("exp.u", Token::ExpU),
("export", Token::Export),
("false", Token::False),
("fri_ext2fold4", Token::FriExt2Fold4),
("gt", Token::Gt),
("gte", Token::Gte),
Expand Down Expand Up @@ -651,6 +657,7 @@ impl<'input> Token<'input> {
("neg", Token::Neg),
("neq", Token::Neq),
("not", Token::Not),
("nop", Token::Nop),
("or", Token::Or),
("padw", Token::Padw),
("pow2", Token::Pow2),
Expand Down
Loading

0 comments on commit ddf536c

Please sign in to comment.