Correctly combine alias.scope metadata by a union instead of intersecting

Summary:
The alias.scope metadata represents sets of things an instruction might
alias with. When generically combining the metadata from two
instructions the result must be the union of the original sets, because
the new instruction might alias with anything any of the original
instructions aliased with.

Reviewers: hfinkel

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D7490

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@228525 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bjorn Steinbrink 2015-02-08 17:07:14 +00:00
parent 186332c0c9
commit 61a16d2a16
6 changed files with 53 additions and 2 deletions

View File

@ -879,6 +879,7 @@ public:
static MDNode *getMostGenericTBAA(MDNode *A, MDNode *B);
static MDNode *getMostGenericFPMath(MDNode *A, MDNode *B);
static MDNode *getMostGenericRange(MDNode *A, MDNode *B);
static MDNode *getMostGenericAliasScope(MDNode *A, MDNode *B);
};
/// \brief Tuple of metadata.

View File

@ -623,8 +623,8 @@ void Instruction::getAAMetadata(AAMDNodes &N, bool Merge) const {
N.TBAA = getMetadata(LLVMContext::MD_tbaa);
if (Merge)
N.Scope =
MDNode::intersect(N.Scope, getMetadata(LLVMContext::MD_alias_scope));
N.Scope = MDNode::getMostGenericAliasScope(
N.Scope, getMetadata(LLVMContext::MD_alias_scope));
else
N.Scope = getMetadata(LLVMContext::MD_alias_scope);

View File

@ -782,6 +782,28 @@ MDNode *MDNode::intersect(MDNode *A, MDNode *B) {
return getOrSelfReference(A->getContext(), MDs);
}
MDNode *MDNode::getMostGenericAliasScope(MDNode *A, MDNode *B) {
if (!A || !B)
return nullptr;
SmallVector<Metadata *, 4> MDs(B->op_begin(), B->op_end());
for (unsigned i = 0, ie = A->getNumOperands(); i != ie; ++i) {
Metadata *MD = A->getOperand(i);
bool insert = true;
for (unsigned j = 0, je = B->getNumOperands(); j != je; ++j)
if (MD == B->getOperand(j)) {
insert = false;
break;
}
if (insert)
MDs.push_back(MD);
}
// FIXME: This preserves long-standing behaviour, but is it really the right
// behaviour? Or was that an unintended side-effect of node uniquing?
return getOrSelfReference(A->getContext(), MDs);
}
MDNode *MDNode::getMostGenericFPMath(MDNode *A, MDNode *B) {
if (!A || !B)
return nullptr;

View File

@ -1334,6 +1334,8 @@ void llvm::combineMetadata(Instruction *K, const Instruction *J, ArrayRef<unsign
K->setMetadata(Kind, MDNode::getMostGenericTBAA(JMD, KMD));
break;
case LLVMContext::MD_alias_scope:
K->setMetadata(Kind, MDNode::getMostGenericAliasScope(JMD, KMD));
break;
case LLVMContext::MD_noalias:
K->setMetadata(Kind, MDNode::intersect(JMD, KMD));
break;

View File

@ -217,6 +217,8 @@ static Instruction *propagateMetadata(Instruction *I, ArrayRef<Value *> VL) {
MD = MDNode::getMostGenericTBAA(MD, IMD);
break;
case LLVMContext::MD_alias_scope:
MD = MDNode::getMostGenericAliasScope(MD, IMD);
break;
case LLVMContext::MD_noalias:
MD = MDNode::intersect(MD, IMD);
break;

View File

@ -0,0 +1,24 @@
; RUN: opt < %s -S -basicaa -memcpyopt | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @test(i8* noalias dereferenceable(1) %in, i8* noalias dereferenceable(1) %out) {
%tmp = alloca i8
%tmp2 = alloca i8
; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %out, i8* %in, i64 1, i32 8, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp, i8* %in, i64 1, i32 8, i1 false), !alias.scope !4
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp2, i8* %tmp, i64 1, i32 8, i1 false), !alias.scope !5
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %out, i8* %tmp2, i64 1, i32 8, i1 false), !noalias !6
ret void
}
declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1)
!0 = !{!0}
!1 = distinct !{!1, !0, !"in"}
!2 = distinct !{!2, !0, !"tmp"}
!3 = distinct !{!3, !0, !"tmp2"}
!4 = distinct !{!1, !2}
!5 = distinct !{!2, !3}
!6 = distinct !{!1, !2}