diff options
| author | bors <bors@rust-lang.org> | 2025-07-05 01:37:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-07-05 01:37:08 +0000 |
| commit | 733b47ea4b1b86216f14ef56e49440c33933f230 (patch) | |
| tree | 17ee40b79aa3e3da70bb9d3a97ed3338585ee1ef /tests/codegen/enum/enum-aggregate.rs | |
| parent | d98a5da813da67eb189387b8ccfb73cf481275d8 (diff) | |
| parent | d020e38fa229d184026ac9b1a7ea73b9f99e8e7a (diff) | |
| download | rust-733b47ea4b1b86216f14ef56e49440c33933f230.tar.gz rust-733b47ea4b1b86216f14ef56e49440c33933f230.zip | |
Auto merge of #138759 - scottmcm:operand-builder, r=saethlin
Allow `enum` and `union` literals to also create SSA values
Today, `Some(x)` always goes through an `alloca`, even in trivial cases where the niching means the constructor doesn't even change the value.
For example, <https://rust.godbolt.org/z/6KG6PqoYz>
```rust
pub fn demo(r: &i32) -> Option<&i32> {
Some(r)
}
```
currently emits the IR
```llvm
define align 4 ptr `@demo(ptr` align 4 %r) unnamed_addr {
start:
%_0 = alloca [8 x i8], align 8
store ptr %r, ptr %_0, align 8
%0 = load ptr, ptr %_0, align 8
ret ptr %0
}
```
but with this PR it becomes just
```llvm
define align 4 ptr `@demo(ptr` align 4 %r) unnamed_addr {
start:
ret ptr %r
}
```
(Of course the optimizer can clean that up, but it'd be nice if it didn't have to -- especially in debug where it doesn't run. This is like rust-lang/rust#123886, but that only handled non-simd `struct`s -- this PR generalizes it to all non-simd ADTs.)
Doing this means handing variants other than `FIRST_VARIANT`, handling the active field for unions, refactoring the discriminant code so the Place and Operand parts can share the calculation, etc.
Other PRs that led up to this one:
- https://github.com/rust-lang/rust/pull/142005
- https://github.com/rust-lang/rust/pull/142103
- https://github.com/rust-lang/rust/pull/142324
- https://github.com/rust-lang/rust/pull/142383
---
try-job: aarch64-gnu
Diffstat (limited to 'tests/codegen/enum/enum-aggregate.rs')
| -rw-r--r-- | tests/codegen/enum/enum-aggregate.rs | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/tests/codegen/enum/enum-aggregate.rs b/tests/codegen/enum/enum-aggregate.rs new file mode 100644 index 00000000000..b6a9b8dd814 --- /dev/null +++ b/tests/codegen/enum/enum-aggregate.rs @@ -0,0 +1,129 @@ +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes +//@ min-llvm-version: 19 +//@ only-64bit + +#![crate_type = "lib"] + +use std::cmp::Ordering; +use std::num::NonZero; +use std::ptr::NonNull; + +#[no_mangle] +fn make_some_bool(x: bool) -> Option<bool> { + // CHECK-LABEL: i8 @make_some_bool(i1 zeroext %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 + // CHECK-NEXT: ret i8 %[[WIDER]] + Some(x) +} + +#[no_mangle] +fn make_none_bool() -> Option<bool> { + // CHECK-LABEL: i8 @make_none_bool() + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 2 + None +} + +#[no_mangle] +fn make_some_ordering(x: Ordering) -> Option<Ordering> { + // CHECK-LABEL: i8 @make_some_ordering(i8 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 %x + Some(x) +} + +#[no_mangle] +fn make_some_u16(x: u16) -> Option<u16> { + // CHECK-LABEL: { i16, i16 } @make_some_u16(i16 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i16, i16 } { i16 1, i16 poison }, i16 %x, 1 + // CHECK-NEXT: ret { i16, i16 } %0 + Some(x) +} + +#[no_mangle] +fn make_none_u16() -> Option<u16> { + // CHECK-LABEL: { i16, i16 } @make_none_u16() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { i16, i16 } { i16 0, i16 undef } + None +} + +#[no_mangle] +fn make_some_nzu32(x: NonZero<u32>) -> Option<NonZero<u32>> { + // CHECK-LABEL: i32 @make_some_nzu32(i32 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret i32 %x + Some(x) +} + +#[no_mangle] +fn make_ok_ptr(x: NonNull<u16>) -> Result<NonNull<u16>, usize> { + // CHECK-LABEL: { i64, ptr } @make_ok_ptr(ptr %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %x, 1 + // CHECK-NEXT: ret { i64, ptr } %0 + Ok(x) +} + +#[no_mangle] +fn make_ok_int(x: usize) -> Result<usize, NonNull<u16>> { + // CHECK-LABEL: { i64, ptr } @make_ok_int(i64 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[NOPROV:.+]] = getelementptr i8, ptr null, i64 %x + // CHECK-NEXT: %[[R:.+]] = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %[[NOPROV]], 1 + // CHECK-NEXT: ret { i64, ptr } %[[R]] + Ok(x) +} + +#[no_mangle] +fn make_some_ref(x: &u16) -> Option<&u16> { + // CHECK-LABEL: ptr @make_some_ref(ptr align 2 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr %x + Some(x) +} + +#[no_mangle] +fn make_none_ref<'a>() -> Option<&'a u16> { + // CHECK-LABEL: ptr @make_none_ref() + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr null + None +} + +#[inline(never)] +fn make_err_generic<E>(e: E) -> Result<u32, E> { + // CHECK-LABEL: define{{.+}}make_err_generic + // CHECK-NEXT: start: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: ret i32 poison + Err(e) +} + +#[no_mangle] +fn make_uninhabited_err_indirectly(n: Never) -> Result<u32, Never> { + // CHECK-LABEL: i32 @make_uninhabited_err_indirectly() + // CHECK-NEXT: start: + // CHECK-NEXT: call{{.+}}make_err_generic + make_err_generic(n) +} + +#[no_mangle] +fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> { + // We don't try to do this in SSA form since the whole type is uninhabited. + + // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v) + // CHECK: %[[ALLOC_V:.+]] = alloca [4 x i8] + // CHECK: %[[RET:.+]] = alloca [8 x i8] + // CHECK: store i32 %v, ptr %[[ALLOC_V]] + // CHECK: %[[TEMP_V:.+]] = load i32, ptr %[[ALLOC_V]] + // CHECK: %[[INNER:.+]] = getelementptr inbounds i8, ptr %[[RET]] + // CHECK: store i32 %[[TEMP_V]], ptr %[[INNER]] + // CHECK: call void @llvm.trap() + // CHECK: unreachable + Ok((v, n)) +} + +enum Never {} |
