Skip to content

Commit 7514309

Browse files
[AtomicExpandPass] Improve atomic expand error messages (llvm#188380)
AtomicExpandPass tells you that an operation is not supported but not why.
1 parent 18bed37 commit 7514309

File tree

7 files changed

+114
-45
lines changed

7 files changed

+114
-45
lines changed

llvm/lib/CodeGen/AtomicExpandPass.cpp

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "llvm/ADT/ArrayRef.h"
1818
#include "llvm/ADT/STLFunctionalExtras.h"
19+
#include "llvm/ADT/SmallString.h"
1920
#include "llvm/ADT/SmallVector.h"
2021
#include "llvm/Analysis/InstSimplifyFolder.h"
2122
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
@@ -74,17 +75,22 @@ class AtomicExpandImpl {
7475
IRBuilderBase &, Value *, Value *, Value *, Align, AtomicOrdering,
7576
SyncScope::ID, Value *&, Value *&, Instruction *)>;
7677

77-
void handleFailure(Instruction &FailedInst, const Twine &Msg) const {
78+
void handleFailure(Instruction &FailedInst, const Twine &Msg,
79+
Instruction *DiagnosticInst = nullptr) const {
7880
LLVMContext &Ctx = FailedInst.getContext();
7981

8082
// TODO: Do not use generic error type.
81-
Ctx.emitError(&FailedInst, Msg);
83+
Ctx.emitError(DiagnosticInst ? DiagnosticInst : &FailedInst, Msg);
8284

8385
if (!FailedInst.getType()->isVoidTy())
8486
FailedInst.replaceAllUsesWith(PoisonValue::get(FailedInst.getType()));
8587
FailedInst.eraseFromParent();
8688
}
8789

90+
template <typename Inst>
91+
void handleUnsupportedAtomicSize(Inst *I, const Twine &AtomicOpName,
92+
Instruction *DiagnosticInst = nullptr) const;
93+
8894
bool bracketInstWithFences(Instruction *I, AtomicOrdering Order);
8995
bool tryInsertTrailingSeqCstFence(Instruction *AtomicI);
9096
template <typename AtomicInst>
@@ -135,7 +141,9 @@ class AtomicExpandImpl {
135141
void expandAtomicLoadToLibcall(LoadInst *LI);
136142
void expandAtomicStoreToLibcall(StoreInst *LI);
137143
void expandAtomicRMWToLibcall(AtomicRMWInst *I);
138-
void expandAtomicCASToLibcall(AtomicCmpXchgInst *I);
144+
void expandAtomicCASToLibcall(AtomicCmpXchgInst *I,
145+
const Twine &AtomicOpName = "cmpxchg",
146+
Instruction *DiagnosticInst = nullptr);
139147

140148
bool expandAtomicRMWToCmpXchg(AtomicRMWInst *AI,
141149
CreateCmpXchgInstFun CreateCmpXchg);
@@ -254,15 +262,46 @@ static void copyMetadataForAtomic(Instruction &Dest,
254262
}
255263
}
256264

257-
// Determine if a particular atomic operation has a supported size,
258-
// and is of appropriate alignment, to be passed through for target
259-
// lowering. (Versus turning into a __atomic libcall)
260265
template <typename Inst>
261266
static bool atomicSizeSupported(const TargetLowering *TLI, Inst *I) {
262267
unsigned Size = getAtomicOpSize(I);
263268
Align Alignment = I->getAlign();
264-
return Alignment >= Size &&
265-
Size <= TLI->getMaxAtomicSizeInBitsSupported() / 8;
269+
unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
270+
return Alignment >= Size && Size <= MaxSize;
271+
}
272+
273+
template <typename Inst>
274+
static void writeUnsupportedAtomicSizeReason(const TargetLowering *TLI, Inst *I,
275+
raw_ostream &OS) {
276+
unsigned Size = getAtomicOpSize(I);
277+
Align Alignment = I->getAlign();
278+
bool NeedSeparator = false;
279+
280+
if (Alignment < Size) {
281+
OS << "instruction alignment " << Alignment.value()
282+
<< " is smaller than the required " << Size
283+
<< "-byte alignment for this atomic operation";
284+
NeedSeparator = true;
285+
}
286+
287+
unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
288+
if (Size > MaxSize) {
289+
if (NeedSeparator)
290+
OS << "; ";
291+
OS << "target supports atomics up to " << MaxSize
292+
<< " bytes, but this atomic accesses " << Size << " bytes";
293+
}
294+
}
295+
296+
template <typename Inst>
297+
void AtomicExpandImpl::handleUnsupportedAtomicSize(
298+
Inst *I, const Twine &AtomicOpName, Instruction *DiagnosticInst) const {
299+
assert(!atomicSizeSupported(TLI, I) && "expected unsupported atomic size");
300+
SmallString<128> FailureReason;
301+
raw_svector_ostream OS(FailureReason);
302+
writeUnsupportedAtomicSizeReason(TLI, I, OS);
303+
handleFailure(*I, Twine("unsupported ") + AtomicOpName + ": " + FailureReason,
304+
DiagnosticInst);
266305
}
267306

268307
bool AtomicExpandImpl::tryInsertTrailingSeqCstFence(Instruction *AtomicI) {
@@ -1820,11 +1859,11 @@ void AtomicExpandImpl::expandAtomicLoadToLibcall(LoadInst *I) {
18201859
RTLIB::ATOMIC_LOAD_4, RTLIB::ATOMIC_LOAD_8, RTLIB::ATOMIC_LOAD_16};
18211860
unsigned Size = getAtomicOpSize(I);
18221861

1823-
bool expanded = expandAtomicOpToLibcall(
1862+
bool Expanded = expandAtomicOpToLibcall(
18241863
I, Size, I->getAlign(), I->getPointerOperand(), nullptr, nullptr,
18251864
I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
1826-
if (!expanded)
1827-
handleFailure(*I, "unsupported atomic load");
1865+
if (!Expanded)
1866+
handleUnsupportedAtomicSize(I, "atomic load");
18281867
}
18291868

18301869
void AtomicExpandImpl::expandAtomicStoreToLibcall(StoreInst *I) {
@@ -1833,26 +1872,28 @@ void AtomicExpandImpl::expandAtomicStoreToLibcall(StoreInst *I) {
18331872
RTLIB::ATOMIC_STORE_4, RTLIB::ATOMIC_STORE_8, RTLIB::ATOMIC_STORE_16};
18341873
unsigned Size = getAtomicOpSize(I);
18351874

1836-
bool expanded = expandAtomicOpToLibcall(
1875+
bool Expanded = expandAtomicOpToLibcall(
18371876
I, Size, I->getAlign(), I->getPointerOperand(), I->getValueOperand(),
18381877
nullptr, I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
1839-
if (!expanded)
1840-
handleFailure(*I, "unsupported atomic store");
1878+
if (!Expanded)
1879+
handleUnsupportedAtomicSize(I, "atomic store");
18411880
}
18421881

1843-
void AtomicExpandImpl::expandAtomicCASToLibcall(AtomicCmpXchgInst *I) {
1882+
void AtomicExpandImpl::expandAtomicCASToLibcall(AtomicCmpXchgInst *I,
1883+
const Twine &AtomicOpName,
1884+
Instruction *DiagnosticInst) {
18441885
static const RTLIB::Libcall Libcalls[6] = {
18451886
RTLIB::ATOMIC_COMPARE_EXCHANGE, RTLIB::ATOMIC_COMPARE_EXCHANGE_1,
18461887
RTLIB::ATOMIC_COMPARE_EXCHANGE_2, RTLIB::ATOMIC_COMPARE_EXCHANGE_4,
18471888
RTLIB::ATOMIC_COMPARE_EXCHANGE_8, RTLIB::ATOMIC_COMPARE_EXCHANGE_16};
18481889
unsigned Size = getAtomicOpSize(I);
18491890

1850-
bool expanded = expandAtomicOpToLibcall(
1891+
bool Expanded = expandAtomicOpToLibcall(
18511892
I, Size, I->getAlign(), I->getPointerOperand(), I->getNewValOperand(),
18521893
I->getCompareOperand(), I->getSuccessOrdering(), I->getFailureOrdering(),
18531894
Libcalls);
1854-
if (!expanded)
1855-
handleFailure(*I, "unsupported cmpxchg");
1895+
if (!Expanded)
1896+
handleUnsupportedAtomicSize(I, AtomicOpName, DiagnosticInst);
18561897
}
18571898

18581899
static ArrayRef<RTLIB::Libcall> GetRMWLibcall(AtomicRMWInst::BinOp Op) {
@@ -1941,10 +1982,10 @@ void AtomicExpandImpl::expandAtomicRMWToLibcall(AtomicRMWInst *I) {
19411982
// CAS libcall, via a CAS loop, instead.
19421983
if (!Success) {
19431984
expandAtomicRMWToCmpXchg(
1944-
I, [this](IRBuilderBase &Builder, Value *Addr, Value *Loaded,
1945-
Value *NewVal, Align Alignment, AtomicOrdering MemOpOrder,
1946-
SyncScope::ID SSID, Value *&Success, Value *&NewLoaded,
1947-
Instruction *MetadataSrc) {
1985+
I, [this, I](IRBuilderBase &Builder, Value *Addr, Value *Loaded,
1986+
Value *NewVal, Align Alignment, AtomicOrdering MemOpOrder,
1987+
SyncScope::ID SSID, Value *&Success, Value *&NewLoaded,
1988+
Instruction *MetadataSrc) {
19481989
// Create the CAS instruction normally...
19491990
AtomicCmpXchgInst *Pair = Builder.CreateAtomicCmpXchg(
19501991
Addr, Loaded, NewVal, Alignment, MemOpOrder,
@@ -1956,7 +1997,10 @@ void AtomicExpandImpl::expandAtomicRMWToLibcall(AtomicRMWInst *I) {
19561997
NewLoaded = Builder.CreateExtractValue(Pair, 0, "newloaded");
19571998

19581999
// ...and then expand the CAS into a libcall.
1959-
expandAtomicCASToLibcall(Pair);
2000+
expandAtomicCASToLibcall(
2001+
Pair,
2002+
"atomicrmw " + AtomicRMWInst::getOperationName(I->getOperation()),
2003+
MetadataSrc);
19602004
});
19612005
}
19622006
}

llvm/test/CodeGen/AMDGPU/unsupported-atomics.ll

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,54 @@
11
; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=null %s 2>&1 | FileCheck %s
22

3-
; CHECK: error: unsupported atomic load
3+
; CHECK: error: unsupported atomic load: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
44
define i128 @test_load_i128(ptr %p) nounwind {
55
%ld = load atomic i128, ptr %p seq_cst, align 16
66
ret i128 %ld
77
}
88

9-
; CHECK: error: unsupported atomic store
9+
; CHECK: error: unsupported atomic store: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
1010
define void @test_store_i128(ptr %p, i128 %val) nounwind {
1111
store atomic i128 %val, ptr %p seq_cst, align 16
1212
ret void
1313
}
1414

15-
; CHECK: error: unsupported cmpxchg
15+
; CHECK: error: unsupported cmpxchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
1616
define { i128, i1 } @cmpxchg_i128(ptr %p, i128 %cmp, i128 %val) nounwind {
1717
%ret = cmpxchg ptr %p, i128 %cmp, i128 %val seq_cst monotonic
1818
ret { i128, i1 } %ret
1919
}
2020

21-
; CHECK: error: unsupported cmpxchg
21+
; CHECK: error: unsupported atomicrmw xchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
2222
define i128 @atomicrmw_xchg_i128(ptr %p, i128 %val) nounwind {
2323
%ret = atomicrmw xchg ptr %p, i128 %val seq_cst
2424
ret i128 %ret
2525
}
2626

27-
; CHECK: error: unsupported cmpxchg
27+
; CHECK: error: unsupported atomicrmw xchg: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
2828
define i64 @atomicrmw_xchg_i64_align4(ptr %p, i64 %val) nounwind {
2929
%ret = atomicrmw xchg ptr %p, i64 %val seq_cst, align 4
3030
ret i64 %ret
3131
}
3232

33-
; CHECK: error: unsupported cmpxchg
33+
; CHECK: error: unsupported atomicrmw fadd: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
3434
define double @atomicrmw_fadd_f64_align4(ptr %p, double %val) nounwind {
3535
%ret = atomicrmw fadd ptr %p, double %val seq_cst, align 4
3636
ret double %ret
3737
}
3838

39-
; CHECK: error: unsupported cmpxchg
39+
; 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
4040
define fp128 @atomicrmw_fadd_f128_align4(ptr %p, fp128 %val) nounwind {
4141
%ret = atomicrmw fadd ptr %p, fp128 %val seq_cst, align 4
4242
ret fp128 %ret
4343
}
4444

45-
; CHECK: error: unsupported cmpxchg
45+
; CHECK: error: unsupported atomicrmw fadd: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
4646
define fp128 @atomicrmw_fadd_f128(ptr %p, fp128 %val) nounwind {
4747
%ret = atomicrmw fadd ptr %p, fp128 %val seq_cst, align 16
4848
ret fp128 %ret
4949
}
5050

51-
; CHECK: error: unsupported cmpxchg
51+
; CHECK: error: unsupported atomicrmw fadd: instruction alignment 2 is smaller than the required 4-byte alignment for this atomic operation
5252
define <2 x half> @test_atomicrmw_fadd_v2f16_global_agent_align2(ptr addrspace(1) %ptr, <2 x half> %value) {
5353
%res = atomicrmw fadd ptr addrspace(1) %ptr, <2 x half> %value syncscope("agent") seq_cst, align 2
5454
ret <2 x half> %res
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; RUN: not llc -mtriple=nvptx64 -mcpu=sm_80 -filetype=null %s 2>&1 | FileCheck %s
2+
3+
; CHECK: error: unsupported atomic load: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
4+
define i32 @load_i32_align1(ptr %p) {
5+
%ret = load atomic i32, ptr %p seq_cst, align 1
6+
ret i32 %ret
7+
}
8+
9+
; CHECK: error: unsupported atomic store: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
10+
define void @store_i32_align1(ptr %p, i32 %v) {
11+
store atomic i32 %v, ptr %p seq_cst, align 1
12+
ret void
13+
}
14+
15+
; CHECK: error: unsupported cmpxchg: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
16+
define { i64, i1 } @cmpxchg_i64_align4(ptr %p, i64 %cmp, i64 %new) {
17+
%ret = cmpxchg ptr %p, i64 %cmp, i64 %new seq_cst monotonic, align 4
18+
ret { i64, i1 } %ret
19+
}
20+
21+
; CHECK: error: unsupported atomicrmw xchg: instruction alignment 4 is smaller than the required 8-byte alignment for this atomic operation
22+
define i64 @atomicrmw_xchg_i64_align4(ptr %p, i64 %v) {
23+
%ret = atomicrmw xchg ptr %p, i64 %v seq_cst, align 4
24+
ret i64 %ret
25+
}

llvm/test/CodeGen/NVPTX/atomicrmw-expand.err.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
; RUN: not llc -mtriple=nvptx64 -mcpu=sm_30 -filetype=null %s 2>&1 | FileCheck %s
22

3-
; CHECK: error: unsupported cmpxchg
4-
; CHECK: error: unsupported cmpxchg
5-
; CHECK: error: unsupported cmpxchg
6-
; CHECK: error: unsupported cmpxchg
3+
; 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
4+
; 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
5+
; 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
6+
; 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
77
define void @bitwise_i256(ptr %0, i256 %1) {
88
entry:
99
%2 = atomicrmw and ptr %0, i256 %1 monotonic, align 16
@@ -13,10 +13,10 @@ entry:
1313
ret void
1414
}
1515

16-
; CHECK: error: unsupported cmpxchg
17-
; CHECK: error: unsupported cmpxchg
18-
; CHECK: error: unsupported cmpxchg
19-
; CHECK: error: unsupported cmpxchg
16+
; 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
17+
; 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
18+
; 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
19+
; 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
2020
define void @minmax_i256(ptr %0, i256 %1) {
2121
entry:
2222
%2 = atomicrmw min ptr %0, i256 %1 monotonic, align 16

llvm/test/CodeGen/NVPTX/atomics-b128.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
target triple = "nvptx64-nvidia-cuda"
1111

1212
;; Check that the first couple of error messages are correct.
13-
; ERROR: error: unsupported cmpxchg
14-
; ERROR: error: unsupported cmpxchg
13+
; ERROR: error: unsupported atomicrmw xchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
14+
; ERROR: error: unsupported atomicrmw xchg: target supports atomics up to 8 bytes, but this atomic accesses 16 bytes
1515

1616
define i128 @test_xchg_generic(ptr %addr, i128 %amt) {
1717
; CHECK-LABEL: test_xchg_generic(

llvm/test/CodeGen/NVPTX/load-store-atomic.err.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; RUN: not llc < %s -march=nvptx64 -mcpu=sm_100 -mattr=+ptx88 2>&1 | FileCheck %s
22

3-
; CHECK: error: unsupported atomic store
4-
; CHECK: error: unsupported atomic load
3+
; CHECK: error: unsupported atomic store: target supports atomics up to 16 bytes, but this atomic accesses 32 bytes
4+
; CHECK: error: unsupported atomic load: target supports atomics up to 16 bytes, but this atomic accesses 32 bytes
55

66
define void @test_i256_global_atomic(ptr addrspace(1) %a, ptr addrspace(1) %b) {
77
%a.load = load atomic i256, ptr addrspace(1) %a seq_cst, align 32

llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
; 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
22

3-
; CHECK: error: unsupported atomic load
3+
; CHECK: error: unsupported atomic load: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
44
define i32 @atomic_load_global_align1(ptr addrspace(1) %ptr) {
55
%val = load atomic i32, ptr addrspace(1) %ptr seq_cst, align 1
66
ret i32 %val

0 commit comments

Comments
 (0)