1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

[AssumeBundles] filter usefull attriutes to preserve

Summary:
This patch will filter attributes to only preserve those that are usefull.
In the case of NoAlias it is filtered out not because it isn't usefull
but because it is incorrect to preserve it as it is only valdi for the
duration of the function.

Reviewers: jdoerfert

Reviewed By: jdoerfert

Subscribers: jdoerfert, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D75828
This commit is contained in:
Tyker 2020-03-13 14:35:26 +01:00
parent f0d2f70372
commit e683b7953c
4 changed files with 212 additions and 222 deletions

View File

@ -95,6 +95,19 @@ bool isLowerOpBundle(const OperandBundleDef &LHS, const OperandBundleDef &RHS) {
return getTuple(LHS) < getTuple(RHS);
}
bool isUsefullToPreserve(Attribute::AttrKind Kind) {
switch (Kind) {
case Attribute::NonNull:
case Attribute::Alignment:
case Attribute::Dereferenceable:
case Attribute::DereferenceableOrNull:
case Attribute::Cold:
return true;
default:
return false;
}
}
/// This class contain all knowledge that have been gather while building an
/// llvm.assume and the function to manipulate it.
struct AssumeBuilderState {
@ -105,13 +118,14 @@ struct AssumeBuilderState {
AssumeBuilderState(Module *M) : M(M) {}
void addAttribute(Attribute Attr, Value *WasOn) {
if (!ShouldPreserveAllAttributes &&
(Attr.isTypeAttribute() || Attr.isStringAttribute() ||
!isUsefullToPreserve(Attr.getKindAsEnum())))
return;
StringRef Name;
Value *AttrArg = nullptr;
if (Attr.isStringAttribute())
if (ShouldPreserveAllAttributes)
Name = Attr.getKindAsString();
else
return;
else
Name = Attribute::getNameFromAttrKind(Attr.getKindAsEnum());
if (Attr.isIntAttribute())
@ -127,7 +141,6 @@ struct AssumeBuilderState {
Idx < AttrList.getNumAttrSets(); Idx++)
for (Attribute Attr : AttrList.getAttributes(Idx))
addAttribute(Attr, Call->getArgOperand(Idx - 1));
if (ShouldPreserveAllAttributes)
for (Attribute Attr : AttrList.getFnAttributes())
addAttribute(Attr, nullptr);
};

View File

@ -14,9 +14,9 @@ define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {
; BASIC-NEXT: call void @func(i32* nonnull dereferenceable(16) [[P]], i32* null)
; BASIC-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1:%.*]], i64 12), "nonnull"(i32* [[P]]) ]
; BASIC-NEXT: call void @func(i32* dereferenceable(12) [[P1]], i32* nonnull [[P]])
; BASIC-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 12) ]
; BASIC-NEXT: call void @llvm.assume(i1 true) [ "cold"(), "dereferenceable"(i32* [[P1]], i64 12) ]
; BASIC-NEXT: call void @func_cold(i32* dereferenceable(12) [[P1]]) #0
; BASIC-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 12) ]
; BASIC-NEXT: call void @llvm.assume(i1 true) [ "cold"(), "dereferenceable"(i32* [[P1]], i64 12) ]
; BASIC-NEXT: call void @func_cold(i32* dereferenceable(12) [[P1]])
; BASIC-NEXT: call void @func(i32* [[P1]], i32* [[P]])
; BASIC-NEXT: call void @func_strbool(i32* [[P1]])

View File

@ -28,29 +28,27 @@ entry:
}
define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
; NO_ASSUME-LABEL: define {{[^@]+}}@foo
; NO_ASSUME-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) #0
; NO_ASSUME-NEXT: entry:
; NO_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3
; NO_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; NO_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0
; NO_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4
; NO_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; NO_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4
; NO_ASSUME-NEXT: ret void
;
; USE_ASSUME-LABEL: define {{[^@]+}}@foo
; USE_ASSUME-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) #0
; USE_ASSUME-NEXT: entry:
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A]]), "noalias"(float* [[C]]), "nocapture"(float* [[A]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ]
; USE_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3
; USE_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; USE_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0
; USE_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4
; USE_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; USE_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4
; USE_ASSUME-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) #0
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3
; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0
; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4
; CHECK-NEXT: ret void
;
; ASSUME-LABEL: @foo(
; ASSUME-NEXT: entry:
; ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A:%.*]]), "noalias"(float* [[C:%.*]]) ]
; ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3
; ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0
; ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4
; ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4
; ASSUME-NEXT: ret void
entry:
tail call void @hello(float* %a, float* %c)
%0 = load float, float* %c, align 4
@ -82,46 +80,24 @@ entry:
; Check that when hello() is inlined into foo(), and then foo() is inlined into
; foo2(), the noalias scopes are properly concatenated.
define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
; NO_ASSUME-LABEL: define {{[^@]+}}@foo2
; NO_ASSUME-SAME: (float* nocapture [[A:%.*]], float* nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) #0
; NO_ASSUME-NEXT: entry:
; NO_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !5, !noalias !10
; NO_ASSUME-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; NO_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !10, !noalias !5
; NO_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !13, !noalias !14
; NO_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; NO_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !14, !noalias !13
; NO_ASSUME-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !15
; NO_ASSUME-NEXT: [[ARRAYIDX_I1:%.*]] = getelementptr inbounds float, float* [[A]], i64 6
; NO_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !19, !noalias !20
; NO_ASSUME-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B]], i64 8
; NO_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !20, !noalias !19
; NO_ASSUME-NEXT: [[TMP3:%.*]] = load float, float* [[C]], align 4
; NO_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; NO_ASSUME-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4
; NO_ASSUME-NEXT: ret void
;
; USE_ASSUME-LABEL: define {{[^@]+}}@foo2
; USE_ASSUME-SAME: (float* nocapture [[A:%.*]], float* nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) #0
; USE_ASSUME-NEXT: entry:
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A]]), "noalias"(float* [[C]]), "nocapture"(float* [[A]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ]
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) #2 [ "noalias"(float* [[A]]), "noalias"(float* [[C]]), "nocapture"(float* [[A]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ], !noalias !5
; USE_ASSUME-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !9, !noalias !12
; USE_ASSUME-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; USE_ASSUME-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !12, !noalias !9
; USE_ASSUME-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !14, !noalias !15
; USE_ASSUME-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; USE_ASSUME-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !15, !noalias !14
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "noalias"(float* [[A]]), "noalias"(float* [[B]]), "nocapture"(float* [[A]]), "nocapture"(float* [[B]]), "nocapture"(float* [[C]]), "readonly"(float* [[C]]) ]
; USE_ASSUME-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !16
; USE_ASSUME-NEXT: [[ARRAYIDX_I1:%.*]] = getelementptr inbounds float, float* [[A]], i64 6
; USE_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !20, !noalias !21
; USE_ASSUME-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B]], i64 8
; USE_ASSUME-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !21, !noalias !20
; USE_ASSUME-NEXT: [[TMP3:%.*]] = load float, float* [[C]], align 4
; USE_ASSUME-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; USE_ASSUME-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4
; USE_ASSUME-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@foo2
; CHECK-SAME: (float* nocapture [[A:%.*]], float* nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) #0
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !5, !noalias !10
; CHECK-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5
; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !10, !noalias !5
; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !13, !noalias !14
; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !14, !noalias !13
; CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !15
; CHECK-NEXT: [[ARRAYIDX_I1:%.*]] = getelementptr inbounds float, float* [[A]], i64 6
; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !19, !noalias !20
; CHECK-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B]], i64 8
; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !20, !noalias !19
; CHECK-NEXT: [[TMP3:%.*]] = load float, float* [[C]], align 4
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7
; CHECK-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4
; CHECK-NEXT: ret void
;
entry:
tail call void @foo(float* %a, float* %c)

View File

@ -40,7 +40,7 @@ static void RunTest(
}
}
static void AssertMatchesExactlyAttributes(CallInst *Assume, Value *WasOn,
bool hasMatchesExactlyAttributes(CallInst *Assume, Value *WasOn,
StringRef AttrToMatch) {
Regex Reg(AttrToMatch);
SmallVector<StringRef, 1> Matches;
@ -50,20 +50,22 @@ static void AssertMatchesExactlyAttributes(CallInst *Assume, Value *WasOn,
#include "llvm/IR/Attributes.inc"
}) {
bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
if (ShouldHaveAttr != hasAttributeInAssume(*Assume, WasOn, Attr)) {
ASSERT_TRUE(false);
}
if (ShouldHaveAttr != hasAttributeInAssume(*Assume, WasOn, Attr))
return false;
}
return true;
}
static void AssertHasTheRightValue(CallInst *Assume, Value *WasOn,
bool hasTheRightValue(CallInst *Assume, Value *WasOn,
Attribute::AttrKind Kind, unsigned Value, bool Both,
AssumeQuery AQ = AssumeQuery::Highest) {
if (!Both) {
uint64_t ArgVal = 0;
ASSERT_TRUE(hasAttributeInAssume(*Assume, WasOn, Kind, &ArgVal, AQ));
ASSERT_EQ(ArgVal, Value);
return;
if (!hasAttributeInAssume(*Assume, WasOn, Kind, &ArgVal, AQ))
return false;
if (ArgVal != Value)
return false;
return true;
}
uint64_t ArgValLow = 0;
uint64_t ArgValHigh = 0;
@ -71,12 +73,11 @@ static void AssertHasTheRightValue(CallInst *Assume, Value *WasOn,
AssumeQuery::Lowest);
bool ResultHigh = hasAttributeInAssume(*Assume, WasOn, Kind, &ArgValHigh,
AssumeQuery::Highest);
if (ResultLow != ResultHigh || ResultHigh == false) {
ASSERT_TRUE(false);
}
if (ArgValLow != Value || ArgValLow != ArgValHigh) {
ASSERT_TRUE(false);
}
if (ResultLow != ResultHigh || ResultHigh == false)
return false;
if (ArgValLow != Value || ArgValLow != ArgValHigh)
return false;
return true;
}
TEST(AssumeQueryAPI, hasAttributeInAssume) {
@ -98,16 +99,16 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
[](Instruction *I) {
CallInst *Assume = BuildAssumeFromInst(I);
Assume->insertBefore(I);
AssertMatchesExactlyAttributes(Assume, I->getOperand(0),
"(nonnull|align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(1),
"(noalias|align)");
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 16, true);
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 4, true);
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 4, true);
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
"(align)"));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 16, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 4, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 4, true));
}));
Tests.push_back(std::make_pair(
"call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
@ -118,48 +119,48 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
[](Instruction *I) {
CallInst *Assume = BuildAssumeFromInst(I);
Assume->insertBefore(I);
AssertMatchesExactlyAttributes(Assume, I->getOperand(0),
"(nonnull|align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(1),
"(nonnull|align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(2),
"(nonnull|align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(3),
"(nonnull|align|dereferenceable)");
AssertHasTheRightValue(Assume, I->getOperand(0),
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 48, false,
AssumeQuery::Highest);
AssertHasTheRightValue(Assume, I->getOperand(0),
AssumeQuery::Highest));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 64, false,
AssumeQuery::Highest);
AssertHasTheRightValue(Assume, I->getOperand(1),
AssumeQuery::Highest));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Alignment, 64, false,
AssumeQuery::Highest);
AssertHasTheRightValue(Assume, I->getOperand(0),
AssumeQuery::Highest));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 4, false,
AssumeQuery::Lowest);
AssertHasTheRightValue(Assume, I->getOperand(0),
AssumeQuery::Lowest));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 8, false,
AssumeQuery::Lowest);
AssertHasTheRightValue(Assume, I->getOperand(1),
AssumeQuery::Lowest));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Alignment, 8, false,
AssumeQuery::Lowest);
AssumeQuery::Lowest));
}));
Tests.push_back(std::make_pair(
"call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
ShouldPreserveAllAttributes.setValue(true);
CallInst *Assume = BuildAssumeFromInst(I);
Assume->insertBefore(I);
AssertMatchesExactlyAttributes(
ASSERT_TRUE(hasMatchesExactlyAttributes(
Assume, nullptr,
"(align|no-jump-tables|less-precise-fpmad|"
"nounwind|norecurse|willreturn|cold)");
"nounwind|norecurse|willreturn|cold)"));
ShouldPreserveAllAttributes.setValue(false);
}));
Tests.push_back(
std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
CallInst *Assume = cast<CallInst>(I);
AssertMatchesExactlyAttributes(Assume, nullptr, "");
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, nullptr, ""));
}));
Tests.push_back(std::make_pair(
"call void @func1(i32* readnone align 32 "
@ -170,31 +171,31 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
[](Instruction *I) {
CallInst *Assume = BuildAssumeFromInst(I);
Assume->insertBefore(I);
AssertMatchesExactlyAttributes(
ASSERT_TRUE(hasMatchesExactlyAttributes(
Assume, I->getOperand(0),
"(readnone|align|dereferenceable|noalias)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(1),
"(align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(2),
"(align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(3),
"(nonnull|align|dereferenceable)");
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 32, true);
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 48, true);
AssertHasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Dereferenceable, 28, true);
AssertHasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Alignment, 8, true);
AssertHasTheRightValue(Assume, I->getOperand(2),
Attribute::AttrKind::Alignment, 64, true);
AssertHasTheRightValue(Assume, I->getOperand(2),
Attribute::AttrKind::Dereferenceable, 4, true);
AssertHasTheRightValue(Assume, I->getOperand(3),
Attribute::AttrKind::Alignment, 16, true);
AssertHasTheRightValue(Assume, I->getOperand(3),
Attribute::AttrKind::Dereferenceable, 12, true);
"(align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
"(align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
"(align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 32, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 48, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Dereferenceable, 28, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
Attribute::AttrKind::Alignment, 8, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
Attribute::AttrKind::Alignment, 64, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
Attribute::AttrKind::Dereferenceable, 4, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
Attribute::AttrKind::Alignment, 16, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
Attribute::AttrKind::Dereferenceable, 12, true));
}));
Tests.push_back(std::make_pair(
@ -209,16 +210,19 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
I->getOperand(1)->dropDroppableUses();
I->getOperand(2)->dropDroppableUses();
I->getOperand(3)->dropDroppableUses();
AssertMatchesExactlyAttributes(
ASSERT_TRUE(hasMatchesExactlyAttributes(
Assume, I->getOperand(0),
"(readnone|align|dereferenceable|noalias)");
AssertMatchesExactlyAttributes(Assume, I->getOperand(1), "");
AssertMatchesExactlyAttributes(Assume, I->getOperand(2), "");
AssertMatchesExactlyAttributes(Assume, I->getOperand(3), "");
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 32, true);
AssertHasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 48, true);
"(align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
""));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
""));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
""));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Alignment, 32, true));
ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
Attribute::AttrKind::Dereferenceable, 48, true));
}));
Tests.push_back(std::make_pair(
"call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
@ -228,18 +232,18 @@ TEST(AssumeQueryAPI, hasAttributeInAssume) {
Assume->insertBefore(I);
Value *New = I->getFunction()->getArg(3);
Value *Old = I->getOperand(0);
AssertMatchesExactlyAttributes(Assume, New, "");
AssertMatchesExactlyAttributes(Assume, Old,
"(nonnull|align|dereferenceable)");
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New, ""));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old,
"(nonnull|align|dereferenceable)"));
Old->replaceAllUsesWith(New);
AssertMatchesExactlyAttributes(Assume, New,
"(nonnull|align|dereferenceable)");
AssertMatchesExactlyAttributes(Assume, Old, "");
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New,
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old, ""));
}));
RunTest(Head, Tail, Tests);
}
static void AssertFindExactlyAttributes(RetainedKnowledgeMap &Map, Value *WasOn,
static bool FindExactlyAttributes(RetainedKnowledgeMap &Map, Value *WasOn,
StringRef AttrToMatch) {
Regex Reg(AttrToMatch);
SmallVector<StringRef, 1> Matches;
@ -250,18 +254,17 @@ static void AssertFindExactlyAttributes(RetainedKnowledgeMap &Map, Value *WasOn,
}) {
bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
if (ShouldHaveAttr != (Map.find(RetainedKnowledgeKey{WasOn, Attribute::getAttrKindFromName(Attr)}) != Map.end())) {
ASSERT_TRUE(false);
}
if (ShouldHaveAttr != (Map.find(RetainedKnowledgeKey{WasOn, Attribute::getAttrKindFromName(Attr)}) != Map.end()))
return false;
}
return true;
}
static void AssertMapHasRightValue(RetainedKnowledgeMap &Map,
static bool MapHasRightValue(RetainedKnowledgeMap &Map,
RetainedKnowledgeKey Key, MinMax MM) {
auto LookupIt = Map.find(Key);
ASSERT_TRUE(LookupIt != Map.end());
ASSERT_TRUE(LookupIt->second.Min == MM.Min);
ASSERT_TRUE(LookupIt->second.Max == MM.Max);
return (LookupIt != Map.end()) && (LookupIt->second.Min == MM.Min) &&
(LookupIt->second.Max == MM.Max);
}
TEST(AssumeQueryAPI, fillMapFromAssume) {
@ -286,16 +289,16 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
RetainedKnowledgeMap Map;
fillMapFromAssume(*Assume, Map);
AssertFindExactlyAttributes(Map, I->getOperand(0),
"(nonnull|align|dereferenceable)");
AssertFindExactlyAttributes(Map, I->getOperand(1),
"(noalias|align)");
AssertMapHasRightValue(
Map, {I->getOperand(0), Attribute::Dereferenceable}, {16, 16});
AssertMapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{4, 4});
AssertMapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{4, 4});
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
"(align)"));
ASSERT_TRUE(MapHasRightValue(
Map, {I->getOperand(0), Attribute::Dereferenceable}, {16, 16}));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{4, 4}));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{4, 4}));
}));
Tests.push_back(std::make_pair(
"call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
@ -310,18 +313,18 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
RetainedKnowledgeMap Map;
fillMapFromAssume(*Assume, Map);
AssertFindExactlyAttributes(Map, I->getOperand(0),
"(nonnull|align|dereferenceable)");
AssertFindExactlyAttributes(Map, I->getOperand(1),
"(nonnull|align|dereferenceable)");
AssertFindExactlyAttributes(Map, I->getOperand(2),
"(nonnull|align|dereferenceable)");
AssertFindExactlyAttributes(Map, I->getOperand(3),
"(nonnull|align|dereferenceable)");
AssertMapHasRightValue(
Map, {I->getOperand(0), Attribute::Dereferenceable}, {4, 48});
AssertMapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{8, 64});
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(MapHasRightValue(
Map, {I->getOperand(0), Attribute::Dereferenceable}, {4, 48}));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{8, 64}));
}));
Tests.push_back(std::make_pair(
"call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
@ -332,8 +335,8 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
RetainedKnowledgeMap Map;
fillMapFromAssume(*Assume, Map);
AssertFindExactlyAttributes(
Map, nullptr, "(nounwind|norecurse|willreturn|cold)");
ASSERT_TRUE(FindExactlyAttributes(
Map, nullptr, "(nounwind|norecurse|willreturn|cold)"));
ShouldPreserveAllAttributes.setValue(false);
}));
Tests.push_back(
@ -341,7 +344,7 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
RetainedKnowledgeMap Map;
fillMapFromAssume(*cast<CallInst>(I), Map);
AssertFindExactlyAttributes(Map, nullptr, "");
ASSERT_TRUE(FindExactlyAttributes(Map, nullptr, ""));
ASSERT_TRUE(Map.empty());
}));
Tests.push_back(std::make_pair(
@ -357,32 +360,30 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
RetainedKnowledgeMap Map;
fillMapFromAssume(*Assume, Map);
AssertFindExactlyAttributes(Map, I->getOperand(0),
"(readnone|align|dereferenceable|noalias)");
AssertFindExactlyAttributes(Map, I->getOperand(1),
"(align|dereferenceable)");
AssertFindExactlyAttributes(Map, I->getOperand(2),
"(align|dereferenceable)");
AssertFindExactlyAttributes(Map, I->getOperand(3),
"(nonnull|align|dereferenceable)");
AssertMapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{32, 32});
AssertMapHasRightValue(
Map, {I->getOperand(0), Attribute::Dereferenceable}, {48, 48});
AssertMapHasRightValue(
Map, {I->getOperand(0), Attribute::NoAlias}, {0, 0});
AssertMapHasRightValue(
Map, {I->getOperand(1), Attribute::Dereferenceable}, {28, 28});
AssertMapHasRightValue(Map, {I->getOperand(1), Attribute::Alignment},
{8, 8});
AssertMapHasRightValue(Map, {I->getOperand(2), Attribute::Alignment},
{64, 64});
AssertMapHasRightValue(
Map, {I->getOperand(2), Attribute::Dereferenceable}, {4, 4});
AssertMapHasRightValue(Map, {I->getOperand(3), Attribute::Alignment},
{16, 16});
AssertMapHasRightValue(
Map, {I->getOperand(3), Attribute::Dereferenceable}, {12, 12});
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
"(align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
"(align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
"(align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(0), Attribute::Alignment},
{32, 32}));
ASSERT_TRUE(MapHasRightValue(
Map, {I->getOperand(0), Attribute::Dereferenceable}, {48, 48}));
ASSERT_TRUE(MapHasRightValue(
Map, {I->getOperand(1), Attribute::Dereferenceable}, {28, 28}));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(1), Attribute::Alignment},
{8, 8}));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(2), Attribute::Alignment},
{64, 64}));
ASSERT_TRUE(MapHasRightValue(
Map, {I->getOperand(2), Attribute::Dereferenceable}, {4, 4}));
ASSERT_TRUE(MapHasRightValue(Map, {I->getOperand(3), Attribute::Alignment},
{16, 16}));
ASSERT_TRUE(MapHasRightValue(
Map, {I->getOperand(3), Attribute::Dereferenceable}, {12, 12}));
}));
/// Keep this test last as it modifies the function.
@ -398,15 +399,15 @@ TEST(AssumeQueryAPI, fillMapFromAssume) {
Value *New = I->getFunction()->getArg(3);
Value *Old = I->getOperand(0);
AssertFindExactlyAttributes(Map, New, "");
AssertFindExactlyAttributes(Map, Old,
"(nonnull|align|dereferenceable)");
ASSERT_TRUE(FindExactlyAttributes(Map, New, ""));
ASSERT_TRUE(FindExactlyAttributes(Map, Old,
"(nonnull|align|dereferenceable)"));
Old->replaceAllUsesWith(New);
Map.clear();
fillMapFromAssume(*Assume, Map);
AssertFindExactlyAttributes(Map, New,
"(nonnull|align|dereferenceable)");
AssertFindExactlyAttributes(Map, Old, "");
ASSERT_TRUE(FindExactlyAttributes(Map, New,
"(nonnull|align|dereferenceable)"));
ASSERT_TRUE(FindExactlyAttributes(Map, Old, ""));
}));
RunTest(Head, Tail, Tests);
}