]> granicus.if.org Git - llvm/commitdiff
Canonicalize all integer "idempotent" atomicrmw ops
authorPhilip Reames <listmail@philipreames.com>
Thu, 14 Feb 2019 20:41:17 +0000 (20:41 +0000)
committerPhilip Reames <listmail@philipreames.com>
Thu, 14 Feb 2019 20:41:17 +0000 (20:41 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354058 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp
test/Transforms/InstCombine/atomicrmw.ll

index 0c7e7ab66a9a358a28353b427eb45aad09e5dde3..b607c6dd608cf5396b21bb01bb9f73ffa61f76b6 100644 (file)
@@ -54,14 +54,22 @@ Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) {
   if (!isIdempotentRMW(RMWI))
     return nullptr;
 
-  // TODO: Canonicalize the operation for an idempotent operation we can't
-  // convert into a simple load.
-
-  // Volatile RMWs perform a load and a store, we cannot replace
-  // this by just a load.
+  // Volatile RMWs perform a load and a store, we cannot replace this by just a
+  // load. We chose not to canonicalize out of general paranoia about user
+  // expectations around volatile. 
   if (RMWI.isVolatile())
     return nullptr;
 
+  // We chose to canonicalize all idempotent operations to an single
+  // operation code and constant.  This makes it easier for the rest of the
+  // optimizer to match easily.  The choice of or w/zero is arbitrary.
+  if (RMWI.getType()->isIntegerTy() &&
+      RMWI.getOperation() != AtomicRMWInst::Or) {
+    RMWI.setOperation(AtomicRMWInst::Or);
+    RMWI.setOperand(1, ConstantInt::get(RMWI.getType(), 0));
+    return &RMWI;
+  }
+
   // Check if the required ordering is compatible with an atomic load.
   AtomicOrdering Ordering = RMWI.getOrdering();
   assert(Ordering != AtomicOrdering::NotAtomic &&
index 0ee747dce2c41712fac81a0fb0080ab485ef7b5d..52ec929abb5bf3e2fea93a90045820627d676f8b 100644 (file)
@@ -87,14 +87,13 @@ define i16 @atomic_syncscope(i16* %addr) {
   ret i16 %res
 }
 
-; Don't transform seq_cst ordering.
 ; By eliminating the store part of the atomicrmw, we would get rid of the
-; release semantic, which is incorrect.
-; CHECK-LABEL: atomic_or_zero_seq_cst
+; release semantic, which is incorrect.  We can canonicalize the operation.
+; CHECK-LABEL: atomic_seq_cst
 ; CHECK-NEXT: %res = atomicrmw or i16* %addr, i16 0 seq_cst
 ; CHECK-NEXT: ret i16 %res
-define i16 @atomic_or_zero_seq_cst(i16* %addr) {
-  %res = atomicrmw or i16* %addr, i16 0 seq_cst
+define i16 @atomic_seq_cst(i16* %addr) {
+  %res = atomicrmw add i16* %addr, i16 0 seq_cst
   ret i16 %res
 }
 
@@ -117,21 +116,21 @@ define i16 @atomic_xor_zero(i16* %addr) {
 }
 
 ; Check that the transformation does not apply when the ordering is
-; incompatible with a load (release).
-; CHECK-LABEL: atomic_or_zero_release
+; incompatible with a load (release).  Do canonicalize.
+; CHECK-LABEL: atomic_release
 ; CHECK-NEXT: %res = atomicrmw or i16* %addr, i16 0 release
 ; CHECK-NEXT: ret i16 %res
-define i16 @atomic_or_zero_release(i16* %addr) {
-  %res = atomicrmw or i16* %addr, i16 0 release
+define i16 @atomic_release(i16* %addr) {
+  %res = atomicrmw sub i16* %addr, i16 0 release
   ret i16 %res
 }
 
 ; Check that the transformation does not apply when the ordering is
-; incompatible with a load (acquire, release).
-; CHECK-LABEL: atomic_or_zero_acq_rel
+; incompatible with a load (acquire, release).  Do canonicalize.
+; CHECK-LABEL: atomic_acq_rel
 ; CHECK-NEXT: %res = atomicrmw or i16* %addr, i16 0 acq_rel
 ; CHECK-NEXT: ret i16 %res
-define i16 @atomic_or_zero_acq_rel(i16* %addr) {
-  %res = atomicrmw or i16* %addr, i16 0 acq_rel
+define i16 @atomic_acq_rel(i16* %addr) {
+  %res = atomicrmw xor i16* %addr, i16 0 acq_rel
   ret i16 %res
 }