diff --git a/cranelift/codegen/meta/src/isa/x86/encodings.rs b/cranelift/codegen/meta/src/isa/x86/encodings.rs index 506abdc53c..c34c13d089 100644 --- a/cranelift/codegen/meta/src/isa/x86/encodings.rs +++ b/cranelift/codegen/meta/src/isa/x86/encodings.rs @@ -9,7 +9,6 @@ use crate::cdsl::instructions::{ }; use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes}; use crate::cdsl::settings::{SettingGroup, SettingPredicateNumber}; - use crate::cdsl::types::ValueType; use crate::shared::types::Bool::{B1, B16, B32, B64, B8}; use crate::shared::types::Float::{F32, F64}; @@ -333,6 +332,7 @@ pub fn define( let load_complex = shared.by_name("load_complex"); let nearest = shared.by_name("nearest"); let popcnt = shared.by_name("popcnt"); + let raw_bitcast = shared.by_name("raw_bitcast"); let regfill = shared.by_name("regfill"); let regmove = shared.by_name("regmove"); let regspill = shared.by_name("regspill"); @@ -452,6 +452,7 @@ pub fn define( let rec_ldWithIndexDisp8 = r.template("ldWithIndexDisp8"); let rec_mulx = r.template("mulx"); let rec_null = r.recipe("null"); + let rec_null_fpr = r.recipe("null_fpr"); let rec_pcrel_fnaddr8 = r.template("pcrel_fnaddr8"); let rec_pcrel_gvaddr8 = r.template("pcrel_gvaddr8"); let rec_popq = r.template("popq"); @@ -1588,5 +1589,17 @@ pub fn define( e.enc_x86_64_isap(instruction, template, use_sse2); } + // SIMD bitcast all 128-bit vectors to each other (for legalizing splat.x16x8) + for from_type in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8) { + for to_type in ValueType::all_lane_types().filter(|t| t.lane_bits() >= 8 && *t != from_type) + { + let instruction = raw_bitcast + .bind_vector(to_type, 128 / to_type.lane_bits()) + .bind_vector(from_type, 128 / from_type.lane_bits()); + e.enc32_rec(instruction.clone(), rec_null_fpr, 0); + e.enc64_rec(instruction, rec_null_fpr, 0); + } + } + e } diff --git a/cranelift/codegen/meta/src/isa/x86/recipes.rs b/cranelift/codegen/meta/src/isa/x86/recipes.rs index 5c1d28ef20..45441cf67a 100644 --- a/cranelift/codegen/meta/src/isa/x86/recipes.rs +++ b/cranelift/codegen/meta/src/isa/x86/recipes.rs @@ -411,6 +411,12 @@ pub fn define<'shared>( .operands_out(vec![0]) .emit(""), ); + recipes.add_recipe( + EncodingRecipeBuilder::new("null_fpr", f_unary, 0) + .operands_in(vec![fpr]) + .operands_out(vec![0]) + .emit(""), + ); recipes.add_recipe( EncodingRecipeBuilder::new("stacknull", f_unary, 0) .operands_in(vec![stack_gpr32]) diff --git a/cranelift/codegen/meta/src/shared/instructions.rs b/cranelift/codegen/meta/src/shared/instructions.rs index 7af098f920..78d017f1a8 100644 --- a/cranelift/codegen/meta/src/shared/instructions.rs +++ b/cranelift/codegen/meta/src/shared/instructions.rs @@ -128,6 +128,8 @@ pub fn define( .build(), ); + let AnyTo = &TypeVar::copy_from(Any, "AnyTo".to_string()); + let Mem = &TypeVar::new( "Mem", "Any type that can be stored in memory", @@ -138,15 +140,7 @@ pub fn define( .build(), ); - let MemTo = &TypeVar::new( - "MemTo", - "Any type that can be stored in memory", - TypeSetBuilder::new() - .ints(Interval::All) - .floats(Interval::All) - .simd_lanes(Interval::All) - .build(), - ); + let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string()); let addr = &operand("addr", iAddr); let c = &operand_doc("c", Testable, "Controlling value to test"); @@ -2640,6 +2634,28 @@ pub fn define( .operands_out(vec![a]), ); + let x = &operand("x", Any); + let a = &operand_doc("a", AnyTo, "Bits of `x` reinterpreted"); + + ig.push( + Inst::new( + "raw_bitcast", + r#" + Cast the bits in `x` as a different type of the same bit width. + + This instruction does not change the data's representation but allows + data in registers to be used as different types, e.g. an i32x4 as a + b8x16. The only constraint on the result `a` is that it can be + `raw_bitcast` back to the original type. Also, in a raw_bitcast between + vector types with the same number of lanes, the value of each result + lane is a raw_bitcast of the corresponding operand lane. TODO there is + currently no mechanism for enforcing the bit width constraint. + "#, + ) + .operands_in(vec![x]) + .operands_out(vec![a]), + ); + let s = &operand_doc("s", Scalar, "A scalar value"); let a = &operand_doc("a", TxN, "A vector value (i.e. held in an XMM register)"); diff --git a/cranelift/codegen/meta/src/shared/mod.rs b/cranelift/codegen/meta/src/shared/mod.rs index 817f67c340..ba1425b844 100644 --- a/cranelift/codegen/meta/src/shared/mod.rs +++ b/cranelift/codegen/meta/src/shared/mod.rs @@ -50,6 +50,12 @@ impl OperandKinds { } } +impl From> for OperandKinds { + fn from(kinds: Vec) -> Self { + OperandKinds(kinds) + } +} + pub fn define() -> Definitions { let mut all_instructions = AllInstructions::new(); diff --git a/cranelift/filetests/filetests/isa/x86/raw_bitcast.clif b/cranelift/filetests/filetests/isa/x86/raw_bitcast.clif new file mode 100644 index 0000000000..5c1c2ea322 --- /dev/null +++ b/cranelift/filetests/filetests/isa/x86/raw_bitcast.clif @@ -0,0 +1,10 @@ +test binemit +target x86_64 + +function %test_raw_bitcast_i16x8_to_b32x4() { +ebb0: +[-, %rbx] v0 = bconst.b16 true +[-, %xmm2] v1 = scalar_to_vector.b16x8 v0 +[-, %xmm2] v2 = raw_bitcast.i32x4 v1 ; bin: + return +}