rust/tests/codegen/intrinsics/transmute-niched.rs
Scott McMurray 511bf307f0 Emit trunc nuw for unchecked shifts and to_immediate_scalar
- For shifts this shrinks the IR by no longer needing an `assume` while still providing the UB information
- Having this on the `i8`→`i1` truncations will hopefully help with some places that have to load `i8`s or pass those in LLVM structs without range information
2025-02-19 11:36:52 -08:00

223 lines
5.4 KiB
Rust

//@ revisions: OPT DBG
//@ [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes
//@ [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes
//@ only-64bit (so I don't need to worry about usize)
#![crate_type = "lib"]
use std::mem::transmute;
use std::num::NonZero;
use std::ptr::NonNull;
#[repr(u8)]
pub enum SmallEnum {
A = 10,
B = 11,
C = 12,
}
// CHECK-LABEL: @check_to_enum(
#[no_mangle]
pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = sub i8 %x, 10
// OPT: %1 = icmp ule i8 %0, 2
// OPT: call void @llvm.assume(i1 %1)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i8 %x
transmute(x)
}
// CHECK-LABEL: @check_from_enum(
#[no_mangle]
pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = sub i8 %x, 10
// OPT: %1 = icmp ule i8 %0, 2
// OPT: call void @llvm.assume(i1 %1)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i8 %x
transmute(x)
}
// CHECK-LABEL: @check_to_ordering(
#[no_mangle]
pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = sub i8 %x, -1
// OPT: %1 = icmp ule i8 %0, 2
// OPT: call void @llvm.assume(i1 %1)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i8 %x
transmute(x)
}
// CHECK-LABEL: @check_from_ordering(
#[no_mangle]
pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = sub i8 %x, -1
// OPT: %1 = icmp ule i8 %0, 2
// OPT: call void @llvm.assume(i1 %1)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i8 %x
transmute(x)
}
#[repr(i32)]
pub enum Minus100ToPlus100 {
A = -100,
B = -90,
C = -80,
D = -70,
E = -60,
F = -50,
G = -40,
H = -30,
I = -20,
J = -10,
K = 0,
L = 10,
M = 20,
N = 30,
O = 40,
P = 50,
Q = 60,
R = 70,
S = 80,
T = 90,
U = 100,
}
// CHECK-LABEL: @check_enum_from_char(
#[no_mangle]
pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = icmp ule i32 %x, 1114111
// OPT: call void @llvm.assume(i1 %0)
// OPT: %1 = sub i32 %x, -100
// OPT: %2 = icmp ule i32 %1, 200
// OPT: call void @llvm.assume(i1 %2)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i32 %x
transmute(x)
}
// CHECK-LABEL: @check_enum_to_char(
#[no_mangle]
pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = sub i32 %x, -100
// OPT: %1 = icmp ule i32 %0, 200
// OPT: call void @llvm.assume(i1 %1)
// OPT: %2 = icmp ule i32 %x, 1114111
// OPT: call void @llvm.assume(i1 %2)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i32 %x
transmute(x)
}
// CHECK-LABEL: @check_swap_pair(
#[no_mangle]
pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = icmp ule i32 %x.0, 1114111
// OPT: call void @llvm.assume(i1 %0)
// OPT: %1 = sub i32 %x.0, 1
// OPT: %2 = icmp ule i32 %1, -2
// OPT: call void @llvm.assume(i1 %2)
// OPT: %3 = sub i32 %x.1, 1
// OPT: %4 = icmp ule i32 %3, -2
// OPT: call void @llvm.assume(i1 %4)
// OPT: %5 = icmp ule i32 %x.1, 1114111
// OPT: call void @llvm.assume(i1 %5)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
// CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1
// CHECK: ret { i32, i32 } %[[P2]]
transmute(x)
}
// CHECK-LABEL: @check_bool_from_ordering(
#[no_mangle]
pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = sub i8 %x, -1
// OPT: %1 = icmp ule i8 %0, 2
// OPT: call void @llvm.assume(i1 %1)
// OPT: %2 = icmp ule i8 %x, 1
// OPT: call void @llvm.assume(i1 %2)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1
// CHECK: ret i1 %[[R]]
transmute(x)
}
// CHECK-LABEL: @check_bool_to_ordering(
#[no_mangle]
pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
// CHECK: %_0 = zext i1 %x to i8
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = icmp ule i8 %_0, 1
// OPT: call void @llvm.assume(i1 %0)
// OPT: %1 = sub i8 %_0, -1
// OPT: %2 = icmp ule i8 %1, 2
// OPT: call void @llvm.assume(i1 %2)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret i8 %_0
transmute(x)
}
// CHECK-LABEL: @check_nonnull_to_ptr(
#[no_mangle]
pub unsafe fn check_nonnull_to_ptr(x: NonNull<u8>) -> *const u8 {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = icmp ne ptr %x, null
// OPT: call void @llvm.assume(i1 %0)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret ptr %x
transmute(x)
}
// CHECK-LABEL: @check_ptr_to_nonnull(
#[no_mangle]
pub unsafe fn check_ptr_to_nonnull(x: *const u8) -> NonNull<u8> {
// CHECK-NOT: icmp
// CHECK-NOT: assume
// OPT: %0 = icmp ne ptr %x, null
// OPT: call void @llvm.assume(i1 %0)
// CHECK-NOT: icmp
// CHECK-NOT: assume
// CHECK: ret ptr %x
transmute(x)
}