Skip to content

Commit f2adae5

Browse files
[MemProf] Optionally save context size info on largest cold allocations (#142507)
In order to allow selective reporting of context hinting during the LTO link, and in the future to allow selective more aggressive cloning, add an option to specify a minimum percent of the max cold size in the profile summary. Contexts that meet that threshold will get context size info metadata (and ThinLTO summary information) on the associated allocations. Specifying -memprof-report-hinted-sizes during the pre-LTO compile step will continue to cause all contexts to receive this metadata. But specifying -memprof-report-hinted-sizes only during the LTO link will cause only those that meet the new threshold and have the metadata to get reported. To support this, because the alloc info summary and associated bitcode requires the context size information to be in the same order as the other context information, 0s are inserted for contexts without this metadata. The bitcode writer uses a more compact format for the context ids to allow better compression of the 0s. As part of this change several helper methods are added to query whether metadata contains context size info on any or all contexts.
1 parent f5a2f00 commit f2adae5

File tree

9 files changed

+352
-40
lines changed

9 files changed

+352
-40
lines changed

llvm/include/llvm/Analysis/MemoryProfileInfo.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ class OptimizationRemarkEmitter;
2424

2525
namespace memprof {
2626

27+
/// Whether the alloc memeprof metadata will include context size info for all
28+
/// MIBs.
29+
LLVM_ABI bool metadataIncludesAllContextSizeInfo();
30+
31+
/// Whether the alloc memprof metadata may include context size info for some
32+
/// MIBs (but possibly not all).
33+
LLVM_ABI bool metadataMayIncludeContextSizeInfo();
34+
35+
/// Whether we need to record the context size info in the alloc trie used to
36+
/// build metadata.
37+
LLVM_ABI bool recordContextSizeInfoForAnalysis();
38+
2739
/// Build callstack metadata from the provided list of call stack ids. Returns
2840
/// the resulting metadata node.
2941
LLVM_ABI MDNode *buildCallstackMetadata(ArrayRef<uint64_t> CallStack,
@@ -87,6 +99,9 @@ class CallStackTrie {
8799
// allocations for which we apply non-context sensitive allocation hints.
88100
OptimizationRemarkEmitter *ORE;
89101

102+
// The maximum size of a cold allocation context, from the profile summary.
103+
uint64_t MaxColdSize;
104+
90105
void deleteTrieNode(CallStackTrieNode *Node) {
91106
if (!Node)
92107
return;
@@ -113,7 +128,9 @@ class CallStackTrie {
113128
uint64_t &ColdBytes);
114129

115130
public:
116-
CallStackTrie(OptimizationRemarkEmitter *ORE = nullptr) : ORE(ORE) {}
131+
CallStackTrie(OptimizationRemarkEmitter *ORE = nullptr,
132+
uint64_t MaxColdSize = 0)
133+
: ORE(ORE), MaxColdSize(MaxColdSize) {}
117134
~CallStackTrie() { deleteTrieNode(Alloc); }
118135

119136
bool empty() const { return Alloc == nullptr; }

llvm/lib/Analysis/MemoryProfileInfo.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,25 @@ cl::opt<unsigned> MinCallsiteColdBytePercent(
4646
cl::desc("Min percent of cold bytes at a callsite to discard non-cold "
4747
"contexts"));
4848

49+
// Enable saving context size information for largest cold contexts, which can
50+
// be used to flag contexts for more aggressive cloning and reporting.
51+
cl::opt<unsigned> MinPercentMaxColdSize(
52+
"memprof-min-percent-max-cold-size", cl::init(100), cl::Hidden,
53+
cl::desc("Min percent of max cold bytes for critical cold context"));
54+
55+
bool llvm::memprof::metadataIncludesAllContextSizeInfo() {
56+
return MemProfReportHintedSizes || MinClonedColdBytePercent < 100;
57+
}
58+
59+
bool llvm::memprof::metadataMayIncludeContextSizeInfo() {
60+
return metadataIncludesAllContextSizeInfo() || MinPercentMaxColdSize < 100;
61+
}
62+
63+
bool llvm::memprof::recordContextSizeInfoForAnalysis() {
64+
return metadataMayIncludeContextSizeInfo() ||
65+
MinCallsiteColdBytePercent < 100;
66+
}
67+
4968
MDNode *llvm::memprof::buildCallstackMetadata(ArrayRef<uint64_t> CallStack,
5069
LLVMContext &Ctx) {
5170
SmallVector<Metadata *, 8> StackVals;
@@ -168,7 +187,8 @@ void CallStackTrie::addCallStack(MDNode *MIB) {
168187
static MDNode *createMIBNode(LLVMContext &Ctx, ArrayRef<uint64_t> MIBCallStack,
169188
AllocationType AllocType,
170189
ArrayRef<ContextTotalSize> ContextSizeInfo,
171-
uint64_t &TotalBytes, uint64_t &ColdBytes) {
190+
const uint64_t MaxColdSize, uint64_t &TotalBytes,
191+
uint64_t &ColdBytes) {
172192
SmallVector<Metadata *> MIBPayload(
173193
{buildCallstackMetadata(MIBCallStack, Ctx)});
174194
MIBPayload.push_back(
@@ -184,12 +204,21 @@ static MDNode *createMIBNode(LLVMContext &Ctx, ArrayRef<uint64_t> MIBCallStack,
184204

185205
for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) {
186206
TotalBytes += TotalSize;
187-
if (AllocType == AllocationType::Cold)
207+
bool LargeColdContext = false;
208+
if (AllocType == AllocationType::Cold) {
188209
ColdBytes += TotalSize;
210+
// If we have the max cold context size from summary information and have
211+
// requested identification of contexts above a percentage of the max, see
212+
// if this context qualifies.
213+
if (MaxColdSize > 0 && MinPercentMaxColdSize < 100 &&
214+
TotalSize * 100 >= MaxColdSize * MinPercentMaxColdSize)
215+
LargeColdContext = true;
216+
}
189217
// Only add the context size info as metadata if we need it in the thin
190-
// link (currently if reporting of hinted sizes is enabled or we have
191-
// specified a threshold for marking allocations cold after cloning).
192-
if (MemProfReportHintedSizes || MinClonedColdBytePercent < 100) {
218+
// link (currently if reporting of hinted sizes is enabled, we have
219+
// specified a threshold for marking allocations cold after cloning, or we
220+
// have identified this as a large cold context of interest above).
221+
if (metadataIncludesAllContextSizeInfo() || LargeColdContext) {
193222
auto *FullStackIdMD = ValueAsMetadata::get(
194223
ConstantInt::get(Type::getInt64Ty(Ctx), FullStackId));
195224
auto *TotalSizeMD = ValueAsMetadata::get(
@@ -357,9 +386,9 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
357386
if (hasSingleAllocType(Node->AllocTypes)) {
358387
std::vector<ContextTotalSize> ContextSizeInfo;
359388
collectContextSizeInfo(Node, ContextSizeInfo);
360-
MIBNodes.push_back(createMIBNode(Ctx, MIBCallStack,
361-
(AllocationType)Node->AllocTypes,
362-
ContextSizeInfo, TotalBytes, ColdBytes));
389+
MIBNodes.push_back(
390+
createMIBNode(Ctx, MIBCallStack, (AllocationType)Node->AllocTypes,
391+
ContextSizeInfo, MaxColdSize, TotalBytes, ColdBytes));
363392
return true;
364393
}
365394

@@ -413,7 +442,8 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
413442
std::vector<ContextTotalSize> ContextSizeInfo;
414443
collectContextSizeInfo(Node, ContextSizeInfo);
415444
MIBNodes.push_back(createMIBNode(Ctx, MIBCallStack, AllocationType::NotCold,
416-
ContextSizeInfo, TotalBytes, ColdBytes));
445+
ContextSizeInfo, MaxColdSize, TotalBytes,
446+
ColdBytes));
417447
return true;
418448
}
419449

llvm/lib/Analysis/ModuleSummaryAnalysis.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ static void computeFunctionSummary(
525525
if (MemProfMD) {
526526
std::vector<MIBInfo> MIBs;
527527
std::vector<std::vector<ContextTotalSize>> ContextSizeInfos;
528+
bool HasNonZeroContextSizeInfos = false;
528529
for (auto &MDOp : MemProfMD->operands()) {
529530
auto *MIBMD = cast<const MDNode>(MDOp);
530531
MDNode *StackNode = getMIBStackNode(MIBMD);
@@ -544,7 +545,8 @@ static void computeFunctionSummary(
544545
}
545546
// If we have context size information, collect it for inclusion in
546547
// the summary.
547-
assert(MIBMD->getNumOperands() > 2 || !MemProfReportHintedSizes);
548+
assert(MIBMD->getNumOperands() > 2 ||
549+
!metadataIncludesAllContextSizeInfo());
548550
if (MIBMD->getNumOperands() > 2) {
549551
std::vector<ContextTotalSize> ContextSizes;
550552
for (unsigned I = 2; I < MIBMD->getNumOperands(); I++) {
@@ -558,14 +560,31 @@ static void computeFunctionSummary(
558560
->getZExtValue();
559561
ContextSizes.push_back({FullStackId, TS});
560562
}
563+
// Flag that we need to keep the ContextSizeInfos array for this
564+
// alloc as it now contains non-zero context info sizes.
565+
HasNonZeroContextSizeInfos = true;
561566
ContextSizeInfos.push_back(std::move(ContextSizes));
567+
} else {
568+
// The ContextSizeInfos must be in the same relative position as the
569+
// associated MIB. In some cases we only include a ContextSizeInfo
570+
// for a subset of MIBs in an allocation. To handle that, eagerly
571+
// fill any MIB entries that don't have context size info metadata
572+
// with a pair of 0s. Later on we will only use this array if it
573+
// ends up containing any non-zero entries (see where we set
574+
// HasNonZeroContextSizeInfos above).
575+
ContextSizeInfos.push_back({{0, 0}});
562576
}
563577
MIBs.push_back(
564578
MIBInfo(getMIBAllocType(MIBMD), std::move(StackIdIndices)));
565579
}
566580
Allocs.push_back(AllocInfo(std::move(MIBs)));
567-
assert(!ContextSizeInfos.empty() || !MemProfReportHintedSizes);
568-
if (!ContextSizeInfos.empty()) {
581+
assert(HasNonZeroContextSizeInfos ||
582+
!metadataIncludesAllContextSizeInfo());
583+
// We eagerly build the ContextSizeInfos array, but it will be filled
584+
// with sub arrays of pairs of 0s if no MIBs on this alloc actually
585+
// contained context size info metadata. Only save it if any MIBs had
586+
// any such metadata.
587+
if (HasNonZeroContextSizeInfos) {
569588
assert(Allocs.back().MIBs.size() == ContextSizeInfos.size());
570589
Allocs.back().ContextSizeInfos = std::move(ContextSizeInfos);
571590
}

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8164,6 +8164,14 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
81648164
ContextSizes.reserve(NumContextSizeInfoEntries);
81658165
for (unsigned J = 0; J < NumContextSizeInfoEntries; J++) {
81668166
assert(ContextIdIndex < PendingContextIds.size());
8167+
// Skip any 0 entries for MIBs without the context size info.
8168+
if (PendingContextIds[ContextIdIndex] == 0) {
8169+
// The size should also be 0 if the context was 0.
8170+
assert(!Record[I]);
8171+
ContextIdIndex++;
8172+
I++;
8173+
continue;
8174+
}
81678175
// PendingContextIds read from the preceding FS_ALLOC_CONTEXT_IDS
81688176
// should be in the same order as the total sizes.
81698177
ContextSizes.push_back(

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/ADT/SmallVector.h"
2424
#include "llvm/ADT/StringMap.h"
2525
#include "llvm/ADT/StringRef.h"
26+
#include "llvm/Analysis/MemoryProfileInfo.h"
2627
#include "llvm/BinaryFormat/Dwarf.h"
2728
#include "llvm/Bitcode/BitcodeCommon.h"
2829
#include "llvm/Bitcode/BitcodeReader.h"
@@ -4585,14 +4586,23 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
45854586
Stream.EmitRecord(bitc::FS_STACK_IDS, Vals, StackIdAbbvId);
45864587
}
45874588

4588-
// n x context id
4589-
auto ContextIdAbbv = std::make_shared<BitCodeAbbrev>();
4590-
ContextIdAbbv->Add(BitCodeAbbrevOp(bitc::FS_ALLOC_CONTEXT_IDS));
4591-
ContextIdAbbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
4592-
// The context ids are hashes that are close to 64 bits in size, so emitting
4593-
// as a pair of 32-bit fixed-width values is more efficient than a VBR.
4594-
ContextIdAbbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
4595-
unsigned ContextIdAbbvId = Stream.EmitAbbrev(std::move(ContextIdAbbv));
4589+
unsigned ContextIdAbbvId = 0;
4590+
if (metadataMayIncludeContextSizeInfo()) {
4591+
// n x context id
4592+
auto ContextIdAbbv = std::make_shared<BitCodeAbbrev>();
4593+
ContextIdAbbv->Add(BitCodeAbbrevOp(bitc::FS_ALLOC_CONTEXT_IDS));
4594+
ContextIdAbbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
4595+
// The context ids are hashes that are close to 64 bits in size, so emitting
4596+
// as a pair of 32-bit fixed-width values is more efficient than a VBR if we
4597+
// are emitting them for all MIBs. Otherwise we use VBR to better compress 0
4598+
// values that are expected to more frequently occur in an alloc's memprof
4599+
// summary.
4600+
if (metadataIncludesAllContextSizeInfo())
4601+
ContextIdAbbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
4602+
else
4603+
ContextIdAbbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
4604+
ContextIdAbbvId = Stream.EmitAbbrev(std::move(ContextIdAbbv));
4605+
}
45964606

45974607
// Abbrev for FS_PERMODULE_PROFILE.
45984608
Abbv = std::make_shared<BitCodeAbbrev>();

llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,9 +2232,8 @@ IndexCallsiteContextGraph::IndexCallsiteContextGraph(
22322232
CallStack<MIBInfo, SmallVector<unsigned>::const_iterator>
22332233
EmptyContext;
22342234
unsigned I = 0;
2235-
assert(
2236-
(!MemProfReportHintedSizes && MinClonedColdBytePercent >= 100) ||
2237-
AN.ContextSizeInfos.size() == AN.MIBs.size());
2235+
assert(!metadataMayIncludeContextSizeInfo() ||
2236+
AN.ContextSizeInfos.size() == AN.MIBs.size());
22382237
// Now add all of the MIBs and their stack nodes.
22392238
for (auto &MIB : AN.MIBs) {
22402239
CallStack<MIBInfo, SmallVector<unsigned>::const_iterator>

llvm/lib/Transforms/Instrumentation/MemProfiler.cpp

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,6 @@ static cl::opt<bool> ClMemProfAttachCalleeGuids(
184184
"Attach calleeguids as value profile metadata for indirect calls."),
185185
cl::init(true), cl::Hidden);
186186

187-
extern cl::opt<bool> MemProfReportHintedSizes;
188-
extern cl::opt<unsigned> MinClonedColdBytePercent;
189-
extern cl::opt<unsigned> MinCallsiteColdBytePercent;
190-
191187
static cl::opt<unsigned> MinMatchedColdBytePercent(
192188
"memprof-matching-cold-threshold", cl::init(100), cl::Hidden,
193189
cl::desc("Min percent of cold bytes matched to hint allocation cold"));
@@ -299,13 +295,6 @@ class ModuleMemProfiler {
299295
Function *MemProfCtorFunction = nullptr;
300296
};
301297

302-
// Options under which we need to record the context size info in the alloc trie
303-
// used to build metadata.
304-
bool recordContextSizeInfo() {
305-
return MemProfReportHintedSizes || MinClonedColdBytePercent < 100 ||
306-
MinCallsiteColdBytePercent < 100;
307-
}
308-
309298
} // end anonymous namespace
310299

311300
MemProfilerPass::MemProfilerPass() = default;
@@ -758,7 +747,7 @@ static AllocationType addCallStack(CallStackTrie &AllocTrie,
758747
AllocInfo->Info.getAllocCount(),
759748
AllocInfo->Info.getTotalLifetime());
760749
std::vector<ContextTotalSize> ContextSizeInfo;
761-
if (recordContextSizeInfo()) {
750+
if (recordContextSizeInfoForAnalysis()) {
762751
auto TotalSize = AllocInfo->Info.getTotalSize();
763752
assert(TotalSize);
764753
assert(FullStackId != 0);
@@ -1003,7 +992,7 @@ static void readMemprof(Module &M, Function &F,
1003992
&FullStackIdToAllocMatchInfo,
1004993
std::set<std::vector<uint64_t>> &MatchedCallSites,
1005994
DenseMap<uint64_t, LocToLocMap> &UndriftMaps,
1006-
OptimizationRemarkEmitter &ORE) {
995+
OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize) {
1007996
auto &Ctx = M.getContext();
1008997
// Previously we used getIRPGOFuncName() here. If F is local linkage,
1009998
// getIRPGOFuncName() returns FuncName with prefix 'FileName;'. But
@@ -1192,7 +1181,7 @@ static void readMemprof(Module &M, Function &F,
11921181
// We may match this instruction's location list to multiple MIB
11931182
// contexts. Add them to a Trie specialized for trimming the contexts to
11941183
// the minimal needed to disambiguate contexts with unique behavior.
1195-
CallStackTrie AllocTrie(&ORE);
1184+
CallStackTrie AllocTrie(&ORE, MaxColdSize);
11961185
uint64_t TotalSize = 0;
11971186
uint64_t TotalColdSize = 0;
11981187
for (auto *AllocInfo : AllocInfoIter->second) {
@@ -1203,7 +1192,7 @@ static void readMemprof(Module &M, Function &F,
12031192
InlinedCallStack)) {
12041193
NumOfMemProfMatchedAllocContexts++;
12051194
uint64_t FullStackId = 0;
1206-
if (ClPrintMemProfMatchInfo || recordContextSizeInfo())
1195+
if (ClPrintMemProfMatchInfo || recordContextSizeInfoForAnalysis())
12071196
FullStackId = computeFullStackId(AllocInfo->CallStack);
12081197
auto AllocType = addCallStack(AllocTrie, AllocInfo, FullStackId);
12091198
TotalSize += AllocInfo->Info.getTotalSize();
@@ -1340,14 +1329,18 @@ PreservedAnalyses MemProfUsePass::run(Module &M, ModuleAnalysisManager &AM) {
13401329
// call stack.
13411330
std::set<std::vector<uint64_t>> MatchedCallSites;
13421331

1332+
uint64_t MaxColdSize = 0;
1333+
if (auto *MemProfSum = MemProfReader->getMemProfSummary())
1334+
MaxColdSize = MemProfSum->getMaxColdTotalSize();
1335+
13431336
for (auto &F : M) {
13441337
if (F.isDeclaration())
13451338
continue;
13461339

13471340
const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
13481341
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
13491342
readMemprof(M, F, MemProfReader.get(), TLI, FullStackIdToAllocMatchInfo,
1350-
MatchedCallSites, UndriftMaps, ORE);
1343+
MatchedCallSites, UndriftMaps, ORE, MaxColdSize);
13511344
}
13521345

13531346
if (ClPrintMemProfMatchInfo) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
;; Test that we get hinted size reporting for just the subset of MIBs that
2+
;; contain context size info in the metadata.
3+
4+
;; Generate the bitcode including ThinLTO summary. Specify
5+
;; -memprof-min-percent-max-cold-size (value doesn't matter) to indicate to
6+
;; the bitcode writer that it should expect and optimize for partial context
7+
;; size info.
8+
; RUN: opt -thinlto-bc -memprof-min-percent-max-cold-size=50 %s >%t.o
9+
10+
; RUN: llvm-lto2 run %t.o -enable-memprof-context-disambiguation \
11+
; RUN: -supports-hot-cold-new \
12+
; RUN: -r=%t.o,main,plx \
13+
; RUN: -r=%t.o,_Znam, \
14+
; RUN: -memprof-report-hinted-sizes \
15+
; RUN: -o %t.out 2>&1 | FileCheck %s --check-prefix=SIZES
16+
17+
;; We should only get these two messages from -memprof-report-hinted-sizes
18+
;; as they are the only MIBs with recorded context size info.
19+
; SIZES-NOT: full allocation context
20+
; SIZES: Cold full allocation context 456 with total size 200 is Cold after cloning (context id 2)
21+
; SIZES: Cold full allocation context 789 with total size 300 is Cold after cloning (context id 2)
22+
; SIZES-NOT: full allocation context
23+
24+
source_filename = "memprof-report-hinted-partial.ll"
25+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
26+
target triple = "x86_64-unknown-linux-gnu"
27+
28+
define i32 @main() #0 {
29+
entry:
30+
%call = call ptr @_Z3foov(), !callsite !0
31+
%call1 = call ptr @_Z3foov(), !callsite !1
32+
ret i32 0
33+
}
34+
35+
define internal ptr @_Z3barv() #0 {
36+
entry:
37+
%call = call ptr @_Znam(i64 0), !memprof !2, !callsite !7
38+
ret ptr null
39+
}
40+
41+
declare ptr @_Znam(i64)
42+
43+
define internal ptr @_Z3bazv() #0 {
44+
entry:
45+
%call = call ptr @_Z3barv(), !callsite !8
46+
ret ptr null
47+
}
48+
49+
define internal ptr @_Z3foov() #0 {
50+
entry:
51+
%call = call ptr @_Z3bazv(), !callsite !9
52+
ret ptr null
53+
}
54+
55+
; uselistorder directives
56+
uselistorder ptr @_Z3foov, { 1, 0 }
57+
58+
attributes #0 = { noinline optnone }
59+
60+
!0 = !{i64 8632435727821051414}
61+
!1 = !{i64 -3421689549917153178}
62+
!2 = !{!3, !5, !13}
63+
!3 = !{!4, !"notcold"}
64+
!4 = !{i64 9086428284934609951, i64 -5964873800580613432, i64 2732490490862098848, i64 8632435727821051414}
65+
!5 = !{!6, !"cold", !11, !12}
66+
!6 = !{i64 9086428284934609951, i64 -5964873800580613432, i64 2732490490862098848, i64 -3421689549917153178}
67+
!7 = !{i64 9086428284934609951}
68+
!8 = !{i64 -5964873800580613432}
69+
!9 = !{i64 2732490490862098848}
70+
!11 = !{i64 456, i64 200}
71+
!12 = !{i64 789, i64 300}
72+
!13 = !{!14, !"cold"}
73+
!14 = !{i64 9086428284934609951, i64 12345}

0 commit comments

Comments
 (0)