Skip to content

Commit 40db498

Browse files
authored
Rollup merge of rust-lang#146791 - folkertdev:readonly-not-pure, r=nikic,joshtriplett
emit attribute for readonly non-pure inline assembly fixes rust-lang#146761 Provide a better `MemoryEffects` to LLVM when an inline assembly block specifies `readonly` but not `pure`. That means that the assembly block may not perform any writes, but that there still may be side effects from its instructions. I haven't been able to find a case yet where this actually matters, though. So the test checks that the right attribute is applied, but the generated assembly is equivalent to not specifying `readonly` at all. r? ````@nikic```` cc ````@Amanieu````
2 parents d144638 + 3565b06 commit 40db498

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

compiler/rustc_codegen_llvm/src/asm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
340340
attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
341341
} else if options.contains(InlineAsmOptions::NOMEM) {
342342
attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
343-
} else {
344-
// LLVM doesn't have an attribute to represent ReadOnly + SideEffect
343+
} else if options.contains(InlineAsmOptions::READONLY) {
344+
attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx));
345345
}
346346
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
347347

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ pub(crate) enum MemoryEffects {
710710
None,
711711
ReadOnly,
712712
InaccessibleMemOnly,
713+
ReadOnlyNotPure,
713714
}
714715

715716
/// LLVMOpcode

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ enum class LLVMRustMemoryEffects {
553553
None,
554554
ReadOnly,
555555
InaccessibleMemOnly,
556+
ReadOnlyNotPure,
556557
};
557558

558559
extern "C" LLVMAttributeRef
@@ -568,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C,
568569
case LLVMRustMemoryEffects::InaccessibleMemOnly:
569570
return wrap(Attribute::getWithMemoryEffects(
570571
*unwrap(C), MemoryEffects::inaccessibleMemOnly()));
572+
case LLVMRustMemoryEffects::ReadOnlyNotPure:
573+
return wrap(Attribute::getWithMemoryEffects(
574+
*unwrap(C),
575+
MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly()));
571576
default:
572577
report_fatal_error("bad MemoryEffects.");
573578
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//@ add-core-stubs
2+
//@ compile-flags: -Copt-level=3 --target x86_64-unknown-linux-gnu
3+
//@ needs-llvm-components: x86
4+
5+
#![crate_type = "rlib"]
6+
#![feature(no_core)]
7+
#![no_core]
8+
9+
// Test that when an inline assembly block specifies `readonly` but not `pure`, a detailed
10+
// `MemoryEffects` is provided to LLVM: this assembly block is not allowed to perform writes,
11+
// but it may have side-effects.
12+
13+
extern crate minicore;
14+
use minicore::*;
15+
16+
pub static mut VAR: i32 = 0;
17+
18+
// CHECK-LABEL: @no_options
19+
// CHECK: call i32 asm
20+
#[no_mangle]
21+
pub unsafe fn no_options() -> i32 {
22+
VAR = 1;
23+
let _ignored: i32;
24+
asm!("mov {0}, 1", out(reg) _ignored);
25+
VAR
26+
}
27+
28+
// CHECK-LABEL: @readonly_pure
29+
// CHECK-NOT: call i32 asm
30+
#[no_mangle]
31+
pub unsafe fn readonly_pure() -> i32 {
32+
VAR = 1;
33+
let _ignored: i32;
34+
asm!("mov {0}, 1", out(reg) _ignored, options(pure, readonly));
35+
VAR
36+
}
37+
38+
// CHECK-LABEL: @readonly_not_pure
39+
// CHECK: call i32 asm {{.*}} #[[ATTR:[0-9]+]]
40+
#[no_mangle]
41+
pub unsafe fn readonly_not_pure() -> i32 {
42+
VAR = 1;
43+
let _ignored: i32;
44+
asm!("mov {0}, 1", out(reg) _ignored, options(readonly));
45+
VAR
46+
}
47+
48+
// CHECK: attributes #[[ATTR]] = { nounwind memory(read, inaccessiblemem: readwrite) }

0 commit comments

Comments
 (0)