diff --git a/crates/polkavm-common/src/assembler.rs b/crates/polkavm-common/src/assembler.rs index db6c0f7c..a1512eba 100644 --- a/crates/polkavm-common/src/assembler.rs +++ b/crates/polkavm-common/src/assembler.rs @@ -437,6 +437,69 @@ pub fn assemble(code: &str) -> Result, String> { } } + if let Some(index) = rhs.find("cpop ") { + if let Some(src) = parse_reg(rhs[index + 5..].trim()) { + match op_marker { + OpMarker::I32 => { + emit_and_continue!(Instruction::count_set_bits_32(dst.into(), src.into())); + } + OpMarker::NONE => { + emit_and_continue!(Instruction::count_set_bits_64(dst.into(), src.into())); + } + } + } + } + + if let Some(index) = rhs.find("clz ") { + if let Some(src) = parse_reg(rhs[index + 4..].trim()) { + match op_marker { + OpMarker::I32 => { + emit_and_continue!(Instruction::count_leading_zero_bits_32(dst.into(), src.into())); + } + OpMarker::NONE => { + emit_and_continue!(Instruction::count_leading_zero_bits_64(dst.into(), src.into())); + } + } + } + } + + if let Some(index) = rhs.find("ctz ") { + if let Some(src) = parse_reg(rhs[index + 4..].trim()) { + match op_marker { + OpMarker::I32 => { + emit_and_continue!(Instruction::count_trailing_zero_bits_32(dst.into(), src.into())); + } + OpMarker::NONE => { + emit_and_continue!(Instruction::count_trailing_zero_bits_64(dst.into(), src.into())); + } + } + } + } + + if let Some(index) = rhs.find("sext.b ") { + if let Some(src) = parse_reg(rhs[index + 7..].trim()) { + emit_and_continue!(Instruction::sign_extend_8(dst.into(), src.into())); + } + } + + if let Some(index) = rhs.find("sext.h ") { + if let Some(src) = parse_reg(rhs[index + 7..].trim()) { + emit_and_continue!(Instruction::sign_extend_16(dst.into(), src.into())); + } + } + + if let Some(index) = rhs.find("zext.h ") { + if let Some(src) = parse_reg(rhs[index + 7..].trim()) { + emit_and_continue!(Instruction::zero_extend_16(dst.into(), src.into())); + } + } + + if let Some(index) = rhs.find("reverse ") { + if let Some(src) = parse_reg(rhs[index + 8..].trim()) { + emit_and_continue!(Instruction::reverse_byte(dst.into(), src.into())); + } + } + if let Some(src) = parse_reg(rhs) { emit_and_continue!(Instruction::move_reg(dst.into(), src.into())); } @@ -456,6 +519,26 @@ pub fn assemble(code: &str) -> Result, String> { emit_and_continue!(MaybeInstruction::LoadLabelAddress(dst, label.to_owned())); } + if let Some(index) = rhs.find("~(") { + let rhs = rhs[index + 2..].trim(); + if let Some(index) = rhs.find(')') { + let rhs = rhs[..index].trim(); + if let Some(index) = rhs.find('^') { + let src1 = rhs[..index].trim(); + let src2 = rhs[index + 1..].trim(); + + if let Some(src1) = parse_reg(src1) { + if let Some(src2) = parse_reg(src2) { + let dst = dst.into(); + let src1 = src1.into(); + let src2 = src2.into(); + emit_and_continue!(Instruction::xnor(dst, src1, src2)); + } + } + } + } + } + enum Op { Add, Sub, @@ -474,13 +557,21 @@ pub fn assemble(code: &str) -> Result, String> { ShiftLeft, ShiftRight, ShiftArithmeticRight, + RotateLeft, + RotateRight, + AndInverted, + OrInverted, } #[allow(clippy::manual_map)] let operation = if let Some(index) = rhs.find('+') { Some((index, 1, Op::Add)) + } else if let Some(index) = rhs.find("& ~") { + Some((index, 3, Op::AndInverted)) } else if let Some(index) = rhs.find('&') { Some((index, 1, Op::And)) + } else if let Some(index) = rhs.find("| ~") { + Some((index, 3, Op::OrInverted)) } else if let Some(index) = rhs.find('|') { Some((index, 1, Op::Or)) } else if let Some(index) = rhs.find('^') { @@ -497,6 +588,10 @@ pub fn assemble(code: &str) -> Result, String> { Some((index, 2, Op::RemSigned)) } else if let Some(index) = rhs.find(">>a") { Some((index, 3, Op::ShiftArithmeticRight)) + } else if let Some(index) = rhs.find(">>r") { + Some((index, 3, Op::RotateRight)) + } else if let Some(index) = rhs.find("<>") { @@ -559,6 +654,14 @@ pub fn assemble(code: &str) -> Result, String> { Op::ShiftLeft => Instruction::shift_logical_left_32(dst, src1, src2), Op::ShiftRight => Instruction::shift_logical_right_32(dst, src1, src2), Op::ShiftArithmeticRight => Instruction::shift_arithmetic_right_32(dst, src1, src2), + Op::RotateLeft => Instruction::rotate_left_32(dst, src1, src2), + Op::RotateRight => Instruction::rotate_right_32(dst, src1, src2), + Op::AndInverted => { + return Err(format!("cannot parse line {nth_line}: i32 not supported for operation")); + } + Op::OrInverted => { + return Err(format!("cannot parse line {nth_line}: i32 not supported for operation")); + } }); } OpMarker::NONE => { @@ -580,6 +683,10 @@ pub fn assemble(code: &str) -> Result, String> { Op::ShiftLeft => Instruction::shift_logical_left_64(dst, src1, src2), Op::ShiftRight => Instruction::shift_logical_right_64(dst, src1, src2), Op::ShiftArithmeticRight => Instruction::shift_arithmetic_right_64(dst, src1, src2), + Op::RotateLeft => Instruction::rotate_left_64(dst, src1, src2), + Op::RotateRight => Instruction::rotate_right_64(dst, src1, src2), + Op::AndInverted => Instruction::and_inverted(dst, src1, src2), + Op::OrInverted => Instruction::or_inverted(dst, src1, src2), }); } } @@ -626,6 +733,20 @@ pub fn assemble(code: &str) -> Result, String> { Op::ShiftLeft => Instruction::shift_logical_left_imm_32(dst, src1, src2), Op::ShiftRight => Instruction::shift_logical_right_imm_32(dst, src1, src2), Op::ShiftArithmeticRight => Instruction::shift_arithmetic_right_imm_32(dst, src1, src2), + Op::RotateLeft => { + return Err(format!("cannot parse line {nth_line}: i32 not supported for operation")); + } + Op::RotateRight => Instruction::rotate_right_imm_32(dst, src1, src2), + Op::AndInverted => { + return Err(format!( + "cannot parse line {nth_line}: i32 and and_inverted not supported for immediates" + )); + } + Op::OrInverted => { + return Err(format!( + "cannot parse line {nth_line}: i32 and or_inverted not supported for immediates" + )); + } }); } OpMarker::NONE => { @@ -649,6 +770,16 @@ pub fn assemble(code: &str) -> Result, String> { Op::ShiftLeft => Instruction::shift_logical_left_imm_64(dst, src1, src2), Op::ShiftRight => Instruction::shift_logical_right_imm_64(dst, src1, src2), Op::ShiftArithmeticRight => Instruction::shift_arithmetic_right_imm_64(dst, src1, src2), + Op::RotateLeft => { + return Err(format!("cannot parse line {nth_line}: rotate_left not supported for immediates")); + } + Op::RotateRight => Instruction::rotate_right_imm_64(dst, src1, src2), + Op::AndInverted => { + return Err(format!("cannot parse line {nth_line}: and_inverted not supported for immediates")); + } + Op::OrInverted => { + return Err(format!("cannot parse line {nth_line}: or_inverted not supported for immediates")); + } }); } } @@ -697,6 +828,22 @@ pub fn assemble(code: &str) -> Result, String> { Op::ShiftLeft => Instruction::shift_logical_left_imm_alt_32(dst, src2, src1), Op::ShiftRight => Instruction::shift_logical_right_imm_alt_32(dst, src2, src1), Op::ShiftArithmeticRight => Instruction::shift_arithmetic_right_imm_alt_32(dst, src2, src1), + Op::RotateLeft => { + return Err(format!( + "cannot parse line {nth_line}: i32 and rotate_left is not supported for immediates" + )); + } + Op::RotateRight => Instruction::rotate_right_imm_alt_32(dst, src2, src1), + Op::AndInverted => { + return Err(format!( + "cannot parse line {nth_line}: i32 and and_inverted not supported for operation" + )); + } + Op::OrInverted => { + return Err(format!( + "cannot parse line {nth_line}: i32 and or_inverted not supported for operation" + )); + } }); } OpMarker::NONE => { @@ -720,6 +867,61 @@ pub fn assemble(code: &str) -> Result, String> { Op::ShiftLeft => Instruction::shift_logical_left_imm_alt_64(dst, src2, src1), Op::ShiftRight => Instruction::shift_logical_right_imm_alt_64(dst, src2, src1), Op::ShiftArithmeticRight => Instruction::shift_arithmetic_right_imm_alt_64(dst, src2, src1), + Op::RotateLeft => { + return Err(format!("cannot parse line {nth_line}: i64 not supported for operation")); + } + Op::RotateRight => Instruction::rotate_right_imm_alt_64(dst, src2, src1), + Op::AndInverted => { + return Err(format!("cannot parse line {nth_line}: and_inverted not supported for immediates")); + } + Op::OrInverted => { + return Err(format!("cannot parse line {nth_line}: or_inverted not supported for immediates")); + } + }); + } + } + } + } + } + + enum MaxMinOp { + Max, + MaxUnsigned, + Min, + MinUnsigned, + } + + #[allow(clippy::manual_map)] + let min_max_op = if let Some(index) = rhs.find("maxs(") { + Some((index, 5, MaxMinOp::Max)) + } else if let Some(index) = rhs.find("maxu(") { + Some((index, 5, MaxMinOp::MaxUnsigned)) + } else if let Some(index) = rhs.find("mins(") { + Some((index, 5, MaxMinOp::Min)) + } else if let Some(index) = rhs.find("minu(") { + Some((index, 5, MaxMinOp::MinUnsigned)) + } else { + None + }; + + if let Some((index, op_len, op)) = min_max_op { + let rhs = rhs[index + op_len..].trim(); + if let Some(index) = rhs.find(')') { + let rhs = rhs[..index].trim(); + if let Some(index) = rhs.find(',') { + let src1 = rhs[..index].trim(); + let src2 = rhs[index + 1..].trim(); + + if let Some(src1) = parse_reg(src1) { + if let Some(src2) = parse_reg(src2) { + let dst = dst.into(); + let src1 = src1.into(); + let src2 = src2.into(); + emit_and_continue!(match op { + MaxMinOp::Max => Instruction::maximum(dst, src1, src2), + MaxMinOp::MaxUnsigned => Instruction::maximum_unsigned(dst, src1, src2), + MaxMinOp::Min => Instruction::minimum(dst, src1, src2), + MaxMinOp::MinUnsigned => Instruction::minimum_unsigned(dst, src1, src2), }); } } diff --git a/tools/spectool/spec/src/inst_and_inverted.txt b/tools/spectool/spec/src/inst_and_inverted.txt new file mode 100644 index 00000000..212d7d8f --- /dev/null +++ b/tools/spectool/spec/src/inst_and_inverted.txt @@ -0,0 +1,9 @@ +pre: a0 = 0b101 +pre: a1 = 0b011 +pre: gas = 10000 + +pub @main: + a2 = a0 & ~a1 + +post: a2 = 0b100 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_count_leading_zero_bits_32.txt b/tools/spectool/spec/src/inst_count_leading_zero_bits_32.txt new file mode 100644 index 00000000..01a68753 --- /dev/null +++ b/tools/spectool/spec/src/inst_count_leading_zero_bits_32.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1000000030000000 +pre: gas = 10000 + +pub @main: + i32 a2 = clz a0 + +post: a2 = 2 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_count_leading_zero_bits_64.txt b/tools/spectool/spec/src/inst_count_leading_zero_bits_64.txt new file mode 100644 index 00000000..0e9af570 --- /dev/null +++ b/tools/spectool/spec/src/inst_count_leading_zero_bits_64.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1000000030000000 +pre: gas = 10000 + +pub @main: + a2 = clz a0 + +post: a2 = 3 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_count_set_bits_32.txt b/tools/spectool/spec/src/inst_count_set_bits_32.txt new file mode 100644 index 00000000..7b981251 --- /dev/null +++ b/tools/spectool/spec/src/inst_count_set_bits_32.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1000000030000000 +pre: gas = 10000 + +pub @main: + i32 a2 = cpop a0 + +post: a2 = 2 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_count_set_bits_64.txt b/tools/spectool/spec/src/inst_count_set_bits_64.txt new file mode 100644 index 00000000..ea021e35 --- /dev/null +++ b/tools/spectool/spec/src/inst_count_set_bits_64.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1000000030000000 +pre: gas = 10000 + +pub @main: + a2 = cpop a0 + +post: a2 = 3 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_count_trailing_zero_bits_32.txt b/tools/spectool/spec/src/inst_count_trailing_zero_bits_32.txt new file mode 100644 index 00000000..b02a0453 --- /dev/null +++ b/tools/spectool/spec/src/inst_count_trailing_zero_bits_32.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1000000030000000 +pre: gas = 10000 + +pub @main: + i32 a2 = ctz a0 + +post: a2 = 28 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_count_trailing_zero_bits_64.txt b/tools/spectool/spec/src/inst_count_trailing_zero_bits_64.txt new file mode 100644 index 00000000..c8de272b --- /dev/null +++ b/tools/spectool/spec/src/inst_count_trailing_zero_bits_64.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1000000030000000 +pre: gas = 10000 + +pub @main: + a2 = ctz a0 + +post: a2 = 28 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_max.txt b/tools/spectool/spec/src/inst_max.txt new file mode 100644 index 00000000..aabdff6c --- /dev/null +++ b/tools/spectool/spec/src/inst_max.txt @@ -0,0 +1,9 @@ +pre: a0 = 1 +pre: a1 = -2 +pre: gas = 10000 + +pub @main: + a2 = maxs(a0, a1) + +post: a2 = 1 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_max_unsigned.txt b/tools/spectool/spec/src/inst_max_unsigned.txt new file mode 100644 index 00000000..94a32eeb --- /dev/null +++ b/tools/spectool/spec/src/inst_max_unsigned.txt @@ -0,0 +1,9 @@ +pre: a0 = 1 +pre: a1 = -2 +pre: gas = 10000 + +pub @main: + a2 = maxu(a0, a1) + +post: a2 = -2 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_min.txt b/tools/spectool/spec/src/inst_min.txt new file mode 100644 index 00000000..b1f41389 --- /dev/null +++ b/tools/spectool/spec/src/inst_min.txt @@ -0,0 +1,9 @@ +pre: a0 = 1 +pre: a1 = -2 +pre: gas = 10000 + +pub @main: + a2 = mins(a0, a1) + +post: a2 = -2 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_min_unsigned.txt b/tools/spectool/spec/src/inst_min_unsigned.txt new file mode 100644 index 00000000..0b5f6c7e --- /dev/null +++ b/tools/spectool/spec/src/inst_min_unsigned.txt @@ -0,0 +1,9 @@ +pre: a0 = 1 +pre: a1 = -2 +pre: gas = 10000 + +pub @main: + a2 = minu(a0, a1) + +post: a2 = 1 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_or_inverted.txt b/tools/spectool/spec/src/inst_or_inverted.txt new file mode 100644 index 00000000..f363b628 --- /dev/null +++ b/tools/spectool/spec/src/inst_or_inverted.txt @@ -0,0 +1,9 @@ +pre: a0 = 0b101 +pre: a1 = 0b011 +pre: gas = 10000 + +pub @main: + a2 = a0 | ~a1 + +post: a2 = 0xfffffffffffffffd +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_reverse.txt b/tools/spectool/spec/src/inst_reverse.txt new file mode 100644 index 00000000..9096d7d2 --- /dev/null +++ b/tools/spectool/spec/src/inst_reverse.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x1122334455667788 +pre: gas = 10000 + +pub @main: + a2 = reverse a0 + +post: a2 = 0x8877665544332211 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_32.txt b/tools/spectool/spec/src/inst_rotate_right_32.txt new file mode 100644 index 00000000..8ae09679 --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_32.txt @@ -0,0 +1,9 @@ +pre: a0 = 0x800000009 +pre: a1 = 3 +pre: gas = 10000 + +pub @main: + i32 a2 = a0 >>r a1 + +post: a2 = 0x20000001 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_32_with_overflow.txt b/tools/spectool/spec/src/inst_rotate_right_32_with_overflow.txt new file mode 100644 index 00000000..1ba2c983 --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_32_with_overflow.txt @@ -0,0 +1,9 @@ +pre: a0 = 0x800000009 +pre: a1 = 34 +pre: gas = 10000 + +pub @main: + i32 a2 = a0 >>r a1 + +post: a2 = 0x40000002 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_64.txt b/tools/spectool/spec/src/inst_rotate_right_64.txt new file mode 100644 index 00000000..bd8550b4 --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_64.txt @@ -0,0 +1,9 @@ +pre: a0 = 0x800000009 +pre: a1 = 3 +pre: gas = 10000 + +pub @main: + a2 = a0 >>r a1 + +post: a2 = 0x2000000100000001 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_64_with_overflow.txt b/tools/spectool/spec/src/inst_rotate_right_64_with_overflow.txt new file mode 100644 index 00000000..95e6c90a --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_64_with_overflow.txt @@ -0,0 +1,9 @@ +pre: a0 = 0x800000009 +pre: a1 = 66 +pre: gas = 10000 + +pub @main: + a2 = a0 >>r a1 + +post: a2 = 0x4000000200000002 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_imm_32.txt b/tools/spectool/spec/src/inst_rotate_right_imm_32.txt new file mode 100644 index 00000000..72326bf6 --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_imm_32.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x800000009 +pre: gas = 10000 + +pub @main: + i32 a2 = a0 >>r 3 + +post: a2 = 0x20000001 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_imm_64.txt b/tools/spectool/spec/src/inst_rotate_right_imm_64.txt new file mode 100644 index 00000000..15257025 --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_imm_64.txt @@ -0,0 +1,8 @@ +pre: a0 = 0x800000009 +pre: gas = 10000 + +pub @main: + a2 = a0 >>r 3 + +post: a2 = 0x2000000100000001 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_imm_alt_32.txt b/tools/spectool/spec/src/inst_rotate_right_imm_alt_32.txt new file mode 100644 index 00000000..1dace75e --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_imm_alt_32.txt @@ -0,0 +1,8 @@ +pre: a0 = 3 +pre: gas = 10000 + +pub @main: + i32 a2 = 9 >>r a0 + +post: a2 = 0x20000001 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_rotate_right_imm_alt_64.txt b/tools/spectool/spec/src/inst_rotate_right_imm_alt_64.txt new file mode 100644 index 00000000..c0314581 --- /dev/null +++ b/tools/spectool/spec/src/inst_rotate_right_imm_alt_64.txt @@ -0,0 +1,8 @@ +pre: a0 = 3 +pre: gas = 10000 + +pub @main: + a2 = 9 >>r a0 + +post: a2 = 0x2000000000000001 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_sign_extend_16.txt b/tools/spectool/spec/src/inst_sign_extend_16.txt new file mode 100644 index 00000000..cd622af8 --- /dev/null +++ b/tools/spectool/spec/src/inst_sign_extend_16.txt @@ -0,0 +1,8 @@ +pre: a0 = 0xaaaa +pre: gas = 10000 + +pub @main: + a2 = sext.h a0 + +post: a2 = 0xffffffffffffaaaa +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_sign_extend_8.txt b/tools/spectool/spec/src/inst_sign_extend_8.txt new file mode 100644 index 00000000..7641eaf9 --- /dev/null +++ b/tools/spectool/spec/src/inst_sign_extend_8.txt @@ -0,0 +1,8 @@ +pre: a0 = 0xaa +pre: gas = 10000 + +pub @main: + a2 = sext.b a0 + +post: a2 = 0xffffffffffffffaa +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_xnor.txt b/tools/spectool/spec/src/inst_xnor.txt new file mode 100644 index 00000000..d1354bbc --- /dev/null +++ b/tools/spectool/spec/src/inst_xnor.txt @@ -0,0 +1,9 @@ +pre: a0 = 0b101 +pre: a1 = 0b011 +pre: gas = 10000 + +pub @main: + a2 = ~(a0 ^ a1) + +post: a2 = 0xfffffffffffffff9 +post: gas = 9998 diff --git a/tools/spectool/spec/src/inst_zero_extend_16.txt b/tools/spectool/spec/src/inst_zero_extend_16.txt new file mode 100644 index 00000000..b5b63e4b --- /dev/null +++ b/tools/spectool/spec/src/inst_zero_extend_16.txt @@ -0,0 +1,8 @@ +pre: a0 = 0xaaaa +pre: gas = 10000 + +pub @main: + a2 = zext.h a0 + +post: a2 = 0x00000000aaaa +post: gas = 9998