@@ -218,7 +218,11 @@ static cl::opt<std::string> ProfileInlineReplayFile(
218
218
" by inlining from sample profile loader." ),
219
219
cl::Hidden);
220
220
221
- extern cl::opt<unsigned > MaxNumPromotions;
221
+ static cl::opt<unsigned >
222
+ MaxNumPromotions (" sample-profile-icp-max-prom" , cl::init(3 ), cl::Hidden,
223
+ cl::ZeroOrMore,
224
+ cl::desc(" Max number of promotions for a single indirect "
225
+ " call callsite in sample profile loader" ));
222
226
223
227
namespace {
224
228
@@ -364,8 +368,7 @@ class SampleProfileLoader final
364
368
// Attempt to promote indirect call and also inline the promoted call
365
369
bool tryPromoteAndInlineCandidate (
366
370
Function &F, InlineCandidate &Candidate, uint64_t SumOrigin,
367
- uint64_t &Sum, DenseSet<Instruction *> &PromotedInsns,
368
- SmallVector<CallBase *, 8 > *InlinedCallSites = nullptr );
371
+ uint64_t &Sum, SmallVector<CallBase *, 8 > *InlinedCallSites = nullptr );
369
372
bool inlineHotFunctions (Function &F,
370
373
DenseSet<GlobalValue::GUID> &InlinedGUIDs);
371
374
InlineCost shouldInlineCandidate (InlineCandidate &Candidate);
@@ -696,43 +699,70 @@ SampleProfileLoader::findFunctionSamples(const Instruction &Inst) const {
696
699
return it.first ->second ;
697
700
}
698
701
699
- // / If the profile count for the promotion candidate \p Candidate is 0,
700
- // / it means \p Candidate has already been promoted for \p Inst.
701
- static bool isPromotedBefore (const Instruction &Inst, StringRef Candidate) {
702
+ // / Check whether the indirect call promotion history of \p Inst allows
703
+ // / the promotion for \p Candidate.
704
+ // / If the profile count for the promotion candidate \p Candidate is
705
+ // / NOMORE_ICP_MAGICNUM, it means \p Candidate has already been promoted
706
+ // / for \p Inst. If we already have at least MaxNumPromotions
707
+ // / NOMORE_ICP_MAGICNUM count values in the value profile of \p Inst, we
708
+ // / cannot promote for \p Inst anymore.
709
+ static bool doesHistoryAllowICP (const Instruction &Inst, StringRef Candidate) {
702
710
uint32_t NumVals = 0 ;
703
711
uint64_t TotalCount = 0 ;
704
712
std::unique_ptr<InstrProfValueData[]> ValueData =
705
713
std::make_unique<InstrProfValueData[]>(MaxNumPromotions);
706
714
bool Valid =
707
715
getValueProfDataFromInst (Inst, IPVK_IndirectCallTarget, MaxNumPromotions,
708
716
ValueData.get (), NumVals, TotalCount, true );
709
- if (Valid) {
710
- for (uint32_t I = 0 ; I < NumVals; I++) {
711
- // If the promotion candidate has 0 count in the metadata, it
712
- // means the candidate has been promoted for this indirect call.
713
- if (ValueData[I].Value == Function::getGUID (Candidate))
714
- return ValueData[I].Count == 0 ;
715
- }
717
+ // No valid value profile so no promoted targets have been recorded
718
+ // before. Ok to do ICP.
719
+ if (!Valid)
720
+ return true ;
721
+
722
+ unsigned NumPromoted = 0 ;
723
+ for (uint32_t I = 0 ; I < NumVals; I++) {
724
+ if (ValueData[I].Count != NOMORE_ICP_MAGICNUM)
725
+ continue ;
726
+
727
+ // If the promotion candidate has NOMORE_ICP_MAGICNUM count in the
728
+ // metadata, it means the candidate has been promoted for this
729
+ // indirect call.
730
+ if (ValueData[I].Value == Function::getGUID (Candidate))
731
+ return false ;
732
+ NumPromoted++;
733
+ // If already have MaxNumPromotions promotion, don't do it anymore.
734
+ if (NumPromoted == MaxNumPromotions)
735
+ return false ;
716
736
}
717
- return false ;
737
+ return true ;
718
738
}
719
739
720
- // / Update indirect call target profile metadata for \p Inst. If \p Total
721
- // / is given, set TotalCount of call targets counts to \p Total, otherwise
722
- // / keep the original value in metadata.
740
+ // / Update indirect call target profile metadata for \p Inst.
741
+ // / Usually \p Sum is the sum of counts of all the targets for \p Inst.
742
+ // / If it is 0, it means updateIDTMetaData is used to mark a
743
+ // / certain target to be promoted already. If it is not zero,
744
+ // / we expect to use it to update the total count in the value profile.
723
745
static void
724
746
updateIDTMetaData (Instruction &Inst,
725
747
const SmallVectorImpl<InstrProfValueData> &CallTargets,
726
- uint64_t Total = 0 ) {
727
- DenseMap<uint64_t , uint64_t > ValueCountMap;
748
+ uint64_t Sum) {
749
+ assert ((Sum != 0 || (CallTargets.size () == 1 &&
750
+ CallTargets[0 ].Count == NOMORE_ICP_MAGICNUM)) &&
751
+ " If sum is 0, assume only one element in CallTargets with count "
752
+ " being NOMORE_ICP_MAGICNUM" );
728
753
729
754
uint32_t NumVals = 0 ;
730
- uint64_t TotalCount = 0 ;
755
+ // OldSum is the existing total count in the value profile data.
756
+ // It will be replaced by Sum if Sum is not 0.
757
+ uint64_t OldSum = 0 ;
731
758
std::unique_ptr<InstrProfValueData[]> ValueData =
732
759
std::make_unique<InstrProfValueData[]>(MaxNumPromotions);
733
760
bool Valid =
734
761
getValueProfDataFromInst (Inst, IPVK_IndirectCallTarget, MaxNumPromotions,
735
- ValueData.get (), NumVals, TotalCount, true );
762
+ ValueData.get (), NumVals, OldSum, true );
763
+
764
+ DenseMap<uint64_t , uint64_t > ValueCountMap;
765
+ // Initialize ValueCountMap with existing value profile data.
736
766
if (Valid) {
737
767
for (uint32_t I = 0 ; I < NumVals; I++)
738
768
ValueCountMap[ValueData[I].Value ] = ValueData[I].Count ;
@@ -742,13 +772,24 @@ updateIDTMetaData(Instruction &Inst,
742
772
auto Pair = ValueCountMap.try_emplace (Data.Value , Data.Count );
743
773
if (Pair.second )
744
774
continue ;
745
- // Update existing profile count of the call target if it is not 0.
746
- // If it is 0, the call target has been promoted so keep it as 0.
747
- if (Pair.first ->second != 0 )
775
+ // Whenever the count is NOMORE_ICP_MAGICNUM for a value, keep it
776
+ // in the ValueCountMap. If both the count in CallTargets and the
777
+ // count in ValueCountMap is not NOMORE_ICP_MAGICNUM, keep the
778
+ // count in CallTargets.
779
+ if (Pair.first ->second != NOMORE_ICP_MAGICNUM &&
780
+ Data.Count == NOMORE_ICP_MAGICNUM) {
781
+ OldSum -= Pair.first ->second ;
782
+ Pair.first ->second = NOMORE_ICP_MAGICNUM;
783
+ } else if (Pair.first ->second == NOMORE_ICP_MAGICNUM &&
784
+ Data.Count != NOMORE_ICP_MAGICNUM) {
785
+ assert (Sum >= Data.Count && " Sum should never be less than Data.Count" );
786
+ Sum -= Data.Count ;
787
+ } else if (Pair.first ->second != NOMORE_ICP_MAGICNUM &&
788
+ Data.Count != NOMORE_ICP_MAGICNUM) {
789
+ // Sum will be used in this case. Although the existing count
790
+ // for the current value in value profile will be overriden,
791
+ // no need to update OldSum.
748
792
Pair.first ->second = Data.Count ;
749
- else {
750
- assert (Total >= Data.Count && " Total should be >= Data.Count" );
751
- Total -= Data.Count ;
752
793
}
753
794
}
754
795
@@ -757,36 +798,38 @@ updateIDTMetaData(Instruction &Inst,
757
798
NewCallTargets.emplace_back (
758
799
InstrProfValueData{ValueCount.first , ValueCount.second });
759
800
}
801
+
760
802
llvm::sort (NewCallTargets,
761
803
[](const InstrProfValueData &L, const InstrProfValueData &R) {
762
804
if (L.Count != R.Count )
763
805
return L.Count > R.Count ;
764
806
return L.Value > R.Value ;
765
807
});
808
+
809
+ uint32_t MaxMDCount =
810
+ std::min (NewCallTargets.size (), static_cast <size_t >(MaxNumPromotions));
766
811
annotateValueSite (*Inst.getParent ()->getParent ()->getParent (), Inst,
767
- NewCallTargets, Total ? Total : TotalCount ,
768
- IPVK_IndirectCallTarget, NewCallTargets. size () );
812
+ NewCallTargets, Sum ? Sum : OldSum, IPVK_IndirectCallTarget ,
813
+ MaxMDCount );
769
814
}
770
815
771
816
// / Attempt to promote indirect call and also inline the promoted call.
772
817
// /
773
818
// / \param F Caller function.
774
819
// / \param Candidate ICP and inline candidate.
775
820
// / \param Sum Sum of target counts for indirect call.
776
- // / \param PromotedInsns Map to keep track of indirect call already processed.
777
821
// / \param InlinedCallSite Output vector for new call sites exposed after
778
822
// / inlining.
779
823
bool SampleProfileLoader::tryPromoteAndInlineCandidate (
780
824
Function &F, InlineCandidate &Candidate, uint64_t SumOrigin, uint64_t &Sum,
781
- DenseSet<Instruction *> &PromotedInsns,
782
825
SmallVector<CallBase *, 8 > *InlinedCallSite) {
783
826
auto CalleeFunctionName = Candidate.CalleeSamples ->getFuncName ();
784
827
auto R = SymbolMap.find (CalleeFunctionName);
785
828
if (R == SymbolMap.end () || !R->getValue ())
786
829
return false ;
787
830
788
831
auto &CI = *Candidate.CallInstr ;
789
- if (isPromotedBefore (CI, R->getValue ()->getName ()))
832
+ if (! doesHistoryAllowICP (CI, R->getValue ()->getName ()))
790
833
return false ;
791
834
792
835
const char *Reason = " Callee function not available" ;
@@ -799,11 +842,11 @@ bool SampleProfileLoader::tryPromoteAndInlineCandidate(
799
842
if (!R->getValue ()->isDeclaration () && R->getValue ()->getSubprogram () &&
800
843
R->getValue ()->hasFnAttribute (" use-sample-profile" ) &&
801
844
R->getValue () != &F && isLegalToPromote (CI, R->getValue (), &Reason)) {
802
- // For promoted target, save 0 count in the value profile metadata so
803
- // the target won't be promoted again.
804
- SmallVector<InstrProfValueData, 1 > SortedCallTargets = {
805
- InstrProfValueData{ Function::getGUID (R->getValue ()->getName ()), 0 }};
806
- updateIDTMetaData (CI, SortedCallTargets);
845
+ // For promoted target, set its value with NOMORE_ICP_MAGICNUM count
846
+ // in the value profile metadata so the target won't be promoted again.
847
+ SmallVector<InstrProfValueData, 1 > SortedCallTargets = {InstrProfValueData{
848
+ Function::getGUID (R->getValue ()->getName ()), NOMORE_ICP_MAGICNUM }};
849
+ updateIDTMetaData (CI, SortedCallTargets, 0 );
807
850
808
851
auto *DI = &pgo::promoteIndirectCall (
809
852
CI, R->getValue (), Candidate.CallsiteCount , Sum, false , ORE);
@@ -817,7 +860,6 @@ bool SampleProfileLoader::tryPromoteAndInlineCandidate(
817
860
// be prorated so that the it will reflect the real callsite counts.
818
861
setProbeDistributionFactor (CI, Candidate.CallsiteDistribution * Sum /
819
862
SumOrigin);
820
- PromotedInsns.insert (Candidate.CallInstr );
821
863
Candidate.CallInstr = DI;
822
864
if (isa<CallInst>(DI) || isa<InvokeInst>(DI)) {
823
865
bool Inlined = tryInlineCandidate (Candidate, InlinedCallSite);
@@ -890,8 +932,6 @@ void SampleProfileLoader::emitOptimizationRemarksForInlineCandidates(
890
932
// / \returns True if there is any inline happened.
891
933
bool SampleProfileLoader::inlineHotFunctions (
892
934
Function &F, DenseSet<GlobalValue::GUID> &InlinedGUIDs) {
893
- DenseSet<Instruction *> PromotedInsns;
894
-
895
935
// ProfAccForSymsInList is used in callsiteIsHot. The assertion makes sure
896
936
// Profile symbol list is ignored when profile-sample-accurate is on.
897
937
assert ((!ProfAccForSymsInList ||
@@ -945,8 +985,6 @@ bool SampleProfileLoader::inlineHotFunctions(
945
985
if (CalledFunction == &F)
946
986
continue ;
947
987
if (I->isIndirectCall ()) {
948
- if (PromotedInsns.count (I))
949
- continue ;
950
988
uint64_t Sum;
951
989
for (const auto *FS : findIndirectCallFunctionSamples (*I, Sum)) {
952
990
uint64_t SumOrigin = Sum;
@@ -959,8 +997,7 @@ bool SampleProfileLoader::inlineHotFunctions(
959
997
continue ;
960
998
961
999
Candidate = {I, FS, FS->getEntrySamples (), 1.0 };
962
- if (tryPromoteAndInlineCandidate (F, Candidate, SumOrigin, Sum,
963
- PromotedInsns)) {
1000
+ if (tryPromoteAndInlineCandidate (F, Candidate, SumOrigin, Sum)) {
964
1001
LocalNotInlinedCallSites.erase (I);
965
1002
LocalChanged = true ;
966
1003
}
@@ -1169,7 +1206,6 @@ SampleProfileLoader::shouldInlineCandidate(InlineCandidate &Candidate) {
1169
1206
1170
1207
bool SampleProfileLoader::inlineHotFunctionsWithPriority (
1171
1208
Function &F, DenseSet<GlobalValue::GUID> &InlinedGUIDs) {
1172
- DenseSet<Instruction *> PromotedInsns;
1173
1209
assert (ProfileIsCS && " Prioritiy based inliner only works with CSSPGO now" );
1174
1210
1175
1211
// ProfAccForSymsInList is used in callsiteIsHot. The assertion makes sure
@@ -1218,8 +1254,6 @@ bool SampleProfileLoader::inlineHotFunctionsWithPriority(
1218
1254
if (CalledFunction == &F)
1219
1255
continue ;
1220
1256
if (I->isIndirectCall ()) {
1221
- if (PromotedInsns.count (I))
1222
- continue ;
1223
1257
uint64_t Sum;
1224
1258
auto CalleeSamples = findIndirectCallFunctionSamples (*I, Sum);
1225
1259
uint64_t SumOrigin = Sum;
@@ -1254,7 +1288,7 @@ bool SampleProfileLoader::inlineHotFunctionsWithPriority(
1254
1288
Candidate = {I, FS, EntryCountDistributed,
1255
1289
Candidate.CallsiteDistribution };
1256
1290
if (tryPromoteAndInlineCandidate (F, Candidate, SumOrigin, Sum,
1257
- PromotedInsns, &InlinedCallSites)) {
1291
+ &InlinedCallSites)) {
1258
1292
for (auto *CB : InlinedCallSites) {
1259
1293
if (getInlineCandidate (&NewCandidate, CB))
1260
1294
CQueue.emplace (NewCandidate);
@@ -1351,6 +1385,8 @@ void SampleProfileLoader::generateMDProfMetadata(Function &F) {
1351
1385
Sum += NameFS.second .getEntrySamples ();
1352
1386
}
1353
1387
}
1388
+ if (!Sum)
1389
+ continue ;
1354
1390
updateIDTMetaData (I, SortedCallTargets, Sum);
1355
1391
} else if (!isa<IntrinsicInst>(&I)) {
1356
1392
I.setMetadata (LLVMContext::MD_prof,
0 commit comments