135 строки
4.1 KiB
C++
135 строки
4.1 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// DxilDeleteRedundantDebugValues.cpp //
|
|
// Copyright (C) Microsoft Corporation. All rights reserved. //
|
|
// This file is distributed under the University of Illinois Open Source //
|
|
// License. See LICENSE.TXT for details. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Removes as many dbg.value's as possible:
|
|
//
|
|
// 1. Search for all scopes (and their parent scopes) that have any real
|
|
// (non-debug)
|
|
// instructions at all.
|
|
//
|
|
// 2. For each dbg.value, if it's refering to a variable from a scope not in
|
|
// the set of scopes from step 1, then delete it.
|
|
//
|
|
// 3. In any contiguous series of dbg.value instructions, if there are
|
|
// dbg.value's
|
|
// that point to the same variable+fragment, then delete all but the last
|
|
// one, since it would be the only authentic mapping for that variable
|
|
// fragment.
|
|
|
|
#include "dxc/HLSL/DxilGenerationPass.h"
|
|
#include "llvm/IR/DebugInfo.h"
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Pass.h"
|
|
|
|
#include <unordered_set>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class DxilDeleteRedundantDebugValues : public ModulePass {
|
|
public:
|
|
static char ID;
|
|
|
|
explicit DxilDeleteRedundantDebugValues() : ModulePass(ID) {
|
|
initializeDxilDeleteRedundantDebugValuesPass(
|
|
*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
bool runOnModule(Module &M) override;
|
|
};
|
|
char DxilDeleteRedundantDebugValues::ID;
|
|
} // namespace
|
|
|
|
bool DxilDeleteRedundantDebugValues::runOnModule(Module &M) {
|
|
if (!llvm::hasDebugInfo(M))
|
|
return false;
|
|
|
|
bool Changed = false;
|
|
|
|
std::unordered_set<DILocalScope *> SeenScopes;
|
|
typedef std::pair<DILocalVariable *, DIExpression *> VarPair;
|
|
SmallDenseMap<VarPair, DbgValueInst *> SeenVar;
|
|
|
|
for (Function &F : M) {
|
|
SeenScopes.clear();
|
|
SeenVar.clear();
|
|
|
|
// Collect a set of all scopes that are attached to non-debug instructions
|
|
// There's no need to keep debug info for any variables in any scopes that
|
|
// don't have any real instructions anyway.
|
|
for (BasicBlock &BB : F) {
|
|
for (Instruction &I : BB) {
|
|
if (isa<DbgInfoIntrinsic>(I))
|
|
continue;
|
|
DebugLoc DL = I.getDebugLoc();
|
|
if (!DL)
|
|
continue;
|
|
|
|
DILocalScope *Scope = cast_or_null<DILocalScope>(DL.getScope());
|
|
if (!Scope)
|
|
continue;
|
|
|
|
while (Scope) {
|
|
SeenScopes.insert(Scope);
|
|
if (DILexicalBlockBase *LB = dyn_cast<DILexicalBlockBase>(Scope)) {
|
|
Scope = LB->getScope();
|
|
} else {
|
|
Scope = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (BasicBlock &BB : F) {
|
|
for (auto it = BB.begin(), end = BB.end(); it != end;) {
|
|
Instruction &I = *(it++);
|
|
if (!isa<DbgInfoIntrinsic>(I)) {
|
|
SeenVar.clear();
|
|
continue;
|
|
}
|
|
|
|
DbgValueInst *DI = dyn_cast<DbgValueInst>(&I);
|
|
if (!DI)
|
|
continue;
|
|
DILocalVariable *Var = DI->getVariable();
|
|
DIExpression *Expr = DI->getExpression();
|
|
VarPair Pair = VarPair(Var, Expr);
|
|
|
|
if (!SeenScopes.count(Var->getScope())) {
|
|
Changed = true;
|
|
DI->eraseFromParent();
|
|
continue;
|
|
}
|
|
|
|
auto findIt = SeenVar.find(Pair);
|
|
if (findIt != SeenVar.end()) {
|
|
findIt->second->eraseFromParent();
|
|
findIt->second = DI;
|
|
Changed = true;
|
|
} else {
|
|
SeenVar[Pair] = DI;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
ModulePass *llvm::createDxilDeleteRedundantDebugValuesPass() {
|
|
return new DxilDeleteRedundantDebugValues();
|
|
}
|
|
|
|
INITIALIZE_PASS(DxilDeleteRedundantDebugValues,
|
|
"dxil-delete-redundant-debug-values",
|
|
"Dxil Delete Redundant Debug Values", false, false)
|