From 9116f7db7b984960bdf1730e6b5df168440db300 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 7 Jul 2026 00:41:13 -0700 Subject: [PATCH] Fix `unaligned_volatile_store` by removing `MemFlags::UNALIGNED` --- compiler/rustc_codegen_gcc/src/builder.rs | 2 +- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 10 -------- compiler/rustc_codegen_llvm/src/builder.rs | 3 +-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 10 -------- compiler/rustc_codegen_ssa/src/lib.rs | 3 ++- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 8 ++---- compiler/rustc_codegen_ssa/src/mir/operand.rs | 8 ------ compiler/rustc_codegen_ssa/src/mir/place.rs | 7 ++++++ tests/codegen-llvm/intrinsics/volatile.rs | 25 +++++++++++++++++-- 9 files changed, 36 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index f9358872299b7..425d9d6226f83 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -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(); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 78a4c7e88c895..80d4a5cf11ad8 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -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 diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 804547745c5d5..844a5028f7184 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -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); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 7bd604bdbbd76..8fb0dd3e2ef8b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -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 diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 200f6aac12502..994c761a5901e 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -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. diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 413cb5f2c860a..6116c0fa9eb98 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -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(); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 0246da3f27829..6459208ea0aa2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -968,14 +968,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { self.store_with_flags(bx, dest, MemFlags::VOLATILE); } - pub fn unaligned_volatile_store>( - self, - bx: &mut Bx, - dest: PlaceRef<'tcx, V>, - ) { - self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED); - } - pub fn nontemporal_store>( self, bx: &mut Bx, diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 50166609670b6..b592e4a339346 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -318,6 +318,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn storage_dead>(&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> { diff --git a/tests/codegen-llvm/intrinsics/volatile.rs b/tests/codegen-llvm/intrinsics/volatile.rs index 4ba4c5edd2df6..42ffd196f3d86 100644 --- a/tests/codegen-llvm/intrinsics/volatile.rs +++ b/tests/codegen-llvm/intrinsics/volatile.rs @@ -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 +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) + // CHECK-NOT: memcpy + // CHECK: ret void intrinsics::unaligned_volatile_store(a, b) }