about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAndy Sadler <andrewsadler122@gmail.com>2023-10-07 23:59:58 -0500
committerAndy Sadler <andrewsadler122@gmail.com>2023-11-28 21:25:17 -0600
commitcc7c9bea1546f9dc07b39feab2d1af776804ee84 (patch)
tree26bf549b41bc39fd44451bd33193a8e694d339ca /src
parentc6bc7ecd65046ee502118664f42637ca318cdfb5 (diff)
downloadrust-cc7c9bea1546f9dc07b39feab2d1af776804ee84.tar.gz
rust-cc7c9bea1546f9dc07b39feab2d1af776804ee84.zip
implement simd_bswap intrinsic
Implements lane-local byte swapping through vector shuffles.  While this
is more setup than non-vector shuffles, this implementation can shuffle
multiple integers concurrently.

Signed-off-by: Andy Sadler <andrewsadler122@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/intrinsic/simd.rs54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs
index 85d3e7234a0..3356d6f4a4b 100644
--- a/src/intrinsic/simd.rs
+++ b/src/intrinsic/simd.rs
@@ -1,3 +1,5 @@
+use std::iter::FromIterator;
+
 use gccjit::ToRValue;
 use gccjit::{BinaryOp, RValue, Type};
 #[cfg(feature = "master")]
@@ -156,6 +158,58 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         return Ok(compare_simd_types(bx, arg1, arg2, in_elem, llret_ty, cmp_op));
     }
 
+    if name == sym::simd_bswap {
+        let vector = args[0].immediate();
+        let ret = match in_elem.kind() {
+            ty::Int(i) if i.bit_width() == Some(8) => vector,
+            ty::Uint(i) if i.bit_width() == Some(8) => vector,
+            ty::Int(_) | ty::Uint(_) => {
+                let v_type = vector.get_type();
+                let vector_type = v_type.unqualified().dyncast_vector().expect("vector type");
+                let elem_type = vector_type.get_element_type();
+                let elem_size_bytes = elem_type.get_size();
+                let type_size_bytes = elem_size_bytes as u64 * in_len;
+
+                let shuffle_indices = Vec::from_iter(0..type_size_bytes);
+                let byte_vector_type = bx.context.new_vector_type(bx.type_u8(), type_size_bytes);
+                let byte_vector = bx.context.new_bitcast(None, args[0].immediate(), byte_vector_type);
+
+                #[cfg(not(feature = "master"))]
+                let shuffled = {
+                    let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _)
+                        .flat_map(|x| x.iter().rev())
+                        .map(|&i| {
+                            let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _);
+                            bx.extract_element(byte_vector, index)
+                        })
+                        .collect();
+
+                    bx.context.new_rvalue_from_vector(None, byte_vector_type, &new_elements)
+                };
+                #[cfg(feature = "master")]
+                let shuffled = {
+                    let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _)
+                        .flat_map(|x| x.iter().rev())
+                        .map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _))
+                        .collect();
+
+                    let mask = bx.context.new_rvalue_from_vector(None, byte_vector_type, &indices);
+                    bx.context.new_rvalue_vector_perm(None, byte_vector, byte_vector, mask)
+                };
+                bx.context.new_bitcast(None, shuffled, v_type)
+            }
+            _ => {
+                return_error!(InvalidMonomorphization::UnsupportedOperation {
+                    span,
+                    name,
+                    in_ty,
+                    in_elem,
+                });
+            }
+        };
+        return Ok(ret);
+    }
+
     if name == sym::simd_shuffle {
         // Make sure this is actually an array, since typeck only checks the length-suffixed
         // version of this intrinsic.