6
6
#![ allow( non_camel_case_types) ]
7
7
8
8
/// A single unconstrained byte (0-255).
9
- #[ derive( Copy , Clone , Debug ) ]
10
- pub struct ImmByte ( u8 ) ;
11
- impl ImmByte {
12
- /// Constructor
13
- #[ inline]
14
- #[ rustc_args_required_const( 0 ) ]
15
- pub const fn new ( value : u8 ) -> Self {
16
- ImmByte ( value)
17
- }
18
- }
19
-
20
- macro_rules! impl_laneidx {
21
- ( $id: ident( $ty: ty) : [ $_from: expr, $_to: expr] | $( #[ $doc: meta] ) * ) => {
22
- #[ derive( Copy , Clone , Debug ) ]
23
- pub struct $id( $ty) ;
24
- impl $id {
25
- #[ inline]
26
- #[ rustc_args_required_const( 0 ) ]
27
- pub const fn new( x: $ty) -> Self {
28
- // FIXME: not allowed in const fn:
29
- // * if statements
30
- // * unreachable_unchecked / panic / abort
31
- //
32
- // if x < $from || x > $to {
33
- // unsafe { ::_core::hint::unreachable_unchecked() };
34
- // debug_assert!(...)
35
- // }
36
- $id( x)
37
- }
38
- }
39
- } ;
40
- }
41
- impl_laneidx ! ( LaneIdx2 ( u8 ) : [ 0 , 1 ] | /// A byte with values in the range 0–1 identifying a lane.
42
- ) ;
43
- impl_laneidx ! ( LaneIdx4 ( u8 ) : [ 0 , 3 ] | /// A byte with values in the range 0–3 identifying a lane.
44
- ) ;
45
- impl_laneidx ! ( LaneIdx8 ( u8 ) : [ 0 , 7 ] | /// A byte with values in the range 0–7 identifying a lane.
46
- ) ;
47
- impl_laneidx ! ( LaneIdx16 ( u8 ) : [ 0 , 15 ] | /// A byte with values in the range 0–15 identifying a lane.
48
- ) ;
49
- impl_laneidx ! ( LaneIdx32 ( u8 ) : [ 0 , 31 ] | /// A byte with values in the range 0–31 identifying a lane.
50
- ) ;
9
+ pub type ImmByte = u8 ;
10
+ /// A byte with values in the range 0–1 identifying a lane.
11
+ pub type LaneIdx2 = u8 ;
12
+ /// A byte with values in the range 0–3 identifying a lane.
13
+ pub type LaneIdx4 = u8 ;
14
+ /// A byte with values in the range 0–7 identifying a lane.
15
+ pub type LaneIdx8 = u8 ;
16
+ /// A byte with values in the range 0–15 identifying a lane.
17
+ pub type LaneIdx16 = u8 ;
18
+ /// A byte with values in the range 0–31 identifying a lane.
19
+ pub type LaneIdx32 = u8 ;
51
20
52
21
types ! {
53
22
/// WASM-specific 128-bit wide SIMD vector type
@@ -102,6 +71,9 @@ mod sealed {
102
71
fn sqrt_v4f32 ( x : f32x4 ) -> f32x4 ;
103
72
#[ link_name = "llvm.sqrt.v2f64" ]
104
73
fn sqrt_v2f64 ( x : f64x2 ) -> f64x2 ;
74
+ #[ link_name = "shufflevector" ]
75
+ pub fn shufflevector_v16i8 ( x : v8x16 , y : v8x16 , i : v8x16 ) -> v8x16 ;
76
+
105
77
}
106
78
impl f32x4 {
107
79
#[ inline( always) ]
@@ -214,7 +186,7 @@ macro_rules! impl_extract_lane {
214
186
a: v128
215
187
}
216
188
// the vectors store a signed integer => extract into it
217
- let v: $selem_ty = simd_extract( U { a } . vec, imm. 0 as u32 /* zero-extends index */ ) ;
189
+ let v: $selem_ty = simd_extract( U { a } . vec, imm as u32 /* zero-extends index */ ) ;
218
190
v as $x_ty
219
191
}
220
192
@@ -233,7 +205,7 @@ macro_rules! impl_extract_lane {
233
205
a: v128
234
206
}
235
207
// the vectors store a signed integer => extract into it
236
- let v: $selem_ty = simd_extract( U { a } . vec, imm. 0 as u32 /* zero-extends index */ ) ;
208
+ let v: $selem_ty = simd_extract( U { a } . vec, imm as u32 /* zero-extends index */ ) ;
237
209
// re-interpret the signed integer as an unsigned one of the same size (no-op)
238
210
let v: $uelem_ty= :: mem:: transmute( v) ;
239
211
// cast the internal unsigned integer to a larger signed integer (zero-extends)
@@ -258,7 +230,7 @@ macro_rules! impl_extract_lane {
258
230
a: v128
259
231
}
260
232
// the vectors store a signed integer => extract into it
261
- simd_extract( U { a } . vec, imm. 0 as u32 /* zero-extends index */ )
233
+ simd_extract( U { a } . vec, imm as u32 /* zero-extends index */ )
262
234
}
263
235
}
264
236
} ;
@@ -291,7 +263,7 @@ macro_rules! impl_replace_lane {
291
263
// the vectors store a signed integer => extract into it
292
264
:: mem:: transmute(
293
265
simd_insert( U { a } . vec,
294
- imm. 0 as u32 /* zero-extends index */ ,
266
+ imm as u32 /* zero-extends index */ ,
295
267
x as $ielem_ty)
296
268
)
297
269
}
@@ -306,23 +278,44 @@ impl_replace_lane!(i64x2[v64x2:i64](LaneIdx2) <= i64);
306
278
impl_replace_lane ! ( f32x4[ f32x4: f32 ] ( LaneIdx4 ) <= f32 ) ;
307
279
impl_replace_lane ! ( f64x2[ f64x2: f64 ] ( LaneIdx2 ) <= f64 ) ;
308
280
309
- impl v8x16 {
310
- /// Shuffle lanes
311
- ///
312
- /// Create vector with lanes selected from the lanes of two input vectors
313
- /// `a` and `b` by the indices specified in the immediate mode operand
314
- /// `imm`. Each index selects an element of the result vector, where the
315
- /// indices `i` in range `[0, 15]` select the `i`-th elements of `a`, and
316
- /// the indices in range `[16, 31]` select the `i - 16`-th element of `b`.
317
- #[ inline]
318
- // #[target_feature(enable = "simd128")]
319
- // FIXME: #[cfg_attr(test, assert_instr(v8x16.shuffle))]
320
- #[ rustc_args_required_const( 2 ) ]
321
- pub unsafe fn shuffle ( a : v128 , b : v128 , imm : [ LaneIdx32 ; 16 ] ) -> v128 {
322
- // FIXME: LLVM does not support v8x16.shuffle (use inline assembly?)
323
- let result: v128 ;
324
- asm ! ( "v8x16.shuffle $0, $1, $2" : "=r" ( result) : "r" ( a) , "r" ( b) , "r" ( imm) : : ) ;
325
- result
281
+ pub use :: coresimd:: simd_llvm:: simd_shuffle16 as __internal_v8x16_shuffle;
282
+ pub use self :: sealed:: v8x16 as __internal_v8x16;
283
+
284
+ /// Shuffle lanes
285
+ ///
286
+ /// Create vector with lanes selected from the lanes of two input vectors
287
+ /// `a` and `b` by the indices specified in the immediate mode operand
288
+ /// `imm`. Each index selects an element of the result vector, where the
289
+ /// indices `i` in range `[0, 15]` select the `i`-th elements of `a`, and
290
+ /// the indices in range `[16, 31]` select the `i - 16`-th element of `b`.
291
+ #[ macro_export]
292
+ macro_rules! v8x16_shuffle {
293
+ ( $a: expr, $b: expr, [
294
+ $imm0: expr, $imm1: expr, $imm2: expr, $imm3: expr,
295
+ $imm4: expr, $imm5: expr, $imm6: expr, $imm7: expr,
296
+ $imm8: expr, $imm9: expr, $imm10: expr, $imm11: expr,
297
+ $imm12: expr, $imm13: expr, $imm14: expr, $imm15: expr
298
+ ] ) => {
299
+ #[ allow( unused_unsafe) ]
300
+ unsafe {
301
+ let a: $crate:: arch:: wasm32:: v128 = $a;
302
+ let b: $crate:: arch:: wasm32:: v128 = $b;
303
+ union U {
304
+ e: v128,
305
+ i: $crate:: arch:: wasm32:: __internal_v8x16,
306
+ }
307
+ let a = U { e: a } . i;
308
+ let b = U { e: b } . i;
309
+
310
+ let r: $crate:: arch:: wasm32:: __internal_v8x16 =
311
+ $crate:: arch:: wasm32:: __internal_v8x16_shuffle( a, b, [
312
+ $imm0 as u32 , $imm1, $imm2, $imm3,
313
+ $imm4, $imm5, $imm6, $imm7,
314
+ $imm8, $imm9, $imm10, $imm11,
315
+ $imm12, $imm13, $imm14, $imm15
316
+ ] ) ;
317
+ U { i: r } . e
318
+ }
326
319
}
327
320
}
328
321
@@ -557,6 +550,9 @@ impl_boolean_reduction!(i64x2[v64x2]);
557
550
558
551
macro_rules! impl_comparisons {
559
552
( $id: ident[ $ivec_ty: ident] ) => {
553
+ impl_comparisons!( $id[ $ivec_ty=>$ivec_ty] ) ;
554
+ } ;
555
+ ( $id: ident[ $ivec_ty: ident=>$rvec_ty: ident] ) => {
560
556
impl $id {
561
557
/// Equality
562
558
#[ inline]
@@ -566,7 +562,7 @@ macro_rules! impl_comparisons {
566
562
use coresimd:: simd_llvm:: simd_eq;
567
563
let a: sealed:: $ivec_ty = :: mem:: transmute( a) ;
568
564
let b: sealed:: $ivec_ty = :: mem:: transmute( b) ;
569
- let c: sealed:: $ivec_ty = simd_eq( a, b) ;
565
+ let c: sealed:: $rvec_ty = simd_eq( a, b) ;
570
566
:: mem:: transmute( c)
571
567
}
572
568
/// Non-Equality
@@ -577,7 +573,7 @@ macro_rules! impl_comparisons {
577
573
use coresimd:: simd_llvm:: simd_ne;
578
574
let a: sealed:: $ivec_ty = :: mem:: transmute( a) ;
579
575
let b: sealed:: $ivec_ty = :: mem:: transmute( b) ;
580
- let c: sealed:: $ivec_ty = simd_ne( a, b) ;
576
+ let c: sealed:: $rvec_ty = simd_ne( a, b) ;
581
577
:: mem:: transmute( c)
582
578
}
583
579
/// Less-than
@@ -588,7 +584,7 @@ macro_rules! impl_comparisons {
588
584
use coresimd:: simd_llvm:: simd_lt;
589
585
let a: sealed:: $ivec_ty = :: mem:: transmute( a) ;
590
586
let b: sealed:: $ivec_ty = :: mem:: transmute( b) ;
591
- let c: sealed:: $ivec_ty = simd_lt( a, b) ;
587
+ let c: sealed:: $rvec_ty = simd_lt( a, b) ;
592
588
:: mem:: transmute( c)
593
589
}
594
590
@@ -600,7 +596,7 @@ macro_rules! impl_comparisons {
600
596
use coresimd:: simd_llvm:: simd_le;
601
597
let a: sealed:: $ivec_ty = :: mem:: transmute( a) ;
602
598
let b: sealed:: $ivec_ty = :: mem:: transmute( b) ;
603
- let c: sealed:: $ivec_ty = simd_le( a, b) ;
599
+ let c: sealed:: $rvec_ty = simd_le( a, b) ;
604
600
:: mem:: transmute( c)
605
601
}
606
602
@@ -612,7 +608,7 @@ macro_rules! impl_comparisons {
612
608
use coresimd:: simd_llvm:: simd_gt;
613
609
let a: sealed:: $ivec_ty = :: mem:: transmute( a) ;
614
610
let b: sealed:: $ivec_ty = :: mem:: transmute( b) ;
615
- let c: sealed:: $ivec_ty = simd_gt( a, b) ;
611
+ let c: sealed:: $rvec_ty = simd_gt( a, b) ;
616
612
:: mem:: transmute( c)
617
613
}
618
614
@@ -624,7 +620,7 @@ macro_rules! impl_comparisons {
624
620
use coresimd:: simd_llvm:: simd_ge;
625
621
let a: sealed:: $ivec_ty = :: mem:: transmute( a) ;
626
622
let b: sealed:: $ivec_ty = :: mem:: transmute( b) ;
627
- let c: sealed:: $ivec_ty = simd_ge( a, b) ;
623
+ let c: sealed:: $rvec_ty = simd_ge( a, b) ;
628
624
:: mem:: transmute( c)
629
625
}
630
626
}
@@ -635,8 +631,8 @@ impl_comparisons!(i8x16[v8x16]);
635
631
impl_comparisons ! ( i16x8[ v16x8] ) ;
636
632
impl_comparisons ! ( i32x4[ v32x4] ) ;
637
633
impl_comparisons ! ( i64x2[ v64x2] ) ;
638
- impl_comparisons ! ( f32x4[ f32x4] ) ;
639
- impl_comparisons ! ( f64x2[ f64x2] ) ;
634
+ impl_comparisons ! ( f32x4[ f32x4=>v32x4 ] ) ;
635
+ impl_comparisons ! ( f64x2[ f64x2=>v64x2 ] ) ;
640
636
641
637
// Load and store
642
638
impl v128 {
@@ -696,10 +692,7 @@ macro_rules! impl_floating_point_ops {
696
692
// #[target_feature(enable = "simd128")]
697
693
// FIXME: #[cfg_attr(test, assert_instr($id.min))]
698
694
pub unsafe fn min( a: v128, b: v128) -> v128 {
699
- use coresimd:: simd_llvm:: simd_fmin;
700
- let a: sealed:: $id = :: mem:: transmute( a) ;
701
- let b: sealed:: $id = :: mem:: transmute( b) ;
702
- :: mem:: transmute( simd_fmin( a, b) )
695
+ v128:: bitselect( a, b, $id:: lt( a, b) )
703
696
}
704
697
705
698
/// NaN-propagating maximum
@@ -709,10 +702,7 @@ macro_rules! impl_floating_point_ops {
709
702
// #[target_feature(enable = "simd128")]
710
703
// FIXME: #[cfg_attr(test, assert_instr($id.max))]
711
704
pub unsafe fn max( a: v128, b: v128) -> v128 {
712
- use coresimd:: simd_llvm:: simd_fmax;
713
- let a: sealed:: $id = :: mem:: transmute( a) ;
714
- let b: sealed:: $id = :: mem:: transmute( b) ;
715
- :: mem:: transmute( simd_fmax( a, b) )
705
+ v128:: bitselect( a, b, $id:: gt( a, b) )
716
706
}
717
707
718
708
/// Square-root
@@ -794,9 +784,9 @@ macro_rules! impl_conversion {
794
784
795
785
// Integer to floating point
796
786
impl_conversion ! ( convert_s_i32x4[ "f32x4.convert_s/i32x4" ] : v32x4 => f32x4 | f32x4) ;
797
- impl_conversion ! ( convert_u_i32x4[ "f32x4.convert_u/i32x4" ] : v32x4 => f32x4 | f32x4) ;
787
+ impl_conversion ! ( convert_u_i32x4[ "f32x4.convert_u/i32x4" ] : u32x4 => f32x4 | f32x4) ;
798
788
impl_conversion ! ( convert_s_i64x2[ "f64x2.convert_s/i64x2" ] : v64x2 => f64x2 | f64x2) ;
799
- impl_conversion ! ( convert_u_i64x2[ "f64x2.convert_u/i64x2" ] : v64x2 => f64x2 | f64x2) ;
789
+ impl_conversion ! ( convert_u_i64x2[ "f64x2.convert_u/i64x2" ] : u64x2 => f64x2 | f64x2) ;
800
790
801
791
// Floating point to integer with saturation
802
792
impl_conversion ! ( trunc_s_f32x4_sat[ "i32x4.trunc_s/f32x4:sat" ] : f32x4 => v32x4 | i32x4) ;
0 commit comments