mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-02 10:18:25 +00:00

For example, transmuting between `bool` and `Ordering` doesn't need two `assume`s because one range is a superset of the other. Multiple are still used for things like `char` <-> `NonZero<u32>`, which overlap but where neither fully contains the other.
257 lines
6.2 KiB
Rust
257 lines
6.2 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 = icmp ule i8 %x, 1
|
|
// OPT: call void @llvm.assume(i1 %0)
|
|
// 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)
|
|
// 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)
|
|
}
|
|
|
|
#[repr(usize)]
|
|
pub enum FourOrEight {
|
|
Four = 4,
|
|
Eight = 8,
|
|
}
|
|
|
|
// CHECK-LABEL: @check_nonnull_to_four_or_eight(
|
|
#[no_mangle]
|
|
pub unsafe fn check_nonnull_to_four_or_eight(x: NonNull<u8>) -> FourOrEight {
|
|
// CHECK: start
|
|
// CHECK-NEXT: %[[RET:.+]] = ptrtoint ptr %x to i64
|
|
// CHECK-NOT: icmp
|
|
// CHECK-NOT: assume
|
|
// OPT: %0 = sub i64 %[[RET]], 4
|
|
// OPT: %1 = icmp ule i64 %0, 4
|
|
// OPT: call void @llvm.assume(i1 %1)
|
|
// CHECK-NOT: icmp
|
|
// CHECK-NOT: assume
|
|
// CHECK: ret i64 %[[RET]]
|
|
|
|
transmute(x)
|
|
}
|
|
|
|
// CHECK-LABEL: @check_four_or_eight_to_nonnull(
|
|
#[no_mangle]
|
|
pub unsafe fn check_four_or_eight_to_nonnull(x: FourOrEight) -> NonNull<u8> {
|
|
// CHECK-NOT: icmp
|
|
// CHECK-NOT: assume
|
|
// OPT: %0 = sub i64 %x, 4
|
|
// OPT: %1 = icmp ule i64 %0, 4
|
|
// OPT: call void @llvm.assume(i1 %1)
|
|
// CHECK-NOT: icmp
|
|
// CHECK-NOT: assume
|
|
// CHECK: %[[RET:.+]] = getelementptr i8, ptr null, i64 %x
|
|
// CHECK-NEXT: ret ptr %[[RET]]
|
|
|
|
transmute(x)
|
|
}
|