Skip to content

Commit 4854742

Browse files
committedFeb 14, 2019
Canonicalize all integer "idempotent" atomicrmw ops
For "idempotent" atomicrmw instructions which we can't simply turn into load, canonicalize the operation and constant. This reduces the matching needed elsewhere in the optimizer, but doesn't directly impact codegen. For any architecture where OR/Zero is not a good default choice, you can extend the AtomicExpand lowerIdempotentRMWIntoFencedLoad mechanism. I reviewed X86 to make sure this works well, haven't audited other backends. Differential Revision: https://reviews.llvm.org/D58244 llvm-svn: 354058
1 parent 04a1ee4 commit 4854742

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed
 

‎llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,22 @@ Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) {
5454
if (!isIdempotentRMW(RMWI))
5555
return nullptr;
5656

57-
// TODO: Canonicalize the operation for an idempotent operation we can't
58-
// convert into a simple load.
59-
60-
// Volatile RMWs perform a load and a store, we cannot replace
61-
// this by just a load.
57+
// Volatile RMWs perform a load and a store, we cannot replace this by just a
58+
// load. We chose not to canonicalize out of general paranoia about user
59+
// expectations around volatile.
6260
if (RMWI.isVolatile())
6361
return nullptr;
6462

63+
// We chose to canonicalize all idempotent operations to an single
64+
// operation code and constant. This makes it easier for the rest of the
65+
// optimizer to match easily. The choice of or w/zero is arbitrary.
66+
if (RMWI.getType()->isIntegerTy() &&
67+
RMWI.getOperation() != AtomicRMWInst::Or) {
68+
RMWI.setOperation(AtomicRMWInst::Or);
69+
RMWI.setOperand(1, ConstantInt::get(RMWI.getType(), 0));
70+
return &RMWI;
71+
}
72+
6573
// Check if the required ordering is compatible with an atomic load.
6674
AtomicOrdering Ordering = RMWI.getOrdering();
6775
assert(Ordering != AtomicOrdering::NotAtomic &&

‎llvm/test/Transforms/InstCombine/atomicrmw.ll

+12-13
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,13 @@ define i16 @atomic_syncscope(i16* %addr) {
8787
ret i16 %res
8888
}
8989

90-
; Don't transform seq_cst ordering.
9190
; By eliminating the store part of the atomicrmw, we would get rid of the
92-
; release semantic, which is incorrect.
93-
; CHECK-LABEL: atomic_or_zero_seq_cst
91+
; release semantic, which is incorrect. We can canonicalize the operation.
92+
; CHECK-LABEL: atomic_seq_cst
9493
; CHECK-NEXT: %res = atomicrmw or i16* %addr, i16 0 seq_cst
9594
; CHECK-NEXT: ret i16 %res
96-
define i16 @atomic_or_zero_seq_cst(i16* %addr) {
97-
%res = atomicrmw or i16* %addr, i16 0 seq_cst
95+
define i16 @atomic_seq_cst(i16* %addr) {
96+
%res = atomicrmw add i16* %addr, i16 0 seq_cst
9897
ret i16 %res
9998
}
10099

@@ -117,21 +116,21 @@ define i16 @atomic_xor_zero(i16* %addr) {
117116
}
118117

119118
; Check that the transformation does not apply when the ordering is
120-
; incompatible with a load (release).
121-
; CHECK-LABEL: atomic_or_zero_release
119+
; incompatible with a load (release). Do canonicalize.
120+
; CHECK-LABEL: atomic_release
122121
; CHECK-NEXT: %res = atomicrmw or i16* %addr, i16 0 release
123122
; CHECK-NEXT: ret i16 %res
124-
define i16 @atomic_or_zero_release(i16* %addr) {
125-
%res = atomicrmw or i16* %addr, i16 0 release
123+
define i16 @atomic_release(i16* %addr) {
124+
%res = atomicrmw sub i16* %addr, i16 0 release
126125
ret i16 %res
127126
}
128127

129128
; Check that the transformation does not apply when the ordering is
130-
; incompatible with a load (acquire, release).
131-
; CHECK-LABEL: atomic_or_zero_acq_rel
129+
; incompatible with a load (acquire, release). Do canonicalize.
130+
; CHECK-LABEL: atomic_acq_rel
132131
; CHECK-NEXT: %res = atomicrmw or i16* %addr, i16 0 acq_rel
133132
; CHECK-NEXT: ret i16 %res
134-
define i16 @atomic_or_zero_acq_rel(i16* %addr) {
135-
%res = atomicrmw or i16* %addr, i16 0 acq_rel
133+
define i16 @atomic_acq_rel(i16* %addr) {
134+
%res = atomicrmw xor i16* %addr, i16 0 acq_rel
136135
ret i16 %res
137136
}

0 commit comments

Comments
 (0)
Please sign in to comment.