about summary refs log tree commit diff
path: root/tests/codegen-llvm/enum/enum-match.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen-llvm/enum/enum-match.rs')
-rw-r--r--tests/codegen-llvm/enum/enum-match.rs779
1 files changed, 779 insertions, 0 deletions
diff --git a/tests/codegen-llvm/enum/enum-match.rs b/tests/codegen-llvm/enum/enum-match.rs
new file mode 100644
index 00000000000..57db44ec74e
--- /dev/null
+++ b/tests/codegen-llvm/enum/enum-match.rs
@@ -0,0 +1,779 @@
+//@ 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{{( samesign)?}} ugt i8 %0, 1
+// 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: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]]
+// 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: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2
+// CHECK-NEXT: ret i1 %[[IS_C]]
+#[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{{( samesign)?}} ugt i8 %0, 1
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// 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,
+    }
+}
+
+// Make an enum where the niche tags wrap both as signed and as unsigned, to hit
+// the most-fallback case where there's just nothing smart to do.
+
+pub enum E10Through65 {
+    D10 = 10,
+    D11 = 11,
+    D12 = 12,
+    D13 = 13,
+    D14 = 14,
+    D15 = 15,
+    D16 = 16,
+    D17 = 17,
+    D18 = 18,
+    D19 = 19,
+    D20 = 20,
+    D21 = 21,
+    D22 = 22,
+    D23 = 23,
+    D24 = 24,
+    D25 = 25,
+    D26 = 26,
+    D27 = 27,
+    D28 = 28,
+    D29 = 29,
+    D30 = 30,
+    D31 = 31,
+    D32 = 32,
+    D33 = 33,
+    D34 = 34,
+    D35 = 35,
+    D36 = 36,
+    D37 = 37,
+    D38 = 38,
+    D39 = 39,
+    D40 = 40,
+    D41 = 41,
+    D42 = 42,
+    D43 = 43,
+    D44 = 44,
+    D45 = 45,
+    D46 = 46,
+    D47 = 47,
+    D48 = 48,
+    D49 = 49,
+    D50 = 50,
+    D51 = 51,
+    D52 = 52,
+    D53 = 53,
+    D54 = 54,
+    D55 = 55,
+    D56 = 56,
+    D57 = 57,
+    D58 = 58,
+    D59 = 59,
+    D60 = 60,
+    D61 = 61,
+    D62 = 62,
+    D63 = 63,
+    D64 = 64,
+    D65 = 65,
+}
+
+pub enum Tricky {
+    Untagged(E10Through65),
+    V001,
+    V002,
+    V003,
+    V004,
+    V005,
+    V006,
+    V007,
+    V008,
+    V009,
+    V010,
+    V011,
+    V012,
+    V013,
+    V014,
+    V015,
+    V016,
+    V017,
+    V018,
+    V019,
+    V020,
+    V021,
+    V022,
+    V023,
+    V024,
+    V025,
+    V026,
+    V027,
+    V028,
+    V029,
+    V030,
+    V031,
+    V032,
+    V033,
+    V034,
+    V035,
+    V036,
+    V037,
+    V038,
+    V039,
+    V040,
+    V041,
+    V042,
+    V043,
+    V044,
+    V045,
+    V046,
+    V047,
+    V048,
+    V049,
+    V050,
+    V051,
+    V052,
+    V053,
+    V054,
+    V055,
+    V056,
+    V057,
+    V058,
+    V059,
+    V060,
+    V061,
+    V062,
+    V063,
+    V064,
+    V065,
+    V066,
+    V067,
+    V068,
+    V069,
+    V070,
+    V071,
+    V072,
+    V073,
+    V074,
+    V075,
+    V076,
+    V077,
+    V078,
+    V079,
+    V080,
+    V081,
+    V082,
+    V083,
+    V084,
+    V085,
+    V086,
+    V087,
+    V088,
+    V089,
+    V090,
+    V091,
+    V092,
+    V093,
+    V094,
+    V095,
+    V096,
+    V097,
+    V098,
+    V099,
+    V100,
+    V101,
+    V102,
+    V103,
+    V104,
+    V105,
+    V106,
+    V107,
+    V108,
+    V109,
+    V110,
+    V111,
+    V112,
+    V113,
+    V114,
+    V115,
+    V116,
+    V117,
+    V118,
+    V119,
+    V120,
+    V121,
+    V122,
+    V123,
+    V124,
+    V125,
+    V126,
+    V127,
+    V128,
+    V129,
+    V130,
+    V131,
+    V132,
+    V133,
+    V134,
+    V135,
+    V136,
+    V137,
+    V138,
+    V139,
+    V140,
+    V141,
+    V142,
+    V143,
+    V144,
+    V145,
+    V146,
+    V147,
+    V148,
+    V149,
+    V150,
+    V151,
+    V152,
+    V153,
+    V154,
+    V155,
+    V156,
+    V157,
+    V158,
+    V159,
+    V160,
+    V161,
+    V162,
+    V163,
+    V164,
+    V165,
+    V166,
+    V167,
+    V168,
+    V169,
+    V170,
+    V171,
+    V172,
+    V173,
+    V174,
+    V175,
+    V176,
+    V177,
+    V178,
+    V179,
+    V180,
+    V181,
+    V182,
+    V183,
+    V184,
+    V185,
+    V186,
+    V187,
+    V188,
+    V189,
+    V190,
+    V191,
+    V192,
+    V193,
+    V194,
+    V195,
+    V196,
+    V197,
+    V198,
+    V199,
+    V200,
+}
+
+const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100);
+
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56
+// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0
+// CHECK-NEXT: ret i8 %[[DISCR]]
+#[no_mangle]
+pub fn discriminant6(e: Tricky) -> u8 {
+    std::intrinsics::discriminant_value(&e) as _
+}
+
+// Case from <https://github.com/rust-lang/rust/issues/104519>,
+// where sign-extension is important.
+
+pub enum OpenResult {
+    Ok(()),
+    Err(()),
+    TransportErr(TransportErr),
+}
+
+#[repr(i32)]
+pub enum TransportErr {
+    UnknownMethod = -2,
+}
+
+#[no_mangle]
+pub fn match7(result: OpenResult) -> u8 {
+    // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1
+    // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8
+    // CHECK-NEXT: ret i8 %[[RET]]
+    match result {
+        OpenResult::Ok(()) => 0,
+        _ => 1,
+    }
+}