1303231Sdim//=-- Profilesummary.cpp - Profile summary support --------------------------=//
2303231Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303231Sdim//
7303231Sdim//===----------------------------------------------------------------------===//
8303231Sdim//
9303231Sdim// This file contains support for converting profile summary data from/to
10303231Sdim// metadata.
11303231Sdim//
12303231Sdim//===----------------------------------------------------------------------===//
13303231Sdim
14303231Sdim#include "llvm/IR/ProfileSummary.h"
15303231Sdim#include "llvm/IR/Attributes.h"
16303231Sdim#include "llvm/IR/Constants.h"
17303231Sdim#include "llvm/IR/Function.h"
18303231Sdim#include "llvm/IR/Metadata.h"
19303231Sdim#include "llvm/IR/Type.h"
20303231Sdim#include "llvm/Support/Casting.h"
21303231Sdim
22303231Sdimusing namespace llvm;
23303231Sdim
24303231Sdim// Return an MDTuple with two elements. The first element is a string Key and
25303231Sdim// the second is a uint64_t Value.
26303231Sdimstatic Metadata *getKeyValMD(LLVMContext &Context, const char *Key,
27303231Sdim                             uint64_t Val) {
28303231Sdim  Type *Int64Ty = Type::getInt64Ty(Context);
29303231Sdim  Metadata *Ops[2] = {MDString::get(Context, Key),
30303231Sdim                      ConstantAsMetadata::get(ConstantInt::get(Int64Ty, Val))};
31303231Sdim  return MDTuple::get(Context, Ops);
32303231Sdim}
33303231Sdim
34303231Sdim// Return an MDTuple with two elements. The first element is a string Key and
35303231Sdim// the second is a string Value.
36303231Sdimstatic Metadata *getKeyValMD(LLVMContext &Context, const char *Key,
37303231Sdim                             const char *Val) {
38303231Sdim  Metadata *Ops[2] = {MDString::get(Context, Key), MDString::get(Context, Val)};
39303231Sdim  return MDTuple::get(Context, Ops);
40303231Sdim}
41303231Sdim
42303231Sdim// This returns an MDTuple representing the detiled summary. The tuple has two
43303231Sdim// elements: a string "DetailedSummary" and an MDTuple representing the value
44303231Sdim// of the detailed summary. Each element of this tuple is again an MDTuple whose
45303231Sdim// elements are the (Cutoff, MinCount, NumCounts) triplet of the
46303231Sdim// DetailedSummaryEntry.
47303231SdimMetadata *ProfileSummary::getDetailedSummaryMD(LLVMContext &Context) {
48303231Sdim  std::vector<Metadata *> Entries;
49303231Sdim  Type *Int32Ty = Type::getInt32Ty(Context);
50303231Sdim  Type *Int64Ty = Type::getInt64Ty(Context);
51303231Sdim  for (auto &Entry : DetailedSummary) {
52303231Sdim    Metadata *EntryMD[3] = {
53303231Sdim        ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Entry.Cutoff)),
54303231Sdim        ConstantAsMetadata::get(ConstantInt::get(Int64Ty, Entry.MinCount)),
55303231Sdim        ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Entry.NumCounts))};
56303231Sdim    Entries.push_back(MDTuple::get(Context, EntryMD));
57303231Sdim  }
58303231Sdim  Metadata *Ops[2] = {MDString::get(Context, "DetailedSummary"),
59303231Sdim                      MDTuple::get(Context, Entries)};
60303231Sdim  return MDTuple::get(Context, Ops);
61303231Sdim}
62303231Sdim
63303231Sdim// This returns an MDTuple representing this ProfileSummary object. The first
64303231Sdim// entry of this tuple is another MDTuple of two elements: a string
65303231Sdim// "ProfileFormat" and a string representing the format ("InstrProf" or
66303231Sdim// "SampleProfile"). The rest of the elements of the outer MDTuple are specific
67303231Sdim// to the kind of profile summary as returned by getFormatSpecificMD.
68303231SdimMetadata *ProfileSummary::getMD(LLVMContext &Context) {
69353358Sdim  const char *KindStr[3] = {"InstrProf", "CSInstrProf", "SampleProfile"};
70341825Sdim  Metadata *Components[] = {
71341825Sdim    getKeyValMD(Context, "ProfileFormat", KindStr[PSK]),
72341825Sdim    getKeyValMD(Context, "TotalCount", getTotalCount()),
73341825Sdim    getKeyValMD(Context, "MaxCount", getMaxCount()),
74341825Sdim    getKeyValMD(Context, "MaxInternalCount", getMaxInternalCount()),
75341825Sdim    getKeyValMD(Context, "MaxFunctionCount", getMaxFunctionCount()),
76341825Sdim    getKeyValMD(Context, "NumCounts", getNumCounts()),
77341825Sdim    getKeyValMD(Context, "NumFunctions", getNumFunctions()),
78341825Sdim    getDetailedSummaryMD(Context),
79341825Sdim  };
80303231Sdim  return MDTuple::get(Context, Components);
81303231Sdim}
82303231Sdim
83303231Sdim// Parse an MDTuple representing (Key, Val) pair.
84303231Sdimstatic bool getVal(MDTuple *MD, const char *Key, uint64_t &Val) {
85303231Sdim  if (!MD)
86303231Sdim    return false;
87303231Sdim  if (MD->getNumOperands() != 2)
88303231Sdim    return false;
89303231Sdim  MDString *KeyMD = dyn_cast<MDString>(MD->getOperand(0));
90303231Sdim  ConstantAsMetadata *ValMD = dyn_cast<ConstantAsMetadata>(MD->getOperand(1));
91303231Sdim  if (!KeyMD || !ValMD)
92303231Sdim    return false;
93303231Sdim  if (!KeyMD->getString().equals(Key))
94303231Sdim    return false;
95303231Sdim  Val = cast<ConstantInt>(ValMD->getValue())->getZExtValue();
96303231Sdim  return true;
97303231Sdim}
98303231Sdim
99303231Sdim// Check if an MDTuple represents a (Key, Val) pair.
100303231Sdimstatic bool isKeyValuePair(MDTuple *MD, const char *Key, const char *Val) {
101303231Sdim  if (!MD || MD->getNumOperands() != 2)
102303231Sdim    return false;
103303231Sdim  MDString *KeyMD = dyn_cast<MDString>(MD->getOperand(0));
104303231Sdim  MDString *ValMD = dyn_cast<MDString>(MD->getOperand(1));
105303231Sdim  if (!KeyMD || !ValMD)
106303231Sdim    return false;
107303231Sdim  if (!KeyMD->getString().equals(Key) || !ValMD->getString().equals(Val))
108303231Sdim    return false;
109303231Sdim  return true;
110303231Sdim}
111303231Sdim
112303231Sdim// Parse an MDTuple representing detailed summary.
113303231Sdimstatic bool getSummaryFromMD(MDTuple *MD, SummaryEntryVector &Summary) {
114303231Sdim  if (!MD || MD->getNumOperands() != 2)
115303231Sdim    return false;
116303231Sdim  MDString *KeyMD = dyn_cast<MDString>(MD->getOperand(0));
117303231Sdim  if (!KeyMD || !KeyMD->getString().equals("DetailedSummary"))
118303231Sdim    return false;
119303231Sdim  MDTuple *EntriesMD = dyn_cast<MDTuple>(MD->getOperand(1));
120303231Sdim  if (!EntriesMD)
121303231Sdim    return false;
122303231Sdim  for (auto &&MDOp : EntriesMD->operands()) {
123303231Sdim    MDTuple *EntryMD = dyn_cast<MDTuple>(MDOp);
124303231Sdim    if (!EntryMD || EntryMD->getNumOperands() != 3)
125303231Sdim      return false;
126303231Sdim    ConstantAsMetadata *Op0 =
127303231Sdim        dyn_cast<ConstantAsMetadata>(EntryMD->getOperand(0));
128303231Sdim    ConstantAsMetadata *Op1 =
129303231Sdim        dyn_cast<ConstantAsMetadata>(EntryMD->getOperand(1));
130303231Sdim    ConstantAsMetadata *Op2 =
131303231Sdim        dyn_cast<ConstantAsMetadata>(EntryMD->getOperand(2));
132303231Sdim
133303231Sdim    if (!Op0 || !Op1 || !Op2)
134303231Sdim      return false;
135303231Sdim    Summary.emplace_back(cast<ConstantInt>(Op0->getValue())->getZExtValue(),
136303231Sdim                         cast<ConstantInt>(Op1->getValue())->getZExtValue(),
137303231Sdim                         cast<ConstantInt>(Op2->getValue())->getZExtValue());
138303231Sdim  }
139303231Sdim  return true;
140303231Sdim}
141303231Sdim
142303231SdimProfileSummary *ProfileSummary::getFromMD(Metadata *MD) {
143341825Sdim  MDTuple *Tuple = dyn_cast_or_null<MDTuple>(MD);
144341825Sdim  if (!Tuple || Tuple->getNumOperands() != 8)
145303231Sdim    return nullptr;
146303231Sdim
147303231Sdim  auto &FormatMD = Tuple->getOperand(0);
148303231Sdim  ProfileSummary::Kind SummaryKind;
149303231Sdim  if (isKeyValuePair(dyn_cast_or_null<MDTuple>(FormatMD), "ProfileFormat",
150303231Sdim                     "SampleProfile"))
151303231Sdim    SummaryKind = PSK_Sample;
152303231Sdim  else if (isKeyValuePair(dyn_cast_or_null<MDTuple>(FormatMD), "ProfileFormat",
153303231Sdim                          "InstrProf"))
154303231Sdim    SummaryKind = PSK_Instr;
155353358Sdim  else if (isKeyValuePair(dyn_cast_or_null<MDTuple>(FormatMD), "ProfileFormat",
156353358Sdim                          "CSInstrProf"))
157353358Sdim    SummaryKind = PSK_CSInstr;
158303231Sdim  else
159303231Sdim    return nullptr;
160303231Sdim
161303231Sdim  uint64_t NumCounts, TotalCount, NumFunctions, MaxFunctionCount, MaxCount,
162303231Sdim      MaxInternalCount;
163303231Sdim  if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(1)), "TotalCount",
164303231Sdim              TotalCount))
165303231Sdim    return nullptr;
166303231Sdim  if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(2)), "MaxCount", MaxCount))
167303231Sdim    return nullptr;
168303231Sdim  if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(3)), "MaxInternalCount",
169303231Sdim              MaxInternalCount))
170303231Sdim    return nullptr;
171303231Sdim  if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(4)), "MaxFunctionCount",
172303231Sdim              MaxFunctionCount))
173303231Sdim    return nullptr;
174303231Sdim  if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(5)), "NumCounts", NumCounts))
175303231Sdim    return nullptr;
176303231Sdim  if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(6)), "NumFunctions",
177303231Sdim              NumFunctions))
178303231Sdim    return nullptr;
179303231Sdim
180303231Sdim  SummaryEntryVector Summary;
181303231Sdim  if (!getSummaryFromMD(dyn_cast<MDTuple>(Tuple->getOperand(7)), Summary))
182303231Sdim    return nullptr;
183341825Sdim  return new ProfileSummary(SummaryKind, std::move(Summary), TotalCount,
184341825Sdim                            MaxCount, MaxInternalCount, MaxFunctionCount,
185341825Sdim                            NumCounts, NumFunctions);
186303231Sdim}
187