@@ -199,6 +199,29 @@ void FunctionPropertiesInfo::updateForBB(const BasicBlock &BB,
199
199
#undef CHECK_OPERAND
200
200
}
201
201
}
202
+
203
+ if (IR2VecVocab) {
204
+ // We instantiate the IR2Vec embedder each time, as having an unique
205
+ // pointer to the embedder as member of the class would make it
206
+ // non-copyable. Instantiating the embedder in itself is not costly.
207
+ auto EmbOrErr = ir2vec::Embedder::create (IR2VecKind::Symbolic,
208
+ *BB.getParent (), *IR2VecVocab);
209
+ if (Error Err = EmbOrErr.takeError ()) {
210
+ handleAllErrors (std::move (Err), [&](const ErrorInfoBase &EI) {
211
+ BB.getContext ().emitError (" Error creating IR2Vec embeddings: " +
212
+ EI.message ());
213
+ });
214
+ return ;
215
+ }
216
+ auto Embedder = std::move (*EmbOrErr);
217
+ const auto &BBEmbedding = Embedder->getBBVector (BB);
218
+ // Subtract BBEmbedding from Function embedding if the direction is -1,
219
+ // and add it if the direction is +1.
220
+ if (Direction == -1 )
221
+ FunctionEmbedding -= BBEmbedding;
222
+ else
223
+ FunctionEmbedding += BBEmbedding;
224
+ }
202
225
}
203
226
204
227
void FunctionPropertiesInfo::updateAggregateStats (const Function &F,
@@ -220,21 +243,91 @@ void FunctionPropertiesInfo::updateAggregateStats(const Function &F,
220
243
221
244
FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo (
222
245
Function &F, FunctionAnalysisManager &FAM) {
246
+ // We use the cached result of the IR2VecVocabAnalysis run by
247
+ // InlineAdvisorAnalysis. If the IR2VecVocabAnalysis is not run, we don't
248
+ // use IR2Vec embeddings.
249
+ auto VocabResult = FAM.getResult <ModuleAnalysisManagerFunctionProxy>(F)
250
+ .getCachedResult <IR2VecVocabAnalysis>(*F.getParent ());
223
251
return getFunctionPropertiesInfo (F, FAM.getResult <DominatorTreeAnalysis>(F),
224
- FAM.getResult <LoopAnalysis>(F));
252
+ FAM.getResult <LoopAnalysis>(F), VocabResult );
225
253
}
226
254
227
255
FunctionPropertiesInfo FunctionPropertiesInfo::getFunctionPropertiesInfo (
228
- const Function &F, const DominatorTree &DT, const LoopInfo &LI) {
256
+ const Function &F, const DominatorTree &DT, const LoopInfo &LI,
257
+ const IR2VecVocabResult *VocabResult) {
229
258
230
259
FunctionPropertiesInfo FPI;
260
+ if (VocabResult && VocabResult->isValid ()) {
261
+ FPI.IR2VecVocab = VocabResult->getVocabulary ();
262
+ FPI.FunctionEmbedding = ir2vec::Embedding (VocabResult->getDimension (), 0.0 );
263
+ }
231
264
for (const auto &BB : F)
232
265
if (DT.isReachableFromEntry (&BB))
233
266
FPI.reIncludeBB (BB);
234
267
FPI.updateAggregateStats (F, LI);
235
268
return FPI;
236
269
}
237
270
271
+ bool FunctionPropertiesInfo::operator ==(
272
+ const FunctionPropertiesInfo &FPI) const {
273
+ if (BasicBlockCount != FPI.BasicBlockCount ||
274
+ BlocksReachedFromConditionalInstruction !=
275
+ FPI.BlocksReachedFromConditionalInstruction ||
276
+ Uses != FPI.Uses ||
277
+ DirectCallsToDefinedFunctions != FPI.DirectCallsToDefinedFunctions ||
278
+ LoadInstCount != FPI.LoadInstCount ||
279
+ StoreInstCount != FPI.StoreInstCount ||
280
+ MaxLoopDepth != FPI.MaxLoopDepth ||
281
+ TopLevelLoopCount != FPI.TopLevelLoopCount ||
282
+ TotalInstructionCount != FPI.TotalInstructionCount ||
283
+ BasicBlocksWithSingleSuccessor != FPI.BasicBlocksWithSingleSuccessor ||
284
+ BasicBlocksWithTwoSuccessors != FPI.BasicBlocksWithTwoSuccessors ||
285
+ BasicBlocksWithMoreThanTwoSuccessors !=
286
+ FPI.BasicBlocksWithMoreThanTwoSuccessors ||
287
+ BasicBlocksWithSinglePredecessor !=
288
+ FPI.BasicBlocksWithSinglePredecessor ||
289
+ BasicBlocksWithTwoPredecessors != FPI.BasicBlocksWithTwoPredecessors ||
290
+ BasicBlocksWithMoreThanTwoPredecessors !=
291
+ FPI.BasicBlocksWithMoreThanTwoPredecessors ||
292
+ BigBasicBlocks != FPI.BigBasicBlocks ||
293
+ MediumBasicBlocks != FPI.MediumBasicBlocks ||
294
+ SmallBasicBlocks != FPI.SmallBasicBlocks ||
295
+ CastInstructionCount != FPI.CastInstructionCount ||
296
+ FloatingPointInstructionCount != FPI.FloatingPointInstructionCount ||
297
+ IntegerInstructionCount != FPI.IntegerInstructionCount ||
298
+ ConstantIntOperandCount != FPI.ConstantIntOperandCount ||
299
+ ConstantFPOperandCount != FPI.ConstantFPOperandCount ||
300
+ ConstantOperandCount != FPI.ConstantOperandCount ||
301
+ InstructionOperandCount != FPI.InstructionOperandCount ||
302
+ BasicBlockOperandCount != FPI.BasicBlockOperandCount ||
303
+ GlobalValueOperandCount != FPI.GlobalValueOperandCount ||
304
+ InlineAsmOperandCount != FPI.InlineAsmOperandCount ||
305
+ ArgumentOperandCount != FPI.ArgumentOperandCount ||
306
+ UnknownOperandCount != FPI.UnknownOperandCount ||
307
+ CriticalEdgeCount != FPI.CriticalEdgeCount ||
308
+ ControlFlowEdgeCount != FPI.ControlFlowEdgeCount ||
309
+ UnconditionalBranchCount != FPI.UnconditionalBranchCount ||
310
+ IntrinsicCount != FPI.IntrinsicCount ||
311
+ DirectCallCount != FPI.DirectCallCount ||
312
+ IndirectCallCount != FPI.IndirectCallCount ||
313
+ CallReturnsIntegerCount != FPI.CallReturnsIntegerCount ||
314
+ CallReturnsFloatCount != FPI.CallReturnsFloatCount ||
315
+ CallReturnsPointerCount != FPI.CallReturnsPointerCount ||
316
+ CallReturnsVectorIntCount != FPI.CallReturnsVectorIntCount ||
317
+ CallReturnsVectorFloatCount != FPI.CallReturnsVectorFloatCount ||
318
+ CallReturnsVectorPointerCount != FPI.CallReturnsVectorPointerCount ||
319
+ CallWithManyArgumentsCount != FPI.CallWithManyArgumentsCount ||
320
+ CallWithPointerArgumentCount != FPI.CallWithPointerArgumentCount ) {
321
+ return false ;
322
+ }
323
+ // Check the equality of the function embeddings. We don't check the equality
324
+ // of Vocabulary as it remains the same.
325
+ if (!FunctionEmbedding.approximatelyEquals (FPI.FunctionEmbedding ))
326
+ return false ;
327
+
328
+ return true ;
329
+ }
330
+
238
331
void FunctionPropertiesInfo::print (raw_ostream &OS) const {
239
332
#define PRINT_PROPERTY (PROP_NAME ) OS << #PROP_NAME " : " << PROP_NAME << " \n " ;
240
333
@@ -322,6 +415,16 @@ FunctionPropertiesUpdater::FunctionPropertiesUpdater(
322
415
// The caller's entry BB may change due to new alloca instructions.
323
416
LikelyToChangeBBs.insert (&*Caller.begin ());
324
417
418
+ // The users of the value returned by call instruction can change
419
+ // leading to the change in embeddings being computed, when used.
420
+ // We conservatively add the BBs with such uses to LikelyToChangeBBs.
421
+ for (const auto *User : CB.users ())
422
+ CallUsers.insert (dyn_cast<Instruction>(User)->getParent ());
423
+ // CallSiteBB can be removed from CallUsers if present, it's taken care
424
+ // separately.
425
+ CallUsers.erase (&CallSiteBB);
426
+ LikelyToChangeBBs.insert_range (CallUsers);
427
+
325
428
// The successors may become unreachable in the case of `invoke` inlining.
326
429
// We track successors separately, too, because they form a boundary, together
327
430
// with the CB BB ('Entry') between which the inlined callee will be pasted.
@@ -435,6 +538,9 @@ void FunctionPropertiesUpdater::finish(FunctionAnalysisManager &FAM) const {
435
538
if (&CallSiteBB != &*Caller.begin ())
436
539
Reinclude.insert (&*Caller.begin ());
437
540
541
+ // Reinclude the BBs which use the values returned by call instruction
542
+ Reinclude.insert_range (CallUsers);
543
+
438
544
// Distribute the successors to the 2 buckets.
439
545
for (const auto *Succ : Successors)
440
546
if (DT.isReachableFromEntry (Succ))
@@ -486,6 +592,9 @@ bool FunctionPropertiesUpdater::isUpdateValid(Function &F,
486
592
return false ;
487
593
DominatorTree DT (F);
488
594
LoopInfo LI (DT);
489
- auto Fresh = FunctionPropertiesInfo::getFunctionPropertiesInfo (F, DT, LI);
595
+ auto VocabResult = FAM.getResult <ModuleAnalysisManagerFunctionProxy>(F)
596
+ .getCachedResult <IR2VecVocabAnalysis>(*F.getParent ());
597
+ auto Fresh =
598
+ FunctionPropertiesInfo::getFunctionPropertiesInfo (F, DT, LI, VocabResult);
490
599
return FPI == Fresh;
491
600
}
0 commit comments