Skip to content
Closed
50 changes: 50 additions & 0 deletions llvm/include/llvm/Analysis/DebugInfoCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===- llvm/Analysis/DebugInfoCache.h - debug info cache --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains an analysis that builds a cache of debug info for each
// DICompileUnit in a module.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_DEBUGINFOCACHE_H
#define LLVM_ANALYSIS_DEBUGINFOCACHE_H

#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/PassManager.h"

namespace llvm {

/// Processes and caches debug info for each DICompileUnit in a module.
///
/// The result of the analysis is a set of DebugInfoFinders primed on their
/// respective DICompileUnit. Such DebugInfoFinders can be used to speed up
/// function cloning which otherwise requires an expensive traversal of
/// DICompileUnit-level debug info. See an example usage in CoroSplit.
class DebugInfoCache {
public:
using DIFinderCache = SmallDenseMap<const DICompileUnit *, DebugInfoFinder>;
DIFinderCache Result;

DebugInfoCache(const Module &M);

bool invalidate(Module &, const PreservedAnalyses &,
ModuleAnalysisManager::Invalidator &);
};

class DebugInfoCacheAnalysis
: public AnalysisInfoMixin<DebugInfoCacheAnalysis> {
friend AnalysisInfoMixin<DebugInfoCacheAnalysis>;
static AnalysisKey Key;

public:
using Result = DebugInfoCache;
Result run(Module &M, ModuleAnalysisManager &);
};
} // namespace llvm

#endif
4 changes: 3 additions & 1 deletion llvm/include/llvm/IR/DebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,13 @@ class DebugInfoFinder {
/// Process subprogram.
void processSubprogram(DISubprogram *SP);

/// Process a compile unit.
void processCompileUnit(DICompileUnit *CU);

/// Clear all lists.
void reset();

private:
void processCompileUnit(DICompileUnit *CU);
void processScope(DIScope *Scope);
void processType(DIType *DT);
bool addCompileUnit(DICompileUnit *CU);
Expand Down
13 changes: 9 additions & 4 deletions llvm/include/llvm/Transforms/Coroutines/ABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef LLVM_TRANSFORMS_COROUTINES_ABI_H
#define LLVM_TRANSFORMS_COROUTINES_ABI_H

#include "llvm/Analysis/DebugInfoCache.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Transforms/Coroutines/CoroShape.h"
#include "llvm/Transforms/Coroutines/MaterializationUtils.h"
Expand Down Expand Up @@ -53,7 +54,8 @@ class BaseABI {
// Perform the function splitting according to the ABI.
virtual void splitCoroutine(Function &F, coro::Shape &Shape,
SmallVectorImpl<Function *> &Clones,
TargetTransformInfo &TTI) = 0;
TargetTransformInfo &TTI,
const DebugInfoCache *DICache) = 0;

Function &F;
coro::Shape &Shape;
Expand All @@ -73,7 +75,8 @@ class SwitchABI : public BaseABI {

void splitCoroutine(Function &F, coro::Shape &Shape,
SmallVectorImpl<Function *> &Clones,
TargetTransformInfo &TTI) override;
TargetTransformInfo &TTI,
const DebugInfoCache *DICache) override;
};

class AsyncABI : public BaseABI {
Expand All @@ -86,7 +89,8 @@ class AsyncABI : public BaseABI {

void splitCoroutine(Function &F, coro::Shape &Shape,
SmallVectorImpl<Function *> &Clones,
TargetTransformInfo &TTI) override;
TargetTransformInfo &TTI,
const DebugInfoCache *DICache) override;
};

class AnyRetconABI : public BaseABI {
Expand All @@ -99,7 +103,8 @@ class AnyRetconABI : public BaseABI {

void splitCoroutine(Function &F, coro::Shape &Shape,
SmallVectorImpl<Function *> &Clones,
TargetTransformInfo &TTI) override;
TargetTransformInfo &TTI,
const DebugInfoCache *DICache) override;
};

} // end namespace coro
Expand Down
55 changes: 42 additions & 13 deletions llvm/include/llvm/Transforms/Utils/Cloning.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,29 @@ void CloneFunctionAttributesInto(Function *NewFunc, const Function *OldFunc,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr);

/// Clone OldFunc's metadata into NewFunc.
///
/// The caller is expected to populate \p VMap beforehand and set an appropriate
/// \p RemapFlag.
///
/// NOTE: This function doesn't clone !llvm.dbg.cu when cloning into a different
/// module. Use CloneFunctionInto for that behavior.
void CloneFunctionMetadataInto(Function *NewFunc, const Function *OldFunc,
ValueToValueMapTy &VMap, RemapFlags RemapFlag,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr);

/// Clone OldFunc's body into NewFunc.
void CloneFunctionBodyInto(Function *NewFunc, const Function *OldFunc,
ValueToValueMapTy &VMap, RemapFlags RemapFlag,
SmallVectorImpl<ReturnInst *> &Returns,
const char *NameSuffix = "",
ClonedCodeInfo *CodeInfo = nullptr,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr);

void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
const Instruction *StartingInst,
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
Expand All @@ -202,7 +225,7 @@ void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
///
void CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc,
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
SmallVectorImpl<ReturnInst*> &Returns,
SmallVectorImpl<ReturnInst *> &Returns,
const char *NameSuffix = "",
ClonedCodeInfo *CodeInfo = nullptr);

Expand All @@ -220,6 +243,13 @@ DISubprogram *CollectDebugInfoForCloning(const Function &F,
CloneFunctionChangeType Changes,
DebugInfoFinder &DIFinder);

/// Based on \p Changes and \p DIFinder populate \p MD with debug info that
/// needs to be identity mapped during Metadata cloning.
void FindDebugInfoToIdentityMap(MetadataSetTy &MD,
CloneFunctionChangeType Changes,
DebugInfoFinder &DIFinder,
DISubprogram *SPClonedWithinModule);

/// This class captures the data input to the InlineFunction call, and records
/// the auxiliary results produced by it.
class InlineFunctionInfo {
Expand Down Expand Up @@ -341,32 +371,31 @@ void updateProfileCallee(
/// Find the 'llvm.experimental.noalias.scope.decl' intrinsics in the specified
/// basic blocks and extract their scope. These are candidates for duplication
/// when cloning.
void identifyNoAliasScopesToClone(
ArrayRef<BasicBlock *> BBs, SmallVectorImpl<MDNode *> &NoAliasDeclScopes);
void identifyNoAliasScopesToClone(ArrayRef<BasicBlock *> BBs,
SmallVectorImpl<MDNode *> &NoAliasDeclScopes);

/// Find the 'llvm.experimental.noalias.scope.decl' intrinsics in the specified
/// instruction range and extract their scope. These are candidates for
/// duplication when cloning.
void identifyNoAliasScopesToClone(
BasicBlock::iterator Start, BasicBlock::iterator End,
SmallVectorImpl<MDNode *> &NoAliasDeclScopes);
void identifyNoAliasScopesToClone(BasicBlock::iterator Start,
BasicBlock::iterator End,
SmallVectorImpl<MDNode *> &NoAliasDeclScopes);

/// Duplicate the specified list of noalias decl scopes.
/// The 'Ext' string is added as an extension to the name.
/// Afterwards, the ClonedScopes contains the mapping of the original scope
/// MDNode onto the cloned scope.
/// Be aware that the cloned scopes are still part of the original scope domain.
void cloneNoAliasScopes(
ArrayRef<MDNode *> NoAliasDeclScopes,
DenseMap<MDNode *, MDNode *> &ClonedScopes,
StringRef Ext, LLVMContext &Context);
void cloneNoAliasScopes(ArrayRef<MDNode *> NoAliasDeclScopes,
DenseMap<MDNode *, MDNode *> &ClonedScopes,
StringRef Ext, LLVMContext &Context);

/// Adapt the metadata for the specified instruction according to the
/// provided mapping. This is normally used after cloning an instruction, when
/// some noalias scopes needed to be cloned.
void adaptNoAliasScopes(
llvm::Instruction *I, const DenseMap<MDNode *, MDNode *> &ClonedScopes,
LLVMContext &Context);
void adaptNoAliasScopes(llvm::Instruction *I,
const DenseMap<MDNode *, MDNode *> &ClonedScopes,
LLVMContext &Context);

/// Clone the specified noalias decl scopes. Then adapt all instructions in the
/// NewBlocks basicblocks to the cloned versions.
Expand Down
67 changes: 49 additions & 18 deletions llvm/include/llvm/Transforms/Utils/ValueMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define LLVM_TRANSFORMS_UTILS_VALUEMAPPER_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/simple_ilist.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/IR/ValueMap.h"
Expand All @@ -35,6 +36,7 @@ class Value;

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

/// This is a class that can be implemented by clients to remap types when
/// cloning constants and instructions.
Expand Down Expand Up @@ -136,6 +138,18 @@ inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) {
/// alternate \a ValueToValueMapTy and \a ValueMaterializer and returns a ID to
/// pass into the schedule*() functions.
///
/// NOTE: \c IdentityMD is used by CloneFunction* to directly specify metadata
/// that should be identity mapped (and hence not cloned). The metadata will be
/// identity mapped in \c VM on first use. There are several reasons for doing
/// it this way rather than eagerly identity mapping metadata nodes in \c VM:
/// 1. Mapping metadata is not cheap, particularly because of tracking.
/// 2. 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.
/// 3. Eagerly identity mapping metadata makes it harder to cache module-level
/// data (e.g. a set of metadata nodes in a \a DICompileUnit).
///
/// TODO: lib/Linker really doesn't need the \a ValueHandle in the \a
/// ValueToValueMapTy. We should template \a ValueMapper (and its
/// implementation classes), and explicitly instantiate on two concrete
Expand All @@ -152,7 +166,8 @@ class ValueMapper {
public:
ValueMapper(ValueToValueMapTy &VM, RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr);
ValueMapper(ValueMapper &&) = delete;
ValueMapper(const ValueMapper &) = delete;
ValueMapper &operator=(ValueMapper &&) = delete;
Expand Down Expand Up @@ -218,8 +233,10 @@ class ValueMapper {
inline Value *MapValue(const Value *V, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapValue(*V);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.mapValue(*V);
}

/// Lookup or compute a mapping for a piece of metadata.
Expand All @@ -231,7 +248,9 @@ inline Value *MapValue(const Value *V, ValueToValueMapTy &VM,
/// \c MD.
/// 3. Else if \c MD is a \a ConstantAsMetadata, call \a MapValue() and
/// re-wrap its return (returning nullptr on nullptr).
/// 4. Else, \c MD is an \a MDNode. These are remapped, along with their
/// 4. Else if \c MD is in \c IdentityMD then add an identity mapping for it
/// and return it.
/// 5. Else, \c MD is an \a MDNode. These are remapped, along with their
/// transitive operands. Distinct nodes are duplicated or moved depending
/// on \a RF_MoveDistinctNodes. Uniqued nodes are remapped like constants.
///
Expand All @@ -240,16 +259,20 @@ inline Value *MapValue(const Value *V, ValueToValueMapTy &VM,
inline Metadata *MapMetadata(const Metadata *MD, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapMetadata(*MD);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.mapMetadata(*MD);
}

/// Version of MapMetadata with type safety for MDNode.
inline MDNode *MapMetadata(const MDNode *MD, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapMDNode(*MD);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.mapMDNode(*MD);
}

/// Convert the instruction operands from referencing the current values into
Expand All @@ -263,17 +286,21 @@ inline MDNode *MapMetadata(const MDNode *MD, ValueToValueMapTy &VM,
inline void RemapInstruction(Instruction *I, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer).remapInstruction(*I);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.remapInstruction(*I);
}

/// Remap the Values used in the DbgRecord \a DR using the value map \a
/// VM.
inline void RemapDbgRecord(Module *M, DbgRecord *DR, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer).remapDbgRecord(M, *DR);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.remapDbgRecord(M, *DR);
}

/// Remap the Values used in the DbgRecords \a Range using the value map \a
Expand All @@ -283,8 +310,9 @@ inline void RemapDbgRecordRange(Module *M,
ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer)
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.remapDbgRecordRange(M, Range);
}

Expand All @@ -297,16 +325,19 @@ inline void RemapDbgRecordRange(Module *M,
inline void RemapFunction(Function &F, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer).remapFunction(F);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD).remapFunction(F);
}

/// Version of MapValue with type safety for Constant.
inline Constant *MapValue(const Constant *V, ValueToValueMapTy &VM,
RemapFlags Flags = RF_None,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer).mapConstant(*V);
ValueMaterializer *Materializer = nullptr,
const MetadataSetTy *IdentityMD = nullptr) {
return ValueMapper(VM, Flags, TypeMapper, Materializer, IdentityMD)
.mapConstant(*V);
}

} // end namespace llvm
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Analysis/CGSCCPassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/DebugInfoCache.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/InstIterator.h"
Expand Down Expand Up @@ -139,6 +140,11 @@ ModuleToPostOrderCGSCCPassAdaptor::run(Module &M, ModuleAnalysisManager &AM) {
// Get the call graph for this module.
LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M);

// Prime DebugInfoCache.
// TODO: Currently, the only user is CoroSplitPass. Consider running
// conditionally.
AM.getResult<DebugInfoCacheAnalysis>(M);

// Get Function analysis manager from its proxy.
FunctionAnalysisManager &FAM =
AM.getCachedResult<FunctionAnalysisManagerModuleProxy>(M)->getManager();
Expand Down Expand Up @@ -350,6 +356,7 @@ ModuleToPostOrderCGSCCPassAdaptor::run(Module &M, ModuleAnalysisManager &AM) {
// analysis proxies by handling them above and in any nested pass managers.
PA.preserveSet<AllAnalysesOn<LazyCallGraph::SCC>>();
PA.preserve<LazyCallGraphAnalysis>();
PA.preserve<DebugInfoCacheAnalysis>();
PA.preserve<CGSCCAnalysisManagerModuleProxy>();
PA.preserve<FunctionAnalysisManagerModuleProxy>();
return PA;
Expand Down
Loading
Loading