rust/tests/codegen/enum/enum-match.rs

473 lines
11 KiB
Rust

//@ compile-flags: -Copt-level=1
//@ only-64bit
#![crate_type = "lib"]
#![feature(core_intrinsics)]
// Check each of the 3 cases for `codegen_get_discr`.
// FIXME: once our min-bar LLVM has `range` attributes, update the various
// tests here to no longer have the `range`s and `nsw`s as optional.
// Case 0: One tagged variant.
pub enum Enum0 {
A(bool),
B,
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2
// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1
// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]]
// CHECK-NEXT: ret i8 %[[R]]
#[no_mangle]
pub fn match0(e: Enum0) -> u8 {
use Enum0::*;
match e {
A(b) => b as u8,
B => 13,
}
}
// Case 1: Niche values are on a boundary for `range`.
pub enum Enum1 {
A(bool),
B,
C,
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2
// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
// CHECK-NEXT: switch i64 %[[DISCR]]
#[no_mangle]
pub fn match1(e: Enum1) -> u8 {
use Enum1::*;
match e {
A(b) => b as u8,
B => 13,
C => 100,
}
}
// Case 2: Special cases don't apply.
#[rustfmt::skip]
pub enum X {
_2=2, _3, _4, _5, _6, _7, _8, _9, _10, _11,
_12, _13, _14, _15, _16, _17, _18, _19, _20,
_21, _22, _23, _24, _25, _26, _27, _28, _29,
_30, _31, _32, _33, _34, _35, _36, _37, _38,
_39, _40, _41, _42, _43, _44, _45, _46, _47,
_48, _49, _50, _51, _52, _53, _54, _55, _56,
_57, _58, _59, _60, _61, _62, _63, _64, _65,
_66, _67, _68, _69, _70, _71, _72, _73, _74,
_75, _76, _77, _78, _79, _80, _81, _82, _83,
_84, _85, _86, _87, _88, _89, _90, _91, _92,
_93, _94, _95, _96, _97, _98, _99, _100, _101,
_102, _103, _104, _105, _106, _107, _108, _109,
_110, _111, _112, _113, _114, _115, _116, _117,
_118, _119, _120, _121, _122, _123, _124, _125,
_126, _127, _128, _129, _130, _131, _132, _133,
_134, _135, _136, _137, _138, _139, _140, _141,
_142, _143, _144, _145, _146, _147, _148, _149,
_150, _151, _152, _153, _154, _155, _156, _157,
_158, _159, _160, _161, _162, _163, _164, _165,
_166, _167, _168, _169, _170, _171, _172, _173,
_174, _175, _176, _177, _178, _179, _180, _181,
_182, _183, _184, _185, _186, _187, _188, _189,
_190, _191, _192, _193, _194, _195, _196, _197,
_198, _199, _200, _201, _202, _203, _204, _205,
_206, _207, _208, _209, _210, _211, _212, _213,
_214, _215, _216, _217, _218, _219, _220, _221,
_222, _223, _224, _225, _226, _227, _228, _229,
_230, _231, _232, _233, _234, _235, _236, _237,
_238, _239, _240, _241, _242, _243, _244, _245,
_246, _247, _248, _249, _250, _251, _252, _253,
}
pub enum Enum2 {
A(X),
B,
C,
D,
E,
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2
// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4
// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
// CHECK-NEXT: switch i64 %[[DISCR]]
#[no_mangle]
pub fn match2(e: Enum2) -> u8 {
use Enum2::*;
match e {
A(b) => b as u8,
B => 13,
C => 100,
D => 200,
E => 250,
}
}
// And make sure it works even if the niched scalar is a pointer.
// (For example, that we don't try to `sub` on pointers.)
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null
// CHECK-NEXT: br i1 %[[IS_NULL]]
#[no_mangle]
pub fn match3(e: Option<&u8>) -> i16 {
match e {
Some(r) => *r as _,
None => -1,
}
}
// If the untagged variant is in the middle, there's an impossible value that's
// not reflected in the `range` parameter attribute, so we assume it away.
#[derive(PartialEq)]
pub enum MiddleNiche {
A,
B,
C(bool),
D,
E,
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5
// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2
// CHECK-NEXT: switch i8 %[[DISCR]]
#[no_mangle]
pub fn match4(e: MiddleNiche) -> u8 {
use MiddleNiche::*;
match e {
A => 13,
B => 100,
C(b) => b as u8,
D => 200,
E => 250,
}
}
// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e)
// CHECK-NEXT: start
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2
// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4
// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
// CHECK-NEXT: ret i1 %[[NOT_NICHE]]
#[no_mangle]
pub fn match4_is_c(e: MiddleNiche) -> bool {
// Before #139098, this couldn't optimize out the `select` because it looked
// like it was possible for a `2` to be produced on both sides.
std::intrinsics::discriminant_value(&e) == 2
}
// You have to do something pretty obnoxious to get a variant index that doesn't
// fit in the tag size, but it's possible
pub enum Never {}
pub enum HugeVariantIndex {
V000(Never),
V001(Never),
V002(Never),
V003(Never),
V004(Never),
V005(Never),
V006(Never),
V007(Never),
V008(Never),
V009(Never),
V010(Never),
V011(Never),
V012(Never),
V013(Never),
V014(Never),
V015(Never),
V016(Never),
V017(Never),
V018(Never),
V019(Never),
V020(Never),
V021(Never),
V022(Never),
V023(Never),
V024(Never),
V025(Never),
V026(Never),
V027(Never),
V028(Never),
V029(Never),
V030(Never),
V031(Never),
V032(Never),
V033(Never),
V034(Never),
V035(Never),
V036(Never),
V037(Never),
V038(Never),
V039(Never),
V040(Never),
V041(Never),
V042(Never),
V043(Never),
V044(Never),
V045(Never),
V046(Never),
V047(Never),
V048(Never),
V049(Never),
V050(Never),
V051(Never),
V052(Never),
V053(Never),
V054(Never),
V055(Never),
V056(Never),
V057(Never),
V058(Never),
V059(Never),
V060(Never),
V061(Never),
V062(Never),
V063(Never),
V064(Never),
V065(Never),
V066(Never),
V067(Never),
V068(Never),
V069(Never),
V070(Never),
V071(Never),
V072(Never),
V073(Never),
V074(Never),
V075(Never),
V076(Never),
V077(Never),
V078(Never),
V079(Never),
V080(Never),
V081(Never),
V082(Never),
V083(Never),
V084(Never),
V085(Never),
V086(Never),
V087(Never),
V088(Never),
V089(Never),
V090(Never),
V091(Never),
V092(Never),
V093(Never),
V094(Never),
V095(Never),
V096(Never),
V097(Never),
V098(Never),
V099(Never),
V100(Never),
V101(Never),
V102(Never),
V103(Never),
V104(Never),
V105(Never),
V106(Never),
V107(Never),
V108(Never),
V109(Never),
V110(Never),
V111(Never),
V112(Never),
V113(Never),
V114(Never),
V115(Never),
V116(Never),
V117(Never),
V118(Never),
V119(Never),
V120(Never),
V121(Never),
V122(Never),
V123(Never),
V124(Never),
V125(Never),
V126(Never),
V127(Never),
V128(Never),
V129(Never),
V130(Never),
V131(Never),
V132(Never),
V133(Never),
V134(Never),
V135(Never),
V136(Never),
V137(Never),
V138(Never),
V139(Never),
V140(Never),
V141(Never),
V142(Never),
V143(Never),
V144(Never),
V145(Never),
V146(Never),
V147(Never),
V148(Never),
V149(Never),
V150(Never),
V151(Never),
V152(Never),
V153(Never),
V154(Never),
V155(Never),
V156(Never),
V157(Never),
V158(Never),
V159(Never),
V160(Never),
V161(Never),
V162(Never),
V163(Never),
V164(Never),
V165(Never),
V166(Never),
V167(Never),
V168(Never),
V169(Never),
V170(Never),
V171(Never),
V172(Never),
V173(Never),
V174(Never),
V175(Never),
V176(Never),
V177(Never),
V178(Never),
V179(Never),
V180(Never),
V181(Never),
V182(Never),
V183(Never),
V184(Never),
V185(Never),
V186(Never),
V187(Never),
V188(Never),
V189(Never),
V190(Never),
V191(Never),
V192(Never),
V193(Never),
V194(Never),
V195(Never),
V196(Never),
V197(Never),
V198(Never),
V199(Never),
V200(Never),
V201(Never),
V202(Never),
V203(Never),
V204(Never),
V205(Never),
V206(Never),
V207(Never),
V208(Never),
V209(Never),
V210(Never),
V211(Never),
V212(Never),
V213(Never),
V214(Never),
V215(Never),
V216(Never),
V217(Never),
V218(Never),
V219(Never),
V220(Never),
V221(Never),
V222(Never),
V223(Never),
V224(Never),
V225(Never),
V226(Never),
V227(Never),
V228(Never),
V229(Never),
V230(Never),
V231(Never),
V232(Never),
V233(Never),
V234(Never),
V235(Never),
V236(Never),
V237(Never),
V238(Never),
V239(Never),
V240(Never),
V241(Never),
V242(Never),
V243(Never),
V244(Never),
V245(Never),
V246(Never),
V247(Never),
V248(Never),
V249(Never),
V250(Never),
V251(Never),
V252(Never),
V253(Never),
V254(Never),
V255(Never),
V256(Never),
Possible257,
Bool258(bool),
Possible259,
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3
// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1
// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257
// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258
// CHECK-NEXT: switch i64 %[[DISCR]],
// CHECK-NEXT: i64 257,
// CHECK-NEXT: i64 258,
// CHECK-NEXT: i64 259,
#[no_mangle]
pub fn match5(e: HugeVariantIndex) -> u8 {
use HugeVariantIndex::*;
match e {
Possible257 => 13,
Bool258(b) => b as u8,
Possible259 => 100,
}
}