Skip to content

Commit 13b1e40

Browse files
committed
More discriminant codegen tests
These are from 139729, updated to pass on master.
1 parent 855e0fe commit 13b1e40

File tree

2 files changed

+538
-0
lines changed

2 files changed

+538
-0
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
2+
//@ min-llvm-version: 20
3+
//@ only-64bit
4+
5+
// The `derive(PartialEq)` on enums with field-less variants compares discriminants,
6+
// so make sure we emit that in some reasonable way.
7+
8+
#![crate_type = "lib"]
9+
#![feature(ascii_char)]
10+
#![feature(core_intrinsics)]
11+
#![feature(repr128)]
12+
13+
use std::ascii::Char as AC;
14+
use std::cmp::Ordering;
15+
use std::intrinsics::discriminant_value;
16+
use std::num::NonZero;
17+
18+
// A type that's bigger than `isize`, unlike the usual cases that have small tags.
19+
#[repr(u128)]
20+
pub enum Giant {
21+
Two = 2,
22+
Three = 3,
23+
Four = 4,
24+
}
25+
26+
#[unsafe(no_mangle)]
27+
pub fn opt_bool_eq_discr(a: Option<bool>, b: Option<bool>) -> bool {
28+
// CHECK-LABEL: @opt_bool_eq_discr(
29+
// CHECK: %[[A:.+]] = icmp ne i8 %a, 2
30+
// CHECK: %[[B:.+]] = icmp eq i8 %b, 2
31+
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
32+
// CHECK: ret i1 %[[R]]
33+
34+
discriminant_value(&a) == discriminant_value(&b)
35+
}
36+
37+
#[unsafe(no_mangle)]
38+
pub fn opt_ord_eq_discr(a: Option<Ordering>, b: Option<Ordering>) -> bool {
39+
// CHECK-LABEL: @opt_ord_eq_discr(
40+
// CHECK: %[[A:.+]] = icmp ne i8 %a, 2
41+
// CHECK: %[[B:.+]] = icmp eq i8 %b, 2
42+
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
43+
// CHECK: ret i1 %[[R]]
44+
45+
discriminant_value(&a) == discriminant_value(&b)
46+
}
47+
48+
#[unsafe(no_mangle)]
49+
pub fn opt_nz32_eq_discr(a: Option<NonZero<u32>>, b: Option<NonZero<u32>>) -> bool {
50+
// CHECK-LABEL: @opt_nz32_eq_discr(
51+
// CHECK: %[[A:.+]] = icmp ne i32 %a, 0
52+
// CHECK: %[[B:.+]] = icmp eq i32 %b, 0
53+
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
54+
// CHECK: ret i1 %[[R]]
55+
56+
discriminant_value(&a) == discriminant_value(&b)
57+
}
58+
59+
#[unsafe(no_mangle)]
60+
pub fn opt_ac_eq_discr(a: Option<AC>, b: Option<AC>) -> bool {
61+
// CHECK-LABEL: @opt_ac_eq_discr(
62+
// CHECK: %[[A:.+]] = icmp ne i8 %a, -128
63+
// CHECK: %[[B:.+]] = icmp eq i8 %b, -128
64+
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
65+
// CHECK: ret i1 %[[R]]
66+
67+
discriminant_value(&a) == discriminant_value(&b)
68+
}
69+
70+
#[unsafe(no_mangle)]
71+
pub fn opt_giant_eq_discr(a: Option<Giant>, b: Option<Giant>) -> bool {
72+
// CHECK-LABEL: @opt_giant_eq_discr(
73+
// CHECK: %[[A:.+]] = icmp ne i128 %a, 1
74+
// CHECK: %[[B:.+]] = icmp eq i128 %b, 1
75+
// CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
76+
// CHECK: ret i1 %[[R]]
77+
78+
discriminant_value(&a) == discriminant_value(&b)
79+
}
80+
81+
pub enum Mid<T> {
82+
Before,
83+
Thing(T),
84+
After,
85+
}
86+
87+
#[unsafe(no_mangle)]
88+
pub fn mid_bool_eq_discr(a: Mid<bool>, b: Mid<bool>) -> bool {
89+
// CHECK-LABEL: @mid_bool_eq_discr(
90+
91+
// CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
92+
// CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3
93+
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1
94+
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
95+
// CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
96+
97+
// CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
98+
// CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3
99+
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1
100+
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
101+
// CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
102+
103+
// CHECK: ret i1 %[[R]]
104+
discriminant_value(&a) == discriminant_value(&b)
105+
}
106+
107+
#[unsafe(no_mangle)]
108+
pub fn mid_ord_eq_discr(a: Mid<Ordering>, b: Mid<Ordering>) -> bool {
109+
// CHECK-LABEL: @mid_ord_eq_discr(
110+
111+
// CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
112+
// CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3
113+
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1
114+
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
115+
// CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
116+
117+
// CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
118+
// CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3
119+
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1
120+
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
121+
// CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
122+
123+
// CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
124+
// CHECK: ret i1 %[[R]]
125+
discriminant_value(&a) == discriminant_value(&b)
126+
}
127+
128+
#[unsafe(no_mangle)]
129+
pub fn mid_nz32_eq_discr(a: Mid<NonZero<u32>>, b: Mid<NonZero<u32>>) -> bool {
130+
// CHECK-LABEL: @mid_nz32_eq_discr(
131+
// CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0
132+
// CHECK: ret i1 %[[R]]
133+
discriminant_value(&a) == discriminant_value(&b)
134+
}
135+
136+
#[unsafe(no_mangle)]
137+
pub fn mid_ac_eq_discr(a: Mid<AC>, b: Mid<AC>) -> bool {
138+
// CHECK-LABEL: @mid_ac_eq_discr(
139+
140+
// CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
141+
// CHECK: %[[A_IS_NICHE:.+]] = icmp ult i8 %[[A_REL_DISCR]], 3
142+
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127
143+
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
144+
// CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
145+
146+
// CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
147+
// CHECK: %[[B_IS_NICHE:.+]] = icmp ult i8 %[[B_REL_DISCR]], 3
148+
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127
149+
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
150+
// CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
151+
152+
// CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
153+
// CHECK: ret i1 %[[R]]
154+
discriminant_value(&a) == discriminant_value(&b)
155+
}
156+
157+
// FIXME: This should be improved once our LLVM fork picks up the fix for
158+
// <https://github.com/llvm/llvm-project/issues/134024>
159+
#[unsafe(no_mangle)]
160+
pub fn mid_giant_eq_discr(a: Mid<Giant>, b: Mid<Giant>) -> bool {
161+
// CHECK-LABEL: @mid_giant_eq_discr(
162+
163+
// CHECK: %[[A_REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5
164+
// CHECK: %[[A_REL_DISCR:.+]] = trunc nsw i128 %[[A_REL_DISCR_WIDE]] to i64
165+
// CHECK: %[[A_IS_NICHE:.+]] = icmp ult i128 %[[A_REL_DISCR_WIDE]], 3
166+
// CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i128 %[[A_REL_DISCR_WIDE]], 1
167+
// CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
168+
// CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1
169+
170+
// CHECK: %[[B_REL_DISCR_WIDE:.+]] = add nsw i128 %b, -5
171+
// CHECK: %[[B_REL_DISCR:.+]] = trunc nsw i128 %[[B_REL_DISCR_WIDE]] to i64
172+
// CHECK: %[[B_IS_NICHE:.+]] = icmp ult i128 %[[B_REL_DISCR_WIDE]], 3
173+
// CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i128 %[[B_REL_DISCR_WIDE]], 1
174+
// CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
175+
// CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1
176+
177+
// CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]]
178+
// CHECK: ret i1 %[[R]]
179+
discriminant_value(&a) == discriminant_value(&b)
180+
}
181+
182+
// In niche-encoded enums, testing for the untagged variant should optimize to a
183+
// straight-forward comparison looking for the natural range of the payload value.
184+
// FIXME: A bunch don't, though.
185+
186+
#[unsafe(no_mangle)]
187+
pub fn mid_bool_is_thing(a: Mid<bool>) -> bool {
188+
// CHECK-LABEL: @mid_bool_is_thing(
189+
190+
// CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2
191+
// CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2
192+
// CHECK: ret i1 %[[R]]
193+
discriminant_value(&a) == 1
194+
}
195+
196+
#[unsafe(no_mangle)]
197+
pub fn mid_ord_is_thing(a: Mid<Ordering>) -> bool {
198+
// CHECK-LABEL: @mid_ord_is_thing(
199+
// CHECK: %[[REL_DISCR:.+]] = add nsw i8 %a, -2
200+
// CHECK: %[[R:.+]] = icmp ugt i8 %[[REL_DISCR]], 2
201+
// CHECK: ret i1 %[[R]]
202+
discriminant_value(&a) == 1
203+
}
204+
205+
#[unsafe(no_mangle)]
206+
pub fn mid_nz32_is_thing(a: Mid<NonZero<u32>>) -> bool {
207+
// CHECK-LABEL: @mid_nz32_is_thing(
208+
// CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1
209+
// CHECK: ret i1 %[[R]]
210+
discriminant_value(&a) == 1
211+
}
212+
213+
#[unsafe(no_mangle)]
214+
pub fn mid_ac_is_thing(a: Mid<AC>) -> bool {
215+
// CHECK-LABEL: @mid_ac_is_thing(
216+
// CHECK: %[[R:.+]] = icmp sgt i8 %a, -1
217+
// CHECK: ret i1 %[[R]]
218+
discriminant_value(&a) == 1
219+
}
220+
221+
#[unsafe(no_mangle)]
222+
pub fn mid_giant_is_thing(a: Mid<Giant>) -> bool {
223+
// CHECK-LABEL: @mid_giant_is_thing(
224+
// CHECK: %[[REL_DISCR_WIDE:.+]] = add nsw i128 %a, -5
225+
// CHECK: %[[REL_DISCR:.+]] = trunc nsw i128 %[[REL_DISCR_WIDE]] to i64
226+
// CHECK: %[[NOT_NICHE:.+]] = icmp ugt i128 %[[REL_DISCR_WIDE]], 2
227+
// CHECK: %[[IS_MID_VARIANT:.+]] = icmp eq i64 %[[REL_DISCR]], 1
228+
// CHECK: %[[R:.+]] = select i1 %[[NOT_NICHE]], i1 true, i1 %[[IS_MID_VARIANT]]
229+
// CHECK: ret i1 %[[R]]
230+
discriminant_value(&a) == 1
231+
}

0 commit comments

Comments
 (0)