Skip to content

Commit

Permalink
Support more intrinsics in mir interpreter
Browse files Browse the repository at this point in the history
  • Loading branch information
HKalbasi committed Jun 23, 2023
1 parent 403433a commit 3ed17f0
Show file tree
Hide file tree
Showing 5 changed files with 465 additions and 54 deletions.
114 changes: 113 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,27 @@ 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,
);
}
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 3ed17f0

Please sign in to comment.