[llvm] 7514309 - [AtomicExpandPass] Improve atomic expand error messages (#188380)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 17:02:29 PDT 2026


Author: Yonah Goldberg
Date: 2026-04-15T17:02:24-07:00
New Revision: 75143099f9c8f56a799c1c89f225debb9caf20f0

URL: https://github.com/llvm/llvm-project/commit/75143099f9c8f56a799c1c89f225debb9caf20f0
DIFF: https://github.com/llvm/llvm-project/commit/75143099f9c8f56a799c1c89f225debb9caf20f0.diff

LOG: [AtomicExpandPass] Improve atomic expand error messages (#188380)

AtomicExpandPass tells you that an operation is not supported but not why.

Added: 
    llvm/test/CodeGen/NVPTX/atomic-alignment.err.ll

Modified: 
    llvm/lib/CodeGen/AtomicExpandPass.cpp
    llvm/test/CodeGen/AMDGPU/unsupported-atomics.ll
    llvm/test/CodeGen/NVPTX/atomicrmw-expand.err.ll
    llvm/test/CodeGen/NVPTX/atomics-b128.ll
    llvm/test/CodeGen/NVPTX/load-store-atomic.err.ll
    llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/AtomicExpandPass.cpp b/llvm/lib/CodeGen/AtomicExpandPass.cpp
index 7ed6c2c966683..068365e0d35a0 100644
--- a/llvm/lib/CodeGen/AtomicExpandPass.cpp
+++ b/llvm/lib/CodeGen/AtomicExpandPass.cpp
@@ -16,6 +16,7 @@
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Analysis/InstSimplifyFolder.h"
 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
@@ -74,17 +75,22 @@ class AtomicExpandImpl {
       IRBuilderBase &, Value *, Value *, Value *, Align, AtomicOrdering,
       SyncScope::ID, Value *&, Value *&, Instruction *)>;
 
-  void handleFailure(Instruction &FailedInst, const Twine &Msg) const {
+  void handleFailure(Instruction &FailedInst, const Twine &Msg,
+                     Instruction *DiagnosticInst = nullptr) const {
     LLVMContext &Ctx = FailedInst.getContext();
 
     // TODO: Do not use generic error type.
-    Ctx.emitError(&FailedInst, Msg);
+    Ctx.emitError(DiagnosticInst ? DiagnosticInst : &FailedInst, Msg);
 
     if (!FailedInst.getType()->isVoidTy())
       FailedInst.replaceAllUsesWith(PoisonValue::get(FailedInst.getType()));
     FailedInst.eraseFromParent();
   }
 
+  template <typename Inst>
+  void handleUnsupportedAtomicSize(Inst *I, const Twine &AtomicOpName,
+                                   Instruction *DiagnosticInst = nullptr) const;
+
   bool bracketInstWithFences(Instruction *I, AtomicOrdering Order);
   bool tryInsertTrailingSeqCstFence(Instruction *AtomicI);
   template <typename AtomicInst>
@@ -135,7 +141,9 @@ class AtomicExpandImpl {
   void expandAtomicLoadToLibcall(LoadInst *LI);
   void expandAtomicStoreToLibcall(StoreInst *LI);
   void expandAtomicRMWToLibcall(AtomicRMWInst *I);
-  void expandAtomicCASToLibcall(AtomicCmpXchgInst *I);
+  void expandAtomicCASToLibcall(AtomicCmpXchgInst *I,
+                                const Twine &AtomicOpName = "cmpxchg",
+                                Instruction *DiagnosticInst = nullptr);
 
   bool expandAtomicRMWToCmpXchg(AtomicRMWInst *AI,
                                 CreateCmpXchgInstFun CreateCmpXchg);
@@ -254,15 +262,46 @@ static void copyMetadataForAtomic(Instruction &Dest,
   }
 }
 
-// Determine if a particular atomic operation has a supported size,
-// and is of appropriate alignment, to be passed through for target
-// lowering. (Versus turning into a __atomic libcall)
 template <typename Inst>
 static bool atomicSizeSupported(const TargetLowering *TLI, Inst *I) {
   unsigned Size = getAtomicOpSize(I);
   Align Alignment = I->getAlign();
-  return Alignment >= Size &&
-         Size <= TLI->getMaxAtomicSizeInBitsSupported() / 8;
+  unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
+  return Alignment >= Size && Size <= MaxSize;
+}
+
+template <typename Inst>
+static void writeUnsupportedAtomicSizeReason(const TargetLowering *TLI, Inst *I,
+                                             raw_ostream &OS) {
+  unsigned Size = getAtomicOpSize(I);
+  Align Alignment = I->getAlign();
+  bool NeedSeparator = false;
+
+  if (Alignment < Size) {
+    OS << "instruction alignment " << Alignment.value()
+       << " is smaller than the required " << Size
+       << "-byte alignment for this atomic operation";
+    NeedSeparator = true;
+  }
+
+  unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
+  if (Size > MaxSize) {
+    if (NeedSeparator)
+      OS << "; ";
+    OS << "target supports atomics up to " << MaxSize
+       << " bytes, but this atomic accesses " << Size << " bytes";
+  }
+}
+
+template <typename Inst>
+void AtomicExpandImpl::handleUnsupportedAtomicSize(
+    Inst *I, const Twine &AtomicOpName, Instruction *DiagnosticInst) const {
+  assert(!atomicSizeSupported(TLI, I) && "expected unsupported atomic size");
+  SmallString<128> FailureReason;
+  raw_svector_ostream OS(FailureReason);
+  writeUnsupportedAtomicSizeReason(TLI, I, OS);
+  handleFailure(*I, Twine("unsupported ") + AtomicOpName + ": " + FailureReason,
+                DiagnosticInst);
 }
 
 bool AtomicExpandImpl::tryInsertTrailingSeqCstFence(Instruction *AtomicI) {
@@ -1820,11 +1859,11 @@ void AtomicExpandImpl::expandAtomicLoadToLibcall(LoadInst *I) {
       RTLIB::ATOMIC_LOAD_4, RTLIB::ATOMIC_LOAD_8, RTLIB::ATOMIC_LOAD_16};
   unsigned Size = getAtomicOpSize(I);
 
-  bool expanded = expandAtomicOpToLibcall(
+  bool Expanded = expandAtomicOpToLibcall(
       I, Size, I->getAlign(), I->getPointerOperand(), nullptr, nullptr,
       I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
-  if (!expanded)
-    handleFailure(*I, "unsupported atomic load");
+  if (!Expanded)
+    handleUnsupportedAtomicSize(I, "atomic load");
 }
 
 void AtomicExpandImpl::expandAtomicStoreToLibcall(StoreInst *I) {
@@ -1833,26 +1872,28 @@ void AtomicExpandImpl::expandAtomicStoreToLibcall(StoreInst *I) {
       RTLIB::ATOMIC_STORE_4, RTLIB::ATOMIC_STORE_8, RTLIB::ATOMIC_STORE_16};
   unsigned Size = getAtomicOpSize(I);
 
-  bool expanded = expandAtomicOpToLibcall(
+  bool Expanded = expandAtomicOpToLibcall(
       I, Size, I->getAlign(), I->getPointerOperand(), I->getValueOperand(),
       nullptr, I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
-  if (!expanded)
-    handleFailure(*I, "unsupported atomic store");
+  if (!Expanded)
+    handleUnsupportedAtomicSize(I, "atomic store");
 }
 
-void AtomicExpandImpl::expandAtomicCASToLibcall(AtomicCmpXchgInst *I) {
+void AtomicExpandImpl::expandAtomicCASToLibcall(AtomicCmpXchgInst *I,
+                                                const Twine &AtomicOpName,
+                                                Instruction *DiagnosticInst) {
   static const RTLIB::Libcall Libcalls[6] = {
       RTLIB::ATOMIC_COMPARE_EXCHANGE,   RTLIB::ATOMIC_COMPARE_EXCHANGE_1,
       RTLIB::ATOMIC_COMPARE_EXCHANGE_2, RTLIB::ATOMIC_COMPARE_EXCHANGE_4,
       RTLIB::ATOMIC_COMPARE_EXCHANGE_8, RTLIB::ATOMIC_COMPARE_EXCHANGE_16};
   unsigned Size = getAtomicOpSize(I);
 
-  bool expanded = expandAtomicOpToLibcall(
+  bool Expanded = expandAtomicOpToLibcall(
       I, Size, I->getAlign(), I->getPointerOperand(), I->getNewValOperand(),
       I->getCompareOperand(), I->getSuccessOrdering(), I->getFailureOrdering(),
       Libcalls);
-  if (!expanded)
-    handleFailure(*I, "unsupported cmpxchg");
+  if (!Expanded)
+    handleUnsupportedAtomicSize(I, AtomicOpName, DiagnosticInst);
 }
 
 static ArrayRef<RTLIB::Libcall> GetRMWLibcall(AtomicRMWInst::BinOp Op) {
@@ -1941,10 +1982,10 @@ void AtomicExpandImpl::expandAtomicRMWToLibcall(AtomicRMWInst *I) {
   // CAS libcall, via a CAS loop, instead.
   if (!Success) {
     expandAtomicRMWToCmpXchg(
-        I, [this](IRBuilderBase &Builder, Value *Addr, Value *Loaded,
-                  Value *NewVal, Align Alignment, AtomicOrdering MemOpOrder,
-                  SyncScope::ID SSID, Value *&Success, Value *&NewLoaded,
-                  Instruction *MetadataSrc) {
+        I, [this, I](IRBuilderBase &Builder, Value *Addr, Value *Loaded,
+                     Value *NewVal, Align Alignment, AtomicOrdering MemOpOrder,
+                     SyncScope::ID SSID, Value *&Success, Value *&NewLoaded,
+                     Instruction *MetadataSrc) {
           // Create the CAS instruction normally...
           AtomicCmpXchgInst *Pair = Builder.CreateAtomicCmpXchg(
               Addr, Loaded, NewVal, Alignment, MemOpOrder,
@@ -1956,7 +1997,10 @@ void AtomicExpandImpl::expandAtomicRMWToLibcall(AtomicRMWInst *I) {
           NewLoaded = Builder.CreateExtractValue(Pair, 0, "newloaded");
 
           // ...and then expand the CAS into a libcall.
-          expandAtomicCASToLibcall(Pair);
+          expandAtomicCASToLibcall(
+              Pair,
+              "atomicrmw " + AtomicRMWInst::getOperationName(I->getOperation()),
+              MetadataSrc);
         });
   }
 }

diff  --git a/llvm/test/CodeGen/AMDGPU/unsupported-atomics.ll b/llvm/test/CodeGen/AMDGPU/unsupported-atomics.ll
index f569c15c27e5d..ee982e390162a 100644
--- a/llvm/test/CodeGen/AMDGPU/unsupported-atomics.ll
+++ b/llvm/test/CodeGen/AMDGPU/unsupported-atomics.ll
@@ -1,54 +1,54 @@
 ; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck %s
 
-; CHECK: error: unsupported atomic load
+; CHECK: error: unsupported atomic load: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 define i128 @test_load_i128(ptr %p) nounwind {
   %ld = load atomic i128, ptr %p seq_cst, align 16
   ret i128 %ld
 }
 
-; CHECK: error: unsupported atomic store
+; CHECK: error: unsupported atomic store: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 define void @test_store_i128(ptr %p, i128 %val) nounwind {
   store atomic i128 %val, ptr %p seq_cst, align 16
   ret void
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported cmpxchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 define { i128, i1 } @cmpxchg_i128(ptr %p, i128 %cmp, i128 %val) nounwind {
   %ret = cmpxchg ptr %p, i128 %cmp, i128 %val seq_cst monotonic
   ret { i128, i1 } %ret
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw xchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 define i128 @atomicrmw_xchg_i128(ptr %p, i128 %val) nounwind {
   %ret = atomicrmw xchg ptr %p, i128 %val seq_cst
   ret i128 %ret
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw xchg: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
 define i64 @atomicrmw_xchg_i64_align4(ptr %p, i64 %val) nounwind {
   %ret = atomicrmw xchg ptr %p, i64 %val seq_cst, align 4
   ret i64 %ret
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw fadd: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
 define double @atomicrmw_fadd_f64_align4(ptr %p, double %val) nounwind {
   %ret = atomicrmw fadd ptr %p, double %val seq_cst, align 4
   ret double %ret
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw fadd: instruction alignment 4 is smaller than the required 16-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 define fp128 @atomicrmw_fadd_f128_align4(ptr %p, fp128 %val) nounwind {
   %ret = atomicrmw fadd ptr %p, fp128 %val seq_cst, align 4
   ret fp128 %ret
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw fadd: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 define fp128 @atomicrmw_fadd_f128(ptr %p, fp128 %val) nounwind {
   %ret = atomicrmw fadd ptr %p, fp128 %val seq_cst, align 16
   ret fp128 %ret
 }
 
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw fadd: instruction alignment 2 is smaller than the required 4-byte alignment for this atomic operation
 define <2 x half> @test_atomicrmw_fadd_v2f16_global_agent_align2(ptr addrspace(1) %ptr, <2 x half> %value) {
   %res = atomicrmw fadd ptr addrspace(1) %ptr, <2 x half> %value syncscope("agent") seq_cst, align 2
   ret <2 x half> %res

diff  --git a/llvm/test/CodeGen/NVPTX/atomic-alignment.err.ll b/llvm/test/CodeGen/NVPTX/atomic-alignment.err.ll
new file mode 100644
index 0000000000000..1db778c2afdb5
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/atomic-alignment.err.ll
@@ -0,0 +1,25 @@
+; RUN: not llc -mtriple=nvptx64 -mcpu=sm_80 -filetype=null %s 2>&1 | FileCheck %s
+
+; CHECK: error: unsupported atomic load: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
+define i32 @load_i32_align1(ptr %p) {
+  %ret = load atomic i32, ptr %p seq_cst, align 1
+  ret i32 %ret
+}
+
+; CHECK: error: unsupported atomic store: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
+define void @store_i32_align1(ptr %p, i32 %v) {
+  store atomic i32 %v, ptr %p seq_cst, align 1
+  ret void
+}
+
+; CHECK: error: unsupported cmpxchg: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
+define { i64, i1 } @cmpxchg_i64_align4(ptr %p, i64 %cmp, i64 %new) {
+  %ret = cmpxchg ptr %p, i64 %cmp, i64 %new seq_cst monotonic, align 4
+  ret { i64, i1 } %ret
+}
+
+; CHECK: error: unsupported atomicrmw xchg: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
+define i64 @atomicrmw_xchg_i64_align4(ptr %p, i64 %v) {
+  %ret = atomicrmw xchg ptr %p, i64 %v seq_cst, align 4
+  ret i64 %ret
+}

diff  --git a/llvm/test/CodeGen/NVPTX/atomicrmw-expand.err.ll b/llvm/test/CodeGen/NVPTX/atomicrmw-expand.err.ll
index 392cd8b26d27e..7979e88be4ffa 100644
--- a/llvm/test/CodeGen/NVPTX/atomicrmw-expand.err.ll
+++ b/llvm/test/CodeGen/NVPTX/atomicrmw-expand.err.ll
@@ -1,9 +1,9 @@
 ; RUN: not llc -mtriple=nvptx64 -mcpu=sm_30 -filetype=null %s 2>&1 | FileCheck %s
 
-; CHECK: error: unsupported cmpxchg
-; CHECK: error: unsupported cmpxchg
-; CHECK: error: unsupported cmpxchg
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw xchg: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomicrmw xor: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomicrmw or: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomicrmw and: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
 define void @bitwise_i256(ptr %0, i256 %1) {
 entry:
   %2 = atomicrmw and ptr %0, i256 %1 monotonic, align 16
@@ -13,10 +13,10 @@ entry:
   ret void
 }
 
-; CHECK: error: unsupported cmpxchg
-; CHECK: error: unsupported cmpxchg
-; CHECK: error: unsupported cmpxchg
-; CHECK: error: unsupported cmpxchg
+; CHECK: error: unsupported atomicrmw umax: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomicrmw umin: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomicrmw max: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomicrmw min: instruction alignment 16 is smaller than the required 32-byte alignment for this atomic operation; target supports atomics up to 8 bytes, but this atomic accesses 32 bytes
 define void @minmax_i256(ptr %0, i256 %1) {
 entry:
   %2 = atomicrmw min ptr %0, i256 %1 monotonic, align 16

diff  --git a/llvm/test/CodeGen/NVPTX/atomics-b128.ll b/llvm/test/CodeGen/NVPTX/atomics-b128.ll
index b2a3f94d11a16..72bf056479ab3 100644
--- a/llvm/test/CodeGen/NVPTX/atomics-b128.ll
+++ b/llvm/test/CodeGen/NVPTX/atomics-b128.ll
@@ -10,8 +10,8 @@
 target triple = "nvptx64-nvidia-cuda"
 
 ;; Check that the first couple of error messages are correct.
-; ERROR: error: unsupported cmpxchg
-; ERROR: error: unsupported cmpxchg
+; ERROR: error: unsupported atomicrmw xchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
+; ERROR: error: unsupported atomicrmw xchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
 
 define i128 @test_xchg_generic(ptr %addr, i128 %amt) {
 ; CHECK-LABEL: test_xchg_generic(

diff  --git a/llvm/test/CodeGen/NVPTX/load-store-atomic.err.ll b/llvm/test/CodeGen/NVPTX/load-store-atomic.err.ll
index 31889e25142ad..70a23aaf160c5 100644
--- a/llvm/test/CodeGen/NVPTX/load-store-atomic.err.ll
+++ b/llvm/test/CodeGen/NVPTX/load-store-atomic.err.ll
@@ -1,7 +1,7 @@
 ; RUN: not llc < %s -march=nvptx64 -mcpu=sm_100 -mattr=+ptx88 2>&1 | FileCheck %s
 
-; CHECK: error: unsupported atomic store
-; CHECK: error: unsupported atomic load
+; CHECK: error: unsupported atomic store: target supports atomics up to 16 bytes, but this atomic accesses 32 bytes
+; CHECK: error: unsupported atomic load: target supports atomics up to 16 bytes, but this atomic accesses 32 bytes
 
 define void @test_i256_global_atomic(ptr addrspace(1) %a, ptr addrspace(1) %b) {
   %a.load = load atomic i256, ptr addrspace(1) %a seq_cst, align 32

diff  --git a/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll b/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
index 0f2ceb329230b..f8f81d0103f83 100644
--- a/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
+++ b/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
@@ -1,6 +1,6 @@
 ; RUN: not opt -disable-output -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -passes='require<libcall-lowering-info>,atomic-expand' %s 2>&1 | FileCheck --implicit-check-not=error %s
 
-; CHECK: error: unsupported atomic load
+; CHECK: error: unsupported atomic load: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
 define i32 @atomic_load_global_align1(ptr addrspace(1) %ptr) {
   %val = load atomic i32, ptr addrspace(1) %ptr  seq_cst, align 1
   ret i32 %val


        


More information about the llvm-commits mailing list