[llvm] e187361 - [Attributor] Teach AAPointerInfo about atomic cmxchg and rmw

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 5 07:27:42 PDT 2022


Author: Johannes Doerfert
Date: 2022-10-05T06:48:00-07:00
New Revision: e18736149c67cff47492617aa02b31f3d6067a51

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

LOG: [Attributor] Teach AAPointerInfo about atomic cmxchg and rmw

The atomic operations behave similar to a store except that we don't
know the new value and we read the result first.

Added: 
    

Modified: 
    llvm/lib/Transforms/IPO/AttributorAttributes.cpp
    llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 642f1f16f20c..2a3ca28b97c4 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -14,6 +14,7 @@
 #include "llvm/Transforms/IPO/Attributor.h"
 
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/SCCIterator.h"
@@ -1374,27 +1375,47 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
                             LoadI->getType());
       }
 
-      if (auto *StoreI = dyn_cast<StoreInst>(Usr)) {
-        if (StoreI->getValueOperand() == CurPtr) {
-          LLVM_DEBUG(dbgs() << "[AAPointerInfo] Escaping use in store "
-                            << *StoreI << "\n");
-          return false;
+      auto HandleStoreLike = [&](Instruction &I, Value *ValueOp, Type &ValueTy,
+                                 ArrayRef<Value *> OtherOps, AccessKind AK) {
+        for (auto *OtherOp : OtherOps) {
+          if (OtherOp == CurPtr) {
+            LLVM_DEBUG(
+                dbgs()
+                << "[AAPointerInfo] Escaping use in store like instruction "
+                << I << "\n");
+            return false;
+          }
         }
+
         // If the access is to a pointer that may or may not be the associated
         // value, e.g. due to a PHI, we cannot assume it will be written.
-        AccessKind AK = AccessKind::AK_W;
         if (getUnderlyingObject(CurPtr) == &AssociatedValue)
           AK = AccessKind(AK | AccessKind::AK_MUST);
         else
           AK = AccessKind(AK | AccessKind::AK_MAY);
         bool UsedAssumedInformation = false;
-        Optional<Value *> Content =
-            A.getAssumedSimplified(*StoreI->getValueOperand(), *this,
-                                   UsedAssumedInformation, AA::Interprocedural);
-        return handleAccess(A, *StoreI, *CurPtr, Content, AK,
-                            OffsetInfoMap[CurPtr].Offset, Changed,
-                            StoreI->getValueOperand()->getType());
-      }
+        Optional<Value *> Content = nullptr;
+        if (ValueOp)
+          Content = A.getAssumedSimplified(
+              *ValueOp, *this, UsedAssumedInformation, AA::Interprocedural);
+        return handleAccess(A, I, *CurPtr, Content, AK,
+                            OffsetInfoMap[CurPtr].Offset, Changed, &ValueTy);
+      };
+
+      if (auto *StoreI = dyn_cast<StoreInst>(Usr))
+        return HandleStoreLike(*StoreI, StoreI->getValueOperand(),
+                               *StoreI->getValueOperand()->getType(),
+                               {StoreI->getValueOperand()}, AccessKind::AK_W);
+      if (auto *RMWI = dyn_cast<AtomicRMWInst>(Usr))
+        return HandleStoreLike(*RMWI, nullptr,
+                               *RMWI->getValOperand()->getType(),
+                               {RMWI->getValOperand()}, AccessKind::AK_RW);
+      if (auto *CXI = dyn_cast<AtomicCmpXchgInst>(Usr))
+        return HandleStoreLike(
+            *CXI, nullptr, *CXI->getNewValOperand()->getType(),
+            {CXI->getCompareOperand(), CXI->getNewValOperand()},
+            AccessKind::AK_RW);
+
       if (auto *CB = dyn_cast<CallBase>(Usr)) {
         if (CB->isLifetimeStartOrEnd())
           return true;

diff  --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll
index 988c3be5b462..a8139321c401 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll
@@ -6,12 +6,13 @@
 ;
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 
-%struct.S = type { i32, double, ptr }
+%struct.S = type { i32, double, ptr, i32 }
 
 ;    struct S {
 ;      int a;
 ;      double b;
 ;      struct S* c;
+;      int written;
 ;    };
 ;
 ;    static const struct S GlobalS = {42, 3.14, 0};
@@ -27,18 +28,20 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
 ;      return r;
 ;    }
 ;
- at GlobalS = internal constant %struct.S { i32 42, double 3.140000e+00, ptr null }, align 8
+ at GlobalS = internal constant %struct.S { i32 42, double 3.140000e+00, ptr null, i32 0 }, align 8
 
 declare void @harmless_use(ptr nocapture readonly) nofree norecurse nosync nounwind readnone willreturn nocallback
 
 ;.
-; CHECK: @[[GLOBALS:[a-zA-Z0-9_$"\\.-]+]] = internal constant [[STRUCT_S:%.*]] { i32 42, double 3.140000e+00, ptr null }, align 8
+; CHECK: @[[GLOBALS:[a-zA-Z0-9_$"\\.-]+]] = internal constant [[STRUCT_S:%.*]] { i32 42, double 3.140000e+00, ptr null, i32 0 }, align 8
 ;.
-define i32 @testOneFieldGlobalS() {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+define i32 @testOneFieldGlobalS(i32 %cmpx) {
+; CHECK: Function Attrs: nofree norecurse nounwind readnone willreturn
 ; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS
-; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
+; CHECK-SAME: (i32 [[CMPX:%.*]]) #[[ATTR1:[0-9]+]] {
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[RMW:%.*]] = atomicrmw add ptr getelementptr inbounds ([[STRUCT_S:%.*]], ptr @GlobalS, i32 0, i32 3), i32 1 monotonic, align 4
+; CHECK-NEXT:    [[CXI:%.*]] = cmpxchg ptr getelementptr inbounds ([[STRUCT_S]], ptr @GlobalS, i32 0, i32 3), i32 [[CMPX]], i32 7 acq_rel monotonic, align 4
 ; CHECK-NEXT:    br label [[IF_END:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    unreachable
@@ -57,6 +60,8 @@ define i32 @testOneFieldGlobalS() {
 entry:
   %i = load i32, ptr @GlobalS, align 8
   call void @harmless_use(ptr @GlobalS)
+  %rmw = atomicrmw add ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 3), i32 1 monotonic, align 4
+  %cxi = cmpxchg ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 3), i32 %cmpx, i32 7 acq_rel monotonic
   %cmp = icmp ne i32 %i, 42
   br i1 %cmp, label %if.then, label %if.end
 
@@ -92,7 +97,7 @@ if.end7:                                          ; preds = %if.then5, %if.end4
 define i32 @testOneFieldGlobalS_type_mismatch() {
 ; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS_type_mismatch
-; CHECK-SAME: () #[[ATTR1]] {
+; CHECK-SAME: () #[[ATTR2:[0-9]+]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[I:%.*]] = load double, ptr @GlobalS, align 8
 ; CHECK-NEXT:    [[IC:%.*]] = fptosi double [[I]] to i32
@@ -158,7 +163,7 @@ if.end7:                                          ; preds = %if.then5, %if.end4
 define i32 @testOneFieldGlobalS_byte_offset_wrong() {
 ; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS_byte_offset_wrong
-; CHECK-SAME: () #[[ATTR1]] {
+; CHECK-SAME: () #[[ATTR2]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[I:%.*]] = load i32, ptr getelementptr inbounds (i32, ptr @GlobalS, i32 1), align 8
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I]], 42
@@ -221,5 +226,6 @@ if.end7:                                          ; preds = %if.then5, %if.end4
 }
 ;.
 ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree norecurse nosync nounwind readnone willreturn }
-; CHECK: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn }
+; CHECK: attributes #[[ATTR1]] = { nofree norecurse nounwind readnone willreturn }
+; CHECK: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn }
 ;.


        


More information about the llvm-commits mailing list