Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// NOTE: libgccjit does not support specifying the alignment on the assignment, so we cast
// to type so it gets the proper alignment.
let destination_type = destination.to_rvalue().get_type().unqualified();
let align = if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() };
let align = align.bytes();
let mut modified_destination_type = destination_type.get_aligned(align);
if flags.contains(MemFlags::VOLATILE) {
modified_destination_type = modified_destination_type.make_volatile();
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,16 +377,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
load
}
}
sym::volatile_store => {
let dst = args[0].deref(self.cx());
args[1].val.volatile_store(self, dst);
return IntrinsicResult::WroteIntoPlace;
}
sym::unaligned_volatile_store => {
let dst = args[0].deref(self.cx());
args[1].val.unaligned_volatile_store(self, dst);
return IntrinsicResult::WroteIntoPlace;
}
sym::prefetch_read_data
| sym::prefetch_write_data
| sym::prefetch_read_instruction
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,8 +873,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
unsafe {
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
let align =
if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint };
let align = align.bytes() as c_uint;
llvm::LLVMSetAlignment(store, align);
if flags.contains(MemFlags::VOLATILE) {
llvm::LLVMSetVolatile(store, llvm::TRUE);
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,16 +389,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
};
}
}
sym::volatile_store => {
let dst = args[0].deref(self.cx());
args[1].val.volatile_store(self, dst);
return IntrinsicResult::Operand(OperandValue::ZeroSized);
}
sym::unaligned_volatile_store => {
let dst = args[0].deref(self.cx());
args[1].val.unaligned_volatile_store(self, dst);
return IntrinsicResult::Operand(OperandValue::ZeroSized);
}
sym::prefetch_read_data
| sym::prefetch_write_data
| sym::prefetch_read_instruction
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,12 @@ pub enum ModuleKind {
}

bitflags::bitflags! {
/// This previously had an `UNALIGNED` variant, but that should never be done via flags.
/// If you want something to be unaligned, see [`mir::place::PlaceRef::unaligned`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MemFlags: u8 {
const VOLATILE = 1 << 0;
const NONTEMPORAL = 1 << 1;
const UNALIGNED = 1 << 2;
/// Indicates that writing through the stored pointer is undefined behavior.
/// Only valid on stores of pointers, or pairs where the first element is a pointer.
/// In the latter case, the flag only applies to the first element of the pair.
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
);
OperandValue::ZeroSized
}
sym::volatile_store => {
sym::volatile_store | sym::unaligned_volatile_store => {
let dst = args[0].deref(bx.cx());
let dst = if name == sym::volatile_store { dst } else { dst.unaligned() };
args[1].val.volatile_store(bx, dst);
OperandValue::ZeroSized
}
sym::unaligned_volatile_store => {
let dst = args[0].deref(bx.cx());
args[1].val.unaligned_volatile_store(bx, dst);
OperandValue::ZeroSized
}
sym::disjoint_bitor => {
let a = args[0].immediate();
let b = args[1].immediate();
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,14 +968,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
self.store_with_flags(bx, dest, MemFlags::VOLATILE);
}

pub fn unaligned_volatile_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
dest: PlaceRef<'tcx, V>,
) {
self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED);
}

pub fn nontemporal_store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
pub fn storage_dead<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
bx.lifetime_end(self.val.llval, self.layout.size);
}

/// The same place, but with [`PlaceValue::align`] lowered to [`Align::ONE`].
pub fn unaligned(self) -> Self {
let Self { val, layout } = self;
let val = PlaceValue { align: Align::ONE, ..val };
Self { val, layout }
}
}

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Expand Down
25 changes: 23 additions & 2 deletions tests/codegen-llvm/intrinsics/volatile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,28 @@ pub unsafe fn unaligned_volatile_load_fat(a: *const UninitFatPointer) -> UninitF

// CHECK-LABEL: @unaligned_volatile_store
#[no_mangle]
pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) {
// CHECK: store volatile
Comment on lines -165 to -166

@scottmcm scottmcm Jul 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this test was essentially useless, since

  1. It didn't actually test the alignment used in the store, and
  2. It used u8 which always has alignment 1 even if you don't use unaligned.

So I expanded them to actually test things.

View changes since the review

pub unsafe fn unaligned_volatile_store(a: *mut u16, b: u16) {
// CHECK: store volatile i16 %b, ptr %a, align 1
intrinsics::unaligned_volatile_store(a, b)
}

// CHECK-LABEL: @unaligned_volatile_store_pair
#[no_mangle]
pub unsafe fn unaligned_volatile_store_pair(a: *mut (u16, u16), b: (u16, u16)) {
// CHECK: store volatile i16 %b.0, ptr %a, align 1
// CHECK: [[TEMP:%.+]] = getelementptr inbounds i8, ptr %a, {{i16|i32|i64}} 2
// CHECK: store volatile i16 %b.1, ptr [[TEMP]], align 1
intrinsics::unaligned_volatile_store(a, b)
}

// CHECK-LABEL: @unaligned_volatile_store_array
#[no_mangle]
pub unsafe fn unaligned_volatile_store_array(a: *mut [u16; 7], b: [u16; 7]) {
// Note that only the store side is unaligned; the load from the argument is aligned.

// CHECK-NOT: memcpy
// CHECK: call void @llvm.memcpy{{.+}}(ptr align 1 %a, ptr align 2 %b, {{i16|i32|i64}} 14, i1 true)

@scottmcm scottmcm Jul 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A volatile memcpy is not actually a good way to do this, but it's not a regression at least since it's what this emits in nightly today (https://rust.godbolt.org/z/josnWhGa6).

(See danlehmann/bitfield#136 for more -- it's looking at this problem that had me looking at volatile stores at all. I'll make another PR after this one to work on that problem.)

View changes since the review

// CHECK-NOT: memcpy
// CHECK: ret void
intrinsics::unaligned_volatile_store(a, b)
}
Loading