diff --git a/Cargo.lock b/Cargo.lock index d4d8ea1951c..d394f5c5c2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6911,6 +6911,7 @@ dependencies = [ "in_definite", "num-traits", "smallvec", + "strsim 0.11.1", "sway-types", "thiserror", "uwuify", diff --git a/sway-ast/src/expr/op_code.rs b/sway-ast/src/expr/op_code.rs index 3bb40b2b91c..acfc54411eb 100644 --- a/sway-ast/src/expr/op_code.rs +++ b/sway-ast/src/expr/op_code.rs @@ -200,6 +200,13 @@ define_op_codes!( (Srli, SrliOpcode, "srli", (ret: reg, lhs: reg, rhs: imm)), (Sub, SubOpcode, "sub", (ret: reg, lhs: reg, rhs: reg)), (Subi, SubiOpcode, "subi", (ret: reg, lhs: reg, rhs: imm)), + (Wqcm, WqcmOpcode, "wqcm", (ret: reg, lhs: reg, rhs: reg, op_mode: imm)), + (Wqop, WqopOpcode, "wqop", (ret: reg, lhs: reg, rhs: reg, op_mode: imm)), + (Wqml, WqmlOpcode, "wqml", (ret: reg, lhs: reg, rhs: reg, indirect: imm)), + (Wqdv, WqdvOpcode, "wqdv", (ret: reg, lhs: reg, rhs: reg, indirect: imm)), + (Wqmd, WqmdOpcode, "wqmd", (ret: reg, lhs_a: reg, lhs_b: reg, rhs: reg)), + (Wqam, WqamOpcode, "wqam", (ret: reg, lhs_a: reg, lhs_b: reg, rhs: reg)), + (Wqmm, WqmmOpcode, "wqmm", (ret: reg, lhs_a: reg, lhs_b: reg, rhs: reg)), (Xor, XorOpcode, "xor", (ret: reg, lhs: reg, rhs: reg)), (Xori, XoriOpcode, "xori", (ret: reg, lhs: reg, rhs: imm)), /* Control Flow Instructions */ diff --git a/sway-core/src/asm_lang/allocated_ops.rs b/sway-core/src/asm_lang/allocated_ops.rs index 23ff1c11acd..5590279cde7 100644 --- a/sway-core/src/asm_lang/allocated_ops.rs +++ b/sway-core/src/asm_lang/allocated_ops.rs @@ -110,6 +110,12 @@ pub(crate) enum AllocatedOpcode { AllocatedRegister, VirtualImmediate06, ), + WQMD( + AllocatedRegister, + AllocatedRegister, + AllocatedRegister, + AllocatedRegister, + ), WQCM( AllocatedRegister, AllocatedRegister, @@ -122,6 +128,12 @@ pub(crate) enum AllocatedOpcode { AllocatedRegister, AllocatedRegister, ), + WQMM( + AllocatedRegister, + AllocatedRegister, + AllocatedRegister, + AllocatedRegister, + ), /* Control Flow Instructions */ JMP(AllocatedRegister), @@ -303,8 +315,10 @@ impl AllocatedOpcode { WQOP(_, _, _, _) => vec![], WQML(_, _, _, _) => vec![], WQDV(_, _, _, _) => vec![], + WQMD(_, _, _, _) => vec![], WQCM(r1, _, _, _) => vec![r1], WQAM(_, _, _, _) => vec![], + WQMM(_, _, _, _) => vec![], /* Control Flow Instructions */ JMP(_r1) => vec![], @@ -428,8 +442,10 @@ impl fmt::Display for AllocatedOpcode { WQOP(a, b, c, d) => write!(fmtr, "wqop {a} {b} {c} {d}"), WQML(a, b, c, d) => write!(fmtr, "wqml {a} {b} {c} {d}"), WQDV(a, b, c, d) => write!(fmtr, "wqdv {a} {b} {c} {d}"), + WQMD(a, b, c, d) => write!(fmtr, "wqmd {a} {b} {c} {d}"), WQCM(a, b, c, d) => write!(fmtr, "wqcm {a} {b} {c} {d}"), WQAM(a, b, c, d) => write!(fmtr, "wqam {a} {b} {c} {d}"), + WQMM(a, b, c, d) => write!(fmtr, "wqmm {a} {b} {c} {d}"), /* Control Flow Instructions */ JMP(a) => write!(fmtr, "jmp {a}"), @@ -594,12 +610,18 @@ impl AllocatedOp { WQDV(a, b, c, d) => { op::WQDV::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id(), d.value.into()).into() } + WQMD(a, b, c, d) => { + op::WQMD::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id(), d.to_reg_id()).into() + } WQCM(a, b, c, d) => { op::WQCM::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id(), d.value.into()).into() } WQAM(a, b, c, d) => { op::WQAM::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id(), d.to_reg_id()).into() } + WQMM(a, b, c, d) => { + op::WQMM::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id(), d.to_reg_id()).into() + } /* Control Flow Instructions */ JMP(a) => op::JMP::new(a.to_reg_id()).into(), diff --git a/sway-core/src/asm_lang/mod.rs b/sway-core/src/asm_lang/mod.rs index 641fbfff9f6..5e1bcaded52 100644 --- a/sway-core/src/asm_lang/mod.rs +++ b/sway-core/src/asm_lang/mod.rs @@ -415,6 +415,34 @@ impl Op { let (r1, r2, imm) = two_regs_imm_12(handler, args, immediate, whole_op_span)?; VirtualOp::SUBI(r1, r2, imm) } + "wqcm" => { + let (r1, r2, r3, imm) = three_regs_imm_06(handler, args, immediate, whole_op_span)?; + VirtualOp::WQCM(r1, r2, r3, imm) + } + "wqop" => { + let (r1, r2, r3, imm) = three_regs_imm_06(handler, args, immediate, whole_op_span)?; + VirtualOp::WQOP(r1, r2, r3, imm) + } + "wqml" => { + let (r1, r2, r3, imm) = three_regs_imm_06(handler, args, immediate, whole_op_span)?; + VirtualOp::WQML(r1, r2, r3, imm) + } + "wqdv" => { + let (r1, r2, r3, imm) = three_regs_imm_06(handler, args, immediate, whole_op_span)?; + VirtualOp::WQDV(r1, r2, r3, imm) + } + "wqmd" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::WQMD(r1, r2, r3, r4) + } + "wqam" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::WQAM(r1, r2, r3, r4) + } + "wqmm" => { + let (r1, r2, r3, r4) = four_regs(handler, args, immediate, whole_op_span)?; + VirtualOp::WQMM(r1, r2, r3, r4) + } "xor" => { let (r1, r2, r3) = three_regs(handler, args, immediate, whole_op_span)?; VirtualOp::XOR(r1, r2, r3) @@ -1148,8 +1176,10 @@ impl fmt::Display for VirtualOp { WQOP(a, b, c, d) => write!(fmtr, "wqop {a} {b} {c} {d}"), WQML(a, b, c, d) => write!(fmtr, "wqml {a} {b} {c} {d}"), WQDV(a, b, c, d) => write!(fmtr, "wqdv {a} {b} {c} {d}"), + WQMD(a, b, c, d) => write!(fmtr, "wqmd {a} {b} {c} {d}"), WQCM(a, b, c, d) => write!(fmtr, "wqcm {a} {b} {c} {d}"), WQAM(a, b, c, d) => write!(fmtr, "wqam {a} {b} {c} {d}"), + WQMM(a, b, c, d) => write!(fmtr, "wqmm {a} {b} {c} {d}"), /* Control Flow Instructions */ JMP(a) => write!(fmtr, "jmp {a}"), diff --git a/sway-core/src/asm_lang/virtual_ops.rs b/sway-core/src/asm_lang/virtual_ops.rs index 29b7da0030e..ffe3509b7cd 100644 --- a/sway-core/src/asm_lang/virtual_ops.rs +++ b/sway-core/src/asm_lang/virtual_ops.rs @@ -75,6 +75,12 @@ pub(crate) enum VirtualOp { VirtualRegister, VirtualImmediate06, ), + WQMD( + VirtualRegister, + VirtualRegister, + VirtualRegister, + VirtualRegister, + ), WQCM( VirtualRegister, VirtualRegister, @@ -87,6 +93,12 @@ pub(crate) enum VirtualOp { VirtualRegister, VirtualRegister, ), + WQMM( + VirtualRegister, + VirtualRegister, + VirtualRegister, + VirtualRegister, + ), /* Control Flow Instructions */ JMP(VirtualRegister), @@ -263,8 +275,10 @@ impl VirtualOp { WQOP(r1, r2, r3, _) => vec![r1, r2, r3], WQML(r1, r2, r3, _) => vec![r1, r2, r3], WQDV(r1, r2, r3, _) => vec![r1, r2, r3], + WQMD(r1, r2, r3, r4) => vec![r1, r2, r3, r4], WQCM(r1, r2, r3, _) => vec![r1, r2, r3], WQAM(r1, r2, r3, r4) => vec![r1, r2, r3, r4], + WQMM(r1, r2, r3, r4) => vec![r1, r2, r3, r4], /* Control Flow Instructions */ JMP(r1) => vec![r1], @@ -399,8 +413,10 @@ impl VirtualOp { WQOP(_, _, _, _) | WQML(_, _, _, _) | WQDV(_, _, _, _) + | WQMD(_, _, _, _) | WQCM(_, _, _, _) | WQAM(_, _, _, _) + | WQMM(_, _, _, _) | JMP(_) | JI(_) | JNE(_, _, _) @@ -493,8 +509,10 @@ impl VirtualOp { | WQOP(_, _, _, _) | WQML(_, _, _, _) | WQDV(_, _, _, _) + | WQMD(_, _, _, _) | WQCM(_, _, _, _) | WQAM(_, _, _, _) + | WQMM(_, _, _, _) // Cryptographic | ECK1(_, _, _) | ECR1(_, _, _) @@ -596,11 +614,16 @@ impl VirtualOp { SUBI(_r1, r2, _i) => vec![r2], XOR(_r1, r2, r3) => vec![r2, r3], XORI(_r1, r2, _i) => vec![r2], + // Note that most of the `WQ..` instructions *read* from the `r1` result register, + // because the register itself does not contain the result, but provides the + // memory address at which the result will be stored. WQOP(r1, r2, r3, _) => vec![r1, r2, r3], WQML(r1, r2, r3, _) => vec![r1, r2, r3], WQDV(r1, r2, r3, _) => vec![r1, r2, r3], + WQMD(r1, r2, r3, r4) => vec![r1, r2, r3, r4], WQCM(_, r2, r3, _) => vec![r2, r3], WQAM(r1, r2, r3, r4) => vec![r1, r2, r3, r4], + WQMM(r1, r2, r3, r4) => vec![r1, r2, r3, r4], /* Control Flow Instructions */ JMP(r1) => vec![r1], @@ -718,8 +741,10 @@ impl VirtualOp { WQOP(_, _, _, _) => vec![], WQML(_, _, _, _) => vec![], WQDV(_, _, _, _) => vec![], + WQMD(_, _, _, _) => vec![], WQCM(r1, _, _, _) => vec![r1], WQAM(_, _, _, _) => vec![], + WQMM(_, _, _, _) => vec![], /* Control Flow Instructions */ JMP(_r1) => vec![], @@ -987,6 +1012,12 @@ impl VirtualOp { update_reg(reg_to_reg_map, r3), i.clone(), ), + WQMD(r1, r2, r3, r4) => Self::WQMD( + update_reg(reg_to_reg_map, r1), + update_reg(reg_to_reg_map, r2), + update_reg(reg_to_reg_map, r3), + update_reg(reg_to_reg_map, r4), + ), WQCM(r1, r2, r3, i) => Self::WQCM( update_reg(reg_to_reg_map, r1), update_reg(reg_to_reg_map, r2), @@ -999,6 +1030,12 @@ impl VirtualOp { update_reg(reg_to_reg_map, r3), update_reg(reg_to_reg_map, r4), ), + WQMM(r1, r2, r3, r4) => Self::WQMM( + update_reg(reg_to_reg_map, r1), + update_reg(reg_to_reg_map, r2), + update_reg(reg_to_reg_map, r3), + update_reg(reg_to_reg_map, r4), + ), /* Control Flow Instructions */ JMP(r1) => Self::JMP(update_reg(reg_to_reg_map, r1)), @@ -1464,6 +1501,12 @@ impl VirtualOp { map_reg(&mapping, reg3), imm.clone(), ), + WQMD(reg1, reg2, reg3, reg4) => AllocatedOpcode::WQMD( + map_reg(&mapping, reg1), + map_reg(&mapping, reg2), + map_reg(&mapping, reg3), + map_reg(&mapping, reg4), + ), WQCM(reg1, reg2, reg3, imm) => AllocatedOpcode::WQCM( map_reg(&mapping, reg1), map_reg(&mapping, reg2), @@ -1476,6 +1519,12 @@ impl VirtualOp { map_reg(&mapping, reg3), map_reg(&mapping, reg4), ), + WQMM(reg1, reg2, reg3, reg4) => AllocatedOpcode::WQMM( + map_reg(&mapping, reg1), + map_reg(&mapping, reg2), + map_reg(&mapping, reg3), + map_reg(&mapping, reg4), + ), /* Control Flow Instructions */ JMP(reg1) => AllocatedOpcode::JMP(map_reg(&mapping, reg1)), diff --git a/sway-error/Cargo.toml b/sway-error/Cargo.toml index 506e1badc6c..8cc56791be2 100644 --- a/sway-error/Cargo.toml +++ b/sway-error/Cargo.toml @@ -13,6 +13,7 @@ either = "1.9.0" in_definite = "1.0.0" num-traits = "0.2.14" smallvec = "1.7" +strsim = "0.11.1" sway-types = { version = "0.63.3", path = "../sway-types" } thiserror = "1.0" uwuify = { version = "^0.2", optional = true } diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index 2131c63f238..ec85cf3298b 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -2646,6 +2646,31 @@ impl ToDiagnostic for CompileError { format!("{} E.g., `*ref_to_mutable_value` or `*max_mut(&mut x, &mut y)`.", Indent::Single), ] }, + ParseErrorKind::UnrecognizedOpCode { known_op_codes } => Diagnostic { + reason: Some(Reason::new(code(1), "Assembly instruction is unknown".to_string())), + issue: Issue::error( + source_engine, + error.span.clone(), + format!("\"{}\" is not a known assembly instruction.", + error.span.as_str() + ) + ), + hints: { + let suggestions = &did_you_mean(error.span.as_str(), known_op_codes.iter(), 2); + if suggestions.is_empty() { + vec![] + } else { + vec![ + Hint::help( + source_engine, + error.span.clone(), + format!("Did you mean {}?", sequence_to_str_or(suggestions, Enclosing::DoubleQuote, 2)) + ), + ] + } + }, + help: vec![] + }, _ => Diagnostic { // TODO: Temporary we use self here to achieve backward compatibility. // In general, self must not be used and will not be used once we diff --git a/sway-error/src/formatting.rs b/sway-error/src/formatting.rs index a81f289df4b..b4483424d6d 100644 --- a/sway-error/src/formatting.rs +++ b/sway-error/src/formatting.rs @@ -3,7 +3,7 @@ use std::{ borrow::Cow, - cmp, + cmp::{self, Ordering}, fmt::{self, Display}, }; @@ -95,6 +95,42 @@ impl Display for Indent { /// /// Panics if the `sequence` is empty, or `max_items` is zero. pub(crate) fn sequence_to_str(sequence: &[T], enclosing: Enclosing, max_items: usize) -> String +where + T: Display, +{ + sequence_to_str_impl(sequence, enclosing, max_items, "and") +} + +/// Returns reading-friendly textual representation of the `sequence`, with comma-separated +/// items and each item optionally enclosed in the specified `enclosing`. +/// If the sequence has more than `max_items` the remaining items are replaced +/// with the text "or more". +/// +/// E.g.: +/// [a] => "a" +/// [a, b] => "a" or "b" +/// [a, b, c] => "a", "b" or "c" +/// [a, b, c, d] => "a", "b", "c" or one more +/// [a, b, c, d, e] => "a", "b", "c" or two more +/// +/// Panics if the `sequence` is empty, or `max_items` is zero. +pub(crate) fn sequence_to_str_or( + sequence: &[T], + enclosing: Enclosing, + max_items: usize, +) -> String +where + T: Display, +{ + sequence_to_str_impl(sequence, enclosing, max_items, "or") +} + +fn sequence_to_str_impl( + sequence: &[T], + enclosing: Enclosing, + max_items: usize, + and_or: &str, +) -> String where T: Display, { @@ -115,12 +151,13 @@ where if !remaining.is_empty() { format!( - "{}, and {} more", + "{}, {} {} more", to_display .iter() .map(fmt_item) .collect::>() .join(", "), + and_or, number_to_str(remaining.len()) ) } else { @@ -128,10 +165,15 @@ where [] => unreachable!("There must be at least one item in the sequence."), [item] => fmt_item(item), [first_item, second_item] => { - format!("{} and {}", fmt_item(first_item), fmt_item(second_item)) + format!( + "{} {} {}", + fmt_item(first_item), + and_or, + fmt_item(second_item) + ) } _ => format!( - "{}, and {}", + "{}, {} {}", to_display .split_last() .unwrap() @@ -140,6 +182,7 @@ where .map(fmt_item) .collect::>() .join(", "), + and_or, fmt_item(to_display.last().unwrap()) ), } @@ -290,3 +333,32 @@ pub(crate) fn first_line(text: &str, with_ellipses: bool) -> Cow { Cow::Owned(text[..index_of_new_line].to_string() + if with_ellipses { "..." } else { "" }) } } + +/// Finds strings from an iterable of `possible_values` similar to a given value `v`. +/// Returns a vector of all possible values that exceed a similarity threshold, +/// sorted by similarity (most similar comes first). The returned vector will have +/// at most `max_num_of_suggestions` elements. +/// +/// The implementation is taken and adapted from the [Clap project](https://github.com/clap-rs/clap/blob/50f7646cf72dd7d4e76d9284d76bdcdaceb7c049/clap_builder/src/parser/features/suggestions.rs#L11). +pub(crate) fn did_you_mean( + v: &str, + possible_values: I, + max_num_of_suggestions: usize, +) -> Vec +where + T: AsRef, + I: IntoIterator, +{ + let mut candidates: Vec<_> = possible_values + .into_iter() + .map(|pv| (strsim::jaro(v, pv.as_ref()), pv.as_ref().to_owned())) + // Confidence of 0.7 so that bar -> baz is suggested. + .filter(|(confidence, _)| *confidence > 0.7) + .collect(); + candidates.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal)); + candidates + .into_iter() + .take(max_num_of_suggestions) + .map(|(_, pv)| pv) + .collect() +} diff --git a/sway-error/src/parser_error.rs b/sway-error/src/parser_error.rs index 9f7d4e364f7..21e417801cf 100644 --- a/sway-error/src/parser_error.rs +++ b/sway-error/src/parser_error.rs @@ -12,8 +12,10 @@ pub enum ParseErrorKind { ExpectedAnItemAfterDocComment, #[error("Expected a comma or closing parenthesis in function arguments.")] ExpectedCommaOrCloseParenInFnArgs, - #[error("Unrecognized op code.")] - UnrecognizedOpCode, + #[error("Unknown assembly instruction.")] + UnrecognizedOpCode { + known_op_codes: &'static [&'static str], + }, #[error("Unexpected token in statement.")] UnexpectedTokenInStatement, #[error("This expression cannot be assigned to.")] diff --git a/sway-parse/src/expr/op_code.rs b/sway-parse/src/expr/op_code.rs index f1819e6223b..1281ca4bae3 100644 --- a/sway-parse/src/expr/op_code.rs +++ b/sway-parse/src/expr/op_code.rs @@ -6,6 +6,10 @@ use sway_types::{Ident, Spanned}; macro_rules! define_op_codes ( ( $(($op_name:ident, $ty_name:ident, $s:literal, ($($arg_name:ident),*)),)* ) => { + pub const OP_CODES: &'static [&'static str] = &[ + $($s),* + ]; + pub fn parse_instruction(ident: Ident, parser: &mut Parser) -> ParseResult { match ident.as_str() { $($s => { @@ -16,7 +20,9 @@ macro_rules! define_op_codes ( },)* _ => { let span = ident.span().clone(); - Err(parser.emit_error_with_span(ParseErrorKind::UnrecognizedOpCode, span)) + Err(parser.emit_error_with_span(ParseErrorKind::UnrecognizedOpCode { + known_op_codes: OP_CODES, + }, span)) }, } } @@ -54,6 +60,13 @@ define_op_codes!( (Srli, SrliOpcode, "srli", (ret, lhs, rhs)), (Sub, SubOpcode, "sub", (ret, lhs, rhs)), (Subi, SubiOpcode, "subi", (ret, lhs, rhs)), + (Wqcm, WqcmOpcode, "wqcm", (ret, lhs, rhs, op_mode)), + (Wqop, WqopOpcode, "wqop", (ret, lhs, rhs, op_mode)), + (Wqml, WqmlOpcode, "wqml", (ret, lhs, rhs, indirect)), + (Wqdv, WqdvOpcode, "wqdv", (ret, lhs, rhs, indirect)), + (Wqmd, WqmdOpcode, "wqmd", (ret, lhs_a, lhs_b, rhs)), + (Wqam, WqamOpcode, "wqam", (ret, lhs_a, lhs_b, rhs)), + (Wqmm, WqmmOpcode, "wqmm", (ret, lhs_a, lhs_b, rhs)), (Xor, XorOpcode, "xor", (ret, lhs, rhs)), (Xori, XoriOpcode, "xori", (ret, lhs, rhs)), /* Control Flow Instructions */ diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/Forc.lock new file mode 100644 index 00000000000..ce1b03b30fa --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/Forc.lock @@ -0,0 +1,3 @@ +[[package]] +name = "asm_unrecognized_opcode" +source = "member" diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/Forc.toml similarity index 79% rename from test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/Forc.toml rename to test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/Forc.toml index c6b847f7ff8..5667453e56f 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] license = "Apache-2.0" implicit-std = false -name = "unrecognized_opcode" +name = "asm_unrecognized_opcode" entry = "main.sw" [dependencies] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/src/main.sw new file mode 100644 index 00000000000..c524244eb9e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/src/main.sw @@ -0,0 +1,15 @@ +library; + +pub fn test() { + asm (r1: 0, r2: 0, r3: 0) { + blobbb r1 r2 r3; + }; + + asm (r1: 0, r2: 0, r3: 0) { + modd r1 r2 r3; + }; + + asm (r1: 0, r2: 0, r3: 0) { + ttllyunknwn r1 r2 r3; + }; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/test.toml new file mode 100644 index 00000000000..963dd58630e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/asm_unrecognized_opcode/test.toml @@ -0,0 +1,28 @@ +category = "fail" + +#check: $()error +#sameln: $()Assembly instruction is unknown +#check: $()blobbb r1 r2 r3; +#nextln: $()"blobbb" is not a known assembly instruction. +#nextln: $()Did you mean "blob"? + +#check: $()Expected an expression + +#check: $()error +#sameln: $()Assembly instruction is unknown +#check: $()modd r1 r2 r3; +#nextln: $()"modd" is not a known assembly instruction. +#nextln: $()Did you mean "mod" or "modi"? + +#check: $()Expected an expression + +#check: $()error +#sameln: $()Assembly instruction is unknown +#check: $()ttllyunknwn r1 r2 r3; +#nextln: $()"ttllyunknwn" is not a known assembly instruction. + +#check: $()Expected an expression + +#not: $()Did you mean + +#check: $()6 errors. \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/Forc.lock deleted file mode 100644 index 1b37fb7e1f1..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/Forc.lock +++ /dev/null @@ -1,3 +0,0 @@ -[[package]] -name = 'unrecognized_opcode' -source = 'member' diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/src/main.sw deleted file mode 100644 index 1fc663e5516..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/src/main.sw +++ /dev/null @@ -1,8 +0,0 @@ -script; - -fn main() { - let _x = asm (r1, r2: 0, r3: 0) { - modd r1 r2 r3; - r1: u64 - }; -} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/test.toml deleted file mode 100644 index 5354716275a..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/unrecognized_opcode/test.toml +++ /dev/null @@ -1,4 +0,0 @@ -category = "fail" - - # check: $()modd r1 r2 r3; - # check: $()Unrecognized op code. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/Forc.lock new file mode 100644 index 00000000000..3b576dee330 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "asm_wqxx_instructions" +source = "member" +dependencies = ["std"] + +[[package]] +name = "core" +source = "path+from-root-DEA77F133437397D" + +[[package]] +name = "std" +source = "path+from-root-DEA77F133437397D" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/Forc.toml new file mode 100644 index 00000000000..c44f1f66715 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "asm_wqxx_instructions" + +[dependencies] +std = { path = "../../../../reduced_std_libs/sway-lib-std-assert" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/src/main.sw new file mode 100644 index 00000000000..3203aa3b494 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/src/main.sw @@ -0,0 +1,137 @@ +library; + +const ZERO: b256 = b256::zero(); +const ONE: b256 = 0x0000000000000000000000000000000000000000000000000000000000000001; +const TWO: b256 = 0x0000000000000000000000000000000000000000000000000000000000000002; +const THREE: b256 = 0x0000000000000000000000000000000000000000000000000000000000000003; +const FOUR: b256 = 0x0000000000000000000000000000000000000000000000000000000000000004; +const FIVE: b256 = 0x0000000000000000000000000000000000000000000000000000000000000005; +const NINE: b256 = 0x0000000000000000000000000000000000000000000000000000000000000009; +const TEN: b256 = 0x000000000000000000000000000000000000000000000000000000000000000A; + +#[test] +fn wqml() { + let mut res = ZERO; + + let a: b256 = TWO; + let b: b256 = TWO; + + asm(res: res, a: a, b: b) { + wqml res a b i48; + } + + assert_eq(res, FOUR); + + let a: u64 = 5; + let b: u64 = 2; + + asm(res: res, a: a, b: b) { + wqml res a b i0; + } + + assert_eq(res, TEN); + + asm(res: res, a: ZERO, b: ZERO) { + wqml res a b i48; + } + + assert_eq(res, ZERO); + + let a: b256 = THREE; + let b: u64 = 3; + + asm(res: res, a: a, b: b) { + wqml res a b i16; + } + + assert_eq(res, NINE); +} + +#[test] +fn all_in_one() { + // WQCM + let a: b256 = TWO; + let b: b256 = TWO; + + let bool_res = asm(b_res, a: a, b: b) { + wqcm b_res a b i32; // a == b + b_res: bool + }; + + assert_eq(bool_res, true); + + // WQOP + let mut res = TEN; + + let a: b256 = TEN; + let b: b256 = NINE; + + asm(res: res, a: a, b: b) { + wqop res a b i33; // a - b + }; + + assert_eq(res, ONE); + + // WQML + let mut res = ZERO; + + let a: b256 = TWO; + let b: b256 = TWO; + + asm(res: res, a: a, b: b) { + wqml res a b i48; // 2 * 2 + } + + assert_eq(res, FOUR); + + // WQDV + let mut res = ZERO; + + let a: b256 = TEN; + let b: b256 = FIVE; + + asm(res: res, a: a, b: b) { + wqdv res a b i32; // 10 / 5 + } + + assert_eq(res, TWO); + + // WQMD + let mut res = ZERO; + + let a: b256 = TEN; + let b: b256 = TWO; + let c: b256 = FIVE; + + asm(res: res, a: a, b: b, c: c) { + wqmd res a b c; // (10 * 2) / 5 + } + + assert_eq(res, FOUR); + + // WQAM + let mut res = ZERO; + + let a: b256 = TEN; + let b: b256 = TWO; + let c: b256 = FIVE; + + asm(res: res, a: a, b: b, c: c) { + wqam res a b c; // (10 + 2) % 5 + } + + assert_eq(res, TWO); + + // WQMM + let mut res = ZERO; + + let a: b256 = TEN; + let b: b256 = TWO; + let c: b256 = THREE; + + asm(res: res, a: a, b: b, c: c) { + wqmm res a b c; // (10 * 2) % 3 + } + + assert_eq(res, TWO); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/test.toml new file mode 100644 index 00000000000..f1958c1b086 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/asm_wqxx_instructions/test.toml @@ -0,0 +1 @@ +category = "unit_tests_pass" \ No newline at end of file