about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/intrinsics/transmute.rs153
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs51
-rw-r--r--tests/codegen/transmute-scalar.rs44
3 files changed, 194 insertions, 54 deletions
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs
index cefcf9ed9ca..7ad0e62213c 100644
--- a/tests/codegen/intrinsics/transmute.rs
+++ b/tests/codegen/intrinsics/transmute.rs
@@ -6,6 +6,7 @@
 #![feature(core_intrinsics)]
 #![feature(custom_mir)]
 #![feature(inline_const)]
+#![allow(unreachable_code)]
 
 use std::mem::transmute;
 
@@ -24,6 +25,9 @@ pub struct Scalar64(i64);
 #[repr(C, align(4))]
 pub struct Aggregate64(u16, u8, i8, f32);
 
+#[repr(C)]
+pub struct Aggregate8(u8);
+
 // CHECK-LABEL: @check_bigger_size(
 #[no_mangle]
 #[custom_mir(dialect = "runtime", phase = "initial")]
@@ -76,23 +80,80 @@ pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
     }
 }
 
+// CHECK-LABEL: @check_intermediate_passthrough(
+#[no_mangle]
+pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 {
+    // CHECK: start
+    // CHECK: %[[TMP:.+]] = add i32 1, %x
+    // CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1
+    // CHECK: ret i32 %[[RET]]
+    unsafe {
+        transmute::<u32, i32>(1 + x) + 1
+    }
+}
+
+// CHECK-LABEL: @check_nop_pair(
+#[no_mangle]
+pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0
+    // CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1
+    // CHECK: ret { i8, i8 } %1
+    unsafe {
+        transmute(x)
+    }
+}
+
 // CHECK-LABEL: @check_to_newtype(
 #[no_mangle]
 pub unsafe fn check_to_newtype(x: u64) -> Scalar64 {
-    // CHECK: %0 = alloca i64
-    // CHECK: store i64 %x, ptr %0
-    // CHECK: %1 = load i64, ptr %0
-    // CHECK: ret i64 %1
+    // CHECK-NOT: alloca
+    // CHECK: ret i64 %x
     transmute(x)
 }
 
 // CHECK-LABEL: @check_from_newtype(
 #[no_mangle]
 pub unsafe fn check_from_newtype(x: Scalar64) -> u64 {
-    // CHECK: %0 = alloca i64
-    // CHECK: store i64 %x, ptr %0
-    // CHECK: %1 = load i64, ptr %0
-    // CHECK: ret i64 %1
+    // CHECK-NOT: alloca
+    // CHECK: ret i64 %x
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_aggregate_to_bool(
+#[no_mangle]
+pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool {
+    // CHECK: %x = alloca %Aggregate8, align 1
+    // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1
+    // CHECK: %[[BOOL:.+]] = trunc i8 %[[BYTE]] to i1
+    // CHECK: ret i1 %[[BOOL]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_aggregate_from_bool(
+#[no_mangle]
+pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 {
+    // CHECK: %0 = alloca %Aggregate8, align 1
+    // CHECK: %[[BYTE:.+]] = zext i1 %x to i8
+    // CHECK: store i8 %[[BYTE]], ptr %0, align 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_byte_to_bool(
+#[no_mangle]
+pub unsafe fn check_byte_to_bool(x: u8) -> bool {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = trunc i8 %x to i1
+    // CHECK: ret i1 %0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_byte_from_bool(
+#[no_mangle]
+pub unsafe fn check_byte_from_bool(x: bool) -> u8 {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = zext i1 %x to i8
+    // CHECK: ret i8 %0
     transmute(x)
 }
 
@@ -122,20 +183,18 @@ pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
 // CHECK-LABEL: @check_to_float(
 #[no_mangle]
 pub unsafe fn check_to_float(x: u32) -> f32 {
-    // CHECK: %0 = alloca float
-    // CHECK: store i32 %x, ptr %0
-    // CHECK: %1 = load float, ptr %0
-    // CHECK: ret float %1
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast i32 %x to float
+    // CHECK: ret float %0
     transmute(x)
 }
 
 // CHECK-LABEL: @check_from_float(
 #[no_mangle]
 pub unsafe fn check_from_float(x: f32) -> u32 {
-    // CHECK: %0 = alloca i32
-    // CHECK: store float %x, ptr %0
-    // CHECK: %1 = load i32, ptr %0
-    // CHECK: ret i32 %1
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast float %x to i32
+    // CHECK: ret i32 %0
     transmute(x)
 }
 
@@ -144,19 +203,15 @@ pub unsafe fn check_from_float(x: f32) -> u32 {
 pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] {
     // CHECK: %0 = alloca [4 x i8], align 1
     // CHECK: store i32 %x, ptr %0, align 1
-    // CHECK: %1 = load i32, ptr %0, align 1
-    // CHECK: ret i32 %1
     transmute(x)
 }
 
 // CHECK-LABEL: @check_from_bytes(
 #[no_mangle]
 pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 {
-    // CHECK: %1 = alloca i32, align 4
     // CHECK: %x = alloca [4 x i8], align 1
-    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false)
-    // CHECK: %3 = load i32, ptr %1, align 4
-    // CHECK: ret i32 %3
+    // CHECK: %[[VAL:.+]] = load i32, ptr %x, align 1
+    // CHECK: ret i32 %[[VAL]]
     transmute(x)
 }
 
@@ -173,7 +228,9 @@ pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 {
 // CHECK-LABEL: @check_from_aggregate(
 #[no_mangle]
 pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 {
-    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false)
+    // CHECK: %x = alloca %Aggregate64, align 4
+    // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 4
+    // CHECK: ret i64 %[[VAL]]
     transmute(x)
 }
 
@@ -194,3 +251,53 @@ pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] {
     // CHECK-NEXT: ret void
     transmute(x)
 }
+
+// CHECK-LABEL: @check_pair_with_bool(
+#[no_mangle]
+pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) {
+    // CHECK-NOT: alloca
+    // CHECK: trunc i8 %x.0 to i1
+    // CHECK: zext i1 %x.1 to i8
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_float_to_pointer(
+#[no_mangle]
+pub unsafe fn check_float_to_pointer(x: f64) -> *const () {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast double %x to i64
+    // CHECK: %1 = inttoptr i64 %0 to ptr
+    // CHECK: ret ptr %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_float_from_pointer(
+#[no_mangle]
+pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = ptrtoint ptr %x to i64
+    // CHECK: %1 = bitcast i64 %0 to double
+    // CHECK: ret double %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_array_to_pair(
+#[no_mangle]
+pub unsafe fn check_array_to_pair(x: [u8; 16]) -> (i64, u64) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[FST:.+]] = load i64, ptr %{{.+}}, align 1, !noundef !
+    // CHECK: %[[SND:.+]] = load i64, ptr %{{.+}}, align 1, !noundef !
+    // CHECK: %[[PAIR0:.+]] = insertvalue { i64, i64 } poison, i64 %[[FST]], 0
+    // CHECK: %[[PAIR01:.+]] = insertvalue { i64, i64 } %[[PAIR0]], i64 %[[SND]], 1
+    // CHECK: ret { i64, i64 } %[[PAIR01]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_pair_to_array(
+#[no_mangle]
+pub unsafe fn check_pair_to_array(x: (i64, u64)) -> [u8; 16] {
+    // CHECK-NOT: alloca
+    // CHECK: store i64 %x.0, ptr %{{.+}}, align 1
+    // CHECK: store i64 %x.1, ptr %{{.+}}, align 1
+    transmute(x)
+}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
index 7c77398dfcc..fd488a14bd3 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -4,7 +4,8 @@
 #![crate_type = "lib"]
 
 #![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
+#![feature(inline_const)]
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
@@ -18,23 +19,65 @@ pub struct T([f32; 4]);
 #[derive(Copy, Clone)]
 pub struct U(f32, f32, f32, f32);
 
+// CHECK-LABEL: @array_align(
+#[no_mangle]
+pub fn array_align() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[ARRAY_ALIGN:[0-9]+]]
+    const { std::mem::align_of::<f32>() }
+}
+
+// CHECK-LABEL: @vector_align(
+#[no_mangle]
+pub fn vector_align() -> usize {
+    // CHECK: ret [[USIZE]] [[VECTOR_ALIGN:[0-9]+]]
+    const { std::mem::align_of::<U>() }
+}
+
 // CHECK-LABEL: @build_array_s
 #[no_mangle]
 pub fn build_array_s(x: [f32; 4]) -> S<4> {
-    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
     S::<4>(x)
 }
 
+// CHECK-LABEL: @build_array_transmute_s
+#[no_mangle]
+pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> {
+    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    unsafe { std::mem::transmute(x) }
+}
+
 // CHECK-LABEL: @build_array_t
 #[no_mangle]
 pub fn build_array_t(x: [f32; 4]) -> T {
-    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
     T(x)
 }
 
+// CHECK-LABEL: @build_array_transmute_t
+#[no_mangle]
+pub fn build_array_transmute_t(x: [f32; 4]) -> T {
+    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    unsafe { std::mem::transmute(x) }
+}
+
 // CHECK-LABEL: @build_array_u
 #[no_mangle]
 pub fn build_array_u(x: [f32; 4]) -> U {
-    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: store float %a, {{.+}}, align [[VECTOR_ALIGN]]
+    // CHECK: store float %b, {{.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store float %c, {{.+}}, align
+    // CHECK: store float %d, {{.+}}, align [[ARRAY_ALIGN]]
+    let [a, b, c, d] = x;
+    U(a, b, c, d)
+}
+
+// CHECK-LABEL: @build_array_transmute_u
+#[no_mangle]
+pub fn build_array_transmute_u(x: [f32; 4]) -> U {
+    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index 4d7a80bfbe5..af2cef472ec 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -5,63 +5,53 @@
 
 // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
 // without needing to pointercast, and SRoA will turn that into a `bitcast`.
-// As such, there's no longer special-casing in `transmute` to attempt to
-// generate `bitcast` ourselves, as that just made the IR longer.
+// Thus memory-to-memory transmutes don't need to generate them ourselves.
 
-// FIXME: That said, `bitcast`s could still be a valuable addition if they could
-// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely.
+// However, `bitcast`s and `ptrtoint`s and `inttoptr`s are still worth doing when
+// that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`.
 
 // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x)
-// CHECK: store float %{{.*}}, ptr %0
-// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0
-// CHECK: ret i32 %[[RES]]
+// CHECK: %0 = bitcast float %x to i32
+// CHECK-NEXT: ret i32 %0
 #[no_mangle]
 pub fn f32_to_bits(x: f32) -> u32 {
     unsafe { std::mem::transmute(x) }
 }
 
 // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 noundef zeroext %b)
-// CHECK: %1 = zext i1 %b to i8
-// CHECK-NEXT: store i8 %1, {{.*}} %0
-// CHECK-NEXT: %2 = load i8, {{.*}} %0
-// CHECK: ret i8 %2
+// CHECK: %0 = zext i1 %b to i8
+// CHECK-NEXT: ret i8 %0
 #[no_mangle]
 pub fn bool_to_byte(b: bool) -> u8 {
     unsafe { std::mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte)
-// CHECK: store i8 %byte, ptr %0
-// CHECK-NEXT: %1 = load i8, {{.*}} %0
-// CHECK-NEXT: %2 = trunc i8 %1 to i1
-// CHECK: ret i1 %2
+// CHECK: %0 = trunc i8 %byte to i1
+// CHECK-NEXT: ret i1 %0
 #[no_mangle]
 pub unsafe fn byte_to_bool(byte: u8) -> bool {
     std::mem::transmute(byte)
 }
 
-// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} noundef %p)
-// CHECK: store {{i8\*|ptr}} %{{.*}}, {{.*}} %0
-// CHECK-NEXT: %[[RES:.*]] = load {{i8\*|ptr}}, {{.*}} %0
-// CHECK: ret {{i8\*|ptr}} %[[RES]]
+// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr noundef %p)
+// CHECK: ret ptr %p
 #[no_mangle]
 pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
     unsafe { std::mem::transmute(p) }
 }
 
-// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p)
-// CHECK: store {{i16\*|ptr}} %p, {{.*}}
-// CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0
-// CHECK: ret [[USIZE]] %[[RES]]
+// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr noundef %p)
+// CHECK: %0 = ptrtoint ptr %p to [[USIZE]]
+// CHECK-NEXT: ret [[USIZE]] %0
 #[no_mangle]
 pub fn ptr_to_int(p: *mut u16) -> usize {
     unsafe { std::mem::transmute(p) }
 }
 
-// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i)
-// CHECK: store [[USIZE]] %i, {{.*}}
-// CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0
-// CHECK: ret {{i16\*|ptr}} %[[RES]]
+// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] noundef %i)
+// CHECK: %0 = inttoptr [[USIZE]] %i to ptr
+// CHECK-NEXT: ret ptr %0
 #[no_mangle]
 pub fn int_to_ptr(i: usize) -> *mut u16 {
     unsafe { std::mem::transmute(i) }