blob: 091c4e9adf49b0694779d746b2094955ae03b9c7 [file] [log] [blame]
//@ 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, // tag 2
B, // tag 3
C(bool), // untagged
D, // tag 5
E, // tag 6
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %0, 4
// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// 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, // tag 2
Bool258(bool), // untagged
Possible259, // tag 4
}
// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %0, 3
// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
// 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: %[[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,
}
}