[llvm-commits] [PATCH] Extend BasicAliasAnalysis to recognize cyclic NoAlias phis in loops

Arnold Schwaighofer arnolds at codeaurora.org
Thu Aug 9 08:54:02 PDT 2012


Hi,

BasicAliasAnalysis should recognize phis that have incoming values from 
outside the loop that are known to not alias and whose other incoming 
values do not change this fact because they perform congruent operations.

Example: We want to prove that ptr_phi and ptr_phi2 do not alias each other.

bb:
  ptr = ptr2 + 1

loop:
   ptr_phi = phi [bb, ptr], [loop, ptr_plus_one]
   ptr2_phi = phi [bb, ptr2], [loop, ptr2_plus_one]
   ...
   ptr_plus_one = gep ptr_phi, 1
   ptr2_plus_one = gep ptr2_phi, 1

This would enable the elimination of one load in code like the following:

extern int foo;

int test_noalias(int *ptr, int num, int* coeff) {
   int *ptr2 = ptr;
   int result = (*ptr++) * (*coeff--);
   while (num--) {
     *ptr2++ = *ptr;
     result +=  (*coeff--) * (*ptr++);
   }
   *ptr = foo;
   return result;
}

Currently, without the improvement to basic alias analysis we generate 
the following code for the loop:

The loads from %r9 are the accesses to "ptr".

.LBB0_2:                                # %while.body
                                         # =>This Inner Loop Header: Depth=1
         movl    (%r9), %ecx
         movl    %ecx, -4(%r9)
         movl    (%r9), %ecx
         imull   (%rdx), %ecx
         addl    %ecx, %eax
         addq    $-4, %rdx
         addq    $4, %r9
         decl    %esi
         jne     .LBB0_2

With the improvement we would generate:

.LBB0_2:                                # %while.body
                                         # =>This Inner Loop Header: Depth=1
         movl    (%r9), %ecx
         movl    %ecx, -4(%r9)
         imull   (%rdx), %ecx
         addl    %ecx, %eax
         addq    $4, %r9
         addq    $-4, %rdx
         decl    %esi
         jne     .LBB0_2

The attached patch implements this enhancement.

http://llvm.org/bugs/show_bug.cgi?id=13564


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum.
-------------- next part --------------
>From 619a514d66e057eee81649db150b54027226c5ac Mon Sep 17 00:00:00 2001
From: Arnold Schwaighofer <arnolds at codeaurora.org>
Date: Wed, 8 Aug 2012 16:33:21 -0500
Subject: [PATCH] Extend BasicAliasAnalysis to recognize NoAlias phis in loops

This change modifies BasicAliasAnalysis to recognize phis that have incoming
values from outside the loop that are known to not alias and whose other
incoming values do not change this fact because they perform congruent
operations.

Example: We want to prove that ptr_phi and ptr_phi2 do not alias each other.

 bb:
    ptr = ptr2 + 1
 loop:
    ptr_phi = phi [bb, ptr], [loop, ptr_plus_one]
    ptr2_phi = phi [bb, ptr2], [loop, ptr2_plus_one]
    ...
    ptr_plus_one = gep ptr_phi, 1
    ptr2_plus_one = gep ptr2_phi, 1

Bug xxxx
---
 lib/Analysis/BasicAliasAnalysis.cpp      |   75 +++++++++++++++++++++++++++++-
 test/Analysis/BasicAA/phi-speculation.ll |   33 +++++++++++++
 2 files changed, 107 insertions(+), 1 deletions(-)
 create mode 100644 test/Analysis/BasicAA/phi-speculation.ll

diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp
index 1d028c2..1e4e820 100644
--- a/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/lib/Analysis/BasicAliasAnalysis.cpp
@@ -33,11 +33,16 @@
 #include "llvm/Target/TargetLibraryInfo.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/CommandLine.h"
+
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/GetElementPtrTypeIterator.h"
 #include <algorithm>
 using namespace llvm;
 
+static cl::opt<bool> IsAAPhiSpeculationEnabled("enable-basicaa-phi-speculation",
+                                               cl::init(true), cl::Hidden);
+
 //===----------------------------------------------------------------------===//
 // Useful predicates
 //===----------------------------------------------------------------------===//
@@ -490,6 +495,7 @@ namespace {
     // aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP
     // instruction against another.
     AliasResult aliasGEP(const GEPOperator *V1, uint64_t V1Size,
+                         const MDNode *V1TBAAInfo,
                          const Value *V2, uint64_t V2Size,
                          const MDNode *V2TBAAInfo,
                          const Value *UnderlyingV1, const Value *UnderlyingV2);
@@ -814,6 +820,7 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS,
 ///
 AliasAnalysis::AliasResult
 BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size,
+                             const MDNode *V1TBAAInfo,
                              const Value *V2, uint64_t V2Size,
                              const MDNode *V2TBAAInfo,
                              const Value *UnderlyingV1,
@@ -824,6 +831,38 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size,
   // If we have two gep instructions with must-alias'ing base pointers, figure
   // out if the indexes to the GEP tell us anything about the derived pointer.
   if (const GEPOperator *GEP2 = dyn_cast<GEPOperator>(V2)) {
+    // Check for constant geps of non-aliasing underlying pointers where the
+    // constant offsets are identical.
+    if (IsAAPhiSpeculationEnabled && V1Size == V2Size) {
+      // Do the base pointers alias assuming type and size.
+      AliasResult PreciseBaseAlias = aliasCheck(UnderlyingV1, V1Size,
+                                                V1TBAAInfo, UnderlyingV2,
+                                                V2Size, V2TBAAInfo);
+      if (PreciseBaseAlias == NoAlias) {
+        // See if the computed offset from the common pointer tells us about the
+        // relation of the resulting pointer.
+        int64_t GEP2BaseOffset;
+        SmallVector<VariableGEPIndex, 4> GEP2VariableIndices;
+        const Value *GEP2BasePtr =
+          DecomposeGEPExpression(GEP2, GEP2BaseOffset, GEP2VariableIndices, TD);
+        const Value *GEP1BasePtr =
+          DecomposeGEPExpression(GEP1, GEP1BaseOffset, GEP1VariableIndices, TD);
+        // If DecomposeGEPExpression isn't able to look all the way through the
+        // addressing operation, we must not have TD and this is too complex for
+        // us to handle without it.
+        if (GEP1BasePtr != UnderlyingV1 || GEP2BasePtr != UnderlyingV2) {
+          assert(TD == 0 &&
+             "DecomposeGEPExpression and GetUnderlyingObject disagree!");
+          return MayAlias;
+        }
+        // Same offsets.
+        if (GEP1BaseOffset-GEP2BaseOffset == 0 && GEP1VariableIndices.empty() &&
+            GEP2VariableIndices.empty())
+          return NoAlias;
+        GEP1VariableIndices.clear();
+      }
+    }
+
     // Do the base pointers alias?
     AliasResult BaseAlias = aliasCheck(UnderlyingV1, UnknownSize, 0,
                                        UnderlyingV2, UnknownSize, 0);
@@ -1004,12 +1043,41 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, uint64_t PNSize,
   // on corresponding edges.
   if (const PHINode *PN2 = dyn_cast<PHINode>(V2))
     if (PN2->getParent() == PN->getParent()) {
+      LocPair Locs(Location(PN, PNSize, PNTBAAInfo),
+                     Location(V2, V2Size, V2TBAAInfo));
+      if (PN > V2)
+        std::swap(Locs.first, Locs.second);
+
       AliasResult Alias =
         aliasCheck(PN->getIncomingValue(0), PNSize, PNTBAAInfo,
                    PN2->getIncomingValueForBlock(PN->getIncomingBlock(0)),
                    V2Size, V2TBAAInfo);
       if (Alias == MayAlias)
         return MayAlias;
+
+      // Check for phis in loops where we know that the incoming value from
+      // outside the loop is NoAlias and the operations inside the loop that are
+      // feeding the phis are congruent.
+      // bb:
+      //    ptr = ptr2 + 1
+      // loop:
+      //    ptr_phi = phi [bb, ptr], [loop, ptr_plus_one]
+      //    ptr2_phi = phi [bb, ptr2], [loop, ptr2_plus_one]
+      //    ...
+      //    ptr_plus_one = gep ptr_phi, 1
+      //    ptr2_plus_one = gep ptr2_phi, 1
+      // We assume that the the phis (ptr_phi, ptr2_phi) do not alias each other
+      // and try to prove otherwise.
+      bool ArePhisAssumedNoAlias = false;
+      AliasResult OrigAliasResult;
+      if  (IsAAPhiSpeculationEnabled && Alias == NoAlias) {
+        // Pretend the phis do not alias and see what happens.
+        assert(AliasCache.count(Locs));
+        OrigAliasResult = AliasCache[Locs];
+        AliasCache[Locs] = NoAlias;
+        ArePhisAssumedNoAlias = true;
+      }
+
       for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) {
         AliasResult ThisAlias =
           aliasCheck(PN->getIncomingValue(i), PNSize, PNTBAAInfo,
@@ -1019,6 +1087,11 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, uint64_t PNSize,
         if (Alias == MayAlias)
           break;
       }
+
+      // Reset if speculation failed.
+      if (IsAAPhiSpeculationEnabled && ArePhisAssumedNoAlias && Alias != NoAlias)
+        AliasCache[Locs] = OrigAliasResult;
+
       return Alias;
     }
 
@@ -1156,7 +1229,7 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, uint64_t V1Size,
     std::swap(O1, O2);
   }
   if (const GEPOperator *GV1 = dyn_cast<GEPOperator>(V1)) {
-    AliasResult Result = aliasGEP(GV1, V1Size, V2, V2Size, V2TBAAInfo, O1, O2);
+    AliasResult Result = aliasGEP(GV1, V1Size, V1TBAAInfo, V2, V2Size, V2TBAAInfo, O1, O2);
     if (Result != MayAlias) return AliasCache[Locs] = Result;
   }
 
diff --git a/test/Analysis/BasicAA/phi-speculation.ll b/test/Analysis/BasicAA/phi-speculation.ll
new file mode 100644
index 0000000..21c6592
--- /dev/null
+++ b/test/Analysis/BasicAA/phi-speculation.ll
@@ -0,0 +1,33 @@
+target datalayout =
+"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; ptr_phi and ptr2_phi do not alias.
+; CHECK: NoAlias: i32* %ptr2_phi, i32* %ptr_phi
+
+define i32 @test_noalias(i32* %ptr2, i32 %count, i32* %coeff) {
+entry:
+  %ptr = getelementptr inbounds i32* %ptr2, i64 1
+  br label %while.body
+
+while.body:
+  %num = phi i32 [ %count, %entry ], [ %dec, %while.body ]
+  %ptr_phi = phi i32* [ %ptr, %entry ], [ %ptr_inc, %while.body ]
+  %ptr2_phi = phi i32* [ %ptr2, %entry ], [ %ptr2_inc, %while.body ]
+  %result.09 = phi i32 [ 0 , %entry ], [ %add, %while.body ]
+  %dec = add nsw i32 %num, -1
+  %0 = load i32* %ptr_phi, align 4
+  store i32 %0, i32* %ptr2_phi, align 4
+  %1 = load i32* %coeff, align 4
+  %2 = load i32* %ptr_phi, align 4
+  %mul = mul nsw i32 %1, %2
+  %add = add nsw i32 %mul, %result.09
+  %tobool = icmp eq i32 %dec, 0
+  %ptr_inc = getelementptr inbounds i32* %ptr_phi, i64 1
+  %ptr2_inc = getelementptr inbounds i32* %ptr2_phi, i64 1
+  br i1 %tobool, label %the_exit, label %while.body
+
+the_exit:
+  ret i32 %add
+}
-- 
1.7.6.4



More information about the llvm-commits mailing list