@@ -128,3 +128,157 @@ TEST(DDGTest, getDependencies) {
128
128
SE.getOne (DL.back ()->getDistance (1 )->getType ()));
129
129
});
130
130
}
131
+
132
+ // / Test to make sure that when pi-blocks are formed, multiple edges of the same
133
+ // / kind and direction are collapsed into a single edge.
134
+ // / In the test below, %loadASubI belongs to an outside node, which has input
135
+ // / dependency with multiple load instructions in the pi-block containing
136
+ // / %loadBSubI. We expect a single memory dependence edge from the outside node
137
+ // / to this pi-block. The pi-block also contains %add and %add7 both of which
138
+ // / feed a phi in an outside node. We expect a single def-use edge from the
139
+ // / pi-block to the node containing that phi.
140
+ TEST (DDGTest, avoidDuplicateEdgesToFromPiBlocks) {
141
+ const char *ModuleStr =
142
+ " target datalayout = \" e-m:e-i64:64-n32:64-v256:256:256-v512:512:512\"\n "
143
+ " \n "
144
+ " define void @foo(float* noalias %A, float* noalias %B, float* noalias "
145
+ " %C, float* noalias %D, i32 signext %n) {\n "
146
+ " entry:\n "
147
+ " %cmp1 = icmp sgt i32 %n, 0\n "
148
+ " br i1 %cmp1, label %for.body.preheader, label %for.end\n "
149
+ " \n "
150
+ " for.body.preheader: ; preds = %entry\n "
151
+ " %wide.trip.count = zext i32 %n to i64\n "
152
+ " br label %for.body\n "
153
+ " \n "
154
+ " for.body: ; preds = "
155
+ " %for.body.preheader, %if.end\n "
156
+ " %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, "
157
+ " %if.end ]\n "
158
+ " %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv\n "
159
+ " %loadASubI = load float, float* %arrayidx, align 4\n "
160
+ " %arrayidx2 = getelementptr inbounds float, float* %B, i64 "
161
+ " %indvars.iv\n "
162
+ " %loadBSubI = load float, float* %arrayidx2, align 4\n "
163
+ " %add = fadd fast float %loadASubI, %loadBSubI\n "
164
+ " %arrayidx4 = getelementptr inbounds float, float* %A, i64 "
165
+ " %indvars.iv\n "
166
+ " store float %add, float* %arrayidx4, align 4\n "
167
+ " %arrayidx6 = getelementptr inbounds float, float* %A, i64 "
168
+ " %indvars.iv\n "
169
+ " %0 = load float, float* %arrayidx6, align 4\n "
170
+ " %add7 = fadd fast float %0, 1.000000e+00\n "
171
+ " %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n "
172
+ " %arrayidx10 = getelementptr inbounds float, float* %B, i64 "
173
+ " %indvars.iv.next\n "
174
+ " store float %add7, float* %arrayidx10, align 4\n "
175
+ " %arrayidx12 = getelementptr inbounds float, float* %A, i64 "
176
+ " %indvars.iv\n "
177
+ " %1 = load float, float* %arrayidx12, align 4\n "
178
+ " %cmp13 = fcmp fast ogt float %1, 1.000000e+02\n "
179
+ " br i1 %cmp13, label %if.then, label %if.else\n "
180
+ " \n "
181
+ " if.then: ; preds = %for.body\n "
182
+ " br label %if.end\n "
183
+ " \n "
184
+ " if.else: ; preds = %for.body\n "
185
+ " br label %if.end\n "
186
+ " \n "
187
+ " if.end: ; preds = %if.else, "
188
+ " %if.then\n "
189
+ " %ff.0 = phi float [ %add, %if.then ], [ %add7, %if.else ]\n "
190
+ " store float %ff.0, float* %C, align 4\n "
191
+ " %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count\n "
192
+ " br i1 %exitcond, label %for.body, label %for.end.loopexit\n "
193
+ " \n "
194
+ " for.end.loopexit: ; preds = %if.end\n "
195
+ " br label %for.end\n "
196
+ " \n "
197
+ " for.end: ; preds = "
198
+ " %for.end.loopexit, %entry\n "
199
+ " ret void\n "
200
+ " }\n " ;
201
+
202
+ LLVMContext Context;
203
+ std::unique_ptr<Module> M = makeLLVMModule (Context, ModuleStr);
204
+
205
+ runTest (
206
+ *M, " foo" ,
207
+ [&](Function &F, LoopInfo &LI, DependenceInfo &DI, ScalarEvolution &SE) {
208
+ Loop *L = *LI.begin ();
209
+ assert (L && " expected the loop to be identified." );
210
+
211
+ DataDependenceGraph DDG (*L, LI, DI);
212
+
213
+ const DDGNode *LoadASubI = nullptr ;
214
+ for (DDGNode *N : DDG) {
215
+ if (!isa<SimpleDDGNode>(N))
216
+ continue ;
217
+ SmallVector<Instruction *, 8 > IList;
218
+ N->collectInstructions ([](const Instruction *I) { return true ; },
219
+ IList);
220
+ if (llvm::any_of (IList, [](Instruction *I) {
221
+ return I->getName () == " loadASubI" ;
222
+ })) {
223
+ LoadASubI = N;
224
+ break ;
225
+ }
226
+ }
227
+ assert (LoadASubI && " Did not find load of A[i]" );
228
+
229
+ const PiBlockDDGNode *PiBlockWithBSubI = nullptr ;
230
+ for (DDGNode *N : DDG) {
231
+ if (!isa<PiBlockDDGNode>(N))
232
+ continue ;
233
+ for (DDGNode *M : cast<PiBlockDDGNode>(N)->getNodes ()) {
234
+ SmallVector<Instruction *, 8 > IList;
235
+ M->collectInstructions ([](const Instruction *I) { return true ; },
236
+ IList);
237
+ if (llvm::any_of (IList, [](Instruction *I) {
238
+ return I->getName () == " loadBSubI" ;
239
+ })) {
240
+ PiBlockWithBSubI = static_cast <PiBlockDDGNode *>(N);
241
+ break ;
242
+ }
243
+ }
244
+ if (PiBlockWithBSubI)
245
+ break ;
246
+ }
247
+ assert (PiBlockWithBSubI &&
248
+ " Did not find pi-block containing load of B[i]" );
249
+
250
+ const DDGNode *FFPhi = nullptr ;
251
+ for (DDGNode *N : DDG) {
252
+ if (!isa<SimpleDDGNode>(N))
253
+ continue ;
254
+ SmallVector<Instruction *, 8 > IList;
255
+ N->collectInstructions ([](const Instruction *I) { return true ; },
256
+ IList);
257
+ if (llvm::any_of (IList, [](Instruction *I) {
258
+ return I->getName () == " ff.0" ;
259
+ })) {
260
+ FFPhi = N;
261
+ break ;
262
+ }
263
+ }
264
+ assert (FFPhi && " Did not find ff.0 phi instruction" );
265
+
266
+ // Expect a single memory edge from '%0 = A[i]' to the pi-block. This
267
+ // means the duplicate incoming memory edges are removed during pi-block
268
+ // formation.
269
+ SmallVector<DDGEdge *, 4 > EL;
270
+ LoadASubI->findEdgesTo (*PiBlockWithBSubI, EL);
271
+ unsigned NumMemoryEdges = llvm::count_if (
272
+ EL, [](DDGEdge *Edge) { return Edge->isMemoryDependence (); });
273
+ EXPECT_EQ (NumMemoryEdges, 1ull );
274
+
275
+ // / Expect a single def-use edge from the pi-block to '%ff.0 = phi...`.
276
+ // / This means the duplicate outgoing def-use edges are removed during
277
+ // / pi-block formation.
278
+ EL.clear ();
279
+ PiBlockWithBSubI->findEdgesTo (*FFPhi, EL);
280
+ NumMemoryEdges =
281
+ llvm::count_if (EL, [](DDGEdge *Edge) { return Edge->isDefUse (); });
282
+ EXPECT_EQ (NumMemoryEdges, 1ull );
283
+ });
284
+ }
0 commit comments