[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