-
Notifications
You must be signed in to change notification settings - Fork 107
/
Copy pathsimd.rs
164 lines (142 loc) · 6.24 KB
/
simd.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use crate::prelude::*;
use super::*;
pub fn codegen_simd_intrinsic_call<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
instance: Instance<'tcx>,
args: &[mir::Operand<'tcx>],
ret: CPlace<'tcx>,
span: Span,
) {
let def_id = instance.def_id();
let substs = instance.substs;
let intrinsic = fx.tcx.item_name(def_id).as_str();
let intrinsic = &intrinsic[..];
intrinsic_match! {
fx, intrinsic, substs, args,
_ => {
fx.tcx.sess.fatal(&format!("Unknown SIMD intrinsic {}", intrinsic));
};
simd_cast, (c a) {
simd_for_each_lane(fx, intrinsic, a, ret, |fx, lane_layout, ret_lane_layout, lane| {
let ret_lane_ty = fx.clif_type(ret_lane_layout.ty).unwrap();
let from_signed = type_sign(lane_layout.ty);
let to_signed = type_sign(ret_lane_layout.ty);
let ret_lane = clif_int_or_float_cast(fx, lane, from_signed, ret_lane_ty, to_signed);
CValue::by_val(ret_lane, ret_lane_layout)
});
};
simd_eq, (c x, c y) {
simd_cmp!(fx, intrinsic, Equal(x, y) -> ret);
};
simd_ne, (c x, c y) {
simd_cmp!(fx, intrinsic, NotEqual(x, y) -> ret);
};
simd_lt, (c x, c y) {
simd_cmp!(fx, intrinsic, UnsignedLessThan|SignedLessThan(x, y) -> ret);
};
simd_le, (c x, c y) {
simd_cmp!(fx, intrinsic, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret);
};
simd_gt, (c x, c y) {
simd_cmp!(fx, intrinsic, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret);
};
simd_ge, (c x, c y) {
simd_cmp!(fx, intrinsic, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret);
};
// simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
_ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
let n: u32 = intrinsic["simd_shuffle".len()..].parse().unwrap();
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
assert_eq!(lane_type, ret_lane_type);
assert_eq!(n, ret_lane_count);
let total_len = lane_count * 2;
let indexes = {
use rustc::mir::interpret::*;
let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");
let idx_bytes = match idx_const.val {
ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => {
let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */);
alloc.get_bytes(fx, ptr, size).unwrap()
}
_ => unreachable!("{:?}", idx_const),
};
(0..ret_lane_count).map(|i| {
let i = usize::try_from(i).unwrap();
let idx = rustc::mir::interpret::read_target_uint(
fx.tcx.data_layout.endian,
&idx_bytes[4*i.. 4*i + 4],
).expect("read_target_uint");
u32::try_from(idx).expect("try_from u32")
}).collect::<Vec<u32>>()
};
for &idx in &indexes {
assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
}
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
let in_lane = if in_idx < lane_count {
x.value_field(fx, mir::Field::new(in_idx.try_into().unwrap()))
} else {
y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap()))
};
let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
out_lane.write_cvalue(fx, in_lane);
}
};
simd_extract, (c v, o idx) {
let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
idx_const
} else {
fx.tcx.sess.span_warn(
fx.mir.span,
"`#[rustc_arg_required_const(..)]` is not yet supported. Calling this function will panic.",
);
crate::trap::trap_panic(fx, "`#[rustc_arg_required_const(..)]` is not yet supported.");
return;
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
}
let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
ret.write_cvalue(fx, ret_lane);
};
simd_add, (c x, c y) {
simd_int_flt_binop!(fx, iadd|fadd(x, y) -> ret);
};
simd_sub, (c x, c y) {
simd_int_flt_binop!(fx, isub|fsub(x, y) -> ret);
};
simd_mul, (c x, c y) {
simd_int_flt_binop!(fx, imul|fmul(x, y) -> ret);
};
simd_div, (c x, c y) {
simd_int_flt_binop!(fx, udiv|sdiv|fdiv(x, y) -> ret);
};
simd_shl, (c x, c y) {
simd_int_binop!(fx, ishl(x, y) -> ret);
};
simd_shr, (c x, c y) {
simd_int_binop!(fx, ushr|sshr(x, y) -> ret);
};
simd_and, (c x, c y) {
simd_int_binop!(fx, band(x, y) -> ret);
};
simd_or, (c x, c y) {
simd_int_binop!(fx, bor(x, y) -> ret);
};
simd_xor, (c x, c y) {
simd_int_binop!(fx, bxor(x, y) -> ret);
};
simd_fmin, (c x, c y) {
simd_flt_binop!(fx, fmin(x, y) -> ret);
};
simd_fmax, (c x, c y) {
simd_flt_binop!(fx, fmax(x, y) -> ret);
};
}
}