Fix AddAliasScopeMetadata again - alias.scope must be a complete description

I thought that I had fixed this problem in r216818, but I did not do a very
good job. The underlying issue is that when we add alias.scope metadata we are
asserting that this metadata completely describes the aliasing relationships
within the current aliasing scope domain, and so in the context of translating
noalias argument attributes, the pointers must all be based on noalias
arguments (as underlying objects) and have no other kind of underlying object.
In r216818 excluding appropriate accesses from getting alias.scope metadata is
done by looking for underlying objects that are not identified function-local
objects -- but that's wrong because allocas, etc. are also function-local
objects and we need to explicitly check that all underlying objects are the
noalias arguments for which we're adding metadata aliasing scopes.

This fixes the underlying-object check for adding alias.scope metadata, and
does some refactoring of the related capture-checking eligibility logic (and
adds more comments; hopefully making everything a bit clearer).

Fixes self-hosting on x86_64 with -mllvm -enable-noalias-to-md-conversion (the
feature is still disabled by default).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216863 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hal Finkel 2014-09-01 04:26:40 +00:00
parent d43e6df10b
commit 5581563457
2 changed files with 40 additions and 15 deletions

View File

@ -487,11 +487,18 @@ static void AddAliasScopeMetadata(CallSite CS, ValueToValueMapTy &VMap,
PtrArgs.push_back(*AI); PtrArgs.push_back(*AI);
} }
bool IsFuncCall = isa<CallInst>(I) || isa<InvokeInst>(I);
// FIXME: We should have a way to access the
// IntrReadArgMem/IntrReadWriteArgMem properties of intrinsics, and we
// should have a way to determine that for regular functions too. For
// now, just do this for the memory intrinsics we understand.
bool IsArgMemOnlyCall = isa<MemIntrinsic>(I);
// If we found no pointers, then this instruction is not suitable for // If we found no pointers, then this instruction is not suitable for
// pairing with an instruction to receive aliasing metadata. // pairing with an instruction to receive aliasing metadata.
// However, if this is a call, this we might just alias with none of the // However, if this is a call, this we might just alias with none of the
// noalias arguments. // noalias arguments.
if (PtrArgs.empty() && !isa<CallInst>(I) && !isa<InvokeInst>(I)) if (PtrArgs.empty() && !IsFuncCall)
continue; continue;
// It is possible that there is only one underlying object, but you // It is possible that there is only one underlying object, but you
@ -520,21 +527,41 @@ static void AddAliasScopeMetadata(CallSite CS, ValueToValueMapTy &VMap,
bool IsNonPtrConst = isa<ConstantInt>(V) || isa<ConstantFP>(V) || bool IsNonPtrConst = isa<ConstantInt>(V) || isa<ConstantFP>(V) ||
isa<ConstantPointerNull>(V) || isa<ConstantPointerNull>(V) ||
isa<ConstantDataVector>(V) || isa<UndefValue>(V); isa<ConstantDataVector>(V) || isa<UndefValue>(V);
if (!IsNonPtrConst && if (IsNonPtrConst)
!isIdentifiedFunctionLocal(const_cast<Value*>(V))) { continue;
// If this is anything other than a noalias argument, then we cannot
// completely describe the aliasing properties using alias.scope
// metadata (and, thus, won't add any).
if (const Argument *A = dyn_cast<Argument>(V)) {
if (!A->hasNoAliasAttr())
UsesAliasingPtr = true;
} else {
UsesAliasingPtr = true; UsesAliasingPtr = true;
if (!isa<Argument>(V)) {
CanDeriveViaCapture = true;
break;
}
} }
// If this is not some identified function-local object (which cannot
// directly alias a noalias argument), or some other argument (which,
// by definition, also cannot alias a noalias argument), then we could
// alias a noalias argument that has been captured).
if (!isa<Argument>(V) &&
!isIdentifiedFunctionLocal(const_cast<Value*>(V)))
CanDeriveViaCapture = true;
} }
// A function call can always get captured noalias pointers (via other
// parameters, globals, etc.).
if (IsFuncCall && !IsArgMemOnlyCall)
CanDeriveViaCapture = true;
// First, we want to figure out all of the sets with which we definitely // First, we want to figure out all of the sets with which we definitely
// don't alias. Iterate over all noalias set, and add those for which: // don't alias. Iterate over all noalias set, and add those for which:
// 1. The noalias argument is not in the set of objects from which we // 1. The noalias argument is not in the set of objects from which we
// definitely derive. // definitely derive.
// 2. The noalias argument has not yet been captured. // 2. The noalias argument has not yet been captured.
// An arbitrary function that might load pointers could see captured
// noalias arguments via other noalias arguments or globals, and so we
// must always check for prior capture.
for (const Argument *A : NoAliasArgs) { for (const Argument *A : NoAliasArgs) {
if (!ObjSet.count(A) && (!CanDeriveViaCapture || if (!ObjSet.count(A) && (!CanDeriveViaCapture ||
// It might be tempting to skip the // It might be tempting to skip the
@ -565,13 +592,8 @@ static void AddAliasScopeMetadata(CallSite CS, ValueToValueMapTy &VMap,
// scopes to arbitrary functions unless we know they don't access any // scopes to arbitrary functions unless we know they don't access any
// non-parameter pointer-values. // non-parameter pointer-values.
bool CanAddScopes = !UsesAliasingPtr; bool CanAddScopes = !UsesAliasingPtr;
if (CanAddScopes && (isa<CallInst>(I) || isa<InvokeInst>(I))) { if (CanAddScopes && IsFuncCall)
// FIXME: We should have a way to access the CanAddScopes = IsArgMemOnlyCall;
// IntrReadArgMem/IntrReadWriteArgMem properties of intrinsics, and we
// should have a way to determine that for regular functions too. For
// now, just do this for the memory intrinsics we understand.
CanAddScopes = isa<MemIntrinsic>(I);
}
if (CanAddScopes) if (CanAddScopes)
for (const Argument *A : NoAliasArgs) { for (const Argument *A : NoAliasArgs) {

View File

@ -7,10 +7,12 @@ declare void @hey() #0
define void @hello(i8* noalias nocapture %a, i8* noalias nocapture readonly %c, i8* nocapture %b) #1 { define void @hello(i8* noalias nocapture %a, i8* noalias nocapture readonly %c, i8* nocapture %b) #1 {
entry: entry:
%l = alloca i8, i32 512, align 1
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 16, i32 16, i1 0) call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 16, i32 16, i1 0)
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c, i64 16, i32 16, i1 0) call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c, i64 16, i32 16, i1 0)
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %c, i64 16, i32 16, i1 0) call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %c, i64 16, i32 16, i1 0)
call void @hey() call void @hey()
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l, i8* %c, i64 16, i32 16, i1 0)
ret void ret void
} }
@ -26,6 +28,7 @@ entry:
; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c, i64 16, i32 16, i1 false) #0, !noalias !3 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c, i64 16, i32 16, i1 false) #0, !noalias !3
; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %c, i64 16, i32 16, i1 false) #0, !alias.scope !5 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %c, i64 16, i32 16, i1 false) #0, !alias.scope !5
; CHECK: call void @hey() #0, !noalias !5 ; CHECK: call void @hey() #0, !noalias !5
; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %c, i64 16, i32 16, i1 false) #0, !noalias !3
; CHECK: ret void ; CHECK: ret void
; CHECK: } ; CHECK: }