Skip to content

Commit d25910e

Browse files
committed
make prefetch intrinsics safe
1 parent 51df7aa commit d25910e

File tree

5 files changed

+70
-72
lines changed

5 files changed

+70
-72
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
330330
_ => bug!(),
331331
};
332332
let ptr = args[0].immediate();
333+
let locality = fn_args.const_at(1).to_value().valtree.unwrap_leaf().to_u32() as i32;
333334
self.call_intrinsic(
334335
"llvm.prefetch",
335336
&[self.val_ty(ptr)],
336-
&[ptr, self.const_i32(rw), args[1].immediate(), self.const_i32(cache_type)],
337+
&[
338+
ptr,
339+
self.const_i32(rw),
340+
self.const_i32(locality),
341+
self.const_i32(cache_type),
342+
],
337343
)
338344
}
339345
sym::carrying_mul_add => {

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
136136
| sym::round_ties_even_f64
137137
| sym::round_ties_even_f128
138138
| sym::autodiff
139+
| sym::prefetch_read_data
140+
| sym::prefetch_write_data
141+
| sym::prefetch_read_instruction
142+
| sym::prefetch_write_instruction
139143
| sym::const_eval_select => hir::Safety::Safe,
140144
_ => hir::Safety::Unsafe,
141145
};
@@ -218,7 +222,7 @@ pub(crate) fn check_intrinsic_type(
218222
| sym::prefetch_write_data
219223
| sym::prefetch_read_instruction
220224
| sym::prefetch_write_instruction => {
221-
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], tcx.types.unit)
225+
(1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.unit)
222226
}
223227
sym::needs_drop => (1, 0, vec![], tcx.types.bool),
224228

library/core/src/intrinsics/mod.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -265,71 +265,67 @@ pub unsafe fn atomic_singlethreadfence<const ORD: AtomicOrdering>();
265265
/// Prefetches have no effect on the behavior of the program but can change its performance
266266
/// characteristics.
267267
///
268-
/// The `locality` argument must be a constant integer and is a temporal locality specifier
269-
/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
268+
/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
269+
/// to (3) - extremely local keep in cache.
270270
///
271271
/// This intrinsic does not have a stable counterpart.
272272
#[rustc_intrinsic]
273273
#[rustc_nounwind]
274274
#[miri::intrinsic_fallback_is_spec]
275-
pub unsafe fn prefetch_read_data<T>(data: *const T, locality: i32) {
275+
pub const fn prefetch_read_data<T, const LOCALITY: i32>(data: *const T) {
276276
// This operation is a no-op, unless it is overridden by the backend.
277277
let _ = data;
278-
let _ = locality;
279278
}
280279

281280
/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
282281
/// for the given address if supported; otherwise, it is a no-op.
283282
/// Prefetches have no effect on the behavior of the program but can change its performance
284283
/// characteristics.
285284
///
286-
/// The `locality` argument must be a constant integer and is a temporal locality specifier
287-
/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
285+
/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
286+
/// to (3) - extremely local keep in cache.
288287
///
289288
/// This intrinsic does not have a stable counterpart.
290289
#[rustc_intrinsic]
291290
#[rustc_nounwind]
292291
#[miri::intrinsic_fallback_is_spec]
293-
pub unsafe fn prefetch_write_data<T>(data: *const T, locality: i32) {
292+
pub const fn prefetch_write_data<T, const LOCALITY: i32>(data: *const T) {
294293
// This operation is a no-op, unless it is overridden by the backend.
295294
let _ = data;
296-
let _ = locality;
297295
}
298296

299297
/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
300298
/// for the given address if supported; otherwise, it is a no-op.
301299
/// Prefetches have no effect on the behavior of the program but can change its performance
302300
/// characteristics.
303301
///
304-
/// The `locality` argument must be a constant integer and is a temporal locality specifier
305-
/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
302+
/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
303+
/// to (3) - extremely local keep in cache.
306304
///
307305
/// This intrinsic does not have a stable counterpart.
308306
#[rustc_intrinsic]
309307
#[rustc_nounwind]
310308
#[miri::intrinsic_fallback_is_spec]
311-
pub unsafe fn prefetch_read_instruction<T>(data: *const T, locality: i32) {
309+
pub const fn prefetch_read_instruction<T, const LOCALITY: i32>(data: *const T) {
312310
// This operation is a no-op, unless it is overridden by the backend.
313311
let _ = data;
314-
let _ = locality;
315312
}
316313

317314
/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
318315
/// for the given address if supported; otherwise, it is a no-op.
319316
/// Prefetches have no effect on the behavior of the program but can change its performance
320317
/// characteristics.
321318
///
322-
/// The `locality` argument must be a constant integer and is a temporal locality specifier
323-
/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
319+
/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
320+
/// to (3) - extremely local keep in cache.
324321
///
325322
/// This intrinsic does not have a stable counterpart.
326323
#[rustc_intrinsic]
327324
#[rustc_nounwind]
328325
#[miri::intrinsic_fallback_is_spec]
329-
pub unsafe fn prefetch_write_instruction<T>(data: *const T, locality: i32) {
326+
pub const fn prefetch_write_instruction<T, const LOCALITY: i32>(data: *const T) {
330327
// This operation is a no-op, unless it is overridden by the backend.
331328
let _ = data;
332-
let _ = locality;
333329
}
334330

335331
/// Executes a breakpoint trap, for inspection by a debugger.

src/tools/miri/tests/pass/prefetch.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
#![feature(core_intrinsics)]
22

3+
// Test that these intrinsics work. Their behavior should be a no-op.
4+
35
fn main() {
46
static X: [u8; 8] = [0; 8];
57

6-
unsafe {
7-
::std::intrinsics::prefetch_read_data(::std::ptr::null::<u8>(), 1);
8-
::std::intrinsics::prefetch_read_data(::std::ptr::dangling::<u8>(), 2);
9-
::std::intrinsics::prefetch_read_data(X.as_ptr(), 3);
8+
::std::intrinsics::prefetch_read_data::<_, 1>(::std::ptr::null::<u8>());
9+
::std::intrinsics::prefetch_read_data::<_, 2>(::std::ptr::dangling::<u8>());
10+
::std::intrinsics::prefetch_read_data::<_, 3>(X.as_ptr());
1011

11-
::std::intrinsics::prefetch_write_data(::std::ptr::null::<u8>(), 1);
12-
::std::intrinsics::prefetch_write_data(::std::ptr::dangling::<u8>(), 2);
13-
::std::intrinsics::prefetch_write_data(X.as_ptr(), 3);
12+
::std::intrinsics::prefetch_write_data::<_, 1>(::std::ptr::null::<u8>());
13+
::std::intrinsics::prefetch_write_data::<_, 2>(::std::ptr::dangling::<u8>());
14+
::std::intrinsics::prefetch_write_data::<_, 3>(X.as_ptr());
1415

15-
::std::intrinsics::prefetch_read_instruction(::std::ptr::null::<u8>(), 1);
16-
::std::intrinsics::prefetch_read_instruction(::std::ptr::dangling::<u8>(), 2);
17-
::std::intrinsics::prefetch_read_instruction(X.as_ptr(), 3);
16+
::std::intrinsics::prefetch_read_instruction::<_, 1>(::std::ptr::null::<u8>());
17+
::std::intrinsics::prefetch_read_instruction::<_, 2>(::std::ptr::dangling::<u8>());
18+
::std::intrinsics::prefetch_read_instruction::<_, 3>(X.as_ptr());
1819

19-
::std::intrinsics::prefetch_write_instruction(::std::ptr::null::<u8>(), 1);
20-
::std::intrinsics::prefetch_write_instruction(::std::ptr::dangling::<u8>(), 2);
21-
::std::intrinsics::prefetch_write_instruction(X.as_ptr(), 3);
22-
}
20+
::std::intrinsics::prefetch_write_instruction::<_, 1>(::std::ptr::null::<u8>());
21+
::std::intrinsics::prefetch_write_instruction::<_, 2>(::std::ptr::dangling::<u8>());
22+
::std::intrinsics::prefetch_write_instruction::<_, 3>(X.as_ptr());
2323
}

tests/codegen-llvm/intrinsics/prefetch.rs

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,48 @@ use std::intrinsics::{
99

1010
#[no_mangle]
1111
pub fn check_prefetch_read_data(data: &[i8]) {
12-
unsafe {
13-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1)
14-
prefetch_read_data(data.as_ptr(), 0);
15-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1)
16-
prefetch_read_data(data.as_ptr(), 1);
17-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1)
18-
prefetch_read_data(data.as_ptr(), 2);
19-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1)
20-
prefetch_read_data(data.as_ptr(), 3);
21-
}
12+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1)
13+
prefetch_read_data::<_, 0>(data.as_ptr());
14+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1)
15+
prefetch_read_data::<_, 1>(data.as_ptr());
16+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1)
17+
prefetch_read_data::<_, 2>(data.as_ptr());
18+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1)
19+
prefetch_read_data::<_, 3>(data.as_ptr());
2220
}
2321

2422
#[no_mangle]
2523
pub fn check_prefetch_write_data(data: &[i8]) {
26-
unsafe {
27-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1)
28-
prefetch_write_data(data.as_ptr(), 0);
29-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1)
30-
prefetch_write_data(data.as_ptr(), 1);
31-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1)
32-
prefetch_write_data(data.as_ptr(), 2);
33-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1)
34-
prefetch_write_data(data.as_ptr(), 3);
35-
}
24+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1)
25+
prefetch_write_data::<_, 0>(data.as_ptr());
26+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1)
27+
prefetch_write_data::<_, 1>(data.as_ptr());
28+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1)
29+
prefetch_write_data::<_, 2>(data.as_ptr());
30+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1)
31+
prefetch_write_data::<_, 3>(data.as_ptr());
3632
}
3733

3834
#[no_mangle]
3935
pub fn check_prefetch_read_instruction(data: &[i8]) {
40-
unsafe {
41-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0)
42-
prefetch_read_instruction(data.as_ptr(), 0);
43-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0)
44-
prefetch_read_instruction(data.as_ptr(), 1);
45-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0)
46-
prefetch_read_instruction(data.as_ptr(), 2);
47-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0)
48-
prefetch_read_instruction(data.as_ptr(), 3);
49-
}
36+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0)
37+
prefetch_read_instruction::<_, 0>(data.as_ptr());
38+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0)
39+
prefetch_read_instruction::<_, 1>(data.as_ptr());
40+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0)
41+
prefetch_read_instruction::<_, 2>(data.as_ptr());
42+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0)
43+
prefetch_read_instruction::<_, 3>(data.as_ptr());
5044
}
5145

5246
#[no_mangle]
5347
pub fn check_prefetch_write_instruction(data: &[i8]) {
54-
unsafe {
55-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0)
56-
prefetch_write_instruction(data.as_ptr(), 0);
57-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0)
58-
prefetch_write_instruction(data.as_ptr(), 1);
59-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0)
60-
prefetch_write_instruction(data.as_ptr(), 2);
61-
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0)
62-
prefetch_write_instruction(data.as_ptr(), 3);
63-
}
48+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0)
49+
prefetch_write_instruction::<_, 0>(data.as_ptr());
50+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0)
51+
prefetch_write_instruction::<_, 1>(data.as_ptr());
52+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0)
53+
prefetch_write_instruction::<_, 2>(data.as_ptr());
54+
// CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0)
55+
prefetch_write_instruction::<_, 3>(data.as_ptr());
6456
}

0 commit comments

Comments
 (0)