#include "../lib/Transforms/Vectorize/VPlan.h"
#include "../lib/Transforms/Vectorize/VPlanCFG.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "gtest/gtest.h"
#include <string>
namespace llvm {
namespace {
#define CHECK_ITERATOR(Range1, ...) …
TEST(VPInstructionTest, insertBefore) { … }
TEST(VPInstructionTest, eraseFromParent) { … }
TEST(VPInstructionTest, moveAfter) { … }
TEST(VPInstructionTest, moveBefore) { … }
TEST(VPInstructionTest, setOperand) { … }
TEST(VPInstructionTest, replaceAllUsesWith) { … }
TEST(VPInstructionTest, releaseOperandsAtDeletion) { … }
TEST(VPBasicBlockTest, getPlan) { … }
TEST(VPBasicBlockTest, TraversingIteratorTest) { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
TEST(VPBasicBlockTest, print) {
VPInstruction *TC = new VPInstruction(Instruction::Add, {});
VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
VPBB0->appendRecipe(TC);
VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1});
VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2});
VPBasicBlock *VPBB1 = new VPBasicBlock();
VPBB1->appendRecipe(I1);
VPBB1->appendRecipe(I2);
VPBB1->appendRecipe(I3);
VPBB1->setName("bb1");
VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1});
VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4});
VPBasicBlock *VPBB2 = new VPBasicBlock();
VPBB2->appendRecipe(I4);
VPBB2->appendRecipe(I5);
VPBB2->setName("bb2");
VPBlockUtils::connectBlocks(VPBB1, VPBB2);
{
std::string I3Dump;
raw_string_ostream OS(I3Dump);
VPSlotTracker SlotTracker;
I3->print(OS, "", SlotTracker);
EXPECT_EQ("EMIT br <badref>, <badref>", I3Dump);
}
VPlan Plan(VPBB0, TC, VPBB1);
std::string FullDump;
raw_string_ostream OS(FullDump);
Plan.printDOT(OS);
const char *ExpectedStr = R"(digraph VPlan {
graph [labelloc=t, fontsize=30; label="Vectorization Plan\n for UF\>=1\nvp\<%1\> = original trip-count\n"]
node [shape=rect, fontname=Courier, fontsize=30]
edge [fontname=Courier, fontsize=30]
compound=true
N0 [label =
"preheader:\l" +
" EMIT vp\<%1\> = add\l" +
"No successors\l"
]
N1 [label =
"bb1:\l" +
" EMIT vp\<%2\> = add\l" +
" EMIT vp\<%3\> = sub vp\<%2\>\l" +
" EMIT br vp\<%2\>, vp\<%3\>\l" +
"Successor(s): bb2\l"
]
N1 -> N2 [ label=""]
N2 [label =
"bb2:\l" +
" EMIT vp\<%5\> = mul vp\<%3\>, vp\<%2\>\l" +
" EMIT ret vp\<%5\>\l" +
"No successors\l"
]
}
)";
EXPECT_EQ(ExpectedStr, FullDump);
const char *ExpectedBlock1Str = R"(bb1:
EMIT vp<%2> = add
EMIT vp<%3> = sub vp<%2>
EMIT br vp<%2>, vp<%3>
Successor(s): bb2
)";
std::string Block1Dump;
raw_string_ostream OS1(Block1Dump);
VPBB1->print(OS1);
EXPECT_EQ(ExpectedBlock1Str, Block1Dump);
const char *ExpectedBlock2Str = R"(bb2:
EMIT vp<%5> = mul vp<%3>, vp<%2>
EMIT ret vp<%5>
No successors
)";
std::string Block2Dump;
raw_string_ostream OS2(Block2Dump);
VPBB2->print(OS2);
EXPECT_EQ(ExpectedBlock2Str, Block2Dump);
{
std::string I3Dump;
raw_string_ostream OS(I3Dump);
VPSlotTracker SlotTracker(&Plan);
I3->print(OS, "", SlotTracker);
EXPECT_EQ("EMIT br vp<%2>, vp<%3>", I3Dump);
}
{
std::string I4Dump;
raw_string_ostream OS(I4Dump);
OS << *I4;
EXPECT_EQ("EMIT vp<%5> = mul vp<%3>, vp<%2>", I4Dump);
}
}
TEST(VPBasicBlockTest, printPlanWithVFsAndUFs) {
VPInstruction *TC = new VPInstruction(Instruction::Sub, {});
VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
VPBB0->appendRecipe(TC);
VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
VPBasicBlock *VPBB1 = new VPBasicBlock();
VPBB1->appendRecipe(I1);
VPBB1->setName("bb1");
VPlan Plan(VPBB0, TC, VPBB1);
Plan.setName("TestPlan");
Plan.addVF(ElementCount::getFixed(4));
{
std::string FullDump;
raw_string_ostream OS(FullDump);
Plan.print(OS);
const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4},UF>=1' {
vp<%1> = original trip-count
preheader:
EMIT vp<%1> = sub
No successors
bb1:
EMIT vp<%2> = add
No successors
}
)";
EXPECT_EQ(ExpectedStr, FullDump);
}
{
Plan.addVF(ElementCount::getScalable(8));
std::string FullDump;
raw_string_ostream OS(FullDump);
Plan.print(OS);
const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4,vscale x 8},UF>=1' {
vp<%1> = original trip-count
preheader:
EMIT vp<%1> = sub
No successors
bb1:
EMIT vp<%2> = add
No successors
}
)";
EXPECT_EQ(ExpectedStr, FullDump);
}
{
Plan.setUF(4);
std::string FullDump;
raw_string_ostream OS(FullDump);
Plan.print(OS);
const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4,vscale x 8},UF={4}' {
vp<%1> = original trip-count
preheader:
EMIT vp<%1> = sub
No successors
bb1:
EMIT vp<%2> = add
No successors
}
)";
EXPECT_EQ(ExpectedStr, FullDump);
}
}
#endif
TEST(VPRecipeTest, CastVPInstructionToVPUser) { … }
TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) { … }
TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) { … }
TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) { … }
TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) { … }
TEST(VPRecipeTest, CastVPBlendRecipeToVPUser) { … }
TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) { … }
TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) { … }
TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) { … }
TEST(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPDef) { … }
TEST(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
TEST(VPRecipeTest, dumpRecipeInPlan) {
VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
VPBasicBlock *VPBB1 = new VPBasicBlock();
VPlan Plan(VPBB0, VPBB1);
LLVMContext C;
IntegerType *Int32 = IntegerType::get(C, 32);
auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
PoisonValue::get(Int32));
AI->setName("a");
SmallVector<VPValue *, 2> Args;
VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
VPValue *ExtVPV2 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
Args.push_back(ExtVPV1);
Args.push_back(ExtVPV2);
VPWidenRecipe *WidenR =
new VPWidenRecipe(*AI, make_range(Args.begin(), Args.end()));
VPBB1->appendRecipe(WidenR);
{
VPValue *VPV = WidenR;
EXPECT_EXIT(
{
VPV->dump();
exit(0);
},
testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
VPRecipeBase *R = WidenR;
EXPECT_EXIT(
{
R->dump();
exit(0);
},
testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
VPDef *D = WidenR;
EXPECT_EXIT(
{
D->dump();
exit(0);
},
testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
}
delete AI;
}
TEST(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) {
VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
VPBasicBlock *VPBB1 = new VPBasicBlock();
VPlan Plan(VPBB0, VPBB1);
LLVMContext C;
IntegerType *Int32 = IntegerType::get(C, 32);
auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
PoisonValue::get(Int32));
AI->setName("a");
SmallVector<VPValue *, 2> Args;
VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
VPValue *ExtVPV2 = Plan.getOrAddLiveIn(AI);
Args.push_back(ExtVPV1);
Args.push_back(ExtVPV2);
VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2});
VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1});
VPBB1->appendRecipe(I1);
VPBB1->appendRecipe(I2);
{
VPValue *VPV = I1;
EXPECT_EXIT(
{
VPV->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
VPRecipeBase *R = I1;
EXPECT_EXIT(
{
R->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
VPDef *D = I1;
EXPECT_EXIT(
{
D->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
}
{
VPValue *VPV = I2;
EXPECT_EXIT(
{
VPV->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
VPRecipeBase *R = I2;
EXPECT_EXIT(
{
R->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
VPDef *D = I2;
EXPECT_EXIT(
{
D->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
}
delete AI;
}
TEST(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
LLVMContext C;
IntegerType *Int32 = IntegerType::get(C, 32);
auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
PoisonValue::get(Int32));
AI->setName("a");
VPValue *ExtVPV1 = new VPValue(ConstantInt::get(Int32, 1));
VPValue *ExtVPV2 = new VPValue(AI);
VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2});
VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1});
{
VPValue *VPV = I1;
EXPECT_EXIT(
{
VPV->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
VPRecipeBase *R = I1;
EXPECT_EXIT(
{
R->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
VPDef *D = I1;
EXPECT_EXIT(
{
D->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
}
{
VPValue *VPV = I2;
EXPECT_EXIT(
{
VPV->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
VPRecipeBase *R = I2;
EXPECT_EXIT(
{
R->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
VPDef *D = I2;
EXPECT_EXIT(
{
D->dump();
exit(0);
},
testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
}
delete I2;
delete I1;
delete ExtVPV2;
delete ExtVPV1;
delete AI;
}
#endif
TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) { … }
TEST(VPRecipeTest, CastVPReductionEVLRecipeToVPUser) { … }
struct VPDoubleValueDef : public VPRecipeBase { … };
TEST(VPDoubleValueDefTest, traverseUseLists) { … }
TEST(VPRecipeTest, CastToVPSingleDefRecipe) { … }
}
}