diff --git a/cranelift/codegen/meta/src/pulley.rs b/cranelift/codegen/meta/src/pulley.rs index 2c95b6e5366b..557c92de2eea 100644 --- a/cranelift/codegen/meta/src/pulley.rs +++ b/cranelift/codegen/meta/src/pulley.rs @@ -137,12 +137,14 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { pat.push_str(","); format_string.push_str(&format!(" // trap={{{name}:?}}")); } - Operand::Binop { .. } => { + Operand::Binop { src2, .. } => { pat.push_str("dst, src1, src2,"); format_string.push_str(" {dst}, {src1}, {src2}"); locals.push_str(&format!("let dst = reg_name(*dst.to_reg());\n")); locals.push_str(&format!("let src1 = reg_name(**src1);\n")); - locals.push_str(&format!("let src2 = reg_name(**src2);\n")); + if src2.contains("Reg") { + locals.push_str(&format!("let src2 = reg_name(**src2);\n")); + } } } } @@ -189,11 +191,14 @@ pub fn generate_rust(filename: &str, out_dir: &Path) -> Result<(), Error> { } } Operand::TrapCode { .. } => {} - Operand::Binop { .. } => { - pat.push_str("dst, src1, src2,"); + Operand::Binop { src2, .. } => { + pat.push_str("dst, src1,"); uses.push("src1"); - uses.push("src2"); defs.push("dst"); + if src2.contains("Reg") { + pat.push_str("src2,"); + uses.push("src2"); + } } } } diff --git a/cranelift/codegen/src/isa/pulley_shared/inst.isle b/cranelift/codegen/src/isa/pulley_shared/inst.isle index 5c2babb05270..a27d421abd7a 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst.isle +++ b/cranelift/codegen/src/isa/pulley_shared/inst.isle @@ -126,6 +126,7 @@ (rule (raw_inst_to_inst inst) (MInst.Raw inst)) (convert RawInst MInst raw_inst_to_inst) +(type U6 (primitive U6)) (type BoxCallInfo (primitive BoxCallInfo)) (type BoxCallIndInfo (primitive BoxCallIndInfo)) (type BoxReturnCallInfo (primitive BoxReturnCallInfo)) diff --git a/cranelift/codegen/src/isa/pulley_shared/lower.isle b/cranelift/codegen/src/isa/pulley_shared/lower.isle index a68d6d4be0da..5b14f38fc01b 100644 --- a/cranelift/codegen/src/isa/pulley_shared/lower.isle +++ b/cranelift/codegen/src/isa/pulley_shared/lower.isle @@ -223,6 +223,15 @@ (rule (lower (has_type $I32 (imul a b))) (pulley_xmul32 a b)) (rule (lower (has_type $I64 (imul a b))) (pulley_xmul64 a b)) +(rule 1 (lower (has_type (ty_int (fits_in_32 _)) (imul a (i32_from_iconst b)))) + (pulley_xmul32_s32 a b)) +(rule 2 (lower (has_type $I64 (imul a (i32_from_iconst b)))) + (pulley_xmul64_s32 a b)) +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (imul a (i8_from_iconst b)))) + (pulley_xmul32_s8 a b)) +(rule 4 (lower (has_type $I64 (imul a (i8_from_iconst b)))) + (pulley_xmul64_s8 a b)) + (rule (lower (has_type $I8X16 (imul a b))) (pulley_vmuli8x16 a b)) (rule (lower (has_type $I16X8 (imul a b))) (pulley_vmuli16x8 a b)) (rule (lower (has_type $I32X4 (imul a b))) (pulley_vmuli32x4 a b)) @@ -294,11 +303,31 @@ (rule (lower (has_type $I64 (ishl a b))) (pulley_xshl64 a b)) +;; Special-case constant shift amounts. +(rule 1 (lower (has_type $I32 (ishl a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshl32_u6 a n)) +(rule 1 (lower (has_type $I64 (ishl a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshl64_u6 a n)) + +;; vector shifts + (rule (lower (has_type $I8X16 (ishl a b))) (pulley_vshli8x16 a b)) (rule (lower (has_type $I16X8 (ishl a b))) (pulley_vshli16x8 a b)) (rule (lower (has_type $I32X4 (ishl a b))) (pulley_vshli32x4 a b)) (rule (lower (has_type $I64X2 (ishl a b))) (pulley_vshli64x2 a b)) +;; Helper to extract a constant from `Value`, mask it to 6 bits, and then make a +;; `U6`. +(decl pure partial u6_shift_from_iconst (Value) U6) +(rule (u6_shift_from_iconst (u64_from_iconst val)) + (if-let (u6_from_u8 x) (u64_as_u8 (u64_and val 0x3f))) + x) + +(decl u6_from_u8 (U6) u8) +(extern extractor u6_from_u8 u6_from_u8) + ;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (rule (lower (has_type $I8 (ushr a b))) @@ -313,6 +342,16 @@ (rule (lower (has_type $I64 (ushr a b))) (pulley_xshr64_u a b)) +;; Special-case constant shift amounts. +(rule 1 (lower (has_type $I32 (ushr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr32_u_u6 a n)) +(rule 1 (lower (has_type $I64 (ushr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr64_u_u6 a n)) + +;; vector shifts + (rule (lower (has_type $I8X16 (ushr a b))) (pulley_vshri8x16_u a b)) (rule (lower (has_type $I16X8 (ushr a b))) (pulley_vshri16x8_u a b)) (rule (lower (has_type $I32X4 (ushr a b))) (pulley_vshri32x4_u a b)) @@ -332,6 +371,16 @@ (rule (lower (has_type $I64 (sshr a b))) (pulley_xshr64_s a b)) +;; Special-case constant shift amounts. +(rule 1 (lower (has_type $I32 (sshr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr32_s_u6 a n)) +(rule 1 (lower (has_type $I64 (sshr a b))) + (if-let n (u6_shift_from_iconst b)) + (pulley_xshr64_s_u6 a n)) + +;; vector shifts + (rule (lower (has_type $I8X16 (sshr a b))) (pulley_vshri8x16_s a b)) (rule (lower (has_type $I16X8 (sshr a b))) (pulley_vshri16x8_s a b)) (rule (lower (has_type $I32X4 (sshr a b))) (pulley_vshri32x4_s a b)) @@ -339,33 +388,51 @@ ;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(rule 0 (lower (has_type (fits_in_32 _) (band a b))) - (pulley_xband32 a b)) +(rule 0 (lower (has_type (fits_in_32 _) (band a b))) (pulley_xband32 a b)) +(rule 1 (lower (has_type $I64 (band a b))) (pulley_xband64 a b)) -(rule 1 (lower (has_type $I64 (band a b))) - (pulley_xband64 a b)) +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (band a (i32_from_iconst b)))) + (pulley_xband32_s32 a b)) +(rule 4 (lower (has_type $I64 (band a (i32_from_iconst b)))) + (pulley_xband64_s32 a b)) +(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (band a (i8_from_iconst b)))) + (pulley_xband32_s8 a b)) +(rule 6 (lower (has_type $I64 (band a (i8_from_iconst b)))) + (pulley_xband64_s8 a b)) (rule 2 (lower (has_type (ty_vec128 _) (band a b))) (pulley_vband128 a b)) ;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(rule 0 (lower (has_type (fits_in_32 _) (bor a b))) - (pulley_xbor32 a b)) +(rule 0 (lower (has_type (fits_in_32 _) (bor a b))) (pulley_xbor32 a b)) +(rule 1 (lower (has_type $I64 (bor a b))) (pulley_xbor64 a b)) -(rule 1 (lower (has_type $I64 (bor a b))) - (pulley_xbor64 a b)) +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (bor a (i32_from_iconst b)))) + (pulley_xbor32_s32 a b)) +(rule 4 (lower (has_type $I64 (bor a (i32_from_iconst b)))) + (pulley_xbor64_s32 a b)) +(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (bor a (i8_from_iconst b)))) + (pulley_xbor32_s8 a b)) +(rule 6 (lower (has_type $I64 (bor a (i8_from_iconst b)))) + (pulley_xbor64_s8 a b)) (rule 2 (lower (has_type (ty_vec128 _) (bor a b))) (pulley_vbor128 a b)) ;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(rule 0 (lower (has_type (fits_in_32 _) (bxor a b))) - (pulley_xbxor32 a b)) - -(rule 1 (lower (has_type $I64 (bxor a b))) - (pulley_xbxor64 a b)) +(rule 0 (lower (has_type (fits_in_32 _) (bxor a b))) (pulley_xbxor32 a b)) +(rule 1 (lower (has_type $I64 (bxor a b))) (pulley_xbxor64 a b)) + +(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (bxor a (i32_from_iconst b)))) + (pulley_xbxor32_s32 a b)) +(rule 4 (lower (has_type $I64 (bxor a (i32_from_iconst b)))) + (pulley_xbxor64_s32 a b)) +(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (bxor a (i8_from_iconst b)))) + (pulley_xbxor32_s8 a b)) +(rule 6 (lower (has_type $I64 (bxor a (i8_from_iconst b)))) + (pulley_xbxor64_s8 a b)) (rule 2 (lower (has_type (ty_vec128 _) (bxor a b))) (pulley_vbxor128 a b)) diff --git a/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs b/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs index e98bbd352e05..fcacef0e04ff 100644 --- a/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs +++ b/cranelift/codegen/src/isa/pulley_shared/lower/isle.rs @@ -21,6 +21,7 @@ use crate::machinst::{ CallInfo, IsTailCall, MachInst, Reg, VCodeConstant, VCodeConstantData, }; use alloc::boxed::Box; +use pulley_interpreter::U6; use regalloc2::PReg; type Unit = (); type VecArgPair = Vec; @@ -120,6 +121,10 @@ where fn cond_invert(&mut self, cond: &Cond) -> Cond { cond.invert() } + + fn u6_from_u8(&mut self, imm: u8) -> Option { + U6::new(imm) + } } /// The main entry point for lowering with ISLE. diff --git a/cranelift/codegen/src/isle_prelude.rs b/cranelift/codegen/src/isle_prelude.rs index 94d273771f51..2f346309b26e 100644 --- a/cranelift/codegen/src/isle_prelude.rs +++ b/cranelift/codegen/src/isle_prelude.rs @@ -919,6 +919,10 @@ macro_rules! isle_common_prelude_methods { val.try_into().ok() } + fn i32_as_i8(&mut self, val: i32) -> Option { + val.try_into().ok() + } + fn u8_as_i8(&mut self, val: u8) -> i8 { val as i8 } diff --git a/cranelift/codegen/src/prelude.isle b/cranelift/codegen/src/prelude.isle index bc898cfc5dd9..3f7b12b991d6 100644 --- a/cranelift/codegen/src/prelude.isle +++ b/cranelift/codegen/src/prelude.isle @@ -158,6 +158,9 @@ (decl u32_as_u16 (u16) u32) (extern extractor u32_as_u16 u32_as_u16) +(decl i32_as_i8 (i8) i32) +(extern extractor i32_as_i8 i32_as_i8) + (decl pure u64_as_i32 (u64) i32) (extern constructor u64_as_i32 u64_as_i32) diff --git a/cranelift/codegen/src/prelude_lower.isle b/cranelift/codegen/src/prelude_lower.isle index 0e929b756e71..ddf0ee081811 100644 --- a/cranelift/codegen/src/prelude_lower.isle +++ b/cranelift/codegen/src/prelude_lower.isle @@ -320,6 +320,10 @@ (extractor (u64_from_iconst x) (def_inst (iconst (u64_from_imm64 x)))) +(decl i8_from_iconst (i8) Value) +(extractor (i8_from_iconst x) + (i32_from_iconst (i32_as_i8 x))) + ;; Extract a constant `i32` from a value defined by an `iconst`. ;; The value is sign extended to 32 bits. (spec (i32_from_iconst arg) diff --git a/cranelift/filetests/filetests/isa/pulley64/band.clif b/cranelift/filetests/filetests/isa/pulley64/band.clif new file mode 100644 index 000000000000..8df24e14f741 --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley64/band.clif @@ -0,0 +1,182 @@ +test compile precise-output +target pulley64 + +function %i8_imm(i8) -> i8 { +block0(v0: i8): + v2 = band_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xband32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xband32_s8 x0, x0, 7 +; ret + +function %i8_imm2(i8) -> i8 { +block0(v0: i8): + v2 = band_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xband32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xband32_s8 x0, x0, -7 +; ret + +function %i16_imm(i16) -> i16 { +block0(v0: i16): + v2 = band_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xband32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xband32_s8 x0, x0, 7 +; ret + +function %i16_imm2(i16) -> i16 { +block0(v0: i16): + v2 = band_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xband32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xband32_s8 x0, x0, -7 +; ret + +function %i32_imm(i32) -> i32 { +block0(v0: i32): + v2 = band_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xband32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xband32_s8 x0, x0, 7 +; ret + +function %i32_imm2(i32) -> i32 { +block0(v0: i32): + v2 = band_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xband32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xband32_s8 x0, x0, -7 +; ret + +function %i32_imm_big(i32) -> i32 { +block0(v0: i32): + v2 = band_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xband32_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xband32_s32 x0, x0, 77777 +; ret + +function %i32_imm_big2(i32) -> i32 { +block0(v0: i32): + v2 = band_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xband32_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xband32_s32 x0, x0, -77777 +; ret + +function %i64_imm(i64) -> i64 { +block0(v0: i64): + v2 = band_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xband64_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xband64_s8 x0, x0, 7 +; ret + +function %i64_imm2(i64) -> i64 { +block0(v0: i64): + v2 = band_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xband64_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xband64_s8 x0, x0, -7 +; ret + +function %i64_imm_big(i64) -> i64 { +block0(v0: i64): + v2 = band_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xband64_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xband64_s32 x0, x0, 77777 +; ret + +function %i64_imm_big2(i64) -> i64 { +block0(v0: i64): + v2 = band_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xband64_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xband64_s32 x0, x0, -77777 +; ret diff --git a/cranelift/filetests/filetests/isa/pulley64/bor.clif b/cranelift/filetests/filetests/isa/pulley64/bor.clif new file mode 100644 index 000000000000..0db4011d9dc3 --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley64/bor.clif @@ -0,0 +1,182 @@ +test compile precise-output +target pulley64 + +function %i8_imm(i8) -> i8 { +block0(v0: i8): + v2 = bor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbor32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbor32_s8 x0, x0, 7 +; ret + +function %i8_imm2(i8) -> i8 { +block0(v0: i8): + v2 = bor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbor32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbor32_s8 x0, x0, -7 +; ret + +function %i16_imm(i16) -> i16 { +block0(v0: i16): + v2 = bor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbor32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbor32_s8 x0, x0, 7 +; ret + +function %i16_imm2(i16) -> i16 { +block0(v0: i16): + v2 = bor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbor32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbor32_s8 x0, x0, -7 +; ret + +function %i32_imm(i32) -> i32 { +block0(v0: i32): + v2 = bor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbor32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbor32_s8 x0, x0, 7 +; ret + +function %i32_imm2(i32) -> i32 { +block0(v0: i32): + v2 = bor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbor32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbor32_s8 x0, x0, -7 +; ret + +function %i32_imm_big(i32) -> i32 { +block0(v0: i32): + v2 = bor_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xbor32_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xbor32_s32 x0, x0, 77777 +; ret + +function %i32_imm_big2(i32) -> i32 { +block0(v0: i32): + v2 = bor_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xbor32_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xbor32_s32 x0, x0, -77777 +; ret + +function %i64_imm(i64) -> i64 { +block0(v0: i64): + v2 = bor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbor64_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbor64_s8 x0, x0, 7 +; ret + +function %i64_imm2(i64) -> i64 { +block0(v0: i64): + v2 = bor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbor64_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbor64_s8 x0, x0, -7 +; ret + +function %i64_imm_big(i64) -> i64 { +block0(v0: i64): + v2 = bor_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xbor64_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xbor64_s32 x0, x0, 77777 +; ret + +function %i64_imm_big2(i64) -> i64 { +block0(v0: i64): + v2 = bor_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xbor64_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xbor64_s32 x0, x0, -77777 +; ret diff --git a/cranelift/filetests/filetests/isa/pulley64/bxor.clif b/cranelift/filetests/filetests/isa/pulley64/bxor.clif new file mode 100644 index 000000000000..8981900ae671 --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley64/bxor.clif @@ -0,0 +1,182 @@ +test compile precise-output +target pulley64 + +function %i8_imm(i8) -> i8 { +block0(v0: i8): + v2 = bxor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbxor32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbxor32_s8 x0, x0, 7 +; ret + +function %i8_imm2(i8) -> i8 { +block0(v0: i8): + v2 = bxor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbxor32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbxor32_s8 x0, x0, -7 +; ret + +function %i16_imm(i16) -> i16 { +block0(v0: i16): + v2 = bxor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbxor32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbxor32_s8 x0, x0, 7 +; ret + +function %i16_imm2(i16) -> i16 { +block0(v0: i16): + v2 = bxor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbxor32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbxor32_s8 x0, x0, -7 +; ret + +function %i32_imm(i32) -> i32 { +block0(v0: i32): + v2 = bxor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbxor32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbxor32_s8 x0, x0, 7 +; ret + +function %i32_imm2(i32) -> i32 { +block0(v0: i32): + v2 = bxor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbxor32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbxor32_s8 x0, x0, -7 +; ret + +function %i32_imm_big(i32) -> i32 { +block0(v0: i32): + v2 = bxor_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xbxor32_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xbxor32_s32 x0, x0, 77777 +; ret + +function %i32_imm_big2(i32) -> i32 { +block0(v0: i32): + v2 = bxor_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xbxor32_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xbxor32_s32 x0, x0, -77777 +; ret + +function %i64_imm(i64) -> i64 { +block0(v0: i64): + v2 = bxor_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xbxor64_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xbxor64_s8 x0, x0, 7 +; ret + +function %i64_imm2(i64) -> i64 { +block0(v0: i64): + v2 = bxor_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xbxor64_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xbxor64_s8 x0, x0, -7 +; ret + +function %i64_imm_big(i64) -> i64 { +block0(v0: i64): + v2 = bxor_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xbxor64_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xbxor64_s32 x0, x0, 77777 +; ret + +function %i64_imm_big2(i64) -> i64 { +block0(v0: i64): + v2 = bxor_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xbxor64_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xbxor64_s32 x0, x0, -77777 +; ret diff --git a/cranelift/filetests/filetests/isa/pulley64/imul.clif b/cranelift/filetests/filetests/isa/pulley64/imul.clif new file mode 100644 index 000000000000..f63c8f84868e --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley64/imul.clif @@ -0,0 +1,183 @@ +test compile precise-output +target pulley64 + +function %i8_imm(i8) -> i8 { +block0(v0: i8): + v2 = imul_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xmul32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xmul32_s8 x0, x0, 7 +; ret + +function %i8_imm2(i8) -> i8 { +block0(v0: i8): + v2 = imul_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xmul32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xmul32_s8 x0, x0, -7 +; ret + +function %i16_imm(i16) -> i16 { +block0(v0: i16): + v2 = imul_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xmul32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xmul32_s8 x0, x0, 7 +; ret + +function %i16_imm2(i16) -> i16 { +block0(v0: i16): + v2 = imul_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xmul32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xmul32_s8 x0, x0, -7 +; ret + +function %i32_imm(i32) -> i32 { +block0(v0: i32): + v2 = imul_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xmul32_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xmul32_s8 x0, x0, 7 +; ret + +function %i32_imm2(i32) -> i32 { +block0(v0: i32): + v2 = imul_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xmul32_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xmul32_s8 x0, x0, -7 +; ret + +function %i32_imm_big(i32) -> i32 { +block0(v0: i32): + v2 = imul_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xmul32_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xmul32_s32 x0, x0, 77777 +; ret + +function %i32_imm_big2(i32) -> i32 { +block0(v0: i32): + v2 = imul_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xmul32_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xmul32_s32 x0, x0, -77777 +; ret + +function %i64_imm(i64) -> i64 { +block0(v0: i64): + v2 = imul_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xmul64_s8 x0, x0, 7 +; ret +; +; Disassembled: +; xmul64_s8 x0, x0, 7 +; ret + +function %i64_imm2(i64) -> i64 { +block0(v0: i64): + v2 = imul_imm v0, -7 + return v2 +} + +; VCode: +; block0: +; xmul64_s8 x0, x0, -7 +; ret +; +; Disassembled: +; xmul64_s8 x0, x0, -7 +; ret + +function %i64_imm_big(i64) -> i64 { +block0(v0: i64): + v2 = imul_imm v0, 77777 + return v2 +} + +; VCode: +; block0: +; xmul64_s32 x0, x0, 77777 +; ret +; +; Disassembled: +; xmul64_s32 x0, x0, 77777 +; ret + +function %i64_imm_big2(i64) -> i64 { +block0(v0: i64): + v2 = imul_imm v0, -77777 + return v2 +} + +; VCode: +; block0: +; xmul64_s32 x0, x0, -77777 +; ret +; +; Disassembled: +; xmul64_s32 x0, x0, -77777 +; ret + diff --git a/cranelift/filetests/filetests/isa/pulley64/shifts.clif b/cranelift/filetests/filetests/isa/pulley64/shifts.clif new file mode 100644 index 000000000000..d60f8c03de46 --- /dev/null +++ b/cranelift/filetests/filetests/isa/pulley64/shifts.clif @@ -0,0 +1,183 @@ +test compile precise-output +target pulley64 + +function %i32_imm(i32) -> i32 { +block0(v0: i32): + v2 = ishl_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xshl32_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshl32_u6 x0, x0, 7 +; ret + +function %i32_imm2(i32) -> i32 { +block0(v0: i32): + v2 = ishl_imm v0, 0x187 + return v2 +} + +; VCode: +; block0: +; xshl32_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshl32_u6 x0, x0, 7 +; ret + +function %i64_imm(i64) -> i64 { +block0(v0: i64): + v2 = ishl_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xshl64_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshl64_u6 x0, x0, 7 +; ret + +function %i64_imm2(i64) -> i64 { +block0(v0: i64): + v2 = ishl_imm v0, 0x187 + return v2 +} + +; VCode: +; block0: +; xshl64_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshl64_u6 x0, x0, 7 +; ret + +function %i32_ushr_imm(i32) -> i32 { +block0(v0: i32): + v2 = ushr_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xshr32_u_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr32_u_u6 x0, x0, 7 +; ret + +function %i32_ushr_imm2(i32) -> i32 { +block0(v0: i32): + v2 = ushr_imm v0, 0x187 + return v2 +} + +; VCode: +; block0: +; xshr32_u_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr32_u_u6 x0, x0, 7 +; ret + +function %i64_ushr_imm(i64) -> i64 { +block0(v0: i64): + v2 = ushr_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xshr64_u_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr64_u_u6 x0, x0, 7 +; ret + +function %i64_ushr_imm2(i64) -> i64 { +block0(v0: i64): + v2 = ushr_imm v0, 0x187 + return v2 +} + +; VCode: +; block0: +; xshr64_u_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr64_u_u6 x0, x0, 7 +; ret + +function %i32_sshr_imm(i32) -> i32 { +block0(v0: i32): + v2 = sshr_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xshr32_s_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr32_s_u6 x0, x0, 7 +; ret + +function %i32_sshr_imm2(i32) -> i32 { +block0(v0: i32): + v2 = sshr_imm v0, 0x187 + return v2 +} + +; VCode: +; block0: +; xshr32_s_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr32_s_u6 x0, x0, 7 +; ret + +function %i64_sshr_imm(i64) -> i64 { +block0(v0: i64): + v2 = sshr_imm v0, 7 + return v2 +} + +; VCode: +; block0: +; xshr64_s_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr64_s_u6 x0, x0, 7 +; ret + +function %i64_sshr_imm2(i64) -> i64 { +block0(v0: i64): + v2 = sshr_imm v0, 0x187 + return v2 +} + +; VCode: +; block0: +; xshr64_s_u6 x0, x0, 7 +; ret +; +; Disassembled: +; xshr64_s_u6 x0, x0, 7 +; ret + diff --git a/pulley/src/decode.rs b/pulley/src/decode.rs index d11fbe482d85..25bf25825eb4 100644 --- a/pulley/src/decode.rs +++ b/pulley/src/decode.rs @@ -431,6 +431,15 @@ impl Decode for BinaryOperands { } } +impl Decode for BinaryOperands { + fn decode(bytecode: &mut T) -> Result + where + T: BytecodeStream, + { + u16::decode(bytecode).map(|bits| Self::from_bits(bits)) + } +} + impl Decode for ScalarBitSet { fn decode(bytecode: &mut T) -> Result where diff --git a/pulley/src/disas.rs b/pulley/src/disas.rs index fedff6ea14be..acb185077109 100644 --- a/pulley/src/disas.rs +++ b/pulley/src/disas.rs @@ -193,6 +193,12 @@ impl Disas for PcRelOffset { } } +impl Disas for U6 { + fn disas(&self, _position: usize, disas: &mut String) { + write!(disas, "{}", u8::from(*self)).unwrap(); + } +} + fn disas_list(position: usize, disas: &mut String, iter: impl IntoIterator) { let mut iter = iter.into_iter(); let Some(first) = iter.next() else { return }; @@ -219,6 +225,20 @@ where } } +impl Disas for BinaryOperands +where + D: Reg + Disas, + S1: Reg + Disas, +{ + fn disas(&self, position: usize, disas: &mut String) { + self.dst.disas(position, disas); + write!(disas, ", ").unwrap(); + self.src1.disas(position, disas); + write!(disas, ", ").unwrap(); + self.src2.disas(position, disas); + } +} + impl Disas for RegSet { fn disas(&self, position: usize, disas: &mut String) { disas_list(position, disas, *self) diff --git a/pulley/src/encode.rs b/pulley/src/encode.rs index c1d7d2dab610..c3de9e17d281 100644 --- a/pulley/src/encode.rs +++ b/pulley/src/encode.rs @@ -180,6 +180,17 @@ impl Encode for BinaryOperands { } } +impl Encode for BinaryOperands { + const WIDTH: u8 = 2; + + fn encode(&self, sink: &mut E) + where + E: Extend, + { + self.to_bits().encode(sink); + } +} + impl Encode for RegSet { const WIDTH: u8 = 4; diff --git a/pulley/src/imms.rs b/pulley/src/imms.rs index cd331e2cd639..c7e2e3510654 100644 --- a/pulley/src/imms.rs +++ b/pulley/src/imms.rs @@ -1,5 +1,7 @@ //! Immediates. +use core::fmt; + /// A PC-relative offset. /// /// This is relative to the start of this offset's containing instruction. @@ -29,3 +31,39 @@ impl From for i32 { offset.0 } } + +/// A 6-byte unsigned integer. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct U6(u8); + +impl U6 { + /// Attempts to create a new `U6` from the provided byte + pub fn new(val: u8) -> Option { + if val << 2 >> 2 == val { + Some(U6(val)) + } else { + None + } + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for U6 { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let byte = u.arbitrary::()?; + Ok(U6(byte << 2 >> 2)) + } +} + +impl From for u8 { + #[inline] + fn from(val: U6) -> Self { + val.0 + } +} + +impl fmt::Display for U6 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + u8::from(*self).fmt(f) + } +} diff --git a/pulley/src/interp.rs b/pulley/src/interp.rs index 03a9367ba505..b87ad44a3eac 100644 --- a/pulley/src/interp.rs +++ b/pulley/src/interp.rs @@ -1312,6 +1312,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xmul32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xmul32_s32(dst, src1, src2.into()) + } + + fn xmul32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i32(); + self.state[dst].set_i32(a.wrapping_mul(src2)); + ControlFlow::Continue(()) + } + fn xmul64(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u64(); let b = self.state[operands.src2].get_u64(); @@ -1319,6 +1329,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xmul64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xmul64_s32(dst, src1, src2.into()) + } + + fn xmul64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i64(); + self.state[dst].set_i64(a.wrapping_mul(src2.into())); + ControlFlow::Continue(()) + } + fn xshl32(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u32(); let b = self.state[operands.src2].get_u32(); @@ -1361,6 +1381,48 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xshl32_u6(&mut self, operands: BinaryOperands) -> ControlFlow { + let a = self.state[operands.src1].get_u32(); + let b = u32::from(u8::from(operands.src2)); + self.state[operands.dst].set_u32(a.wrapping_shl(b)); + ControlFlow::Continue(()) + } + + fn xshr32_u_u6(&mut self, operands: BinaryOperands) -> ControlFlow { + let a = self.state[operands.src1].get_u32(); + let b = u32::from(u8::from(operands.src2)); + self.state[operands.dst].set_u32(a.wrapping_shr(b)); + ControlFlow::Continue(()) + } + + fn xshr32_s_u6(&mut self, operands: BinaryOperands) -> ControlFlow { + let a = self.state[operands.src1].get_i32(); + let b = u32::from(u8::from(operands.src2)); + self.state[operands.dst].set_i32(a.wrapping_shr(b)); + ControlFlow::Continue(()) + } + + fn xshl64_u6(&mut self, operands: BinaryOperands) -> ControlFlow { + let a = self.state[operands.src1].get_u64(); + let b = u32::from(u8::from(operands.src2)); + self.state[operands.dst].set_u64(a.wrapping_shl(b)); + ControlFlow::Continue(()) + } + + fn xshr64_u_u6(&mut self, operands: BinaryOperands) -> ControlFlow { + let a = self.state[operands.src1].get_u64(); + let b = u32::from(u8::from(operands.src2)); + self.state[operands.dst].set_u64(a.wrapping_shr(b)); + ControlFlow::Continue(()) + } + + fn xshr64_s_u6(&mut self, operands: BinaryOperands) -> ControlFlow { + let a = self.state[operands.src1].get_i64(); + let b = u32::from(u8::from(operands.src2)); + self.state[operands.dst].set_i64(a.wrapping_shr(b)); + ControlFlow::Continue(()) + } + fn xneg32(&mut self, dst: XReg, src: XReg) -> ControlFlow { let a = self.state[src].get_i32(); self.state[dst].set_i32(a.wrapping_neg()); @@ -1833,6 +1895,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xband32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xband32_s32(dst, src1, src2.into()) + } + + fn xband32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i32(); + self.state[dst].set_i32(a & src2); + ControlFlow::Continue(()) + } + fn xband64(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u64(); let b = self.state[operands.src2].get_u64(); @@ -1840,6 +1912,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xband64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xband64_s32(dst, src1, src2.into()) + } + + fn xband64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i64(); + self.state[dst].set_i64(a & i64::from(src2)); + ControlFlow::Continue(()) + } + fn xbor32(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u32(); let b = self.state[operands.src2].get_u32(); @@ -1847,6 +1929,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xbor32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xbor32_s32(dst, src1, src2.into()) + } + + fn xbor32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i32(); + self.state[dst].set_i32(a | src2); + ControlFlow::Continue(()) + } + fn xbor64(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u64(); let b = self.state[operands.src2].get_u64(); @@ -1854,6 +1946,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xbor64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xbor64_s32(dst, src1, src2.into()) + } + + fn xbor64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i64(); + self.state[dst].set_i64(a | i64::from(src2)); + ControlFlow::Continue(()) + } + fn xbxor32(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u32(); let b = self.state[operands.src2].get_u32(); @@ -1861,6 +1963,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xbxor32_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xbxor32_s32(dst, src1, src2.into()) + } + + fn xbxor32_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i32(); + self.state[dst].set_i32(a ^ src2); + ControlFlow::Continue(()) + } + fn xbxor64(&mut self, operands: BinaryOperands) -> ControlFlow { let a = self.state[operands.src1].get_u64(); let b = self.state[operands.src2].get_u64(); @@ -1868,6 +1980,16 @@ impl OpVisitor for Interpreter<'_> { ControlFlow::Continue(()) } + fn xbxor64_s8(&mut self, dst: XReg, src1: XReg, src2: i8) -> ControlFlow { + self.xbxor64_s32(dst, src1, src2.into()) + } + + fn xbxor64_s32(&mut self, dst: XReg, src1: XReg, src2: i32) -> ControlFlow { + let a = self.state[src1].get_i64(); + self.state[dst].set_i64(a ^ i64::from(src2)); + ControlFlow::Continue(()) + } + fn xbnot32(&mut self, dst: XReg, src: XReg) -> ControlFlow { let a = self.state[src].get_u32(); self.state[dst].set_u32(!a); diff --git a/pulley/src/lib.rs b/pulley/src/lib.rs index aaccb54d6c00..37fb02c78ddf 100644 --- a/pulley/src/lib.rs +++ b/pulley/src/lib.rs @@ -192,9 +192,17 @@ macro_rules! for_each_op { /// `low32(dst) = low32(src1) * low32(src2)` xmul32 = XMul32 { operands: BinaryOperands }; + /// Same as `xmul64` but `src2` is a sign-extended 8-bit immediate. + xmul32_s8 = Xmul32S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xmul32` but `src2` is a sign-extended 32-bit immediate. + xmul32_s32 = Xmul32S32 { dst: XReg, src1: XReg, src2: i32 }; /// `dst = src1 * src2` xmul64 = XMul64 { operands: BinaryOperands }; + /// Same as `xmul64` but `src2` is a sign-extended 8-bit immediate. + xmul64_s8 = Xmul64S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xmul64` but `src2` is a sign-extended 64-bit immediate. + xmul64_s32 = Xmul64S32 { dst: XReg, src1: XReg, src2: i32 }; /// `low32(dst) = trailing_zeros(low32(src))` xctz32 = Xctz32 { dst: XReg, src: XReg }; @@ -234,6 +242,19 @@ macro_rules! for_each_op { /// `dst = src1 >> low6(src2)` xshr64_u = Xshr64U { operands: BinaryOperands }; + /// `low32(dst) = low32(src1) << low5(src2)` + xshl32_u6 = Xshl32U6 { operands: BinaryOperands }; + /// `low32(dst) = low32(src1) >> low5(src2)` + xshr32_s_u6 = Xshr32SU6 { operands: BinaryOperands }; + /// `low32(dst) = low32(src1) >> low5(src2)` + xshr32_u_u6 = Xshr32UU6 { operands: BinaryOperands }; + /// `dst = src1 << low5(src2)` + xshl64_u6 = Xshl64U6 { operands: BinaryOperands }; + /// `dst = src1 >> low6(src2)` + xshr64_s_u6 = Xshr64SU6 { operands: BinaryOperands }; + /// `dst = src1 >> low6(src2)` + xshr64_u_u6 = Xshr64UU6 { operands: BinaryOperands }; + /// `low32(dst) = -low32(src)` xneg32 = Xneg32 { dst: XReg, src: XReg }; /// `dst = -src` @@ -389,17 +410,41 @@ macro_rules! for_each_op { /// `low32(dst) = low32(src1) & low32(src2)` xband32 = XBand32 { operands: BinaryOperands }; + /// Same as `xband64` but `src2` is a sign-extended 8-bit immediate. + xband32_s8 = Xband32S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xband32` but `src2` is a sign-extended 32-bit immediate. + xband32_s32 = Xband32S32 { dst: XReg, src1: XReg, src2: i32 }; /// `dst = src1 & src2` xband64 = XBand64 { operands: BinaryOperands }; + /// Same as `xband64` but `src2` is a sign-extended 8-bit immediate. + xband64_s8 = Xband64S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xband64` but `src2` is a sign-extended 32-bit immediate. + xband64_s32 = Xband64S32 { dst: XReg, src1: XReg, src2: i32 }; /// `low32(dst) = low32(src1) | low32(src2)` xbor32 = XBor32 { operands: BinaryOperands }; + /// Same as `xbor64` but `src2` is a sign-extended 8-bit immediate. + xbor32_s8 = Xbor32S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xbor32` but `src2` is a sign-extended 32-bit immediate. + xbor32_s32 = Xbor32S32 { dst: XReg, src1: XReg, src2: i32 }; /// `dst = src1 | src2` xbor64 = XBor64 { operands: BinaryOperands }; + /// Same as `xbor64` but `src2` is a sign-extended 8-bit immediate. + xbor64_s8 = Xbor64S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xbor64` but `src2` is a sign-extended 32-bit immediate. + xbor64_s32 = Xbor64S32 { dst: XReg, src1: XReg, src2: i32 }; /// `low32(dst) = low32(src1) ^ low32(src2)` xbxor32 = XBxor32 { operands: BinaryOperands }; + /// Same as `xbxor64` but `src2` is a sign-extended 8-bit immediate. + xbxor32_s8 = Xbxor32S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xbxor32` but `src2` is a sign-extended 32-bit immediate. + xbxor32_s32 = Xbxor32S32 { dst: XReg, src1: XReg, src2: i32 }; /// `dst = src1 ^ src2` xbxor64 = XBxor64 { operands: BinaryOperands }; + /// Same as `xbxor64` but `src2` is a sign-extended 8-bit immediate. + xbxor64_s8 = Xbxor64S8 { dst: XReg, src1: XReg, src2: i8 }; + /// Same as `xbxor64` but `src2` is a sign-extended 32-bit immediate. + xbxor64_s32 = Xbxor64S32 { dst: XReg, src1: XReg, src2: i32 }; /// `low32(dst) = !low32(src1)` xbnot32 = XBnot32 { dst: XReg, src: XReg }; diff --git a/pulley/src/regs.rs b/pulley/src/regs.rs index 00262bf233ff..72e4bbf2129e 100644 --- a/pulley/src/regs.rs +++ b/pulley/src/regs.rs @@ -1,5 +1,6 @@ //! Pulley registers. +use crate::U6; use core::hash::Hash; use core::marker::PhantomData; use core::{fmt, ops::Range}; @@ -173,7 +174,7 @@ pub struct BinaryOperands { pub src2: S2, } -impl BinaryOperands { +impl BinaryOperands { /// Convenience constructor for applying `Into` pub fn new(dst: impl Into, src1: impl Into, src2: impl Into) -> Self { Self { @@ -182,7 +183,9 @@ impl BinaryOperands { src2: src2.into(), } } +} +impl BinaryOperands { /// Convert to dense 16 bit encoding. pub fn to_bits(self) -> u16 { let dst = self.dst.to_u8(); @@ -201,6 +204,25 @@ impl BinaryOperands { } } +impl BinaryOperands { + /// Convert to dense 16 bit encoding. + pub fn to_bits(self) -> u16 { + let dst = self.dst.to_u8(); + let src1 = self.src1.to_u8(); + let src2 = u8::from(self.src2); + (dst as u16) | ((src1 as u16) << 5) | ((src2 as u16) << 10) + } + + /// Convert from dense 16 bit encoding. The topmost bit is ignored. + pub fn from_bits(bits: u16) -> Self { + Self { + dst: D::new((bits & 0b11111) as u8).unwrap(), + src1: S1::new(((bits >> 5) & 0b11111) as u8).unwrap(), + src2: U6::new(((bits >> 10) & 0b111111) as u8).unwrap(), + } + } +} + /// A set of registers, packed into a 32-bit bitset. pub struct RegSet { bitset: ScalarBitSet, @@ -321,8 +343,8 @@ mod tests { src2: XReg::new(src2).unwrap(), }; assert_eq!(operands.to_bits(), i); - assert_eq!(BinaryOperands::from_bits(i), operands); - assert_eq!(BinaryOperands::from_bits(0x8000 | i), operands); + assert_eq!(BinaryOperands::::from_bits(i), operands); + assert_eq!(BinaryOperands::::from_bits(0x8000 | i), operands); i += 1; } }