Fix simd_cast

This commit is contained in:
bjorn3 2019-07-31 09:45:11 +02:00
parent aa803f4fa6
commit b806070a88
6 changed files with 130 additions and 86 deletions

View file

@ -68,6 +68,7 @@ unsafe fn test_simd() {
test_mm256_movemask_epi8();
test_mm_add_epi8();
test_mm_add_pd();
test_mm_cvtepi8_epi16();
let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
assert_eq!(mask1, 1);
@ -170,6 +171,18 @@ pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
}
}
#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_cvtepi8_epi16() {
let a = _mm_set1_epi8(10);
let r = _mm_cvtepi8_epi16(a);
let e = _mm_set1_epi16(10);
assert_eq_m128i(r, e);
let a = _mm_set1_epi8(-10);
let r = _mm_cvtepi8_epi16(a);
let e = _mm_set1_epi16(-10);
assert_eq_m128i(r, e);
}
#[derive(PartialEq)]
enum LoopState {
Continue(()),

View file

@ -436,7 +436,6 @@ fn trans_stmt<'a, 'tcx: 'a>(
let discr = trans_get_discriminant(fx, place, fx.layout_of(to_ty));
lval.write_cvalue(fx, discr);
} else {
let from_clif_ty = fx.clif_type(from_ty).unwrap();
let to_clif_ty = fx.clif_type(to_ty).unwrap();
let from = operand.load_scalar(fx);
@ -447,43 +446,7 @@ fn trans_stmt<'a, 'tcx: 'a>(
_ => panic!("{}", from_ty),
};
let res = if from_clif_ty.is_int() && to_clif_ty.is_int() {
// int-like -> int-like
crate::common::clif_intcast(
fx,
from,
to_clif_ty,
signed,
)
} else if from_clif_ty.is_int() && to_clif_ty.is_float() {
// int-like -> float
if signed {
fx.bcx.ins().fcvt_from_sint(to_clif_ty, from)
} else {
fx.bcx.ins().fcvt_from_uint(to_clif_ty, from)
}
} else if from_clif_ty.is_float() && to_clif_ty.is_int() {
// float -> int-like
let from = operand.load_scalar(fx);
if signed {
fx.bcx.ins().fcvt_to_sint_sat(to_clif_ty, from)
} else {
fx.bcx.ins().fcvt_to_uint_sat(to_clif_ty, from)
}
} else if from_clif_ty.is_float() && to_clif_ty.is_float() {
// float -> float
match (from_clif_ty, to_clif_ty) {
(types::F32, types::F64) => {
fx.bcx.ins().fpromote(types::F64, from)
}
(types::F64, types::F32) => {
fx.bcx.ins().fdemote(types::F32, from)
}
_ => from,
}
} else {
unimpl!("rval misc {:?} {:?}", from_ty, to_ty)
};
let res = clif_int_or_float_cast(fx, from, to_clif_ty, signed);
lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
}
}

93
src/cast.rs Normal file
View file

@ -0,0 +1,93 @@
use crate::prelude::*;
pub fn clif_intcast<'a, 'tcx: 'a>(
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
val: Value,
to: Type,
signed: bool,
) -> Value {
let from = fx.bcx.func.dfg.value_type(val);
match (from, to) {
// equal
(_, _) if from == to => val,
// extend
(_, types::I128) => {
let wider = if from == types::I64 {
val
} else if signed {
fx.bcx.ins().sextend(types::I64, val)
} else {
fx.bcx.ins().uextend(types::I64, val)
};
let zero = fx.bcx.ins().iconst(types::I64, 0);
fx.bcx.ins().iconcat(wider, zero)
}
(_, _) if to.wider_or_equal(from) => {
if signed {
fx.bcx.ins().sextend(to, val)
} else {
fx.bcx.ins().uextend(to, val)
}
}
// reduce
(types::I128, _) => {
let (lsb, _msb) = fx.bcx.ins().isplit(val);
if to == types::I64 {
lsb
} else {
fx.bcx.ins().ireduce(to, lsb)
}
}
(_, _) => {
fx.bcx.ins().ireduce(to, val)
}
}
}
pub fn clif_int_or_float_cast(
fx: &mut FunctionCx<'_, '_, impl Backend>,
from: Value,
to_ty: Type,
signed: bool,
) -> Value {
let from_ty = fx.bcx.func.dfg.value_type(from);
if from_ty.is_int() && to_ty.is_int() {
// int-like -> int-like
clif_intcast(
fx,
from,
to_ty,
signed,
)
} else if from_ty.is_int() && to_ty.is_float() {
// int-like -> float
if signed {
fx.bcx.ins().fcvt_from_sint(to_ty, from)
} else {
fx.bcx.ins().fcvt_from_uint(to_ty, from)
}
} else if from_ty.is_float() && to_ty.is_int() {
// float -> int-like
if signed {
fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
} else {
fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
}
} else if from_ty.is_float() && to_ty.is_float() {
// float -> float
match (from_ty, to_ty) {
(types::F32, types::F64) => {
fx.bcx.ins().fpromote(types::F64, from)
}
(types::F64, types::F32) => {
fx.bcx.ins().fdemote(types::F32, from)
}
_ => from,
}
} else {
unreachable!("cast value from {:?} to {:?}", from_ty, to_ty);
}
}

View file

@ -73,52 +73,6 @@ pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: V
}
}
pub fn clif_intcast<'a, 'tcx: 'a>(
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
val: Value,
to: Type,
signed: bool,
) -> Value {
let from = fx.bcx.func.dfg.value_type(val);
match (from, to) {
// equal
(_, _) if from == to => val,
// extend
(_, types::I128) => {
let wider = if from == types::I64 {
val
} else if signed {
fx.bcx.ins().sextend(types::I64, val)
} else {
fx.bcx.ins().uextend(types::I64, val)
};
let zero = fx.bcx.ins().iconst(types::I64, 0);
fx.bcx.ins().iconcat(wider, zero)
}
(_, _) if to.wider_or_equal(from) => {
if signed {
fx.bcx.ins().sextend(to, val)
} else {
fx.bcx.ins().uextend(to, val)
}
}
// reduce
(types::I128, _) => {
let (lsb, _msb) = fx.bcx.ins().isplit(val);
if to == types::I64 {
lsb
} else {
fx.bcx.ins().ireduce(to, lsb)
}
}
(_, _) => {
fx.bcx.ins().ireduce(to, val)
}
}
}
fn resolve_normal_value_imm(func: &Function, val: Value) -> Option<i64> {
if let ValueDef::Result(inst, 0 /*param*/) = func.dfg.value_def(val) {
if let InstructionData::UnaryImm {

View file

@ -853,8 +853,27 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
ret.write_cvalue(fx, val);
};
simd_cast, (c x) {
ret.write_cvalue(fx, x.unchecked_cast_to(ret.layout()));
simd_cast, (c a) {
let (lane_layout, lane_count) = lane_type_and_count(fx, a.layout(), intrinsic);
let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx, ret.layout(), intrinsic);
assert_eq!(lane_count, ret_lane_count);
let ret_lane_ty = fx.clif_type(ret_lane_layout.ty).unwrap();
let signed = match lane_layout.ty.sty {
ty::Uint(..) => false,
ty::Int(..) => true,
ty::Float(..) => false, // `signed` is unused for floats
_ => panic!("{}", lane_layout.ty),
};
for lane in 0..lane_count {
let lane = mir::Field::new(lane.try_into().unwrap());
let a_lane = a.value_field(fx, lane).load_scalar(fx);
let res = clif_int_or_float_cast(fx, a_lane, ret_lane_ty, signed);
ret.place_field(fx, lane).write_cvalue(fx, CValue::by_val(res, ret_lane_layout));
}
};
simd_eq, (c x, c y) {

View file

@ -33,6 +33,7 @@ mod allocator;
mod analyze;
mod archive;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
@ -94,6 +95,7 @@ mod prelude {
pub use crate::abi::*;
pub use crate::base::{trans_operand, trans_place};
pub use crate::cast::*;
pub use crate::common::*;
pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
pub use crate::trap::*;