VPlanSlpTest.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. //===- llvm/unittest/Transforms/Vectorize/VPlanSlpTest.cpp ---------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "../lib/Transforms/Vectorize/VPlan.h"
  9. #include "../lib/Transforms/Vectorize/VPlanHCFGBuilder.h"
  10. #include "../lib/Transforms/Vectorize/VPlanHCFGTransforms.h"
  11. #include "VPlanTestBase.h"
  12. #include "llvm/Analysis/VectorUtils.h"
  13. #include "gtest/gtest.h"
  14. namespace llvm {
  15. namespace {
  16. class VPlanSlpTest : public VPlanTestBase {
  17. protected:
  18. TargetLibraryInfoImpl TLII;
  19. TargetLibraryInfo TLI;
  20. DataLayout DL;
  21. std::unique_ptr<AssumptionCache> AC;
  22. std::unique_ptr<ScalarEvolution> SE;
  23. std::unique_ptr<AAResults> AARes;
  24. std::unique_ptr<BasicAAResult> BasicAA;
  25. std::unique_ptr<LoopAccessInfo> LAI;
  26. std::unique_ptr<PredicatedScalarEvolution> PSE;
  27. std::unique_ptr<InterleavedAccessInfo> IAI;
  28. VPlanSlpTest()
  29. : TLII(), TLI(TLII),
  30. DL("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-"
  31. "f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:"
  32. "16:32:64-S128") {}
  33. VPInterleavedAccessInfo getInterleavedAccessInfo(Function &F, Loop *L,
  34. VPlan &Plan) {
  35. AC.reset(new AssumptionCache(F));
  36. SE.reset(new ScalarEvolution(F, TLI, *AC, *DT, *LI));
  37. BasicAA.reset(new BasicAAResult(DL, F, TLI, *AC, &*DT, &*LI));
  38. AARes.reset(new AAResults(TLI));
  39. AARes->addAAResult(*BasicAA);
  40. PSE.reset(new PredicatedScalarEvolution(*SE, *L));
  41. LAI.reset(new LoopAccessInfo(L, &*SE, &TLI, &*AARes, &*DT, &*LI));
  42. IAI.reset(new InterleavedAccessInfo(*PSE, L, &*DT, &*LI, &*LAI));
  43. IAI->analyzeInterleaving(false);
  44. return {Plan, *IAI};
  45. }
  46. };
  47. TEST_F(VPlanSlpTest, testSlpSimple_2) {
  48. const char *ModuleString =
  49. "%struct.Test = type { i32, i32 }\n"
  50. "%struct.Test3 = type { i32, i32, i32 }\n"
  51. "%struct.Test4xi8 = type { i8, i8, i8 }\n"
  52. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  53. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  54. "entry:\n"
  55. " br label %for.body\n"
  56. "for.body: ; preds = %for.body, "
  57. "%entry\n"
  58. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  59. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  60. "%indvars.iv, i32 0\n"
  61. " %vA0 = load i32, i32* %A0, align 4\n"
  62. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  63. "%indvars.iv, i32 0\n"
  64. " %vB0 = load i32, i32* %B0, align 4\n"
  65. " %add0 = add nsw i32 %vA0, %vB0\n"
  66. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  67. "%indvars.iv, i32 1\n"
  68. " %vA1 = load i32, i32* %A1, align 4\n"
  69. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  70. "%indvars.iv, i32 1\n"
  71. " %vB1 = load i32, i32* %B1, align 4\n"
  72. " %add1 = add nsw i32 %vA1, %vB1\n"
  73. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  74. "%indvars.iv, i32 0\n"
  75. " store i32 %add0, i32* %C0, align 4\n"
  76. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  77. "%indvars.iv, i32 1\n"
  78. " store i32 %add1, i32* %C1, align 4\n"
  79. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  80. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  81. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  82. "for.cond.cleanup: ; preds = %for.body\n"
  83. " ret void\n"
  84. "}\n";
  85. Module &M = parseModule(ModuleString);
  86. Function *F = M.getFunction("add_x2");
  87. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  88. auto Plan = buildHCFG(LoopHeader);
  89. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  90. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  91. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  92. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  93. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
  94. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
  95. VPlanSlp Slp(VPIAI, *Body);
  96. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  97. VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
  98. EXPECT_EQ(64u, Slp.getWidestBundleBits());
  99. EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
  100. auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
  101. EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
  102. auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
  103. auto *CombinedLoadB = cast<VPInstruction>(CombinedAdd->getOperand(1));
  104. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
  105. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
  106. }
  107. TEST_F(VPlanSlpTest, testSlpSimple_3) {
  108. const char *ModuleString =
  109. "%struct.Test = type { i32, i32 }\n"
  110. "%struct.Test3 = type { i32, i32, i32 }\n"
  111. "%struct.Test4xi8 = type { i8, i8, i8 }\n"
  112. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  113. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  114. "entry:\n"
  115. " br label %for.body\n"
  116. "for.body: ; preds = %for.body, "
  117. "%entry\n"
  118. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  119. " %A0 = getelementptr %struct.Test, %struct.Test* %A, i64 "
  120. " %indvars.iv, i32 0\n"
  121. " %vA0 = load i32, i32* %A0, align 4\n"
  122. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  123. " %indvars.iv, i32 0\n"
  124. " %vB0 = load i32, i32* %B0, align 4\n"
  125. " %add0 = add nsw i32 %vA0, %vB0\n"
  126. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  127. " %indvars.iv, i32 1\n"
  128. " %vA1 = load i32, i32* %A1, align 4\n"
  129. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  130. " %indvars.iv, i32 1\n"
  131. " %vB1 = load i32, i32* %B1, align 4\n"
  132. " %add1 = add nsw i32 %vA1, %vB1\n"
  133. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  134. " %indvars.iv, i32 0\n"
  135. " store i32 %add0, i32* %C0, align 4\n"
  136. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  137. " %indvars.iv, i32 1\n"
  138. " store i32 %add1, i32* %C1, align 4\n"
  139. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  140. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  141. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  142. "for.cond.cleanup: ; preds = %for.body\n"
  143. " ret void\n"
  144. "}\n";
  145. Module &M = parseModule(ModuleString);
  146. Function *F = M.getFunction("add_x2");
  147. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  148. auto Plan = buildHCFG(LoopHeader);
  149. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  150. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  151. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  152. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
  153. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
  154. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  155. VPlanSlp Slp(VPIAI, *Body);
  156. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  157. VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
  158. EXPECT_EQ(64u, Slp.getWidestBundleBits());
  159. EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
  160. auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
  161. EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
  162. auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
  163. auto *CombinedLoadB = cast<VPInstruction>(CombinedAdd->getOperand(1));
  164. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
  165. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
  166. VPInstruction *GetA = cast<VPInstruction>(&*std::next(Body->begin(), 1));
  167. VPInstruction *GetB = cast<VPInstruction>(&*std::next(Body->begin(), 3));
  168. EXPECT_EQ(GetA, CombinedLoadA->getOperand(0));
  169. EXPECT_EQ(GetB, CombinedLoadB->getOperand(0));
  170. }
  171. TEST_F(VPlanSlpTest, testSlpReuse_1) {
  172. const char *ModuleString =
  173. "%struct.Test = type { i32, i32 }\n"
  174. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  175. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  176. "entry:\n"
  177. " br label %for.body\n"
  178. "for.body: ; preds = %for.body, "
  179. "%entry\n"
  180. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  181. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  182. "%indvars.iv, i32 0\n"
  183. " %vA0 = load i32, i32* %A0, align 4\n"
  184. " %add0 = add nsw i32 %vA0, %vA0\n"
  185. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  186. "%indvars.iv, i32 1\n"
  187. " %vA1 = load i32, i32* %A1, align 4\n"
  188. " %add1 = add nsw i32 %vA1, %vA1\n"
  189. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  190. "%indvars.iv, i32 0\n"
  191. " store i32 %add0, i32* %C0, align 4\n"
  192. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  193. "%indvars.iv, i32 1\n"
  194. " store i32 %add1, i32* %C1, align 4\n"
  195. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  196. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  197. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  198. "for.cond.cleanup: ; preds = %for.body\n"
  199. " ret void\n"
  200. "}\n";
  201. Module &M = parseModule(ModuleString);
  202. Function *F = M.getFunction("add_x2");
  203. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  204. auto Plan = buildHCFG(LoopHeader);
  205. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  206. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  207. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  208. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  209. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 8));
  210. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 10));
  211. VPlanSlp Slp(VPIAI, *Body);
  212. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  213. VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
  214. EXPECT_EQ(64u, Slp.getWidestBundleBits());
  215. EXPECT_EQ(VPInstruction::SLPStore, CombinedStore->getOpcode());
  216. auto *CombinedAdd = cast<VPInstruction>(CombinedStore->getOperand(0));
  217. EXPECT_EQ(Instruction::Add, CombinedAdd->getOpcode());
  218. auto *CombinedLoadA = cast<VPInstruction>(CombinedAdd->getOperand(0));
  219. EXPECT_EQ(CombinedLoadA, CombinedAdd->getOperand(1));
  220. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
  221. }
  222. TEST_F(VPlanSlpTest, testSlpReuse_2) {
  223. const char *ModuleString =
  224. "%struct.Test = type { i32, i32 }\n"
  225. "define i32 @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  226. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  227. "entry:\n"
  228. " br label %for.body\n"
  229. "for.body: ; preds = %for.body, "
  230. "%entry\n"
  231. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  232. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  233. "%indvars.iv, i32 0\n"
  234. " %vA0 = load i32, i32* %A0, align 4\n"
  235. " %add0 = add nsw i32 %vA0, %vA0\n"
  236. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  237. "%indvars.iv, i32 0\n"
  238. " store i32 %add0, i32* %C0, align 4\n"
  239. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  240. "%indvars.iv, i32 1\n"
  241. " %vA1 = load i32, i32* %A1, align 4\n"
  242. " %add1 = add nsw i32 %vA1, %vA1\n"
  243. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  244. "%indvars.iv, i32 1\n"
  245. " store i32 %add1, i32* %C1, align 4\n"
  246. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  247. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  248. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  249. "for.cond.cleanup: ; preds = %for.body\n"
  250. " ret i32 %vA1\n"
  251. "}\n";
  252. Module &M = parseModule(ModuleString);
  253. Function *F = M.getFunction("add_x2");
  254. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  255. auto Plan = buildHCFG(LoopHeader);
  256. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  257. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  258. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  259. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  260. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 5));
  261. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 10));
  262. VPlanSlp Slp(VPIAI, *Body);
  263. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  264. Slp.buildGraph(StoreRoot);
  265. EXPECT_FALSE(Slp.isCompletelySLP());
  266. }
  267. static void checkReorderExample(VPInstruction *Store1, VPInstruction *Store2,
  268. VPBasicBlock *Body,
  269. VPInterleavedAccessInfo &&IAI) {
  270. VPlanSlp Slp(IAI, *Body);
  271. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  272. VPInstruction *CombinedStore = Slp.buildGraph(StoreRoot);
  273. EXPECT_TRUE(Slp.isCompletelySLP());
  274. EXPECT_EQ(CombinedStore->getOpcode(), VPInstruction::SLPStore);
  275. VPInstruction *CombinedAdd =
  276. cast<VPInstruction>(CombinedStore->getOperand(0));
  277. EXPECT_EQ(CombinedAdd->getOpcode(), Instruction::Add);
  278. VPInstruction *CombinedMulAB =
  279. cast<VPInstruction>(CombinedAdd->getOperand(0));
  280. VPInstruction *CombinedMulCD =
  281. cast<VPInstruction>(CombinedAdd->getOperand(1));
  282. EXPECT_EQ(CombinedMulAB->getOpcode(), Instruction::Mul);
  283. VPInstruction *CombinedLoadA =
  284. cast<VPInstruction>(CombinedMulAB->getOperand(0));
  285. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadA->getOpcode());
  286. VPInstruction *LoadvA0 = cast<VPInstruction>(&*std::next(Body->begin(), 2));
  287. VPInstruction *LoadvA1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
  288. EXPECT_EQ(LoadvA0->getOperand(0), CombinedLoadA->getOperand(0));
  289. EXPECT_EQ(LoadvA1->getOperand(0), CombinedLoadA->getOperand(1));
  290. VPInstruction *CombinedLoadB =
  291. cast<VPInstruction>(CombinedMulAB->getOperand(1));
  292. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadB->getOpcode());
  293. VPInstruction *LoadvB0 = cast<VPInstruction>(&*std::next(Body->begin(), 4));
  294. VPInstruction *LoadvB1 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
  295. EXPECT_EQ(LoadvB0->getOperand(0), CombinedLoadB->getOperand(0));
  296. EXPECT_EQ(LoadvB1->getOperand(0), CombinedLoadB->getOperand(1));
  297. EXPECT_EQ(CombinedMulCD->getOpcode(), Instruction::Mul);
  298. VPInstruction *CombinedLoadC =
  299. cast<VPInstruction>(CombinedMulCD->getOperand(0));
  300. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadC->getOpcode());
  301. VPInstruction *LoadvC0 = cast<VPInstruction>(&*std::next(Body->begin(), 7));
  302. VPInstruction *LoadvC1 = cast<VPInstruction>(&*std::next(Body->begin(), 17));
  303. EXPECT_EQ(LoadvC0->getOperand(0), CombinedLoadC->getOperand(0));
  304. EXPECT_EQ(LoadvC1->getOperand(0), CombinedLoadC->getOperand(1));
  305. VPInstruction *CombinedLoadD =
  306. cast<VPInstruction>(CombinedMulCD->getOperand(1));
  307. EXPECT_EQ(VPInstruction::SLPLoad, CombinedLoadD->getOpcode());
  308. VPInstruction *LoadvD0 = cast<VPInstruction>(&*std::next(Body->begin(), 9));
  309. VPInstruction *LoadvD1 = cast<VPInstruction>(&*std::next(Body->begin(), 19));
  310. EXPECT_EQ(LoadvD0->getOperand(0), CombinedLoadD->getOperand(0));
  311. EXPECT_EQ(LoadvD1->getOperand(0), CombinedLoadD->getOperand(1));
  312. }
  313. TEST_F(VPlanSlpTest, testSlpReorder_1) {
  314. LLVMContext Ctx;
  315. const char *ModuleString =
  316. "%struct.Test = type { i32, i32 }\n"
  317. "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
  318. "%C, %struct.Test* %D, %struct.Test* %E) {\n"
  319. "entry:\n"
  320. " br label %for.body\n"
  321. "for.body: ; preds = %for.body, "
  322. "%entry\n"
  323. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  324. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  325. "%indvars.iv, i32 0\n"
  326. " %vA0 = load i32, i32* %A0, align 4\n"
  327. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  328. "%indvars.iv, i32 0\n"
  329. " %vB0 = load i32, i32* %B0, align 4\n"
  330. " %mul11 = mul nsw i32 %vA0, %vB0\n"
  331. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  332. "%indvars.iv, i32 0\n"
  333. " %vC0 = load i32, i32* %C0, align 4\n"
  334. " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  335. "%indvars.iv, i32 0\n"
  336. " %vD0 = load i32, i32* %D0, align 4\n"
  337. " %mul12 = mul nsw i32 %vC0, %vD0\n"
  338. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  339. "%indvars.iv, i32 1\n"
  340. " %vA1 = load i32, i32* %A1, align 4\n"
  341. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  342. "%indvars.iv, i32 1\n"
  343. " %vB1 = load i32, i32* %B1, align 4\n"
  344. " %mul21 = mul nsw i32 %vA1, %vB1\n"
  345. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  346. "%indvars.iv, i32 1\n"
  347. " %vC1 = load i32, i32* %C1, align 4\n"
  348. " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  349. "%indvars.iv, i32 1\n"
  350. " %vD1 = load i32, i32* %D1, align 4\n"
  351. " %mul22 = mul nsw i32 %vC1, %vD1\n"
  352. " %add1 = add nsw i32 %mul11, %mul12\n"
  353. " %add2 = add nsw i32 %mul22, %mul21\n"
  354. " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  355. "%indvars.iv, i32 0\n"
  356. " store i32 %add1, i32* %E0, align 4\n"
  357. " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  358. "%indvars.iv, i32 1\n"
  359. " store i32 %add2, i32* %E1, align 4\n"
  360. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  361. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  362. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  363. "for.cond.cleanup: ; preds = %for.body\n"
  364. " ret void\n"
  365. "}\n";
  366. Module &M = parseModule(ModuleString);
  367. Function *F = M.getFunction("add_x3");
  368. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  369. auto Plan = buildHCFG(LoopHeader);
  370. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  371. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  372. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  373. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
  374. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
  375. checkReorderExample(
  376. Store1, Store2, Body,
  377. getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
  378. }
  379. TEST_F(VPlanSlpTest, testSlpReorder_2) {
  380. LLVMContext Ctx;
  381. const char *ModuleString =
  382. "%struct.Test = type { i32, i32 }\n"
  383. "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
  384. "%C, %struct.Test* %D, %struct.Test* %E) {\n"
  385. "entry:\n"
  386. " br label %for.body\n"
  387. "for.body: ; preds = %for.body, "
  388. "%entry\n"
  389. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  390. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  391. "%indvars.iv, i32 0\n"
  392. " %vA0 = load i32, i32* %A0, align 4\n"
  393. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  394. "%indvars.iv, i32 0\n"
  395. " %vB0 = load i32, i32* %B0, align 4\n"
  396. " %mul11 = mul nsw i32 %vA0, %vB0\n"
  397. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  398. "%indvars.iv, i32 0\n"
  399. " %vC0 = load i32, i32* %C0, align 4\n"
  400. " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  401. "%indvars.iv, i32 0\n"
  402. " %vD0 = load i32, i32* %D0, align 4\n"
  403. " %mul12 = mul nsw i32 %vC0, %vD0\n"
  404. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  405. "%indvars.iv, i32 1\n"
  406. " %vA1 = load i32, i32* %A1, align 4\n"
  407. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  408. "%indvars.iv, i32 1\n"
  409. " %vB1 = load i32, i32* %B1, align 4\n"
  410. " %mul21 = mul nsw i32 %vB1, %vA1\n"
  411. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  412. "%indvars.iv, i32 1\n"
  413. " %vC1 = load i32, i32* %C1, align 4\n"
  414. " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  415. "%indvars.iv, i32 1\n"
  416. " %vD1 = load i32, i32* %D1, align 4\n"
  417. " %mul22 = mul nsw i32 %vD1, %vC1\n"
  418. " %add1 = add nsw i32 %mul11, %mul12\n"
  419. " %add2 = add nsw i32 %mul22, %mul21\n"
  420. " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  421. "%indvars.iv, i32 0\n"
  422. " store i32 %add1, i32* %E0, align 4\n"
  423. " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  424. "%indvars.iv, i32 1\n"
  425. " store i32 %add2, i32* %E1, align 4\n"
  426. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  427. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  428. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  429. "for.cond.cleanup: ; preds = %for.body\n"
  430. " ret void\n"
  431. "}\n";
  432. Module &M = parseModule(ModuleString);
  433. Function *F = M.getFunction("add_x3");
  434. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  435. auto Plan = buildHCFG(LoopHeader);
  436. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  437. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  438. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  439. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
  440. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
  441. checkReorderExample(
  442. Store1, Store2, Body,
  443. getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
  444. }
  445. TEST_F(VPlanSlpTest, testSlpReorder_3) {
  446. LLVMContext Ctx;
  447. const char *ModuleString =
  448. "%struct.Test = type { i32, i32 }\n"
  449. "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
  450. "%C, %struct.Test* %D, %struct.Test* %E) {\n"
  451. "entry:\n"
  452. " br label %for.body\n"
  453. "for.body: ; preds = %for.body, "
  454. "%entry\n"
  455. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  456. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  457. "%indvars.iv, i32 1\n"
  458. " %vA1 = load i32, i32* %A1, align 4\n"
  459. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  460. "%indvars.iv, i32 0\n"
  461. " %vB0 = load i32, i32* %B0, align 4\n"
  462. " %mul11 = mul nsw i32 %vA1, %vB0\n"
  463. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  464. "%indvars.iv, i32 0\n"
  465. " %vC0 = load i32, i32* %C0, align 4\n"
  466. " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  467. "%indvars.iv, i32 0\n"
  468. " %vD0 = load i32, i32* %D0, align 4\n"
  469. " %mul12 = mul nsw i32 %vC0, %vD0\n"
  470. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  471. "%indvars.iv, i32 0\n"
  472. " %vA0 = load i32, i32* %A0, align 4\n"
  473. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  474. "%indvars.iv, i32 1\n"
  475. " %vB1 = load i32, i32* %B1, align 4\n"
  476. " %mul21 = mul nsw i32 %vB1, %vA0\n"
  477. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  478. "%indvars.iv, i32 1\n"
  479. " %vC1 = load i32, i32* %C1, align 4\n"
  480. " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  481. "%indvars.iv, i32 1\n"
  482. " %vD1 = load i32, i32* %D1, align 4\n"
  483. " %mul22 = mul nsw i32 %vD1, %vC1\n"
  484. " %add1 = add nsw i32 %mul11, %mul12\n"
  485. " %add2 = add nsw i32 %mul22, %mul21\n"
  486. " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  487. "%indvars.iv, i32 0\n"
  488. " store i32 %add1, i32* %E0, align 4\n"
  489. " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  490. "%indvars.iv, i32 1\n"
  491. " store i32 %add2, i32* %E1, align 4\n"
  492. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  493. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  494. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  495. "for.cond.cleanup: ; preds = %for.body\n"
  496. " ret void\n"
  497. "}\n";
  498. Module &M = parseModule(ModuleString);
  499. Function *F = M.getFunction("add_x3");
  500. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  501. auto Plan = buildHCFG(LoopHeader);
  502. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  503. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  504. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  505. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
  506. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
  507. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  508. VPlanSlp Slp(VPIAI, *Body);
  509. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  510. EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
  511. // FIXME Need to select better first value for lane0.
  512. EXPECT_FALSE(Slp.isCompletelySLP());
  513. }
  514. TEST_F(VPlanSlpTest, testSlpReorder_4) {
  515. LLVMContext Ctx;
  516. const char *ModuleString =
  517. "%struct.Test = type { i32, i32 }\n"
  518. "define void @add_x3(%struct.Test* %A, %struct.Test* %B, %struct.Test* "
  519. "%C, %struct.Test* %D, %struct.Test* %E) {\n"
  520. "entry:\n"
  521. " br label %for.body\n"
  522. "for.body: ; preds = %for.body, "
  523. "%entry\n"
  524. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  525. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  526. "%indvars.iv, i32 0\n"
  527. " %vA0 = load i32, i32* %A0, align 4\n"
  528. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  529. "%indvars.iv, i32 0\n"
  530. " %vB0 = load i32, i32* %B0, align 4\n"
  531. " %mul11 = mul nsw i32 %vA0, %vB0\n"
  532. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  533. "%indvars.iv, i32 0\n"
  534. " %vC0 = load i32, i32* %C0, align 4\n"
  535. " %D0 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  536. "%indvars.iv, i32 0\n"
  537. " %vD0 = load i32, i32* %D0, align 4\n"
  538. " %mul12 = mul nsw i32 %vC0, %vD0\n"
  539. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  540. "%indvars.iv, i32 1\n"
  541. " %vA1 = load i32, i32* %A1, align 4\n"
  542. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  543. "%indvars.iv, i32 1\n"
  544. " %vB1 = load i32, i32* %B1, align 4\n"
  545. " %mul21 = mul nsw i32 %vA1, %vB1\n"
  546. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  547. "%indvars.iv, i32 1\n"
  548. " %vC1 = load i32, i32* %C1, align 4\n"
  549. " %D1 = getelementptr inbounds %struct.Test, %struct.Test* %D, i64 "
  550. "%indvars.iv, i32 1\n"
  551. " %vD1 = load i32, i32* %D1, align 4\n"
  552. " %mul22 = mul nsw i32 %vC1, %vD1\n"
  553. " %add1 = add nsw i32 %mul11, %mul12\n"
  554. " %add2 = add nsw i32 %mul22, %mul21\n"
  555. " %E0 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  556. "%indvars.iv, i32 0\n"
  557. " store i32 %add1, i32* %E0, align 4\n"
  558. " %E1 = getelementptr inbounds %struct.Test, %struct.Test* %E, i64 "
  559. "%indvars.iv, i32 1\n"
  560. " store i32 %add2, i32* %E1, align 4\n"
  561. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  562. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  563. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  564. "for.cond.cleanup: ; preds = %for.body\n"
  565. " ret void\n"
  566. "}\n";
  567. Module &M = parseModule(ModuleString);
  568. Function *F = M.getFunction("add_x3");
  569. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  570. auto Plan = buildHCFG(LoopHeader);
  571. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  572. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  573. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  574. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 24));
  575. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 26));
  576. checkReorderExample(
  577. Store1, Store2, Body,
  578. getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan));
  579. }
  580. // Make sure we do not combine instructions with operands in different BBs.
  581. TEST_F(VPlanSlpTest, testInstrsInDifferentBBs) {
  582. const char *ModuleString =
  583. "%struct.Test = type { i32, i32 }\n"
  584. "%struct.Test3 = type { i32, i32, i32 }\n"
  585. "%struct.Test4xi8 = type { i8, i8, i8 }\n"
  586. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  587. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  588. "entry:\n"
  589. " br label %for.body\n"
  590. "for.body: ; preds = %for.body, "
  591. "%entry\n"
  592. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  593. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  594. "%indvars.iv, i32 0\n"
  595. " %vA0 = load i32, i32* %A0, align 4\n"
  596. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  597. "%indvars.iv, i32 0\n"
  598. " %vB0 = load i32, i32* %B0, align 4\n"
  599. " %add0 = add nsw i32 %vA0, %vB0\n"
  600. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  601. "%indvars.iv, i32 1\n"
  602. " %vA1 = load i32, i32* %A1, align 4\n"
  603. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  604. "%indvars.iv, i32 1\n"
  605. " br label %bb2\n"
  606. "bb2:\n"
  607. " %vB1 = load i32, i32* %B1, align 4\n"
  608. " %add1 = add nsw i32 %vA1, %vB1\n"
  609. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  610. "%indvars.iv, i32 0\n"
  611. " store i32 %add0, i32* %C0, align 4\n"
  612. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  613. "%indvars.iv, i32 1\n"
  614. " store i32 %add1, i32* %C1, align 4\n"
  615. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  616. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  617. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  618. "for.cond.cleanup: ; preds = %for.body\n"
  619. " ret void\n"
  620. "}\n";
  621. Module &M = parseModule(ModuleString);
  622. Function *F = M.getFunction("add_x2");
  623. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  624. auto Plan = buildHCFG(LoopHeader);
  625. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  626. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  627. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  628. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  629. VPBasicBlock *BB2 = Body->getSingleSuccessor()->getEntryBasicBlock();
  630. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(BB2->begin(), 3));
  631. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(BB2->begin(), 5));
  632. VPlanSlp Slp(VPIAI, *BB2);
  633. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  634. EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
  635. EXPECT_EQ(0u, Slp.getWidestBundleBits());
  636. }
  637. // Make sure we do not combine instructions with operands in different BBs.
  638. TEST_F(VPlanSlpTest, testInstrsInDifferentBBs2) {
  639. const char *ModuleString =
  640. "%struct.Test = type { i32, i32 }\n"
  641. "%struct.Test3 = type { i32, i32, i32 }\n"
  642. "%struct.Test4xi8 = type { i8, i8, i8 }\n"
  643. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  644. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  645. "entry:\n"
  646. " br label %for.body\n"
  647. "for.body: ; preds = %for.body, "
  648. "%entry\n"
  649. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  650. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  651. "%indvars.iv, i32 0\n"
  652. " %vA0 = load i32, i32* %A0, align 4\n"
  653. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  654. "%indvars.iv, i32 0\n"
  655. " %vB0 = load i32, i32* %B0, align 4\n"
  656. " %add0 = add nsw i32 %vA0, %vB0\n"
  657. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  658. "%indvars.iv, i32 1\n"
  659. " %vA1 = load i32, i32* %A1, align 4\n"
  660. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  661. "%indvars.iv, i32 1\n"
  662. " %vB1 = load i32, i32* %B1, align 4\n"
  663. " %add1 = add nsw i32 %vA1, %vB1\n"
  664. " br label %bb2\n"
  665. "bb2:\n"
  666. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  667. "%indvars.iv, i32 0\n"
  668. " store i32 %add0, i32* %C0, align 4\n"
  669. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  670. "%indvars.iv, i32 1\n"
  671. " store i32 %add1, i32* %C1, align 4\n"
  672. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  673. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  674. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  675. "for.cond.cleanup: ; preds = %for.body\n"
  676. " ret void\n"
  677. "}\n";
  678. Module &M = parseModule(ModuleString);
  679. Function *F = M.getFunction("add_x2");
  680. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  681. auto Plan = buildHCFG(LoopHeader);
  682. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  683. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  684. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  685. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  686. VPBasicBlock *BB2 = Body->getSingleSuccessor()->getEntryBasicBlock();
  687. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(BB2->begin(), 1));
  688. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(BB2->begin(), 3));
  689. VPlanSlp Slp(VPIAI, *BB2);
  690. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  691. EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
  692. EXPECT_EQ(0u, Slp.getWidestBundleBits());
  693. }
  694. TEST_F(VPlanSlpTest, testSlpAtomicLoad) {
  695. const char *ModuleString =
  696. "%struct.Test = type { i32, i32 }\n"
  697. "%struct.Test3 = type { i32, i32, i32 }\n"
  698. "%struct.Test4xi8 = type { i8, i8, i8 }\n"
  699. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  700. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  701. "entry:\n"
  702. " br label %for.body\n"
  703. "for.body: ; preds = %for.body, "
  704. "%entry\n"
  705. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  706. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  707. "%indvars.iv, i32 0\n"
  708. " %vA0 = load atomic i32, i32* %A0 monotonic, align 4\n"
  709. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  710. "%indvars.iv, i32 0\n"
  711. " %vB0 = load i32, i32* %B0, align 4\n"
  712. " %add0 = add nsw i32 %vA0, %vB0\n"
  713. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  714. "%indvars.iv, i32 1\n"
  715. " %vA1 = load i32, i32* %A1, align 4\n"
  716. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  717. "%indvars.iv, i32 1\n"
  718. " %vB1 = load i32, i32* %B1, align 4\n"
  719. " %add1 = add nsw i32 %vA1, %vB1\n"
  720. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  721. "%indvars.iv, i32 0\n"
  722. " store i32 %add0, i32* %C0, align 4\n"
  723. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  724. "%indvars.iv, i32 1\n"
  725. " store i32 %add1, i32* %C1, align 4\n"
  726. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  727. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  728. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  729. "for.cond.cleanup: ; preds = %for.body\n"
  730. " ret void\n"
  731. "}\n";
  732. Module &M = parseModule(ModuleString);
  733. Function *F = M.getFunction("add_x2");
  734. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  735. auto Plan = buildHCFG(LoopHeader);
  736. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  737. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  738. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  739. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  740. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
  741. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
  742. VPlanSlp Slp(VPIAI, *Body);
  743. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  744. EXPECT_EQ(nullptr, Slp.buildGraph(StoreRoot));
  745. EXPECT_FALSE(Slp.isCompletelySLP());
  746. }
  747. TEST_F(VPlanSlpTest, testSlpAtomicStore) {
  748. const char *ModuleString =
  749. "%struct.Test = type { i32, i32 }\n"
  750. "%struct.Test3 = type { i32, i32, i32 }\n"
  751. "%struct.Test4xi8 = type { i8, i8, i8 }\n"
  752. "define void @add_x2(%struct.Test* nocapture readonly %A, %struct.Test* "
  753. "nocapture readonly %B, %struct.Test* nocapture %C) {\n"
  754. "entry:\n"
  755. " br label %for.body\n"
  756. "for.body: ; preds = %for.body, "
  757. "%entry\n"
  758. " %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
  759. " %A0 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  760. "%indvars.iv, i32 0\n"
  761. " %vA0 = load i32, i32* %A0, align 4\n"
  762. " %B0 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  763. "%indvars.iv, i32 0\n"
  764. " %vB0 = load i32, i32* %B0, align 4\n"
  765. " %add0 = add nsw i32 %vA0, %vB0\n"
  766. " %A1 = getelementptr inbounds %struct.Test, %struct.Test* %A, i64 "
  767. "%indvars.iv, i32 1\n"
  768. " %vA1 = load i32, i32* %A1, align 4\n"
  769. " %B1 = getelementptr inbounds %struct.Test, %struct.Test* %B, i64 "
  770. "%indvars.iv, i32 1\n"
  771. " %vB1 = load i32, i32* %B1, align 4\n"
  772. " %add1 = add nsw i32 %vA1, %vB1\n"
  773. " %C0 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  774. "%indvars.iv, i32 0\n"
  775. " store atomic i32 %add0, i32* %C0 monotonic, align 4\n"
  776. " %C1 = getelementptr inbounds %struct.Test, %struct.Test* %C, i64 "
  777. "%indvars.iv, i32 1\n"
  778. " store i32 %add1, i32* %C1, align 4\n"
  779. " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"
  780. " %exitcond = icmp eq i64 %indvars.iv.next, 1024\n"
  781. " br i1 %exitcond, label %for.cond.cleanup, label %for.body\n"
  782. "for.cond.cleanup: ; preds = %for.body\n"
  783. " ret void\n"
  784. "}\n";
  785. Module &M = parseModule(ModuleString);
  786. Function *F = M.getFunction("add_x2");
  787. BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
  788. auto Plan = buildHCFG(LoopHeader);
  789. auto VPIAI = getInterleavedAccessInfo(*F, LI->getLoopFor(LoopHeader), *Plan);
  790. VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
  791. EXPECT_NE(nullptr, Entry->getSingleSuccessor());
  792. VPBasicBlock *Body = Entry->getSingleSuccessor()->getEntryBasicBlock();
  793. VPInstruction *Store1 = cast<VPInstruction>(&*std::next(Body->begin(), 12));
  794. VPInstruction *Store2 = cast<VPInstruction>(&*std::next(Body->begin(), 14));
  795. VPlanSlp Slp(VPIAI, *Body);
  796. SmallVector<VPValue *, 4> StoreRoot = {Store1, Store2};
  797. Slp.buildGraph(StoreRoot);
  798. EXPECT_FALSE(Slp.isCompletelySLP());
  799. }
  800. } // namespace
  801. } // namespace llvm