Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions tests/codegen-llvm/issues/multiple-option-or-permutations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Tests output of multiple permutations of `Option::or`
//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled

#![crate_type = "lib"]

extern crate core;
use core::num::NonZero;

// CHECK-LABEL: @or_match_u8
// CHECK-SAME: (i1{{.+}}%0, i8 %1, i1{{.+}}%optb.0, i8 %optb.1)
#[no_mangle]
pub fn or_match_u8(opta: Option<u8>, optb: Option<u8>) -> Option<u8> {
// CHECK: start:
// CHECK-DAG: or i1 %0
// CHECK-DAG: select i1 %0
// CHECK-NEXT: insertvalue { i1, i8 }
// CHECK-NEXT: insertvalue { i1, i8 }
// ret { i1, i8 }
match opta {
Some(x) => Some(x),
None => optb,
}
}

// CHECK-LABEL: @or_match_alt_u8
// CHECK-SAME: (i1{{.+}}%opta.0, i8 %opta.1, i1{{.+}}%optb.0, i8 %optb.1)
#[no_mangle]
pub fn or_match_alt_u8(opta: Option<u8>, optb: Option<u8>) -> Option<u8> {
// CHECK: start:
// CHECK-DAG: select i1
// CHECK-DAG: or i1
// CHECK-NEXT: insertvalue { i1, i8 }
// CHECK-NEXT: insertvalue { i1, i8 }
// ret { i1, i8 }
match opta {
Some(_) => opta,
None => optb,
}
}

// CHECK-LABEL: @option_or_u8
// CHECK-SAME: (i1{{.+}}%opta.0, i8 %opta.1, i1{{.+}}%optb.0, i8 %optb.1)
#[no_mangle]
pub fn option_or_u8(opta: Option<u8>, optb: Option<u8>) -> Option<u8> {
// CHECK: start:
// CHECK-DAG: select i1
// CHECK-DAG: or i1
// CHECK-NEXT: insertvalue { i1, i8 }
// CHECK-NEXT: insertvalue { i1, i8 }
// ret { i1, i8 }
opta.or(optb)
}

// CHECK-LABEL: @if_some_u8
// CHECK-SAME: (i1{{.+}}%opta.0, i8 %opta.1, i1{{.+}}%optb.0, i8 %optb.1)
#[no_mangle]
pub fn if_some_u8(opta: Option<u8>, optb: Option<u8>) -> Option<u8> {
// CHECK: start:
// CHECK-DAG: select i1
// CHECK-DAG: or i1
// CHECK-NEXT: insertvalue { i1, i8 }
// CHECK-NEXT: insertvalue { i1, i8 }
// ret { i1, i8 }
if opta.is_some() { opta } else { optb }
}

// Tests a case where an input is a type that is represented as `BackendRepr::Memory`

// CHECK-LABEL: @or_match_slice_u8
// CHECK-SAME: (i16 %0, i16 %1)
#[no_mangle]
pub fn or_match_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> {
// CHECK: start:
// CHECK-NEXT: trunc i16 %0 to i1
// CHECK-NEXT: select i1 %2, i16 %0, i16 %1
// ret i16
match opta {
Some(x) => Some(x),
None => optb,
}
}

// CHECK-LABEL: @or_match_slice_alt_u8
// CHECK-SAME: (i16 %0, i16 %1)
#[no_mangle]
pub fn or_match_slice_alt_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> {
// CHECK: start:
// CHECK-NEXT: trunc i16 %0 to i1
// CHECK-NEXT: select i1 %2, i16 %0, i16 %1
// ret i16
match opta {
Some(_) => opta,
None => optb,
}
}

// CHECK-LABEL: @option_or_slice_u8
// CHECK-SAME: (i16 %0, i16 %1)
#[no_mangle]
pub fn option_or_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> {
// CHECK: start:
// CHECK-NEXT: trunc i16 %0 to i1
// CHECK-NEXT: select i1 %2, i16 %0, i16 %1
// ret i16
opta.or(optb)
}

// CHECK-LABEL: @if_some_slice_u8
// CHECK-SAME: (i16 %0, i16 %1)
#[no_mangle]
pub fn if_some_slice_u8(opta: Option<[u8; 1]>, optb: Option<[u8; 1]>) -> Option<[u8; 1]> {
// CHECK: start:
// CHECK-NEXT: trunc i16 %0 to i1
// CHECK-NEXT: select i1 %2, i16 %0, i16 %1
// ret i16
if opta.is_some() { opta } else { optb }
}

// Test a niche optimization case of `NonZero<u8>`

// CHECK-LABEL: @or_match_nz_u8
// CHECK-SAME: (i8{{.+}}%0, i8{{.+}}%optb)
#[no_mangle]
pub fn or_match_nz_u8(opta: Option<NonZero<u8>>, optb: Option<NonZero<u8>>) -> Option<NonZero<u8>> {
// CHECK: start:
// CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %0, 0
// CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %0
// ret i8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding these! Nice to see the argument names and such too, since it's short so that's not a big deal.

But that ret on its own isn't actually checking anything. How about, instead,

Suggested change
pub fn or_match_nz_u8(opta: Option<NonZero<u8>>, optb: Option<NonZero<u8>>) -> Option<NonZero<u8>> {
// CHECK: start:
// CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %0, 0
// CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %0
// ret i8
pub fn or_match_nz_u8(opta: Option<NonZero<u8>>, optb: Option<NonZero<u8>>) -> Option<NonZero<u8>> {
// CHECK: start:
// CHECK: [[NOT_A:%.+]] = icmp eq i8 %0, 0
// CHECK: [[R:%.+]] = select i1 [[NOT_A]], i8 %optb, i8 %0
// CHECK: ret i8 [[R]]

Since naming the values means that we're not concerned about other things showing up in the middle, and thus don't need to use the -NEXT that the ones looking at just the instructions do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(And of course ditto the others below)

match opta {
Some(x) => Some(x),
None => optb,
}
}

// CHECK-LABEL: @or_match_alt_nz_u8
// CHECK-SAME: (i8{{.+}}%opta, i8{{.+}}%optb)
#[no_mangle]
pub fn or_match_alt_nz_u8(
opta: Option<NonZero<u8>>,
optb: Option<NonZero<u8>>,
) -> Option<NonZero<u8>> {
// CHECK: start:
// CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0
// CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta
// ret i8
match opta {
Some(_) => opta,
None => optb,
}
}

// CHECK-LABEL: @option_or_nz_u8
// CHECK-SAME: (i8{{.+}}%opta, i8{{.+}}%optb)
#[no_mangle]
pub fn option_or_nz_u8(
opta: Option<NonZero<u8>>,
optb: Option<NonZero<u8>>,
) -> Option<NonZero<u8>> {
// CHECK: start:
// CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0
// CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta
// ret i8
opta.or(optb)
}

// CHECK-LABEL: @if_some_nz_u8
// CHECK-SAME: (i8{{.+}}%opta, i8{{.+}}%optb)
#[no_mangle]
pub fn if_some_nz_u8(opta: Option<NonZero<u8>>, optb: Option<NonZero<u8>>) -> Option<NonZero<u8>> {
// CHECK: start:
// CHECK-NEXT: [[NOT_A:%.*]] = icmp eq i8 %opta, 0
// CHECK-NEXT: select i1 [[NOT_A]], i8 %optb, i8 %opta
// ret i8
if opta.is_some() { opta } else { optb }
}
Loading