[DirectX] Add DXILDebugInfo pass (#191254)
The pass is enabled for DXILBitcodeWriter and ValueEnumerator to transform LLVM IR and provide data required to lower it to DXIL. There are 3 ways how DXILDebugInfo pass can change lowering to DXIL: 1. Transform LLVM IR directly in DXILDebugInfoPass::run. This works well when the target IR does not break any invariants of LLVM IR. 2. Add extra metadata for ValueEnumerator to process with MDExtra map. When ValueEnumerator enumerates a Key of MDExtra, it also follows the Value and all its operands. 3. Replace a metadata for ValueEnumerator with a another metadata. When ValueEnumerator enumerates a Key of MDReplace, or when the writer uses getMetadataID, the corresponding value of MDReplace map is returned instead. Co-authored-by: Andrew Savonichev <andrew.savonichev@gmail.com>
This commit is contained in:
@@ -49,7 +49,7 @@ add_llvm_target(DirectXCodeGen
|
||||
DXILBitWriter
|
||||
DirectXDesc
|
||||
DirectXInfo
|
||||
DirectXPointerTypeAnalysis
|
||||
DirectXIRPasses
|
||||
FrontendHLSL
|
||||
IPO
|
||||
MC
|
||||
|
||||
@@ -12,7 +12,7 @@ add_llvm_component_library(LLVMDXILBitWriter
|
||||
Analysis
|
||||
BitWriter
|
||||
Core
|
||||
DirectXPointerTypeAnalysis
|
||||
DirectXIRPasses
|
||||
MC
|
||||
Object
|
||||
Support
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "DXILBitcodeWriter.h"
|
||||
#include "DXILValueEnumerator.h"
|
||||
#include "DirectXIRPasses/DXILDebugInfo.h"
|
||||
#include "DirectXIRPasses/PointerTypeAnalysis.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
@@ -128,16 +129,20 @@ class DXILBitcodeWriter {
|
||||
/// This maps values to their typed pointers
|
||||
PointerTypeMap PointerMap;
|
||||
|
||||
/// Tracks debug info metadata.
|
||||
const DXILDebugInfoMap &DebugInfo;
|
||||
|
||||
public:
|
||||
/// Constructs a ModuleBitcodeWriter object for the given Module,
|
||||
/// writing to the provided \p Buffer.
|
||||
DXILBitcodeWriter(const Module &M, SmallVectorImpl<char> &Buffer,
|
||||
StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream)
|
||||
StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream,
|
||||
const DXILDebugInfoMap &DebugInfo)
|
||||
: I8Ty(Type::getInt8Ty(M.getContext())),
|
||||
I8PtrTy(TypedPointerType::get(I8Ty, 0)), Stream(Stream),
|
||||
StrtabBuilder(StrtabBuilder), M(M), VE(M, I8PtrTy), Buffer(Buffer),
|
||||
BitcodeStartBit(Stream.GetCurrentBitNo()),
|
||||
PointerMap(PointerTypeAnalysis::run(M)) {
|
||||
StrtabBuilder(StrtabBuilder), M(M), VE(M, I8PtrTy, DebugInfo),
|
||||
Buffer(Buffer), BitcodeStartBit(Stream.GetCurrentBitNo()),
|
||||
PointerMap(PointerTypeAnalysis::run(M)), DebugInfo(DebugInfo) {
|
||||
GlobalValueId = VE.getValues().size();
|
||||
// Enumerate the typed pointers
|
||||
for (auto El : PointerMap)
|
||||
@@ -393,7 +398,8 @@ dxil::BitcodeWriter::BitcodeWriter(SmallVectorImpl<char> &Buffer)
|
||||
dxil::BitcodeWriter::~BitcodeWriter() { }
|
||||
|
||||
/// Write the specified module to the specified output stream.
|
||||
void dxil::WriteDXILToFile(const Module &M, raw_ostream &Out) {
|
||||
void dxil::WriteDXILToFile(const Module &M, raw_ostream &Out,
|
||||
const DXILDebugInfoMap &DebugInfo) {
|
||||
SmallVector<char, 0> Buffer;
|
||||
Buffer.reserve(256 * 1024);
|
||||
|
||||
@@ -404,7 +410,7 @@ void dxil::WriteDXILToFile(const Module &M, raw_ostream &Out) {
|
||||
Buffer.insert(Buffer.begin(), BWH_HeaderSize, 0);
|
||||
|
||||
BitcodeWriter Writer(Buffer);
|
||||
Writer.writeModule(M);
|
||||
Writer.writeModule(M, DebugInfo);
|
||||
|
||||
// Write the generated bitstream to "Out".
|
||||
if (!Buffer.empty())
|
||||
@@ -424,7 +430,8 @@ void BitcodeWriter::writeBlob(unsigned Block, unsigned Record, StringRef Blob) {
|
||||
Stream->ExitBlock();
|
||||
}
|
||||
|
||||
void BitcodeWriter::writeModule(const Module &M) {
|
||||
void BitcodeWriter::writeModule(const Module &M,
|
||||
const DXILDebugInfoMap &DebugInfo) {
|
||||
|
||||
// The Mods vector is used by irsymtab::build, which requires non-const
|
||||
// Modules in case it needs to materialize metadata. But the bitcode writer
|
||||
@@ -433,7 +440,7 @@ void BitcodeWriter::writeModule(const Module &M) {
|
||||
assert(M.isMaterialized());
|
||||
Mods.push_back(const_cast<Module *>(&M));
|
||||
|
||||
DXILBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream);
|
||||
DXILBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream, DebugInfo);
|
||||
ModuleWriter.write();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ class raw_ostream;
|
||||
|
||||
namespace dxil {
|
||||
|
||||
class DXILDebugInfoMap;
|
||||
|
||||
class BitcodeWriter {
|
||||
SmallVectorImpl<char> &Buffer;
|
||||
std::unique_ptr<BitstreamWriter> Stream;
|
||||
@@ -50,14 +52,15 @@ public:
|
||||
~BitcodeWriter();
|
||||
|
||||
/// Write the specified module to the buffer specified at construction time.
|
||||
void writeModule(const Module &M);
|
||||
void writeModule(const Module &M, const DXILDebugInfoMap &DebugInfo);
|
||||
};
|
||||
|
||||
/// Write the specified module to the specified raw output stream.
|
||||
///
|
||||
/// For streams where it matters, the given stream should be in "binary"
|
||||
/// mode.
|
||||
void WriteDXILToFile(const Module &M, raw_ostream &Out);
|
||||
void WriteDXILToFile(const Module &M, raw_ostream &Out,
|
||||
const DXILDebugInfoMap &DebugInfo);
|
||||
|
||||
} // namespace dxil
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DXILValueEnumerator.h"
|
||||
#include "DirectXIRPasses/DXILDebugInfo.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
@@ -361,7 +362,9 @@ static UseListOrderStack predictUseListOrder(const Module &M) {
|
||||
return Stack;
|
||||
}
|
||||
|
||||
ValueEnumerator::ValueEnumerator(const Module &M, Type *PrefixType) {
|
||||
ValueEnumerator::ValueEnumerator(const Module &M, Type *PrefixType,
|
||||
const DXILDebugInfoMap &DebugInfo)
|
||||
: DebugInfo(DebugInfo) {
|
||||
EnumerateType(PrefixType);
|
||||
|
||||
UseListOrders = predictUseListOrder(M);
|
||||
@@ -648,6 +651,8 @@ void ValueEnumerator::dropFunctionFromMetadata(
|
||||
}
|
||||
|
||||
void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
|
||||
MD = getDXILMetadata(MD);
|
||||
|
||||
// It's vital for reader efficiency that uniqued subgraphs are done in
|
||||
// post-order; it's expensive when their operands have forward references.
|
||||
// If a distinct node is referenced from a uniqued node, it'll be delayed
|
||||
@@ -669,7 +674,7 @@ void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
|
||||
Worklist.back().second, N->op_end(),
|
||||
[&](const Metadata *MD) { return enumerateMetadataImpl(F, MD); });
|
||||
if (I != N->op_end()) {
|
||||
auto *Op = cast<MDNode>(*I);
|
||||
auto *Op = cast<MDNode>(getDXILMetadata(*I));
|
||||
Worklist.back().second = ++I;
|
||||
|
||||
// Delay traversing Op if it's a distinct node and N is uniqued.
|
||||
@@ -680,6 +685,15 @@ void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const Metadata *ExtraMD = DebugInfo.MDExtra.lookup(N)) {
|
||||
if (enumerateMetadataImpl(F, ExtraMD)) {
|
||||
if (const auto *ExtraN = dyn_cast<MDNode>(ExtraMD)) {
|
||||
Worklist.push_back(std::make_pair(ExtraN, ExtraN->op_begin()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All the operands have been visited. Now assign an ID.
|
||||
Worklist.pop_back();
|
||||
MDs.push_back(N);
|
||||
@@ -697,6 +711,8 @@ void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) {
|
||||
|
||||
const MDNode *ValueEnumerator::enumerateMetadataImpl(unsigned F,
|
||||
const Metadata *MD) {
|
||||
MD = getDXILMetadata(MD);
|
||||
|
||||
if (!MD)
|
||||
return nullptr;
|
||||
|
||||
@@ -867,6 +883,12 @@ void ValueEnumerator::organizeMetadata() {
|
||||
FunctionMDInfo[PrevF] = R;
|
||||
}
|
||||
|
||||
const Metadata *ValueEnumerator::getDXILMetadata(const Metadata *M) const {
|
||||
if (const Metadata *Replace = DebugInfo.MDReplace.lookup(M))
|
||||
return Replace;
|
||||
return M;
|
||||
}
|
||||
|
||||
void ValueEnumerator::incorporateFunctionMetadata(const Function &F) {
|
||||
NumModuleMDs = MDs.size();
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ class ValueSymbolTable;
|
||||
|
||||
namespace dxil {
|
||||
|
||||
class DXILDebugInfoMap;
|
||||
|
||||
class ValueEnumerator {
|
||||
public:
|
||||
using TypeList = std::vector<Type *>;
|
||||
@@ -138,8 +140,11 @@ private:
|
||||
unsigned FirstFuncConstantID;
|
||||
unsigned FirstInstID;
|
||||
|
||||
const DXILDebugInfoMap &DebugInfo;
|
||||
|
||||
public:
|
||||
ValueEnumerator(const Module &M, Type *PrefixType);
|
||||
ValueEnumerator(const Module &M, Type *PrefixType,
|
||||
const DXILDebugInfoMap &DebugInfo);
|
||||
ValueEnumerator(const ValueEnumerator &) = delete;
|
||||
ValueEnumerator &operator=(const ValueEnumerator &) = delete;
|
||||
|
||||
@@ -157,7 +162,7 @@ public:
|
||||
}
|
||||
|
||||
unsigned getMetadataOrNullID(const Metadata *MD) const {
|
||||
return MetadataMap.lookup(MD).ID;
|
||||
return MetadataMap.lookup(getDXILMetadata(MD)).ID;
|
||||
}
|
||||
|
||||
unsigned numMDs() const { return MDs.size(); }
|
||||
@@ -231,6 +236,8 @@ public:
|
||||
/// should only be used by rare constructs such as address-of-label.
|
||||
unsigned getGlobalBasicBlockID(const BasicBlock *BB) const;
|
||||
|
||||
const Metadata *getDXILMetadata(const Metadata *M) const;
|
||||
|
||||
/// incorporateFunction/purgeFunction - If you'd like to deal with a function,
|
||||
/// use these two methods to get its data into the ValueEnumerator!
|
||||
void incorporateFunction(const Function &F);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "DXILWriterPass.h"
|
||||
#include "DXILBitcodeWriter.h"
|
||||
#include "DirectXIRPasses/DXILDebugInfo.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
@@ -49,7 +50,8 @@ public:
|
||||
StringRef getPassName() const override { return "Bitcode Writer"; }
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
WriteDXILToFile(M, OS);
|
||||
const auto DIMap = DXILDebugInfoPass::run(M);
|
||||
WriteDXILToFile(M, OS, DIMap);
|
||||
return false;
|
||||
}
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
@@ -153,7 +155,8 @@ public:
|
||||
// fail the Module Verifier if performed in an earlier pass
|
||||
legalizeLifetimeIntrinsics(M);
|
||||
|
||||
WriteDXILToFile(M, OS);
|
||||
const auto DIMap = DXILDebugInfoPass::run(M);
|
||||
WriteDXILToFile(M, OS, DIMap);
|
||||
|
||||
// We no longer need lifetime intrinsics after bitcode serialization, so we
|
||||
// simply remove them to keep the Module Verifier happy after our
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
add_llvm_component_library(LLVMDirectXPointerTypeAnalysis
|
||||
add_llvm_component_library(LLVMDirectXIRPasses
|
||||
DXILDebugInfo.cpp
|
||||
PointerTypeAnalysis.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
|
||||
24
llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
Normal file
24
llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
//===--- DXILDebugInfo.cpp - analysis&lowering for Debug info -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DXILDebugInfo.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
||||
#define DEBUG_TYPE "dx-debug-info"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dxil;
|
||||
|
||||
DXILDebugInfoMap DXILDebugInfoPass::run(Module &M) {
|
||||
DXILDebugInfoMap Res;
|
||||
DebugInfoFinder DIF;
|
||||
DIF.processModule(M);
|
||||
|
||||
return Res;
|
||||
}
|
||||
44
llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.h
Normal file
44
llvm/lib/Target/DirectX/DirectXIRPasses/DXILDebugInfo.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//===----- DebugInfo.h - analysis and lowering for Debug info -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file Analyze and downgrade debug info metadata to match DXIL (LLVM 3.7).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_DIRECTX_DXILDEBUGINFO_H
|
||||
#define LLVM_LIB_TARGET_DIRECTX_DXILDEBUGINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Module;
|
||||
class Metadata;
|
||||
|
||||
namespace dxil {
|
||||
|
||||
class DXILDebugInfoMap {
|
||||
public:
|
||||
using MDMap = DenseMap<const Metadata *, const Metadata *>;
|
||||
|
||||
/// Enumerate extra metadata when Key is encountered in ValueEnumerator.
|
||||
MDMap MDExtra;
|
||||
|
||||
/// Completely replace one metadata with another in ValueEnumerator.
|
||||
MDMap MDReplace;
|
||||
};
|
||||
|
||||
namespace DXILDebugInfoPass {
|
||||
|
||||
DXILDebugInfoMap run(Module &M);
|
||||
|
||||
} // namespace DXILDebugInfoPass
|
||||
} // namespace dxil
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_TARGET_DIRECTX_DXILDEBUGINFO_H
|
||||
@@ -10,7 +10,7 @@ set(LLVM_LINK_COMPONENTS
|
||||
DirectXCodeGen
|
||||
DirectXDesc
|
||||
DirectXInfo
|
||||
DirectXPointerTypeAnalysis
|
||||
DirectXIRPasses
|
||||
MC
|
||||
Passes
|
||||
Support
|
||||
|
||||
Reference in New Issue
Block a user