emit attribute for readonly non-pure inline assembly

This commit is contained in:
Folkert de Vries 2025-09-19 20:39:47 +02:00
parent 1d23da6b73
commit 3565b0699d
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
4 changed files with 56 additions and 2 deletions

View file

@ -340,8 +340,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
} else if options.contains(InlineAsmOptions::NOMEM) {
attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
} else {
// LLVM doesn't have an attribute to represent ReadOnly + SideEffect
} else if options.contains(InlineAsmOptions::READONLY) {
attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx));
}
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });

View file

@ -710,6 +710,7 @@ pub(crate) enum MemoryEffects {
None,
ReadOnly,
InaccessibleMemOnly,
ReadOnlyNotPure,
}
/// LLVMOpcode

View file

@ -553,6 +553,7 @@ enum class LLVMRustMemoryEffects {
None,
ReadOnly,
InaccessibleMemOnly,
ReadOnlyNotPure,
};
extern "C" LLVMAttributeRef
@ -568,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C,
case LLVMRustMemoryEffects::InaccessibleMemOnly:
return wrap(Attribute::getWithMemoryEffects(
*unwrap(C), MemoryEffects::inaccessibleMemOnly()));
case LLVMRustMemoryEffects::ReadOnlyNotPure:
return wrap(Attribute::getWithMemoryEffects(
*unwrap(C),
MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly()));
default:
report_fatal_error("bad MemoryEffects.");
}

View file

@ -0,0 +1,48 @@
//@ add-core-stubs
//@ compile-flags: -Copt-level=3 --target x86_64-unknown-linux-gnu
//@ needs-llvm-components: x86
#![crate_type = "rlib"]
#![feature(no_core)]
#![no_core]
// Test that when an inline assembly block specifies `readonly` but not `pure`, a detailed
// `MemoryEffects` is provided to LLVM: this assembly block is not allowed to perform writes,
// but it may have side-effects.
extern crate minicore;
use minicore::*;
pub static mut VAR: i32 = 0;
// CHECK-LABEL: @no_options
// CHECK: call i32 asm
#[no_mangle]
pub unsafe fn no_options() -> i32 {
VAR = 1;
let _ignored: i32;
asm!("mov {0}, 1", out(reg) _ignored);
VAR
}
// CHECK-LABEL: @readonly_pure
// CHECK-NOT: call i32 asm
#[no_mangle]
pub unsafe fn readonly_pure() -> i32 {
VAR = 1;
let _ignored: i32;
asm!("mov {0}, 1", out(reg) _ignored, options(pure, readonly));
VAR
}
// CHECK-LABEL: @readonly_not_pure
// CHECK: call i32 asm {{.*}} #[[ATTR:[0-9]+]]
#[no_mangle]
pub unsafe fn readonly_not_pure() -> i32 {
VAR = 1;
let _ignored: i32;
asm!("mov {0}, 1", out(reg) _ignored, options(readonly));
VAR
}
// CHECK: attributes #[[ATTR]] = { nounwind memory(read, inaccessiblemem: readwrite) }