Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -1194,12 +1194,19 @@ /// Returns the maximum atomic operation size (in bits) supported by /// the backend. Atomic operations greater than this size (as well - /// as ones that are not naturally aligned), will be expanded by - /// AtomicExpandPass into an __atomic_* library call. + /// as ones that are not correctly aligned, see `atomicAlignmentValid`), + /// will be expanded by AtomicExpandPass into an __atomic_* library call. unsigned getMaxAtomicSizeInBitsSupported() const { return MaxAtomicSizeInBitsSupported; } + /// Check if alignment is valid for atomic operation. The default is + /// natural alignment, but there are platforms like x86 where for certain + /// sizes different alignments are valid. + virtual bool atomicAlignmentValid(unsigned Size, unsigned Align) const { + return Align >= Size; + } + /// Returns the size of the smallest cmpxchg or ll/sc instruction /// the backend supports. Any smaller operations are widened in /// AtomicExpandPass. Index: lib/CodeGen/AtomicExpandPass.cpp =================================================================== --- lib/CodeGen/AtomicExpandPass.cpp +++ lib/CodeGen/AtomicExpandPass.cpp @@ -167,7 +167,7 @@ bool atomicSizeSupported(const TargetLowering *TLI, Inst *I) { unsigned Size = getAtomicOpSize(I); unsigned Align = getAtomicOpAlign(I); - return Align >= Size && Size <= TLI->getMaxAtomicSizeInBitsSupported() / 8; + return TLI->atomicAlignmentValid(Size, Align) && Size <= TLI->getMaxAtomicSizeInBitsSupported() / 8; } } // end anonymous namespace Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -1031,6 +1031,8 @@ bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override; + bool atomicAlignmentValid(unsigned Size, unsigned Align) const override; + /// \brief Customize the preferred legalization strategy for certain types. LegalizeTypeAction getPreferredVectorAction(EVT VT) const override; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -2078,6 +2078,13 @@ return SrcAS < 256 && DestAS < 256; } +bool X86TargetLowering::atomicAlignmentValid(unsigned Size, unsigned Align) const { + // Atomic operations of for size < 16 don't need to be aligned on X86 + if (Size < 16) + return true; + return Align >= Size; +} + //===----------------------------------------------------------------------===// // Return Value Calling Convention Implementation //===----------------------------------------------------------------------===// Index: test/CodeGen/X86/atomic-load-store-wide.ll =================================================================== --- test/CodeGen/X86/atomic-load-store-wide.ll +++ test/CodeGen/X86/atomic-load-store-wide.ll @@ -11,9 +11,24 @@ ret void } -define i64 @test2(i64* %ptr) { +define void @test2(i64* %ptr, i64 %val1) { ; CHECK-LABEL: test2 ; CHECK: lock cmpxchg8b +; CHECK-NEXT: jne + store atomic i64 %val1, i64* %ptr seq_cst, align 4 + ret void +} + +define i64 @test3(i64* %ptr) { +; CHECK-LABEL: test3 +; CHECK: lock cmpxchg8b %val = load atomic i64, i64* %ptr seq_cst, align 8 ret i64 %val } + +define i64 @test4(i64* %ptr) { +; CHECK-LABEL: test4 +; CHECK: lock cmpxchg8b + %val = load atomic i64, i64* %ptr seq_cst, align 4 + ret i64 %val +}