Skip to content

Commit

Permalink
Auto merge of #15119 - HKalbasi:mir, r=HKalbasi
Browse files Browse the repository at this point in the history
Support more intrinsics in mir interpreter

Increases passed tests on self from 49 to 52
  • Loading branch information
bors committed Jun 23, 2023
2 parents 246d11b + 5eb4796 commit 06b99d4
Show file tree
Hide file tree
Showing 6 changed files with 493 additions and 60 deletions.
134 changes: 133 additions & 1 deletion crates/hir-ty/src/consteval/tests/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,66 @@ fn size_of() {
);
}

#[test]
fn size_of_val() {
check_number(
r#"
//- minicore: coerce_unsized
extern "rust-intrinsic" {
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X(i32, u8);
const GOAL: usize = size_of_val(&X(1, 2));
"#,
8,
);
check_number(
r#"
//- minicore: coerce_unsized
extern "rust-intrinsic" {
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = {
let x: &[i32] = &[1, 2, 3];
size_of_val(x)
};
"#,
12,
);
check_number(
r#"
//- minicore: coerce_unsized, fmt, builtin_impls
extern "rust-intrinsic" {
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = {
let x: &i16 = &5;
let y: &dyn core::fmt::Debug = x;
let z: &dyn core::fmt::Debug = &y;
size_of_val(x) + size_of_val(y) * 10 + size_of_val(z) * 100
};
"#,
1622,
);
check_number(
r#"
//- minicore: coerce_unsized
extern "rust-intrinsic" {
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = {
size_of_val("salam")
};
"#,
5,
);
}

#[test]
fn transmute() {
check_number(
Expand Down Expand Up @@ -69,7 +129,7 @@ fn wrapping_add() {
}

#[test]
fn saturating_add() {
fn saturating() {
check_number(
r#"
extern "rust-intrinsic" {
Expand All @@ -80,6 +140,16 @@ fn saturating_add() {
"#,
255,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn saturating_sub<T>(a: T, b: T) -> T;
}
const GOAL: bool = saturating_sub(5u8, 7) == 0 && saturating_sub(8u8, 4) == 4;
"#,
1,
);
check_number(
r#"
extern "rust-intrinsic" {
Expand Down Expand Up @@ -160,6 +230,24 @@ fn needs_drop() {
);
}

#[test]
fn discriminant_value() {
check_number(
r#"
//- minicore: discriminant, option
use core::marker::DiscriminantKind;
extern "rust-intrinsic" {
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
}
const GOAL: bool = {
discriminant_value(&Some(2i32)) == discriminant_value(&Some(5i32))
&& discriminant_value(&Some(2i32)) != discriminant_value(&None::<i32>)
};
"#,
1,
);
}

#[test]
fn likely() {
check_number(
Expand Down Expand Up @@ -376,3 +464,47 @@ fn cttz() {
3,
);
}

#[test]
fn rotate() {
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i64 = rotate_left(0xaa00000000006e1i64, 12);
"#,
0x6e10aa,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i64 = rotate_right(0x6e10aa, 12);
"#,
0xaa00000000006e1,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i8 = rotate_left(129, 2);
"#,
6,
);
check_number(
r#"
extern "rust-intrinsic" {
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i32 = rotate_right(10006016, 1020315);
"#,
320192512,
);
}
107 changes: 56 additions & 51 deletions crates/hir-ty/src/mir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,57 +1049,8 @@ impl Evaluator<'_> {
Rvalue::Discriminant(p) => {
let ty = self.place_ty(p, locals)?;
let bytes = self.eval_place(p, locals)?.get(&self)?;
let layout = self.layout(&ty)?;
let enum_id = 'b: {
match ty.kind(Interner) {
TyKind::Adt(e, _) => match e.0 {
AdtId::EnumId(e) => break 'b e,
_ => (),
},
_ => (),
}
return Ok(Owned(0u128.to_le_bytes().to_vec()));
};
match &layout.variants {
Variants::Single { index } => {
let r = self.const_eval_discriminant(EnumVariantId {
parent: enum_id,
local_id: index.0,
})?;
Owned(r.to_le_bytes().to_vec())
}
Variants::Multiple { tag, tag_encoding, variants, .. } => {
let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else {
not_supported!("missing target data layout");
};
let size = tag.size(&*target_data_layout).bytes_usize();
let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
match tag_encoding {
TagEncoding::Direct => {
let tag = &bytes[offset..offset + size];
Owned(pad16(tag, false).to_vec())
}
TagEncoding::Niche { untagged_variant, niche_start, .. } => {
let tag = &bytes[offset..offset + size];
let candidate_tag = i128::from_le_bytes(pad16(tag, false))
.wrapping_sub(*niche_start as i128)
as usize;
let variant = variants
.iter_enumerated()
.map(|(x, _)| x)
.filter(|x| x != untagged_variant)
.nth(candidate_tag)
.unwrap_or(*untagged_variant)
.0;
let result = self.const_eval_discriminant(EnumVariantId {
parent: enum_id,
local_id: variant,
})?;
Owned(result.to_le_bytes().to_vec())
}
}
}
}
let result = self.compute_discriminant(ty, bytes)?;
Owned(result.to_le_bytes().to_vec())
}
Rvalue::Repeat(x, len) => {
let len = match try_const_usize(self.db, &len) {
Expand Down Expand Up @@ -1229,6 +1180,60 @@ impl Evaluator<'_> {
})
}

fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result<i128> {
let layout = self.layout(&ty)?;
let enum_id = 'b: {
match ty.kind(Interner) {
TyKind::Adt(e, _) => match e.0 {
AdtId::EnumId(e) => break 'b e,
_ => (),
},
_ => (),
}
return Ok(0);
};
match &layout.variants {
Variants::Single { index } => {
let r = self.const_eval_discriminant(EnumVariantId {
parent: enum_id,
local_id: index.0,
})?;
Ok(r)
}
Variants::Multiple { tag, tag_encoding, variants, .. } => {
let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else {
not_supported!("missing target data layout");
};
let size = tag.size(&*target_data_layout).bytes_usize();
let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
match tag_encoding {
TagEncoding::Direct => {
let tag = &bytes[offset..offset + size];
Ok(i128::from_le_bytes(pad16(tag, false)))
}
TagEncoding::Niche { untagged_variant, niche_start, .. } => {
let tag = &bytes[offset..offset + size];
let candidate_tag = i128::from_le_bytes(pad16(tag, false))
.wrapping_sub(*niche_start as i128)
as usize;
let variant = variants
.iter_enumerated()
.map(|(x, _)| x)
.filter(|x| x != untagged_variant)
.nth(candidate_tag)
.unwrap_or(*untagged_variant)
.0;
let result = self.const_eval_discriminant(EnumVariantId {
parent: enum_id,
local_id: variant,
})?;
Ok(result)
}
}
}
}
}

fn coerce_unsized_look_through_fields<T>(
&self,
ty: &Ty,
Expand Down

0 comments on commit 06b99d4

Please sign in to comment.