Add raw_bitcast instruction
Casts bits as a different type of the same width with no change to the data (unlike bitcast)
This commit is contained in:
@@ -9,7 +9,6 @@ use crate::cdsl::instructions::{
|
|||||||
};
|
};
|
||||||
use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes};
|
use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes};
|
||||||
use crate::cdsl::settings::{SettingGroup, SettingPredicateNumber};
|
use crate::cdsl::settings::{SettingGroup, SettingPredicateNumber};
|
||||||
|
|
||||||
use crate::cdsl::types::ValueType;
|
use crate::cdsl::types::ValueType;
|
||||||
use crate::shared::types::Bool::{B1, B16, B32, B64, B8};
|
use crate::shared::types::Bool::{B1, B16, B32, B64, B8};
|
||||||
use crate::shared::types::Float::{F32, F64};
|
use crate::shared::types::Float::{F32, F64};
|
||||||
@@ -333,6 +332,7 @@ pub fn define(
|
|||||||
let load_complex = shared.by_name("load_complex");
|
let load_complex = shared.by_name("load_complex");
|
||||||
let nearest = shared.by_name("nearest");
|
let nearest = shared.by_name("nearest");
|
||||||
let popcnt = shared.by_name("popcnt");
|
let popcnt = shared.by_name("popcnt");
|
||||||
|
let raw_bitcast = shared.by_name("raw_bitcast");
|
||||||
let regfill = shared.by_name("regfill");
|
let regfill = shared.by_name("regfill");
|
||||||
let regmove = shared.by_name("regmove");
|
let regmove = shared.by_name("regmove");
|
||||||
let regspill = shared.by_name("regspill");
|
let regspill = shared.by_name("regspill");
|
||||||
@@ -452,6 +452,7 @@ pub fn define(
|
|||||||
let rec_ldWithIndexDisp8 = r.template("ldWithIndexDisp8");
|
let rec_ldWithIndexDisp8 = r.template("ldWithIndexDisp8");
|
||||||
let rec_mulx = r.template("mulx");
|
let rec_mulx = r.template("mulx");
|
||||||
let rec_null = r.recipe("null");
|
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_fnaddr8 = r.template("pcrel_fnaddr8");
|
||||||
let rec_pcrel_gvaddr8 = r.template("pcrel_gvaddr8");
|
let rec_pcrel_gvaddr8 = r.template("pcrel_gvaddr8");
|
||||||
let rec_popq = r.template("popq");
|
let rec_popq = r.template("popq");
|
||||||
@@ -1588,5 +1589,17 @@ pub fn define(
|
|||||||
e.enc_x86_64_isap(instruction, template, use_sse2);
|
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
|
e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,6 +411,12 @@ pub fn define<'shared>(
|
|||||||
.operands_out(vec![0])
|
.operands_out(vec![0])
|
||||||
.emit(""),
|
.emit(""),
|
||||||
);
|
);
|
||||||
|
recipes.add_recipe(
|
||||||
|
EncodingRecipeBuilder::new("null_fpr", f_unary, 0)
|
||||||
|
.operands_in(vec![fpr])
|
||||||
|
.operands_out(vec![0])
|
||||||
|
.emit(""),
|
||||||
|
);
|
||||||
recipes.add_recipe(
|
recipes.add_recipe(
|
||||||
EncodingRecipeBuilder::new("stacknull", f_unary, 0)
|
EncodingRecipeBuilder::new("stacknull", f_unary, 0)
|
||||||
.operands_in(vec![stack_gpr32])
|
.operands_in(vec![stack_gpr32])
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ pub fn define(
|
|||||||
.build(),
|
.build(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let AnyTo = &TypeVar::copy_from(Any, "AnyTo".to_string());
|
||||||
|
|
||||||
let Mem = &TypeVar::new(
|
let Mem = &TypeVar::new(
|
||||||
"Mem",
|
"Mem",
|
||||||
"Any type that can be stored in memory",
|
"Any type that can be stored in memory",
|
||||||
@@ -138,15 +140,7 @@ pub fn define(
|
|||||||
.build(),
|
.build(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let MemTo = &TypeVar::new(
|
let MemTo = &TypeVar::copy_from(Mem, "MemTo".to_string());
|
||||||
"MemTo",
|
|
||||||
"Any type that can be stored in memory",
|
|
||||||
TypeSetBuilder::new()
|
|
||||||
.ints(Interval::All)
|
|
||||||
.floats(Interval::All)
|
|
||||||
.simd_lanes(Interval::All)
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let addr = &operand("addr", iAddr);
|
let addr = &operand("addr", iAddr);
|
||||||
let c = &operand_doc("c", Testable, "Controlling value to test");
|
let c = &operand_doc("c", Testable, "Controlling value to test");
|
||||||
@@ -2640,6 +2634,28 @@ pub fn define(
|
|||||||
.operands_out(vec![a]),
|
.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 s = &operand_doc("s", Scalar, "A scalar value");
|
||||||
let a = &operand_doc("a", TxN, "A vector value (i.e. held in an XMM register)");
|
let a = &operand_doc("a", TxN, "A vector value (i.e. held in an XMM register)");
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ impl OperandKinds {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Vec<OperandKind>> for OperandKinds {
|
||||||
|
fn from(kinds: Vec<OperandKind>) -> Self {
|
||||||
|
OperandKinds(kinds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn define() -> Definitions {
|
pub fn define() -> Definitions {
|
||||||
let mut all_instructions = AllInstructions::new();
|
let mut all_instructions = AllInstructions::new();
|
||||||
|
|
||||||
|
|||||||
10
cranelift/filetests/filetests/isa/x86/raw_bitcast.clif
Normal file
10
cranelift/filetests/filetests/isa/x86/raw_bitcast.clif
Normal file
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user