Skip to content

Commit 06b99d4

Browse files
committed
Auto merge of #15119 - HKalbasi:mir, r=HKalbasi
Support more intrinsics in mir interpreter Increases passed tests on self from 49 to 52
2 parents 246d11b + 5eb4796 commit 06b99d4

File tree

6 files changed

+493
-60
lines changed

6 files changed

+493
-60
lines changed

crates/hir-ty/src/consteval/tests/intrinsics.rs

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,66 @@ fn size_of() {
1414
);
1515
}
1616

17+
#[test]
18+
fn size_of_val() {
19+
check_number(
20+
r#"
21+
//- minicore: coerce_unsized
22+
extern "rust-intrinsic" {
23+
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
24+
}
25+
26+
struct X(i32, u8);
27+
28+
const GOAL: usize = size_of_val(&X(1, 2));
29+
"#,
30+
8,
31+
);
32+
check_number(
33+
r#"
34+
//- minicore: coerce_unsized
35+
extern "rust-intrinsic" {
36+
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
37+
}
38+
39+
const GOAL: usize = {
40+
let x: &[i32] = &[1, 2, 3];
41+
size_of_val(x)
42+
};
43+
"#,
44+
12,
45+
);
46+
check_number(
47+
r#"
48+
//- minicore: coerce_unsized, fmt, builtin_impls
49+
extern "rust-intrinsic" {
50+
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
51+
}
52+
53+
const GOAL: usize = {
54+
let x: &i16 = &5;
55+
let y: &dyn core::fmt::Debug = x;
56+
let z: &dyn core::fmt::Debug = &y;
57+
size_of_val(x) + size_of_val(y) * 10 + size_of_val(z) * 100
58+
};
59+
"#,
60+
1622,
61+
);
62+
check_number(
63+
r#"
64+
//- minicore: coerce_unsized
65+
extern "rust-intrinsic" {
66+
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
67+
}
68+
69+
const GOAL: usize = {
70+
size_of_val("salam")
71+
};
72+
"#,
73+
5,
74+
);
75+
}
76+
1777
#[test]
1878
fn transmute() {
1979
check_number(
@@ -69,7 +129,7 @@ fn wrapping_add() {
69129
}
70130

71131
#[test]
72-
fn saturating_add() {
132+
fn saturating() {
73133
check_number(
74134
r#"
75135
extern "rust-intrinsic" {
@@ -80,6 +140,16 @@ fn saturating_add() {
80140
"#,
81141
255,
82142
);
143+
check_number(
144+
r#"
145+
extern "rust-intrinsic" {
146+
pub fn saturating_sub<T>(a: T, b: T) -> T;
147+
}
148+
149+
const GOAL: bool = saturating_sub(5u8, 7) == 0 && saturating_sub(8u8, 4) == 4;
150+
"#,
151+
1,
152+
);
83153
check_number(
84154
r#"
85155
extern "rust-intrinsic" {
@@ -160,6 +230,24 @@ fn needs_drop() {
160230
);
161231
}
162232

233+
#[test]
234+
fn discriminant_value() {
235+
check_number(
236+
r#"
237+
//- minicore: discriminant, option
238+
use core::marker::DiscriminantKind;
239+
extern "rust-intrinsic" {
240+
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
241+
}
242+
const GOAL: bool = {
243+
discriminant_value(&Some(2i32)) == discriminant_value(&Some(5i32))
244+
&& discriminant_value(&Some(2i32)) != discriminant_value(&None::<i32>)
245+
};
246+
"#,
247+
1,
248+
);
249+
}
250+
163251
#[test]
164252
fn likely() {
165253
check_number(
@@ -376,3 +464,47 @@ fn cttz() {
376464
3,
377465
);
378466
}
467+
468+
#[test]
469+
fn rotate() {
470+
check_number(
471+
r#"
472+
extern "rust-intrinsic" {
473+
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
474+
}
475+
476+
const GOAL: i64 = rotate_left(0xaa00000000006e1i64, 12);
477+
"#,
478+
0x6e10aa,
479+
);
480+
check_number(
481+
r#"
482+
extern "rust-intrinsic" {
483+
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
484+
}
485+
486+
const GOAL: i64 = rotate_right(0x6e10aa, 12);
487+
"#,
488+
0xaa00000000006e1,
489+
);
490+
check_number(
491+
r#"
492+
extern "rust-intrinsic" {
493+
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
494+
}
495+
496+
const GOAL: i8 = rotate_left(129, 2);
497+
"#,
498+
6,
499+
);
500+
check_number(
501+
r#"
502+
extern "rust-intrinsic" {
503+
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
504+
}
505+
506+
const GOAL: i32 = rotate_right(10006016, 1020315);
507+
"#,
508+
320192512,
509+
);
510+
}

crates/hir-ty/src/mir/eval.rs

Lines changed: 56 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,57 +1049,8 @@ impl Evaluator<'_> {
10491049
Rvalue::Discriminant(p) => {
10501050
let ty = self.place_ty(p, locals)?;
10511051
let bytes = self.eval_place(p, locals)?.get(&self)?;
1052-
let layout = self.layout(&ty)?;
1053-
let enum_id = 'b: {
1054-
match ty.kind(Interner) {
1055-
TyKind::Adt(e, _) => match e.0 {
1056-
AdtId::EnumId(e) => break 'b e,
1057-
_ => (),
1058-
},
1059-
_ => (),
1060-
}
1061-
return Ok(Owned(0u128.to_le_bytes().to_vec()));
1062-
};
1063-
match &layout.variants {
1064-
Variants::Single { index } => {
1065-
let r = self.const_eval_discriminant(EnumVariantId {
1066-
parent: enum_id,
1067-
local_id: index.0,
1068-
})?;
1069-
Owned(r.to_le_bytes().to_vec())
1070-
}
1071-
Variants::Multiple { tag, tag_encoding, variants, .. } => {
1072-
let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else {
1073-
not_supported!("missing target data layout");
1074-
};
1075-
let size = tag.size(&*target_data_layout).bytes_usize();
1076-
let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
1077-
match tag_encoding {
1078-
TagEncoding::Direct => {
1079-
let tag = &bytes[offset..offset + size];
1080-
Owned(pad16(tag, false).to_vec())
1081-
}
1082-
TagEncoding::Niche { untagged_variant, niche_start, .. } => {
1083-
let tag = &bytes[offset..offset + size];
1084-
let candidate_tag = i128::from_le_bytes(pad16(tag, false))
1085-
.wrapping_sub(*niche_start as i128)
1086-
as usize;
1087-
let variant = variants
1088-
.iter_enumerated()
1089-
.map(|(x, _)| x)
1090-
.filter(|x| x != untagged_variant)
1091-
.nth(candidate_tag)
1092-
.unwrap_or(*untagged_variant)
1093-
.0;
1094-
let result = self.const_eval_discriminant(EnumVariantId {
1095-
parent: enum_id,
1096-
local_id: variant,
1097-
})?;
1098-
Owned(result.to_le_bytes().to_vec())
1099-
}
1100-
}
1101-
}
1102-
}
1052+
let result = self.compute_discriminant(ty, bytes)?;
1053+
Owned(result.to_le_bytes().to_vec())
11031054
}
11041055
Rvalue::Repeat(x, len) => {
11051056
let len = match try_const_usize(self.db, &len) {
@@ -1229,6 +1180,60 @@ impl Evaluator<'_> {
12291180
})
12301181
}
12311182

1183+
fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result<i128> {
1184+
let layout = self.layout(&ty)?;
1185+
let enum_id = 'b: {
1186+
match ty.kind(Interner) {
1187+
TyKind::Adt(e, _) => match e.0 {
1188+
AdtId::EnumId(e) => break 'b e,
1189+
_ => (),
1190+
},
1191+
_ => (),
1192+
}
1193+
return Ok(0);
1194+
};
1195+
match &layout.variants {
1196+
Variants::Single { index } => {
1197+
let r = self.const_eval_discriminant(EnumVariantId {
1198+
parent: enum_id,
1199+
local_id: index.0,
1200+
})?;
1201+
Ok(r)
1202+
}
1203+
Variants::Multiple { tag, tag_encoding, variants, .. } => {
1204+
let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else {
1205+
not_supported!("missing target data layout");
1206+
};
1207+
let size = tag.size(&*target_data_layout).bytes_usize();
1208+
let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
1209+
match tag_encoding {
1210+
TagEncoding::Direct => {
1211+
let tag = &bytes[offset..offset + size];
1212+
Ok(i128::from_le_bytes(pad16(tag, false)))
1213+
}
1214+
TagEncoding::Niche { untagged_variant, niche_start, .. } => {
1215+
let tag = &bytes[offset..offset + size];
1216+
let candidate_tag = i128::from_le_bytes(pad16(tag, false))
1217+
.wrapping_sub(*niche_start as i128)
1218+
as usize;
1219+
let variant = variants
1220+
.iter_enumerated()
1221+
.map(|(x, _)| x)
1222+
.filter(|x| x != untagged_variant)
1223+
.nth(candidate_tag)
1224+
.unwrap_or(*untagged_variant)
1225+
.0;
1226+
let result = self.const_eval_discriminant(EnumVariantId {
1227+
parent: enum_id,
1228+
local_id: variant,
1229+
})?;
1230+
Ok(result)
1231+
}
1232+
}
1233+
}
1234+
}
1235+
}
1236+
12321237
fn coerce_unsized_look_through_fields<T>(
12331238
&self,
12341239
ty: &Ty,

0 commit comments

Comments
 (0)