Skip to content

Commit 174199c

Browse files
committed
[Utils] Identity map module-level debug info on first use in CloneFunction*
Summary: To avoid cloning module-level debug info (owned by the module rather than the function), CloneFunction implementation used to eagerly identity map such debug info into ValueMap's MD map. In larger modules with meaningful volume of debug info this gets very expensive. By passing such debug info metadata via an IdentityMD set for the ValueMapper to map on first use, we get several benefits: 1. Mapping metadata is not cheap, particularly because of tracking. When cloning a Function we identity map lots of global module-level metadata to avoid cloning it, while only a fraction of it is actually used by the function. Mapping on first use is a lot faster for modules with meaningful amount of debug info. 2. Eagerly identity mapping metadata makes it harder to cache module-level data (e.g. a set of metadata nodes in a \a DICompileUnit). With this patch we can cache certain module-level metadata calculations to speed things up further. Anecdata from compiling a sample cpp file with full debug info shows that this moderately speeds up CoroSplitPass which is one of the heavier users of cloning: | | Baseline | IdentityMD set | |-----------------|----------|----------------| | CoroSplitPass | 306ms | 221ms | | CoroCloner | 101ms | 72ms | | Speed up | 1x | 1.4x | Test Plan: ninja check-llvm-unit ninja check-llvm stack-info: PR: #118627, branch: users/artempyanykh/fast-coro-upstream/8
1 parent 3ed28bb commit 174199c

File tree

4 files changed

+106
-65
lines changed

4 files changed

+106
-65
lines changed

llvm/include/llvm/Transforms/Utils/Cloning.h

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ void CloneFunctionAttributesInto(Function *NewFunc, const Function *OldFunc,
193193
void CloneFunctionMetadataInto(Function &NewFunc, const Function &OldFunc,
194194
ValueToValueMapTy &VMap, RemapFlags RemapFlag,
195195
ValueMapTypeRemapper *TypeMapper = nullptr,
196-
ValueMaterializer *Materializer = nullptr);
196+
ValueMaterializer *Materializer = nullptr,
197+
const MetadataSetTy *IdentityMD = nullptr);
197198

198199
/// Clone OldFunc's body into NewFunc.
199200
void CloneFunctionBodyInto(Function &NewFunc, const Function &OldFunc,
@@ -202,7 +203,8 @@ void CloneFunctionBodyInto(Function &NewFunc, const Function &OldFunc,
202203
const char *NameSuffix = "",
203204
ClonedCodeInfo *CodeInfo = nullptr,
204205
ValueMapTypeRemapper *TypeMapper = nullptr,
205-
ValueMaterializer *Materializer = nullptr);
206+
ValueMaterializer *Materializer = nullptr,
207+
const MetadataSetTy *IdentityMD = nullptr);
206208

207209
void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
208210
const Instruction *StartingInst,
@@ -242,13 +244,24 @@ DISubprogram *CollectDebugInfoForCloning(const Function &F,
242244
CloneFunctionChangeType Changes,
243245
DebugInfoFinder &DIFinder);
244246

245-
/// Build a map of debug info to use during Metadata cloning.
246-
/// Returns true if cloning would need module level changes and false if there
247-
/// would only be local changes.
248-
bool BuildDebugInfoMDMap(DenseMap<const Metadata *, TrackingMDRef> &MD,
249-
CloneFunctionChangeType Changes,
250-
DebugInfoFinder &DIFinder,
251-
DISubprogram *SPClonedWithinModule);
247+
/// Based on \p Changes and \p DIFinder return debug info that needs to be
248+
/// identity mapped during Metadata cloning.
249+
///
250+
/// NOTE: Such \a MetadataSetTy can be used by \a CloneFunction* to directly
251+
/// specify metadata that should be identity mapped (and hence not cloned). The
252+
/// metadata will be identity mapped in \a ValueToValueMapTy on first use. There
253+
/// are several reasons for doing it this way rather than eagerly identity
254+
/// mapping metadata nodes in a \a ValueMap:
255+
/// 1. Mapping metadata is not cheap, particularly because of tracking.
256+
/// 2. When cloning a Function we identity map lots of global module-level
257+
/// metadata to avoid cloning it, while only a fraction of it is actually
258+
/// used by the function. Mapping on first use is a lot faster for modules
259+
/// with meaningful amount of debug info.
260+
/// 3. Eagerly identity mapping metadata makes it harder to cache module-level
261+
/// data (e.g. a set of metadata nodes in a \a DICompileUnit).
262+
MetadataSetTy FindDebugInfoToIdentityMap(CloneFunctionChangeType Changes,
263+
DebugInfoFinder &DIFinder,
264+
DISubprogram *SPClonedWithinModule);
252265

253266
/// This class captures the data input to the InlineFunction call, and records
254267
/// the auxiliary results produced by it.

llvm/include/llvm/Transforms/Utils/ValueMapper.h

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_TRANSFORMS_UTILS_VALUEMAPPER_H
1616

1717
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/SmallPtrSet.h"
1819
#include "llvm/ADT/simple_ilist.h"
1920
#include "llvm/IR/ValueHandle.h"
2021
#include "llvm/IR/ValueMap.h"
@@ -35,6 +36,7 @@ class Value;
3536

3637
using ValueToValueMapTy = ValueMap<const Value *, WeakTrackingVH>;
3738
using DbgRecordIterator = simple_ilist<DbgRecord>::iterator;
39+
using MetadataSetTy = SmallPtrSet<const Metadata *, 16>;
3840

3941
/// This is a class that can be implemented by clients to remap types when
4042
/// cloning constants and instructions.
@@ -112,7 +114,7 @@ inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) {
112114
///
113115
/// A shared context used for mapping and remapping of Value and Metadata
114116
/// instances using \a ValueToValueMapTy, \a RemapFlags, \a
115-
/// ValueMapTypeRemapper, and \a ValueMaterializer.
117+
/// ValueMapTypeRemapper, \a ValueMaterializer, and \a IdentityMD.
116118
///
117119
/// There are a number of top-level entry points:
118120
/// - \a mapValue() (and \a mapConstant());
@@ -136,6 +138,9 @@ inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) {
136138
/// alternate \a ValueToValueMapTy and \a ValueMaterializer and returns a ID to
137139
/// pass into the schedule*() functions.
138140
///
141+
/// If an \a IdentityMD set is optionally provided, \a Metadata inside this set
142+
/// will be mapped onto itself in \a VM on first use.
143+
///
139144
/// TODO: lib/Linker really doesn't need the \a ValueHandle in the \a
140145
/// ValueToValueMapTy. We should template \a ValueMapper (and its
141146
/// implementation classes), and explicitly instantiate on two concrete
@@ -152,7 +157,8 @@ class ValueMapper {
152157
public:
153158
ValueMapper(ValueToValueMapTy &VM, RemapFlags Flags = RF_None,
154159
ValueMapTypeRemapper *TypeMapper = nullptr,
155-
ValueMaterializer *Materializer = nullptr);
160+
ValueMaterializer *Materializer = nullptr,
161+
const MetadataSetTy *IdentityMD = nullptr);
156162
ValueMapper(ValueMapper &&) = delete;
157163
ValueMapper(const ValueMapper &) = delete;
158164
ValueMapper &operator=(ValueMapper &&) = delete;
@@ -218,8 +224,10 @@ class ValueMapper {
218224
inline Value *MapValue(const Value *V, ValueToValueMapTy &VM,
219225
RemapFlags Flags = RF_None,
220226
ValueMapTypeRemapper *TypeMapper = nullptr,
221-
ValueMaterializer *Materializer = nullptr) {
222-
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapValue(*V);
227+
ValueMaterializer *Materializer = nullptr,
228+
const MetadataSetTy *IdentityMD = nullptr) {
229+
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
230+
.mapValue(*V);
223231
}
224232

225233
/// Lookup or compute a mapping for a piece of metadata.
@@ -231,7 +239,9 @@ inline Value *MapValue(const Value *V, ValueToValueMapTy &VM,
231239
/// \c MD.
232240
/// 3. Else if \c MD is a \a ConstantAsMetadata, call \a MapValue() and
233241
/// re-wrap its return (returning nullptr on nullptr).
234-
/// 4. Else, \c MD is an \a MDNode. These are remapped, along with their
242+
/// 4. Else if \c MD is in \c IdentityMD then add an identity mapping for it
243+
/// and return it.
244+
/// 5. Else, \c MD is an \a MDNode. These are remapped, along with their
235245
/// transitive operands. Distinct nodes are duplicated or moved depending
236246
/// on \a RF_MoveDistinctNodes. Uniqued nodes are remapped like constants.
237247
///
@@ -240,16 +250,20 @@ inline Value *MapValue(const Value *V, ValueToValueMapTy &VM,
240250
inline Metadata *MapMetadata(const Metadata *MD, ValueToValueMapTy &VM,
241251
RemapFlags Flags = RF_None,
242252
ValueMapTypeRemapper *TypeMapper = nullptr,
243-
ValueMaterializer *Materializer = nullptr) {
244-
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapMetadata(*MD);
253+
ValueMaterializer *Materializer = nullptr,
254+
const MetadataSetTy *IdentityMD = nullptr) {
255+
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
256+
.mapMetadata(*MD);
245257
}
246258

247259
/// Version of MapMetadata with type safety for MDNode.
248260
inline MDNode *MapMetadata(const MDNode *MD, ValueToValueMapTy &VM,
249261
RemapFlags Flags = RF_None,
250262
ValueMapTypeRemapper *TypeMapper = nullptr,
251-
ValueMaterializer *Materializer = nullptr) {
252-
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapMDNode(*MD);
263+
ValueMaterializer *Materializer = nullptr,
264+
const MetadataSetTy *IdentityMD = nullptr) {
265+
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
266+
.mapMDNode(*MD);
253267
}
254268

255269
/// Convert the instruction operands from referencing the current values into
@@ -263,17 +277,21 @@ inline MDNode *MapMetadata(const MDNode *MD, ValueToValueMapTy &VM,
263277
inline void RemapInstruction(Instruction *I, ValueToValueMapTy &VM,
264278
RemapFlags Flags = RF_None,
265279
ValueMapTypeRemapper *TypeMapper = nullptr,
266-
ValueMaterializer *Materializer = nullptr) {
267-
ValueMapper(VM, Flags, TypeMapper, Materializer).remapInstruction(*I);
280+
ValueMaterializer *Materializer = nullptr,
281+
const MetadataSetTy *IdentityMD = nullptr) {
282+
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
283+
.remapInstruction(*I);
268284
}
269285

270286
/// Remap the Values used in the DbgRecord \a DR using the value map \a
271287
/// VM.
272288
inline void RemapDbgRecord(Module *M, DbgRecord *DR, ValueToValueMapTy &VM,
273289
RemapFlags Flags = RF_None,
274290
ValueMapTypeRemapper *TypeMapper = nullptr,
275-
ValueMaterializer *Materializer = nullptr) {
276-
ValueMapper(VM, Flags, TypeMapper, Materializer).remapDbgRecord(M, *DR);
291+
ValueMaterializer *Materializer = nullptr,
292+
const MetadataSetTy *IdentityMD = nullptr) {
293+
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
294+
.remapDbgRecord(M, *DR);
277295
}
278296

279297
/// Remap the Values used in the DbgRecords \a Range using the value map \a
@@ -283,8 +301,9 @@ inline void RemapDbgRecordRange(Module *M,
283301
ValueToValueMapTy &VM,
284302
RemapFlags Flags = RF_None,
285303
ValueMapTypeRemapper *TypeMapper = nullptr,
286-
ValueMaterializer *Materializer = nullptr) {
287-
ValueMapper(VM, Flags, TypeMapper, Materializer)
304+
ValueMaterializer *Materializer = nullptr,
305+
const MetadataSetTy *IdentityMD = nullptr) {
306+
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
288307
.remapDbgRecordRange(M, Range);
289308
}
290309

@@ -297,16 +316,19 @@ inline void RemapDbgRecordRange(Module *M,
297316
inline void RemapFunction(Function &F, ValueToValueMapTy &VM,
298317
RemapFlags Flags = RF_None,
299318
ValueMapTypeRemapper *TypeMapper = nullptr,
300-
ValueMaterializer *Materializer = nullptr) {
301-
ValueMapper(VM, Flags, TypeMapper, Materializer).remapFunction(F);
319+
ValueMaterializer *Materializer = nullptr,
320+
const MetadataSetTy *IdentityMD = nullptr) {
321+
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD).remapFunction(F);
302322
}
303323

304324
/// Version of MapValue with type safety for Constant.
305325
inline Constant *MapValue(const Constant *V, ValueToValueMapTy &VM,
306326
RemapFlags Flags = RF_None,
307327
ValueMapTypeRemapper *TypeMapper = nullptr,
308-
ValueMaterializer *Materializer = nullptr) {
309-
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapConstant(*V);
328+
ValueMaterializer *Materializer = nullptr,
329+
const MetadataSetTy *IdentityMD = nullptr) {
330+
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
331+
.mapConstant(*V);
310332
}
311333

312334
} // end namespace llvm

llvm/lib/Transforms/Utils/CloneFunction.cpp

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -152,61 +152,52 @@ DISubprogram *llvm::CollectDebugInfoForCloning(const Function &F,
152152
return SPClonedWithinModule;
153153
}
154154

155-
bool llvm::BuildDebugInfoMDMap(DenseMap<const Metadata *, TrackingMDRef> &MD,
156-
CloneFunctionChangeType Changes,
157-
DebugInfoFinder &DIFinder,
158-
DISubprogram *SPClonedWithinModule) {
159-
bool ModuleLevelChanges = Changes > CloneFunctionChangeType::LocalChangesOnly;
155+
MetadataSetTy
156+
llvm::FindDebugInfoToIdentityMap(CloneFunctionChangeType Changes,
157+
DebugInfoFinder &DIFinder,
158+
DISubprogram *SPClonedWithinModule) {
159+
MetadataSetTy MD;
160+
160161
if (Changes < CloneFunctionChangeType::DifferentModule &&
161162
DIFinder.subprogram_count() > 0) {
162-
// Turn on module-level changes, since we need to clone (some of) the
163-
// debug info metadata.
164-
//
165-
// FIXME: Metadata effectively owned by a function should be made
166-
// local, and only that local metadata should be cloned.
167-
ModuleLevelChanges = true;
168-
169-
auto mapToSelfIfNew = [&MD](MDNode *N) {
170-
// Avoid clobbering an existing mapping.
171-
(void)MD.try_emplace(N, N);
172-
};
173-
174163
// Avoid cloning types, compile units, and (other) subprograms.
175164
for (DISubprogram *ISP : DIFinder.subprograms()) {
176165
if (ISP != SPClonedWithinModule)
177-
mapToSelfIfNew(ISP);
166+
MD.insert(ISP);
178167
}
179168

180169
// If a subprogram isn't going to be cloned skip its lexical blocks as well.
181170
for (DIScope *S : DIFinder.scopes()) {
182171
auto *LScope = dyn_cast<DILocalScope>(S);
183172
if (LScope && LScope->getSubprogram() != SPClonedWithinModule)
184-
mapToSelfIfNew(S);
173+
MD.insert(S);
185174
}
186175

187176
for (DICompileUnit *CU : DIFinder.compile_units())
188-
mapToSelfIfNew(CU);
177+
MD.insert(CU);
189178

190179
for (DIType *Type : DIFinder.types())
191-
mapToSelfIfNew(Type);
180+
MD.insert(Type);
192181
} else {
193182
assert(!SPClonedWithinModule &&
194183
"Subprogram should be in DIFinder->subprogram_count()...");
195184
}
196185

197-
return ModuleLevelChanges;
186+
return MD;
198187
}
199188

200189
void llvm::CloneFunctionMetadataInto(Function &NewFunc, const Function &OldFunc,
201190
ValueToValueMapTy &VMap,
202191
RemapFlags RemapFlag,
203192
ValueMapTypeRemapper *TypeMapper,
204-
ValueMaterializer *Materializer) {
193+
ValueMaterializer *Materializer,
194+
const MetadataSetTy *IdentityMD) {
205195
SmallVector<std::pair<unsigned, MDNode *>, 1> MDs;
206196
OldFunc.getAllMetadata(MDs);
207197
for (auto MD : MDs) {
208-
NewFunc.addMetadata(MD.first, *MapMetadata(MD.second, VMap, RemapFlag,
209-
TypeMapper, Materializer));
198+
NewFunc.addMetadata(MD.first,
199+
*MapMetadata(MD.second, VMap, RemapFlag, TypeMapper,
200+
Materializer, IdentityMD));
210201
}
211202
}
212203

@@ -216,7 +207,8 @@ void llvm::CloneFunctionBodyInto(Function &NewFunc, const Function &OldFunc,
216207
const char *NameSuffix,
217208
ClonedCodeInfo *CodeInfo,
218209
ValueMapTypeRemapper *TypeMapper,
219-
ValueMaterializer *Materializer) {
210+
ValueMaterializer *Materializer,
211+
const MetadataSetTy *IdentityMD) {
220212
if (OldFunc.isDeclaration())
221213
return;
222214

@@ -258,9 +250,10 @@ void llvm::CloneFunctionBodyInto(Function &NewFunc, const Function &OldFunc,
258250
// Loop over all instructions, fixing each one as we find it, and any
259251
// attached debug-info records.
260252
for (Instruction &II : *BB) {
261-
RemapInstruction(&II, VMap, RemapFlag, TypeMapper, Materializer);
253+
RemapInstruction(&II, VMap, RemapFlag, TypeMapper, Materializer,
254+
IdentityMD);
262255
RemapDbgRecordRange(II.getModule(), II.getDbgRecordRange(), VMap,
263-
RemapFlag, TypeMapper, Materializer);
256+
RemapFlag, TypeMapper, Materializer, IdentityMD);
264257
}
265258
}
266259

@@ -322,16 +315,19 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
322315
DISubprogram *SPClonedWithinModule =
323316
CollectDebugInfoForCloning(*OldFunc, Changes, DIFinder);
324317

325-
ModuleLevelChanges =
326-
BuildDebugInfoMDMap(VMap.MD(), Changes, DIFinder, SPClonedWithinModule);
318+
MetadataSetTy IdentityMD =
319+
FindDebugInfoToIdentityMap(Changes, DIFinder, SPClonedWithinModule);
327320

328-
const auto RemapFlag = ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges;
321+
// Cloning is always a Module level operation, since Metadata needs to be
322+
// cloned.
323+
const auto RemapFlag = RF_None;
329324

330325
CloneFunctionMetadataInto(*NewFunc, *OldFunc, VMap, RemapFlag, TypeMapper,
331-
Materializer);
326+
Materializer, &IdentityMD);
332327

333328
CloneFunctionBodyInto(*NewFunc, *OldFunc, VMap, RemapFlag, Returns,
334-
NameSuffix, CodeInfo, TypeMapper, Materializer);
329+
NameSuffix, CodeInfo, TypeMapper, Materializer,
330+
&IdentityMD);
335331

336332
// Only update !llvm.dbg.cu for DifferentModule (not CloneModule). In the
337333
// same module, the compile unit will already be listed (or not). When

llvm/lib/Transforms/Utils/ValueMapper.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,14 @@ class Mapper {
120120
SmallVector<WorklistEntry, 4> Worklist;
121121
SmallVector<DelayedBasicBlock, 1> DelayedBBs;
122122
SmallVector<Constant *, 16> AppendingInits;
123+
const MetadataSetTy *IdentityMD;
123124

124125
public:
125126
Mapper(ValueToValueMapTy &VM, RemapFlags Flags,
126-
ValueMapTypeRemapper *TypeMapper, ValueMaterializer *Materializer)
127+
ValueMapTypeRemapper *TypeMapper, ValueMaterializer *Materializer,
128+
const MetadataSetTy *IdentityMD)
127129
: Flags(Flags), TypeMapper(TypeMapper),
128-
MCs(1, MappingContext(VM, Materializer)) {}
130+
MCs(1, MappingContext(VM, Materializer)), IdentityMD(IdentityMD) {}
129131

130132
/// ValueMapper should explicitly call \a flush() before destruction.
131133
~Mapper() { assert(!hasWorkToDo() && "Expected to be flushed"); }
@@ -899,6 +901,13 @@ std::optional<Metadata *> Mapper::mapSimpleMetadata(const Metadata *MD) {
899901
return wrapConstantAsMetadata(*CMD, mapValue(CMD->getValue()));
900902
}
901903

904+
// Map metadata from IdentityMD on first use. We need to add these nodes to
905+
// the mapping as otherwise metadata nodes numbering gets messed up. This is
906+
// still economical because the amount of data in IdentityMD may be a lot
907+
// larger than what will actually get used.
908+
if (IdentityMD && IdentityMD->contains(MD))
909+
return getVM().MD()[MD] = TrackingMDRef(const_cast<Metadata *>(MD));
910+
902911
assert(isa<MDNode>(MD) && "Expected a metadata node");
903912

904913
return std::nullopt;
@@ -1198,8 +1207,9 @@ class FlushingMapper {
11981207

11991208
ValueMapper::ValueMapper(ValueToValueMapTy &VM, RemapFlags Flags,
12001209
ValueMapTypeRemapper *TypeMapper,
1201-
ValueMaterializer *Materializer)
1202-
: pImpl(new Mapper(VM, Flags, TypeMapper, Materializer)) {}
1210+
ValueMaterializer *Materializer,
1211+
const MetadataSetTy *IdentityMD)
1212+
: pImpl(new Mapper(VM, Flags, TypeMapper, Materializer, IdentityMD)) {}
12031213

12041214
ValueMapper::~ValueMapper() { delete getAsMapper(pImpl); }
12051215

0 commit comments

Comments
 (0)