summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Analysis/AliasAnalysis.h4
-rw-r--r--llvm/lib/Analysis/AliasAnalysis.cpp11
-rw-r--r--llvm/lib/Target/README.txt4
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp15
-rw-r--r--llvm/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll33
-rw-r--r--llvm/utils/TableGen/IntrinsicEmitter.cpp2
6 files changed, 60 insertions, 9 deletions
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index 2d43bddf7e0..9f411350a79 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -197,6 +197,10 @@ public:
virtual ModRefBehavior getModRefBehavior(Function *F,
std::vector<PointerAccessInfo> *Info = 0);
+ /// getModRefBehavior - Return the modref behavior of the intrinsic with the
+ /// given id.
+ static ModRefBehavior getModRefBehavior(unsigned iid);
+
/// doesNotAccessMemory - If the specified call is known to never read or
/// write memory, return true. If the call only reads from known-constant
/// memory, it is also legal to return true. Calls that unwind the stack
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index dee9b535871..371dcafa9f3 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -116,13 +116,16 @@ AliasAnalysis::getModRefBehavior(Function *F,
return DoesNotAccessMemory;
if (F->onlyReadsMemory())
return OnlyReadsMemory;
- if (unsigned id = F->getIntrinsicID()) {
+ if (unsigned id = F->getIntrinsicID())
+ return getModRefBehavior(id);
+ }
+ return UnknownModRefBehavior;
+}
+
+AliasAnalysis::ModRefBehavior AliasAnalysis::getModRefBehavior(unsigned iid) {
#define GET_INTRINSIC_MODREF_BEHAVIOR
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_MODREF_BEHAVIOR
- }
- }
- return UnknownModRefBehavior;
}
AliasAnalysis::ModRefResult
diff --git a/llvm/lib/Target/README.txt b/llvm/lib/Target/README.txt
index 22dadfeb3dd..38c3daa9383 100644
--- a/llvm/lib/Target/README.txt
+++ b/llvm/lib/Target/README.txt
@@ -1678,8 +1678,8 @@ And functionattrs doesn't realize that the p.0 load points to function local
memory.
Also, functionattrs doesn't know about memcpy/memset. This function should be
-marked readnone, since it only twiddles local memory, but functionattrs doesn't
-handle memset/memcpy/memmove aggressively:
+marked readnone rather than readonly, since it only twiddles local memory, but
+functionattrs doesn't handle memset/memcpy/memmove aggressively:
struct X { int *p; int *q; };
int foo() {
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index a16d335ef50..0bff2b94e9d 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -136,6 +136,21 @@ bool FunctionAttrs::AddReadAttrs(const std::vector<CallGraphNode *> &SCC) {
// Ignore calls to functions in the same SCC.
if (SCCNodes.count(CS.getCalledFunction()))
continue;
+ // Ignore intrinsics that only access local memory.
+ if (unsigned id = CS.getCalledFunction()->getIntrinsicID())
+ if (AliasAnalysis::getModRefBehavior(id) ==
+ AliasAnalysis::AccessesArguments) {
+ // Check that all pointer arguments point to local memory.
+ for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
+ CI != CE; ++CI) {
+ Value *Arg = *CI;
+ if (isa<PointerType>(Arg->getType()) && !PointsToLocalMemory(Arg))
+ // Writes memory. Just give up.
+ return false;
+ }
+ // Only reads and writes local memory.
+ continue;
+ }
} else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
// Ignore loads from local memory.
if (PointsToLocalMemory(LI->getPointerOperand()))
diff --git a/llvm/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll b/llvm/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll
index 09eb4687ac2..460780d8ea5 100644
--- a/llvm/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll
+++ b/llvm/test/Transforms/FunctionAttrs/2008-10-04-LocalMemory.ll
@@ -1,6 +1,8 @@
-; RUN: opt < %s -functionattrs -S | grep readnone | count 2
+; RUN: opt < %s -functionattrs -S | grep readonly | count 3
-declare i32 @g(i32*) readnone
+%struct.X = type { i32*, i32* }
+
+declare i32 @g(i32*) readonly
define i32 @f() {
%x = alloca i32 ; <i32*> [#uses=2]
@@ -8,3 +10,30 @@ define i32 @f() {
%y = call i32 @g(i32* %x) ; <i32> [#uses=1]
ret i32 %y
}
+
+define i32 @foo() nounwind {
+entry:
+ %y = alloca %struct.X ; <%struct.X*> [#uses=2]
+ %x = alloca %struct.X ; <%struct.X*> [#uses=2]
+ %j = alloca i32 ; <i32*> [#uses=2]
+ %i = alloca i32 ; <i32*> [#uses=2]
+ %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
+ store i32 0, i32* %i, align 4
+ store i32 1, i32* %j, align 4
+ %0 = getelementptr inbounds %struct.X* %y, i32 0, i32 0 ; <i32**> [#uses=1]
+ store i32* %i, i32** %0, align 8
+ %1 = getelementptr inbounds %struct.X* %x, i32 0, i32 1 ; <i32**> [#uses=1]
+ store i32* %j, i32** %1, align 8
+ %x1 = bitcast %struct.X* %x to i8* ; <i8*> [#uses=2]
+ %y2 = bitcast %struct.X* %y to i8* ; <i8*> [#uses=1]
+ call void @llvm.memcpy.i64(i8* %x1, i8* %y2, i64 8, i32 1)
+ %2 = bitcast i8* %x1 to i32** ; <i32**> [#uses=1]
+ %3 = load i32** %2, align 8 ; <i32*> [#uses=1]
+ %4 = load i32* %3, align 4 ; <i32> [#uses=1]
+ br label %return
+
+return: ; preds = %entry
+ ret i32 %4
+}
+
+declare void @llvm.memcpy.i64(i8* nocapture, i8* nocapture, i64, i32) nounwind
diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp
index 23919d97f2b..c5df9e411c6 100644
--- a/llvm/utils/TableGen/IntrinsicEmitter.cpp
+++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp
@@ -522,7 +522,7 @@ void IntrinsicEmitter::
EmitModRefBehavior(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS){
OS << "// Determine intrinsic alias analysis mod/ref behavior.\n";
OS << "#ifdef GET_INTRINSIC_MODREF_BEHAVIOR\n";
- OS << "switch (id) {\n";
+ OS << "switch (iid) {\n";
OS << "default:\n return UnknownModRefBehavior;\n";
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
if (Ints[i].ModRef == CodeGenIntrinsic::WriteMem)
OpenPOWER on IntegriCloud