Merge remote-tracking branch 'ms/19h1-rel' into dxil-1-5

This commit is contained in:
Tex Riddell 2019-02-11 13:44:43 -08:00
Родитель 51db8e386d 27a7bf4b0b
Коммит 1fccba0362
386 изменённых файлов: 12983 добавлений и 4951 удалений

Просмотреть файл

@ -33,9 +33,6 @@ matrix:
sources: ubuntu-toolchain-r-test
packages: ninja-build g++-5
env: DXC_BUILD_TYPE=Release
allow_failures:
- os: linux
- os: osx
cache:
apt: true
@ -53,7 +50,12 @@ addons:
packages: ninja-build libstdc++-5-dev
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
wget -q https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-mac.zip;
unzip -q ninja-mac.zip;
chmod +x ninja;
export PATH="$PWD:$PATH";
fi
before_script:
- git submodule update --init

Просмотреть файл

@ -1,13 +1,17 @@
# Find the win10 SDK path.
get_filename_component(WIN10_SDK_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;InstallationFolder]" ABSOLUTE CACHE)
get_filename_component(TEMP_WIN10_SDK_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;ProductVersion]" ABSOLUTE CACHE)
get_filename_component(WIN10_SDK_VERSION ${TEMP_WIN10_SDK_VERSION} NAME)
if ("$ENV{WIN10_SDK_PATH}$ENV{WIN10_SDK_VERSION}" STREQUAL "" )
get_filename_component(WIN10_SDK_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;InstallationFolder]" ABSOLUTE CACHE)
get_filename_component(TEMP_WIN10_SDK_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;ProductVersion]" ABSOLUTE CACHE)
get_filename_component(WIN10_SDK_VERSION ${TEMP_WIN10_SDK_VERSION} NAME)
elseif(TRUE)
set (WIN10_SDK_PATH $ENV{WIN10_SDK_PATH})
set (WIN10_SDK_VERSION $ENV{WIN10_SDK_VERSION})
endif ("$ENV{WIN10_SDK_PATH}$ENV{WIN10_SDK_VERSION}" STREQUAL "" )
# WIN10_SDK_PATH will be something like C:\Program Files (x86)\Windows Kits\10
# WIN10_SDK_VERSION will be something like 10.0.14393 or 10.0.14393.0; we need the
# one that matches the directory name.
if (IS_DIRECTORY "${WIN10_SDK_PATH}/Include/${WIN10_SDK_VERSION}.0")
set(WIN10_SDK_VERSION "${WIN10_SDK_VERSION}.0")
endif (IS_DIRECTORY "${WIN10_SDK_PATH}/Include/${WIN10_SDK_VERSION}.0")

Просмотреть файл

@ -4,14 +4,12 @@ get_filename_component(VS_PATH64 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Mi
# VS_PATH32 will be something like C:/Program Files (x86)/Microsoft Visual Studio 14.0/Common7/IDE
# Also look for in vs15 install.
# TODO: update this to be a non-hardcoded path. Registry keys were removed
# in vs15 in favor of COM server dlls.
# https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/
get_filename_component(VS15_C_PATH32 "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/Common7/IDE" ABSOLUTE CACHE)
get_filename_component(VS15_P_PATH32 "C:/Program Files (x86)/Microsoft Visual Studio/2017/Professional/Common7/IDE" ABSOLUTE CACHE)
get_filename_component(VS15_E_PATH32 "C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/Common7/IDE" ABSOLUTE CACHE)
set(PROGRAMFILES_X86 "ProgramFiles(x86)")
get_filename_component(VS15_C_PATH32 "$ENV{${PROGRAMFILES_X86}}/Microsoft Visual Studio/2017/Community/Common7/IDE" ABSOLUTE CACHE)
get_filename_component(VS15_P_PATH32 "$ENV{${PROGRAMFILES_X86}}/Microsoft Visual Studio/2017/Professional/Common7/IDE" ABSOLUTE CACHE)
get_filename_component(VS15_E_PATH32 "$ENV{${PROGRAMFILES_X86}}/Microsoft Visual Studio/2017/Enterprise/Common7/IDE" ABSOLUTE CACHE)
# Find the TAEF path, it will typically look something like this.
# Find the DIA SDK path, it will typically look something like this.
# C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\DIA SDK\include
# C:\Program Files (x86)\Microsoft Visual Studio 14.0\DIA SDK\include\dia2.h
find_path(DIASDK_INCLUDE_DIR # Set variable DIASDK_INCLUDE_DIR

2
external/SPIRV-Headers поставляемый

@ -1 +1 @@
Subproject commit d5b2e1255f706ce1f88812217e9a554f299848af
Subproject commit 17da9f8231f78cf519b4958c2229463a63ead9e2

2
external/SPIRV-Tools поставляемый

@ -1 +1 @@
Subproject commit 6e85d1a6fc75c4d37ccf7772fbb05e11b4fd69b0
Subproject commit 248debf55ad6de4a80f6d4a128ef195b6ed05a30

Просмотреть файл

@ -14,6 +14,7 @@
#include <string>
#include <memory>
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/Constants.h"
namespace llvm {
@ -30,6 +31,7 @@ class BasicBlock;
class raw_ostream;
class ModulePass;
class PassRegistry;
class DebugLoc;
ModulePass *createDxilLoadMetadataPass();
void initializeDxilLoadMetadataPass(llvm::PassRegistry&);
@ -52,12 +54,13 @@ namespace dxilutil {
bool HasDynamicIndexing(llvm::Value *V);
// Find alloca insertion point, given instruction
llvm::Instruction *FindAllocaInsertionPt(llvm::Instruction* I);
llvm::Instruction *FindAllocaInsertionPt(llvm::Instruction* I); // Considers entire parent function
llvm::Instruction *FindAllocaInsertionPt(llvm::BasicBlock* BB); // Only considers provided block
llvm::Instruction *FindAllocaInsertionPt(llvm::Function* F);
llvm::Instruction *SkipAllocas(llvm::Instruction *I);
// Get first non-alloca insertion point, to avoid inserting non-allocas before alloca
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Instruction* I);
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::BasicBlock* BB);
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Instruction* I); // Considers entire parent function
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::BasicBlock* BB); // Only considers provided block
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Function* F);
bool IsStaticGlobal(llvm::GlobalVariable *GV);
@ -66,6 +69,8 @@ namespace dxilutil {
llvm::Function *PatchConstantFunc, bool IsLib);
void EmitErrorOnInstruction(llvm::Instruction *I, llvm::StringRef Msg);
void EmitResMappingError(llvm::Instruction *Res);
std::string FormatMessageAtLocation(const llvm::DebugLoc &DL, const llvm::Twine& Msg);
llvm::Twine FormatMessageWithoutLocation(const llvm::Twine& Msg);
// Simple demangle just support case "\01?name@" pattern.
llvm::StringRef DemangleFunctionName(llvm::StringRef name);
// ReplaceFunctionName replaces the undecorated portion of originalName with undecorated newName
@ -91,6 +96,7 @@ namespace dxilutil {
llvm::Value *MergeSelectOnSameValue(llvm::Instruction *SelInst,
unsigned startOpIdx,
unsigned numOperands);
bool SimplifyTrivialPHIs(llvm::BasicBlock *BB);
std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC,
llvm::LLVMContext &Ctx, std::string &DiagStr);
std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::MemoryBuffer *MB,
@ -99,6 +105,7 @@ namespace dxilutil {
// Returns true if type contains HLSL Object type (resource)
bool ContainsHLSLObjectType(llvm::Type *Ty);
bool IsHLSLObjectType(llvm::Type *Ty);
bool IsHLSLMatrixType(llvm::Type *Ty);
bool IsSplat(llvm::ConstantDataVector *cdv);
}

Просмотреть файл

@ -16,6 +16,7 @@ class ModulePass;
class PassRegistry;
ModulePass *createDxilAddPixelHitInstrumentationPass();
ModulePass *createDxilAnnotateWithVirtualRegisterPass();
ModulePass *createDxilOutputColorBecomesConstantPass();
ModulePass *createDxilRemoveDiscardsPass();
ModulePass *createDxilReduceMSAAToSingleSamplePass();
@ -24,6 +25,7 @@ ModulePass *createDxilDebugInstrumentationPass();
ModulePass *createDxilShaderAccessTrackingPass();
void initializeDxilAddPixelHitInstrumentationPass(llvm::PassRegistry&);
void initializeDxilAnnotateWithVirtualRegisterPass(llvm::PassRegistry&);
void initializeDxilOutputColorBecomesConstantPass(llvm::PassRegistry&);
void initializeDxilRemoveDiscardsPass(llvm::PassRegistry&);
void initializeDxilReduceMSAAToSingleSamplePass(llvm::PassRegistry&);

Просмотреть файл

@ -66,6 +66,7 @@ ModulePass *createDxilPromoteStaticResources();
ModulePass *createDxilLegalizeResources();
ModulePass *createDxilLegalizeEvalOperationsPass();
FunctionPass *createDxilLegalizeSampleOffsetPass();
FunctionPass *createDxilSimpleGVNHoistPass();
ModulePass *createFailUndefResourcePass();
FunctionPass *createSimplifyInstPass();
ModulePass *createDxilTranslateRawBuffer();
@ -96,6 +97,7 @@ void initializeDxilPromoteStaticResourcesPass(llvm::PassRegistry&);
void initializeDxilLegalizeResourcesPass(llvm::PassRegistry&);
void initializeDxilLegalizeEvalOperationsPass(llvm::PassRegistry&);
void initializeDxilLegalizeSampleOffsetPassPass(llvm::PassRegistry&);
void initializeDxilSimpleGVNHoistPass(llvm::PassRegistry&);
void initializeFailUndefResourcePass(llvm::PassRegistry&);
void initializeSimplifyInstPass(llvm::PassRegistry&);
void initializeDxilTranslateRawBufferPass(llvm::PassRegistry&);

Просмотреть файл

@ -27,21 +27,30 @@ class DxilTypeSystem;
namespace HLMatrixLower {
// TODO: use type annotation.
bool IsMatrixType(llvm::Type *Ty);
DxilFieldAnnotation *FindAnnotationFromMatUser(llvm::Value *Mat,
DxilTypeSystem &typeSys);
// Translate matrix type to vector type.
llvm::Type *LowerMatrixType(llvm::Type *Ty);
llvm::Type *LowerMatrixType(llvm::Type *Ty, bool forMem = false);
// TODO: use type annotation.
llvm::Type *GetMatrixInfo(llvm::Type *Ty, unsigned &col, unsigned &row);
// TODO: use type annotation.
bool IsMatrixArrayPointer(llvm::Type *Ty);
// Translate matrix array pointer type to vector array pointer type.
llvm::Type *LowerMatrixArrayPointer(llvm::Type *Ty);
llvm::Type *LowerMatrixArrayPointer(llvm::Type *Ty, bool forMem = false);
llvm::Value *BuildVector(llvm::Type *EltTy, unsigned size,
llvm::ArrayRef<llvm::Value *> elts,
llvm::IRBuilder<> &Builder);
llvm::Value *VecMatrixMemToReg(llvm::Value *VecVal, llvm::Type *MatType,
llvm::IRBuilder<> &Builder);
llvm::Value *VecMatrixRegToMem(llvm::Value* VecVal, llvm::Type *MatType,
llvm::IRBuilder<> &Builder);
llvm::Instruction *CreateVecMatrixLoad(llvm::Value *VecPtr,
llvm::Type *MatType, llvm::IRBuilder<> &Builder);
llvm::Instruction *CreateVecMatrixStore(llvm::Value* VecVal, llvm::Value *VecPtr,
llvm::Type *MatType, llvm::IRBuilder<> &Builder);
// For case like mat[i][j].
// IdxList is [i][0], [i][1], [i][2],[i][3].
// Idx is j.

Просмотреть файл

@ -196,8 +196,9 @@ public:
llvm::ArrayRef<llvm::Value *> paramList,
llvm::Module &M);
static unsigned FindCastOp(bool fromUnsigned, bool toUnsigned,
llvm::Type *SrcTy, llvm::Type *DstTy);
// Caller must handle conversions to bool and no-ops
static unsigned GetNumericCastOp(
llvm::Type *SrcTy, bool SrcIsUnsigned, llvm::Type *DstTy, bool DstIsUnsigned);
// Precise attribute.
// Note: Precise will be marked on alloca inst with metadata in code gen.
@ -319,3 +320,4 @@ public:
};
} // namespace hlsl

Просмотреть файл

@ -265,12 +265,14 @@ import hctdb_instrhelp
IOP_WaveActiveUSum,
IOP_WavePrefixUProduct,
IOP_WavePrefixUSum,
IOP_uabs,
IOP_uclamp,
IOP_ufirstbithigh,
IOP_umad,
IOP_umax,
IOP_umin,
IOP_umul,
IOP_usign,
MOP_InterlockedUMax,
MOP_InterlockedUMin,
Num_Intrinsics,
@ -293,12 +295,14 @@ import hctdb_instrhelp
case IntrinsicOp::IOP_WaveActiveSum:
case IntrinsicOp::IOP_WavePrefixProduct:
case IntrinsicOp::IOP_WavePrefixSum:
case IntrinsicOp::IOP_abs:
case IntrinsicOp::IOP_clamp:
case IntrinsicOp::IOP_firstbithigh:
case IntrinsicOp::IOP_mad:
case IntrinsicOp::IOP_max:
case IntrinsicOp::IOP_min:
case IntrinsicOp::IOP_mul:
case IntrinsicOp::IOP_sign:
case IntrinsicOp::MOP_InterlockedMax:
case IntrinsicOp::MOP_InterlockedMin:
// HLSL-HAS-UNSIGNED-INTRINSICS:END
@ -332,6 +336,8 @@ import hctdb_instrhelp
return static_cast<unsigned>(IntrinsicOp::IOP_WavePrefixUProduct);
case IntrinsicOp::IOP_WavePrefixSum:
return static_cast<unsigned>(IntrinsicOp::IOP_WavePrefixUSum);
case IntrinsicOp::IOP_abs:
return static_cast<unsigned>(IntrinsicOp::IOP_uabs);
case IntrinsicOp::IOP_clamp:
return static_cast<unsigned>(IntrinsicOp::IOP_uclamp);
case IntrinsicOp::IOP_firstbithigh:
@ -344,6 +350,8 @@ import hctdb_instrhelp
return static_cast<unsigned>(IntrinsicOp::IOP_umin);
case IntrinsicOp::IOP_mul:
return static_cast<unsigned>(IntrinsicOp::IOP_umul);
case IntrinsicOp::IOP_sign:
return static_cast<unsigned>(IntrinsicOp::IOP_usign);
case IntrinsicOp::MOP_InterlockedMax:
return static_cast<unsigned>(IntrinsicOp::MOP_InterlockedUMax);
case IntrinsicOp::MOP_InterlockedMin:

Просмотреть файл

@ -162,6 +162,7 @@ public:
bool LegacyResourceReservation = false; // OPT_flegacy_resource_reservation
unsigned long AutoBindingSpace = UINT_MAX; // OPT_auto_binding_space
bool ExportShadersOnly = false; // OPT_export_shaders_only
bool ResMayAlias = false; // OPT_res_may_alias
bool IsRootSignatureProfile();
bool IsLibraryProfile();

Просмотреть файл

@ -365,11 +365,11 @@ def mergeUAVs : JoinedOrSeparate<["-", "/"], "mergeUAVs">, MetaVarName<"<file>">
HelpText<"Merge UAV slots of template shader and current shader">;
def matchUAVs : JoinedOrSeparate<["-", "/"], "matchUAVs">, MetaVarName<"<file>">, Group<hlslcomp_Group>,
HelpText<"Match template shader UAV slots in current shader">;
def res_may_alias : Flag<["-", "/"], "res_may_alias">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
HelpText<"Assume that UAVs/SRVs may alias">;
def enable_unbounded_descriptor_tables : Flag<["-", "/"], "enable_unbounded_descriptor_tables">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
HelpText<"Enables unbounded descriptor tables">;
*/
def res_may_alias : Flag<["-", "/"], "res_may_alias">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
HelpText<"Assume that UAVs/SRVs may alias">;
def all_resources_bound : Flag<["-", "/"], "all_resources_bound">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
HelpText<"Enables agressive flattening">;

Просмотреть файл

@ -259,6 +259,7 @@ void initializeMultiDimArrayToOneDimArrayPass(PassRegistry&);
void initializeResourceToHandlePass(PassRegistry&);
void initializeSROA_SSAUp_HLSLPass(PassRegistry&);
void initializeHoistConstantArrayPass(PassRegistry&);
void initializeDxilLoopUnrollPass(PassRegistry&);
// HLSL Change Ends
void initializeScalarEvolutionAliasAnalysisPass(PassRegistry&);
void initializeScalarEvolutionPass(PassRegistry&);

Просмотреть файл

@ -128,6 +128,7 @@ public:
bool PrepareForLTO;
bool HLSLHighLevel = false; // HLSL Change
hlsl::HLSLExtensionsCodegenHelper *HLSLExtensionsCodeGen = nullptr; // HLSL Change
bool HLSLResMayAlias = false; // HLSL Change
private:
/// ExtensionList - This is list of all of the extensions that are registered.

Просмотреть файл

@ -94,7 +94,8 @@ FunctionPass *createBitTrackingDCEPass();
//
// SROA - Replace aggregates or pieces of aggregates with scalar SSA values.
//
FunctionPass *createSROAPass(bool RequiresDomTree = true);
FunctionPass *createSROAPass(bool RequiresDomTree = true,
bool SkipHLSLMat = true);
//===----------------------------------------------------------------------===//
//
@ -122,6 +123,9 @@ void initializeSROA_DT_HLSLPass(PassRegistry&);
//
ModulePass *createSROA_Parameter_HLSL();
void initializeSROA_Parameter_HLSLPass(PassRegistry&);
Pass *createDxilLoopUnrollPass(unsigned MaxIterationAttempt);
void initializeDxilLoopUnrollPass(PassRegistry&);
//===----------------------------------------------------------------------===//
//
// LowerStaticGlobalIntoAlloca. Replace static globals with alloca if only used

Просмотреть файл

@ -24,6 +24,9 @@ add_subdirectory(DxcSupport) # HLSL Change
add_subdirectory(HLSL) # HLSL Change
add_subdirectory(DXIL) # HLSL Change
add_subdirectory(DxilContainer) # HLSL Change
if(WIN32) # HLSL Change
add_subdirectory(DxilDia) # HLSL Change
endif(WIN32) # HLSL Change
add_subdirectory(DxilPIXPasses) # HLSL Change
add_subdirectory(DxilRootSignature) # HLSL Change
add_subdirectory(DxrFallback) # HLSL Change

Просмотреть файл

@ -76,6 +76,9 @@ void DxilSubobject::CopyUnionedContents(const DxilSubobject &other) {
HitGroup.ClosestHit = other.HitGroup.ClosestHit;
HitGroup.Intersection = other.HitGroup.Intersection;
break;
default:
DXASSERT(0, "invalid kind");
break;
}
}

Просмотреть файл

@ -192,9 +192,8 @@ std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::MemoryBuffer *MB,
llvm::LLVMContext &Ctx,
std::string &DiagStr) {
// Note: the DiagStr is not used.
ErrorOr<std::unique_ptr<llvm::Module>> pModule(
llvm::parseBitcodeFile(MB->getMemBufferRef(), Ctx));
if (std::error_code ec = pModule.getError()) {
auto pModule = llvm::parseBitcodeFile(MB->getMemBufferRef(), Ctx);
if (!pModule) {
return nullptr;
}
return std::unique_ptr<llvm::Module>(pModule.get().release());
@ -229,20 +228,29 @@ static bool EmitErrorOnInstructionFollowPhiSelect(
return false;
}
std::string FormatMessageAtLocation(const DebugLoc &DL, const Twine& Msg) {
std::string locString;
raw_string_ostream os(locString);
DL.print(os);
os << ": " << Msg;
return os.str();
}
Twine FormatMessageWithoutLocation(const Twine& Msg) {
return Msg + " Use /Zi for source location.";
}
void EmitErrorOnInstruction(Instruction *I, StringRef Msg) {
const DebugLoc &DL = I->getDebugLoc();
if (DL.get()) {
std::string locString;
raw_string_ostream os(locString);
DL.print(os);
I->getContext().emitError(os.str() + ": " + Twine(Msg));
I->getContext().emitError(FormatMessageAtLocation(DL, Msg));
return;
} else if (isa<PHINode>(I) || isa<SelectInst>(I)) {
if (EmitErrorOnInstructionFollowPhiSelect(I, Msg))
return;
}
I->getContext().emitError(Twine(Msg) + " Use /Zi for source location.");
I->getContext().emitError(FormatMessageWithoutLocation(Msg));
}
const StringRef kResourceMapErrorMsg =
@ -296,6 +304,28 @@ Value *MergeSelectOnSameValue(Instruction *SelInst, unsigned startOpIdx,
return op0;
}
bool SimplifyTrivialPHIs(BasicBlock *BB) {
bool Changed = false;
SmallVector<Instruction *, 16> Removed;
for (Instruction &I : *BB) {
PHINode *PN = dyn_cast<PHINode>(&I);
if (!PN)
continue;
if (PN->getNumIncomingValues() == 1) {
Value *V = PN->getIncomingValue(0);
PN->replaceAllUsesWith(V);
Removed.push_back(PN);
Changed = true;
}
}
for (Instruction *I : Removed)
I->eraseFromParent();
return Changed;
}
Value *SelectOnOperation(llvm::Instruction *Inst, unsigned operandIdx) {
Instruction *prototype = Inst;
for (unsigned i = 0; i < prototype->getNumOperands(); i++) {
@ -343,26 +373,27 @@ llvm::Instruction *SkipAllocas(llvm::Instruction *I) {
I = I->getNextNode();
return I;
}
llvm::Instruction *FindAllocaInsertionPt(llvm::BasicBlock* BB) {
return &*BB->getFirstInsertionPt();
}
llvm::Instruction *FindAllocaInsertionPt(llvm::Function* F) {
return FindAllocaInsertionPt(&F->getEntryBlock());
}
llvm::Instruction *FindAllocaInsertionPt(llvm::Instruction* I) {
Function *F = I->getParent()->getParent();
if (F)
return &*F->getEntryBlock().getFirstInsertionPt();
return FindAllocaInsertionPt(F);
else // BB with no parent function
return &*I->getParent()->getFirstInsertionPt();
}
llvm::Instruction *FindAllocaInsertionPt(llvm::Function* F) {
return &*F->getEntryBlock().getFirstInsertionPt();
return FindAllocaInsertionPt(I->getParent());
}
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Instruction* I) {
return SkipAllocas(FindAllocaInsertionPt(I));
}
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::BasicBlock* BB) {
return SkipAllocas(
&*BB->getFirstInsertionPt());
return SkipAllocas(FindAllocaInsertionPt(BB));
}
llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Function* F) {
return SkipAllocas(
&*F->getEntryBlock().getFirstInsertionPt());
return SkipAllocas(FindAllocaInsertionPt(F));
}
bool IsHLSLObjectType(llvm::Type *Ty) {
@ -432,6 +463,20 @@ bool IsHLSLObjectType(llvm::Type *Ty) {
return false;
}
bool IsHLSLMatrixType(Type *Ty) {
if (StructType *ST = dyn_cast<StructType>(Ty)) {
Type *EltTy = ST->getElementType(0);
if (!ST->getName().startswith("class.matrix"))
return false;
bool isVecArray =
EltTy->isArrayTy() && EltTy->getArrayElementType()->isVectorTy();
return isVecArray && EltTy->getArrayNumElements() <= 4;
}
return false;
}
bool ContainsHLSLObjectType(llvm::Type *Ty) {
// Unwrap pointer/array
while (llvm::isa<llvm::PointerType>(Ty))

Просмотреть файл

@ -544,6 +544,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
opts.LegacyMacroExpansion = Args.hasFlag(OPT_flegacy_macro_expansion, OPT_INVALID, false);
opts.LegacyResourceReservation = Args.hasFlag(OPT_flegacy_resource_reservation, OPT_INVALID, false);
opts.ExportShadersOnly = Args.hasFlag(OPT_export_shaders_only, OPT_INVALID, false);
opts.ResMayAlias = Args.hasFlag(OPT_res_may_alias, OPT_INVALID, false);
if (opts.DefaultColMajor && opts.DefaultRowMajor) {
errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";

Просмотреть файл

@ -0,0 +1,30 @@
# Copyright (C) Microsoft Corporation. All rights reserved.
# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
if (WIN32)
find_package(DiaSDK REQUIRED) # Used for constants and declarations.
endif (WIN32)
add_llvm_library(LLVMDxilDia
DxilDia.cpp
DxilDiaDataSource.cpp
DxilDiaEnumTables.cpp
DxilDiaSession.cpp
DxilDiaTable.cpp
DxilDiaTableFrameData.cpp
DxilDiaTableInjectedSources.cpp
DxilDiaTableInputAssemblyFile.cpp
DxilDiaTableLineNumbers.cpp
DxilDiaTableSections.cpp
DxilDiaTableSegmentMap.cpp
DxilDiaTableSourceFiles.cpp
DxilDiaTableSymbols.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/IR
)
if (WIN32)
target_link_libraries(LLVMDxilDia PRIVATE ${LIBRARIES} ${DIASDK_LIBRARIES})
include_directories(AFTER ${LLVM_INCLUDE_DIR}/dxc/Tracing ${DIASDK_INCLUDE_DIRS})
endif (WIN32)

33
lib/DxilDia/DxilDia.cpp Normal file
Просмотреть файл

@ -0,0 +1,33 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDia.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDia.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/Unicode.h"
HRESULT dxil_dia::StringRefToBSTR(llvm::StringRef value, BSTR *pRetVal) {
try {
wchar_t *wide;
size_t sideSize;
if (!Unicode::UTF8BufferToUTF16Buffer(value.data(), value.size(), &wide,
&sideSize))
return E_FAIL;
*pRetVal = SysAllocString(wide);
delete[] wide;
}
CATCH_CPP_RETURN_HRESULT();
return S_OK;
}
HRESULT dxil_dia::ENotImpl() {
return E_NOTIMPL;
}

30
lib/DxilDia/DxilDia.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDia.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "llvm/ADT/StringRef.h"
namespace dxil_dia {
// Single program, single compiland allows for some simplifications.
static constexpr DWORD HlslProgramId = 1;
static constexpr DWORD HlslCompilandId = 2;
static constexpr DWORD HlslCompilandDetailsId = 3;
static constexpr DWORD HlslCompilandEnvFlagsId = 4;
static constexpr DWORD HlslCompilandEnvTargetId = 5;
static constexpr DWORD HlslCompilandEnvEntryId = 6;
static constexpr DWORD HlslCompilandEnvDefinesId = 7;
static constexpr DWORD HlslCompilandEnvArgumentsId = 8;
HRESULT ENotImpl();
HRESULT StringRefToBSTR(llvm::StringRef value, BSTR *pRetVal);
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,145 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaDataSource.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaDataSource.h"
#include "dxc/DxilContainer/DxilContainer.h"
#include "dxc/DXIL/DxilUtil.h"
#include "dxc/Support/FileIOHelper.h"
#include "dxc/Support/dxcapi.impl.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "DxilDiaSession.h"
dxil_dia::DataSource::DataSource(IMalloc *pMalloc) : m_pMalloc(pMalloc) {
}
dxil_dia::DataSource::~DataSource() {
// These are cross-referenced, so let's be explicit.
m_finder.reset();
m_module.reset();
m_context.reset();
}
STDMETHODIMP dxil_dia::DataSource::get_lastError(BSTR *pRetVal) {
*pRetVal = nullptr;
return S_OK;
}
namespace dxil_dia
{
std::unique_ptr<llvm::MemoryBuffer> getMemBufferFromBlob(_In_ IDxcBlob *pBlob,
const llvm::Twine &BufferName) {
llvm::StringRef Data((LPSTR)pBlob->GetBufferPointer(), pBlob->GetBufferSize());
return llvm::MemoryBuffer::getMemBufferCopy(Data, BufferName);
}
std::unique_ptr<llvm::MemoryBuffer> getMemBufferFromStream(_In_ IStream *pStream,
const llvm::Twine &BufferName) {
CComPtr<IDxcBlob> pBlob;
if (SUCCEEDED(pStream->QueryInterface(&pBlob))) {
return getMemBufferFromBlob(pBlob, BufferName);
}
STATSTG statstg;
IFT(pStream->Stat(&statstg, STATFLAG_NONAME));
size_t size = statstg.cbSize.LowPart;
std::unique_ptr<llvm::MemoryBuffer> result(
llvm::MemoryBuffer::getNewUninitMemBuffer(size, BufferName));
char *pBuffer = (char *)result.get()->getBufferStart();
ULONG read;
IFT(pStream->Read(pBuffer, size, &read));
return result;
}
} // namespace dxil_dia
STDMETHODIMP dxil_dia::DataSource::loadDataFromIStream(_In_ IStream *pIStream) {
DxcThreadMalloc TM(m_pMalloc);
if (m_module.get() != nullptr) {
return E_FAIL;
}
m_context.reset();
m_finder.reset();
try {
m_context = std::make_shared<llvm::LLVMContext>();
llvm::MemoryBuffer *pBitcodeBuffer;
std::unique_ptr<llvm::MemoryBuffer> pEmbeddedBuffer;
std::unique_ptr<llvm::MemoryBuffer> pBuffer =
getMemBufferFromStream(pIStream, "data");
size_t bufferSize = pBuffer->getBufferSize();
// The buffer can hold LLVM bitcode for a module, or the ILDB
// part from a container.
if (bufferSize < sizeof(UINT32)) {
return DXC_E_MALFORMED_CONTAINER;
}
const UINT32 BC_C0DE = ((INT32)(INT8)'B' | (INT32)(INT8)'C' << 8 | (INT32)0xDEC0 << 16); // BC0xc0de in big endian
if (BC_C0DE == *(const UINT32*)pBuffer->getBufferStart()) {
pBitcodeBuffer = pBuffer.get();
} else {
if (bufferSize <= sizeof(hlsl::DxilProgramHeader)) {
return DXC_E_MALFORMED_CONTAINER;
}
hlsl::DxilProgramHeader *pDxilProgramHeader = (hlsl::DxilProgramHeader *)pBuffer->getBufferStart();
if (pDxilProgramHeader->BitcodeHeader.DxilMagic != hlsl::DxilMagicValue) {
return DXC_E_MALFORMED_CONTAINER;
}
UINT32 BlobSize;
const char *pBitcode = nullptr;
hlsl::GetDxilProgramBitcode(pDxilProgramHeader, &pBitcode, &BlobSize);
UINT32 offset = (UINT32)(pBitcode - (const char *)pDxilProgramHeader);
std::unique_ptr<llvm::MemoryBuffer> p = llvm::MemoryBuffer::getMemBuffer(
llvm::StringRef(pBitcode, bufferSize - offset), "data");
pEmbeddedBuffer.swap(p);
pBitcodeBuffer = pEmbeddedBuffer.get();
}
std::string DiagStr;
std::unique_ptr<llvm::Module> pModule = hlsl::dxilutil::LoadModuleFromBitcode(
pBitcodeBuffer, *m_context.get(), DiagStr);
if (!pModule.get())
return E_FAIL;
m_finder = std::make_shared<llvm::DebugInfoFinder>();
m_finder->processModule(*pModule.get());
m_module.reset(pModule.release());
}
CATCH_CPP_RETURN_HRESULT();
return S_OK;
}
STDMETHODIMP dxil_dia::DataSource::openSession(_COM_Outptr_ IDiaSession **ppSession) {
DxcThreadMalloc TM(m_pMalloc);
*ppSession = nullptr;
if (m_module.get() == nullptr)
return E_FAIL;
CComPtr<Session> pSession = Session::Alloc(DxcGetThreadMallocNoRef());
IFROOM(pSession.p);
pSession->Init(m_context, m_module, m_finder);
*ppSession = pSession.Detach();
return S_OK;
}
HRESULT CreateDxcDiaDataSource(_In_ REFIID riid, _Out_ LPVOID* ppv) {
CComPtr<dxil_dia::DataSource> result = CreateOnMalloc<dxil_dia::DataSource>(DxcGetThreadMallocNoRef());
if (result == nullptr) {
*ppv = nullptr;
return E_OUTOFMEMORY;
}
return result.p->QueryInterface(riid, ppv);
}

Просмотреть файл

@ -0,0 +1,84 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaDataSource.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include <memory>
#include "dia2.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/Support/Global.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class DataSource : public IDiaDataSource {
private:
DXC_MICROCOM_TM_REF_FIELDS()
std::shared_ptr<llvm::Module> m_module;
std::shared_ptr<llvm::LLVMContext> m_context;
std::shared_ptr<llvm::DebugInfoFinder> m_finder;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaDataSource>(this, iid, ppvObject);
}
DataSource(IMalloc *pMalloc);
~DataSource();
STDMETHODIMP get_lastError(BSTR *pRetVal) override;
STDMETHODIMP loadDataFromPdb(_In_ LPCOLESTR pdbPath) override { return ENotImpl(); }
STDMETHODIMP loadAndValidateDataFromPdb(
_In_ LPCOLESTR pdbPath,
_In_ GUID *pcsig70,
_In_ DWORD sig,
_In_ DWORD age) override { return ENotImpl(); }
STDMETHODIMP loadDataForExe(
_In_ LPCOLESTR executable,
_In_ LPCOLESTR searchPath,
_In_ IUnknown *pCallback) override { return ENotImpl(); }
STDMETHODIMP loadDataFromIStream(_In_ IStream *pIStream) override;
STDMETHODIMP openSession(_COM_Outptr_ IDiaSession **ppSession) override;
HRESULT STDMETHODCALLTYPE loadDataFromCodeViewInfo(
_In_ LPCOLESTR executable,
_In_ LPCOLESTR searchPath,
_In_ DWORD cbCvInfo,
_In_ BYTE *pbCvInfo,
_In_ IUnknown *pCallback) override { return ENotImpl(); }
HRESULT STDMETHODCALLTYPE loadDataFromMiscInfo(
_In_ LPCOLESTR executable,
_In_ LPCOLESTR searchPath,
_In_ DWORD timeStampExe,
_In_ DWORD timeStampDbg,
_In_ DWORD sizeOfExe,
_In_ DWORD cbMiscInfo,
_In_ BYTE *pbMiscInfo,
_In_ IUnknown *pCallback) override { return ENotImpl(); }
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,88 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaEnumTables.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaEnumTables.h"
#include "DxilDia.h"
#include "DxilDiaSession.h"
#include "DxilDiaTable.h"
STDMETHODIMP dxil_dia::EnumTables::get_Count(_Out_ LONG *pRetVal) {
*pRetVal = ((unsigned)Table::LastKind - (unsigned)Table::FirstKind) + 1;
return S_OK;
}
STDMETHODIMP dxil_dia::EnumTables::Item(
/* [in] */ VARIANT index,
/* [retval][out] */ IDiaTable **table) {
// Avoid pulling in additional variant support (could have used VariantChangeType instead).
DWORD indexVal;
switch (index.vt) {
case VT_UI4:
indexVal = index.uintVal;
break;
case VT_I4:
IFR(IntToDWord(index.intVal, &indexVal));
break;
default:
return E_INVALIDARG;
}
if (indexVal > (unsigned)Table::LastKind) {
return E_INVALIDARG;
}
HRESULT hr = S_OK;
if (!m_tables[indexVal]) {
DxcThreadMalloc TM(m_pMalloc);
hr = Table::Create(m_pSession, (Table::Kind)indexVal, &m_tables[indexVal]);
}
m_tables[indexVal].p->AddRef();
*table = m_tables[indexVal];
return hr;
}
STDMETHODIMP dxil_dia::EnumTables::Next(
ULONG celt,
IDiaTable **rgelt,
ULONG *pceltFetched) {
DxcThreadMalloc TM(m_pMalloc);
ULONG fetched = 0;
while (fetched < celt && m_next <= (unsigned)Table::LastKind) {
HRESULT hr = S_OK;
if (!m_tables[m_next]) {
DxcThreadMalloc TM(m_pMalloc);
hr = Table::Create(m_pSession, (Table::Kind)m_next, &m_tables[m_next]);
if (FAILED(hr)) {
return hr; // TODO: this leaks prior tables.
}
}
m_tables[m_next].p->AddRef();
rgelt[fetched] = m_tables[m_next];
++m_next, ++fetched;
}
if (pceltFetched != nullptr)
*pceltFetched = fetched;
return (fetched == celt) ? S_OK : S_FALSE;
}
STDMETHODIMP dxil_dia::EnumTables::Reset() {
m_next = 0;
return S_OK;
}
HRESULT dxil_dia::EnumTables::Create(
/* [in] */ dxil_dia::Session *pSession,
/* [out] */ IDiaEnumTables **ppEnumTables) {
*ppEnumTables = CreateOnMalloc<EnumTables>(pSession->GetMallocNoRef(), pSession);
if (*ppEnumTables == nullptr)
return E_OUTOFMEMORY;
(*ppEnumTables)->AddRef();
return S_OK;
}

Просмотреть файл

@ -0,0 +1,76 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaEnumTable.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include <array>
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class EnumTables : public IDiaEnumTables {
private:
DXC_MICROCOM_TM_REF_FIELDS()
protected:
CComPtr<Session> m_pSession;
unsigned m_next;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaEnumTables>(this, iid, ppvObject);
}
EnumTables(IMalloc *pMalloc, Session *pSession)
: m_pMalloc(pMalloc), m_pSession(pSession), m_dwRef(0), m_next(0) {
m_tables.fill(nullptr);
}
STDMETHODIMP get__NewEnum(
/* [retval][out] */ IUnknown **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_Count(_Out_ LONG *pRetVal) override;
STDMETHODIMP Item(
/* [in] */ VARIANT index,
/* [retval][out] */ IDiaTable **table) override;
STDMETHODIMP Next(
ULONG celt,
IDiaTable **rgelt,
ULONG *pceltFetched) override;
STDMETHODIMP Skip(
/* [in] */ ULONG celt) override { return ENotImpl(); }
STDMETHODIMP Reset(void) override;
STDMETHODIMP Clone(
/* [out] */ IDiaEnumTables **ppenum) override { return ENotImpl(); }
static HRESULT Create(Session *pSession,
IDiaEnumTables **ppEnumTables);
private:
std::array<CComPtr<IDiaTable>, (int)Table::LastKind+1> m_tables;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,205 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaSession.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaSession.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "DxilDia.h"
#include "DxilDiaEnumTables.h"
#include "DxilDiaTable.h"
#include "DxilDiaTableInjectedSources.h"
#include "DxilDiaTableLineNumbers.h"
void dxil_dia::Session::Init(
std::shared_ptr<llvm::LLVMContext> context,
std::shared_ptr<llvm::Module> module,
std::shared_ptr<llvm::DebugInfoFinder> finder) {
m_pEnumTables = nullptr;
m_module = module;
m_context = context;
m_finder = finder;
m_dxilModule = std::make_unique<hlsl::DxilModule>(module.get());
// Extract HLSL metadata.
m_dxilModule->LoadDxilMetadata();
// Get file contents.
m_contents =
m_module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceContentsMDName);
if (!m_contents)
m_contents = m_module->getNamedMetadata("llvm.dbg.contents");
m_defines =
m_module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceDefinesMDName);
if (!m_defines)
m_defines = m_module->getNamedMetadata("llvm.dbg.defines");
m_mainFileName =
m_module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceMainFileNameMDName);
if (!m_mainFileName)
m_mainFileName = m_module->getNamedMetadata("llvm.dbg.mainFileName");
m_arguments =
m_module->getNamedMetadata(hlsl::DxilMDHelper::kDxilSourceArgsMDName);
if (!m_arguments)
m_arguments = m_module->getNamedMetadata("llvm.dbg.args");
// Build up a linear list of instructions. The index will be used as the
// RVA. Debug instructions are ommitted from this enumeration.
for (const llvm::Function &fn : m_module->functions()) {
for (llvm::const_inst_iterator it = inst_begin(fn), end = inst_end(fn); it != end; ++it) {
const llvm::Instruction &i = *it;
if (const auto *call = llvm::dyn_cast<const llvm::CallInst>(&i)) {
const llvm::Function *pFn = call->getCalledFunction();
if (pFn && pFn->getName().startswith("llvm.dbg.")) {
continue;
}
}
m_rvaMap.insert({ &i, static_cast<RVA>(m_instructions.size()) });
m_instructions.push_back(&i);
if (i.getDebugLoc()) {
m_instructionLines.push_back(&i);
}
}
}
// Sanity check to make sure rva map is same as instruction index.
for (size_t i = 0, e = m_instructions.size(); i < e; ++i) {
DXASSERT(m_rvaMap.find(m_instructions[i]) != m_rvaMap.end(), "instruction not mapped to rva");
DXASSERT(m_rvaMap[m_instructions[i]] == i, "instruction mapped to wrong rva");
}
}
HRESULT dxil_dia::Session::getSourceFileIdByName(
llvm::StringRef fileName,
DWORD *pRetVal) {
if (Contents() != nullptr) {
for (unsigned i = 0; i < Contents()->getNumOperands(); ++i) {
llvm::StringRef fn =
llvm::dyn_cast<llvm::MDString>(Contents()->getOperand(i)->getOperand(0))
->getString();
if (fn.equals(fileName)) {
*pRetVal = i;
return S_OK;
}
}
}
*pRetVal = 0;
return S_FALSE;
}
STDMETHODIMP dxil_dia::Session::get_loadAddress(
/* [retval][out] */ ULONGLONG *pRetVal) {
*pRetVal = 0;
return S_OK;
}
STDMETHODIMP dxil_dia::Session::getEnumTables(
/* [out] */ _COM_Outptr_ IDiaEnumTables **ppEnumTables) {
if (!m_pEnumTables) {
DxcThreadMalloc TM(m_pMalloc);
IFR(EnumTables::Create(this, &m_pEnumTables));
}
m_pEnumTables.p->AddRef();
*ppEnumTables = m_pEnumTables;
return S_OK;
}
STDMETHODIMP dxil_dia::Session::findFileById(
/* [in] */ DWORD uniqueId,
/* [out] */ IDiaSourceFile **ppResult) {
if (!m_pEnumTables) {
return E_INVALIDARG;
}
CComPtr<IDiaTable> pTable;
VARIANT vtIndex;
vtIndex.vt = VT_UI4;
vtIndex.uintVal = (int)Table::Kind::SourceFiles;
IFR(m_pEnumTables->Item(vtIndex, &pTable));
CComPtr<IUnknown> pElt;
IFR(pTable->Item(uniqueId, &pElt));
return pElt->QueryInterface(ppResult);
}
namespace dxil_dia {
static HRESULT DxcDiaFindLineNumbersByRVA(
Session *pSession,
DWORD rva,
DWORD length,
IDiaEnumLineNumbers **ppResult)
{
if (!ppResult)
return E_POINTER;
std::vector<const llvm::Instruction*> instructions;
const std::vector<const llvm::Instruction*> &allInstructions = pSession->InstructionsRef();
// Gather the list of insructions that map to the given rva range.
for (DWORD i = rva; i < rva + length; ++i) {
if (i >= allInstructions.size())
return E_INVALIDARG;
// Only include the instruction if it has debug info for line mappings.
const llvm::Instruction *inst = allInstructions[i];
if (inst->getDebugLoc())
instructions.push_back(inst);
}
// Create line number table from explicit instruction list.
IMalloc *pMalloc = pSession->GetMallocNoRef();
*ppResult = CreateOnMalloc<LineNumbersTable>(pMalloc, pSession, std::move(instructions));
if (*ppResult == nullptr)
return E_OUTOFMEMORY;
(*ppResult)->AddRef();
return S_OK;
}
} // namespace dxil_dia
STDMETHODIMP dxil_dia::Session::findLinesByAddr(
/* [in] */ DWORD seg,
/* [in] */ DWORD offset,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) {
DxcThreadMalloc TM(m_pMalloc);
return DxcDiaFindLineNumbersByRVA(this, offset, length, ppResult);
}
STDMETHODIMP dxil_dia::Session::findLinesByRVA(
/* [in] */ DWORD rva,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) {
DxcThreadMalloc TM(m_pMalloc);
return DxcDiaFindLineNumbersByRVA(this, rva, length, ppResult);
}
STDMETHODIMP dxil_dia::Session::findInjectedSource(
/* [in] */ LPCOLESTR srcFile,
/* [out] */ IDiaEnumInjectedSources **ppResult) {
if (Contents() != nullptr) {
CW2A pUtf8FileName(srcFile);
DxcThreadMalloc TM(m_pMalloc);
IDiaTable *pTable;
IFT(Table::Create(this, Table::Kind::InjectedSource, &pTable));
auto *pInjectedSource =
reinterpret_cast<InjectedSourcesTable *>(pTable);
pInjectedSource->Init(pUtf8FileName.m_psz);
*ppResult = pInjectedSource;
return S_OK;
}
return S_FALSE;
}

Просмотреть файл

@ -0,0 +1,379 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaSession.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include <memory>
#include <unordered_map>
#include <vector>
#include "dia2.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
namespace dxil_dia {
class Session : public IDiaSession {
public:
using RVA = unsigned;
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
DXC_MICROCOM_TM_CTOR(Session)
IMalloc *GetMallocNoRef() { return m_pMalloc.p; }
void Init(std::shared_ptr<llvm::LLVMContext> context,
std::shared_ptr<llvm::Module> module,
std::shared_ptr<llvm::DebugInfoFinder> finder);
llvm::NamedMDNode *Contents() { return m_contents; }
llvm::NamedMDNode *Defines() { return m_defines; }
llvm::NamedMDNode *MainFileName() { return m_mainFileName; }
llvm::NamedMDNode *Arguments() { return m_arguments; }
hlsl::DxilModule &DxilModuleRef() { return *m_dxilModule.get(); }
llvm::Module &ModuleRef() { return *m_module.get(); }
llvm::DebugInfoFinder &InfoRef() { return *m_finder.get(); }
std::vector<const llvm::Instruction *> &InstructionsRef() { return m_instructions; }
std::vector<const llvm::Instruction *> &InstructionLinesRef() { return m_instructionLines; }
std::unordered_map<const llvm::Instruction *, RVA> &RvaMapRef() { return m_rvaMap; }
HRESULT getSourceFileIdByName(llvm::StringRef fileName, DWORD *pRetVal);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaSession>(this, iid, ppvObject);
}
STDMETHODIMP get_loadAddress(
/* [retval][out] */ ULONGLONG *pRetVal) override;
STDMETHODIMP put_loadAddress(
/* [in] */ ULONGLONG NewVal) override { return ENotImpl(); }
STDMETHODIMP get_globalScope(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP getEnumTables(
_COM_Outptr_ IDiaEnumTables **ppEnumTables) override;
STDMETHODIMP getSymbolsByAddr(
/* [out] */ IDiaEnumSymbolsByAddr **ppEnumbyAddr) override { return ENotImpl(); }
STDMETHODIMP findChildren(
/* [in] */ IDiaSymbol *parent,
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenEx(
/* [in] */ IDiaSymbol *parent,
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenExByAddr(
/* [in] */ IDiaSymbol *parent,
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenExByVA(
/* [in] */ IDiaSymbol *parent,
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [in] */ ULONGLONG va,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenExByRVA(
/* [in] */ IDiaSymbol *parent,
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [in] */ DWORD rva,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findSymbolByAddr(
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [in] */ enum SymTagEnum symtag,
/* [out] */ IDiaSymbol **ppSymbol) override { return ENotImpl(); }
STDMETHODIMP findSymbolByRVA(
/* [in] */ DWORD rva,
/* [in] */ enum SymTagEnum symtag,
/* [out] */ IDiaSymbol **ppSymbol) override { return ENotImpl(); }
STDMETHODIMP findSymbolByVA(
/* [in] */ ULONGLONG va,
/* [in] */ enum SymTagEnum symtag,
/* [out] */ IDiaSymbol **ppSymbol) override { return ENotImpl(); }
STDMETHODIMP findSymbolByToken(
/* [in] */ ULONG token,
/* [in] */ enum SymTagEnum symtag,
/* [out] */ IDiaSymbol **ppSymbol) override { return ENotImpl(); }
STDMETHODIMP symsAreEquiv(
/* [in] */ IDiaSymbol *symbolA,
/* [in] */ IDiaSymbol *symbolB) override { return ENotImpl(); }
STDMETHODIMP symbolById(
/* [in] */ DWORD id,
/* [out] */ IDiaSymbol **ppSymbol) override { return ENotImpl(); }
STDMETHODIMP findSymbolByRVAEx(
/* [in] */ DWORD rva,
/* [in] */ enum SymTagEnum symtag,
/* [out] */ IDiaSymbol **ppSymbol,
/* [out] */ long *displacement) override { return ENotImpl(); }
STDMETHODIMP findSymbolByVAEx(
/* [in] */ ULONGLONG va,
/* [in] */ enum SymTagEnum symtag,
/* [out] */ IDiaSymbol **ppSymbol,
/* [out] */ long *displacement) override { return ENotImpl(); }
STDMETHODIMP findFile(
/* [in] */ IDiaSymbol *pCompiland,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [out] */ IDiaEnumSourceFiles **ppResult) override { return ENotImpl(); }
STDMETHODIMP findFileById(
/* [in] */ DWORD uniqueId,
/* [out] */ IDiaSourceFile **ppResult) override;
STDMETHODIMP findLines(
/* [in] */ IDiaSymbol *compiland,
/* [in] */ IDiaSourceFile *file,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findLinesByAddr(
/* [in] */ DWORD seg,
/* [in] */ DWORD offset,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override;
STDMETHODIMP findLinesByRVA(
/* [in] */ DWORD rva,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override;
STDMETHODIMP findLinesByVA(
/* [in] */ ULONGLONG va,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findLinesByLinenum(
/* [in] */ IDiaSymbol *compiland,
/* [in] */ IDiaSourceFile *file,
/* [in] */ DWORD linenum,
/* [in] */ DWORD column,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInjectedSource(
/* [in] */ LPCOLESTR srcFile,
/* [out] */ IDiaEnumInjectedSources **ppResult) override;
STDMETHODIMP getEnumDebugStreams(
/* [out] */ IDiaEnumDebugStreams **ppEnumDebugStreams) override { return ENotImpl(); }
STDMETHODIMP findInlineFramesByAddr(
/* [in] */ IDiaSymbol *parent,
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineFramesByRVA(
/* [in] */ IDiaSymbol *parent,
/* [in] */ DWORD rva,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineFramesByVA(
/* [in] */ IDiaSymbol *parent,
/* [in] */ ULONGLONG va,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLines(
/* [in] */ IDiaSymbol *parent,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByAddr(
/* [in] */ IDiaSymbol *parent,
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByRVA(
/* [in] */ IDiaSymbol *parent,
/* [in] */ DWORD rva,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByVA(
/* [in] */ IDiaSymbol *parent,
/* [in] */ ULONGLONG va,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByLinenum(
/* [in] */ IDiaSymbol *compiland,
/* [in] */ IDiaSourceFile *file,
/* [in] */ DWORD linenum,
/* [in] */ DWORD column,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineesByName(
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD option,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findAcceleratorInlineeLinesByLinenum(
/* [in] */ IDiaSymbol *parent,
/* [in] */ IDiaSourceFile *file,
/* [in] */ DWORD linenum,
/* [in] */ DWORD column,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findSymbolsForAcceleratorPointerTag(
/* [in] */ IDiaSymbol *parent,
/* [in] */ DWORD tagValue,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findSymbolsByRVAForAcceleratorPointerTag(
/* [in] */ IDiaSymbol *parent,
/* [in] */ DWORD tagValue,
/* [in] */ DWORD rva,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findAcceleratorInlineesByName(
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD option,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP addressForVA(
/* [in] */ ULONGLONG va,
/* [out] */ DWORD *pISect,
/* [out] */ DWORD *pOffset) override { return ENotImpl(); }
STDMETHODIMP addressForRVA(
/* [in] */ DWORD rva,
/* [out] */ DWORD *pISect,
/* [out] */ DWORD *pOffset) override { return ENotImpl(); }
STDMETHODIMP findILOffsetsByAddr(
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findILOffsetsByRVA(
/* [in] */ DWORD rva,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findILOffsetsByVA(
/* [in] */ ULONGLONG va,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInputAssemblyFiles(
/* [out] */ IDiaEnumInputAssemblyFiles **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInputAssembly(
/* [in] */ DWORD index,
/* [out] */ IDiaInputAssemblyFile **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInputAssemblyById(
/* [in] */ DWORD uniqueId,
/* [out] */ IDiaInputAssemblyFile **ppResult) override { return ENotImpl(); }
STDMETHODIMP getFuncMDTokenMapSize(
/* [out] */ DWORD *pcb) override { return ENotImpl(); }
STDMETHODIMP getFuncMDTokenMap(
/* [in] */ DWORD cb,
/* [out] */ DWORD *pcb,
/* [size_is][out] */ BYTE *pb) override { return ENotImpl(); }
STDMETHODIMP getTypeMDTokenMapSize(
/* [out] */ DWORD *pcb) override { return ENotImpl(); }
STDMETHODIMP getTypeMDTokenMap(
/* [in] */ DWORD cb,
/* [out] */ DWORD *pcb,
/* [size_is][out] */ BYTE *pb) override { return ENotImpl(); }
STDMETHODIMP getNumberOfFunctionFragments_VA(
/* [in] */ ULONGLONG vaFunc,
/* [in] */ DWORD cbFunc,
/* [out] */ DWORD *pNumFragments) override { return ENotImpl(); }
STDMETHODIMP getNumberOfFunctionFragments_RVA(
/* [in] */ DWORD rvaFunc,
/* [in] */ DWORD cbFunc,
/* [out] */ DWORD *pNumFragments) override { return ENotImpl(); }
STDMETHODIMP getFunctionFragments_VA(
/* [in] */ ULONGLONG vaFunc,
/* [in] */ DWORD cbFunc,
/* [in] */ DWORD cFragments,
/* [size_is][out] */ ULONGLONG *pVaFragment,
/* [size_is][out] */ DWORD *pLenFragment) override { return ENotImpl(); }
STDMETHODIMP getFunctionFragments_RVA(
/* [in] */ DWORD rvaFunc,
/* [in] */ DWORD cbFunc,
/* [in] */ DWORD cFragments,
/* [size_is][out] */ DWORD *pRvaFragment,
/* [size_is][out] */ DWORD *pLenFragment) override { return ENotImpl(); }
STDMETHODIMP getExports(
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP getHeapAllocationSites(
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInputAssemblyFile(
/* [in] */ IDiaSymbol *pSymbol,
/* [out] */ IDiaInputAssemblyFile **ppResult) override { return ENotImpl(); }
private:
DXC_MICROCOM_TM_REF_FIELDS()
std::shared_ptr<llvm::LLVMContext> m_context;
std::shared_ptr<llvm::Module> m_module;
std::shared_ptr<llvm::DebugInfoFinder> m_finder;
std::unique_ptr<hlsl::DxilModule> m_dxilModule;
llvm::NamedMDNode *m_contents;
llvm::NamedMDNode *m_defines;
llvm::NamedMDNode *m_mainFileName;
llvm::NamedMDNode *m_arguments;
std::vector<const llvm::Instruction *> m_instructions;
std::vector<const llvm::Instruction *> m_instructionLines; // Instructions with line info.
std::unordered_map<const llvm::Instruction *, RVA> m_rvaMap; // Map instruction to its RVA.
private:
CComPtr<IDiaEnumTables> m_pEnumTables;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,46 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTable.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTable.h"
#include "DxilDiaSession.h"
#include "DxilDiaTableFrameData.h"
#include "DxilDiaTableInjectedSources.h"
#include "DxilDiaTableInputAssemblyFile.h"
#include "DxilDiaTableLineNumbers.h"
#include "DxilDiaTableSections.h"
#include "DxilDiaTableSegmentMap.h"
#include "DxilDiaTableSourceFiles.h"
#include "DxilDiaTableSymbols.h"
HRESULT dxil_dia::Table::Create(
/* [in] */ Session *pSession,
/* [in] */ Table::Kind kind,
/* [out] */ IDiaTable **ppTable) {
*ppTable = nullptr;
IMalloc *pMalloc = pSession->GetMallocNoRef();
switch (kind) {
case Table::Kind::Symbols: *ppTable = CreateOnMalloc<SymbolsTable>(pMalloc, pSession); break;
case Table::Kind::SourceFiles: *ppTable = CreateOnMalloc<SourceFilesTable>(pMalloc, pSession); break;
case Table::Kind::LineNumbers: *ppTable = CreateOnMalloc<LineNumbersTable>(pMalloc, pSession); break;
case Table::Kind::Sections: *ppTable = CreateOnMalloc<SectionsTable>(pMalloc, pSession); break;
case Table::Kind::SegmentMap: *ppTable = CreateOnMalloc<SegmentMapTable>(pMalloc, pSession); break;
case Table::Kind::InjectedSource: *ppTable = CreateOnMalloc<InjectedSourcesTable>(pMalloc, pSession); break;
case Table::Kind::FrameData: *ppTable = CreateOnMalloc<FrameDataTable>(pMalloc, pSession); break;
case Table::Kind::InputAssemblyFile: *ppTable = CreateOnMalloc<InputAssemblyFilesTable>(pMalloc, pSession); break;
default: return E_FAIL;
}
if (*ppTable == nullptr)
return E_OUTOFMEMORY;
(*ppTable)->AddRef();
return S_OK;
return E_NOTIMPL;
}

173
lib/DxilDia/DxilDiaTable.h Normal file
Просмотреть файл

@ -0,0 +1,173 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTable.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "dia2.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
namespace dxil_dia {
class Session;
namespace Table {
enum class Kind {
Symbols,
SourceFiles,
LineNumbers,
Sections,
SegmentMap,
InjectedSource,
FrameData,
InputAssemblyFile
};
static constexpr Kind FirstKind = Kind::Symbols;
static constexpr Kind LastKind = Kind::InputAssemblyFile;
HRESULT Create(
/* [in] */ Session *pSession,
/* [in] */ Kind kind,
/* [out] */ IDiaTable **ppTable);
} // namespace Table
namespace impl {
template<typename T, typename TItem>
class TableBase : public IDiaTable, public T {
protected:
static constexpr LPCWSTR TableNames[] = {
L"Symbols",
L"SourceFiles",
L"LineNumbers",
L"Sections",
L"SegmentMap",
L"InjectedSource",
L"FrameData",
L"InputAssemblyFiles"
};
DXC_MICROCOM_TM_REF_FIELDS()
CComPtr<Session> m_pSession;
unsigned m_next;
unsigned m_count;
Table::Kind m_kind;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaTable, T, IEnumUnknown>(this, iid, ppvObject);
}
TableBase(IMalloc *pMalloc, Session *pSession, Table::Kind kind) {
m_pMalloc = pMalloc;
m_pSession = pSession;
m_kind = kind;
m_next = 0;
m_count = 0;
}
// IEnumUnknown implementation.
STDMETHODIMP Next(
_In_ ULONG celt,
_Out_writes_to_(celt, *pceltFetched) IUnknown **rgelt,
_Out_opt_ ULONG *pceltFetched) override {
DxcThreadMalloc TM(m_pMalloc);
ULONG fetched = 0;
while (fetched < celt && m_next < m_count) {
HRESULT hr = Item(m_next, &rgelt[fetched]);
if (FAILED(hr)) {
return hr; // TODO: this leaks prior tables.
}
++m_next, ++fetched;
}
if (pceltFetched != nullptr)
*pceltFetched = fetched;
return (fetched == celt) ? S_OK : S_FALSE;
}
STDMETHODIMP Skip(ULONG celt) override {
if (celt + m_next <= m_count) {
m_next += celt;
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP Reset(void) override {
m_next = 0;
return S_OK;
}
STDMETHODIMP Clone(IEnumUnknown **ppenum) override {
return ENotImpl();
}
// IDiaTable implementation.
STDMETHODIMP get__NewEnum(IUnknown **pRetVal) override {
return ENotImpl();
}
STDMETHODIMP get_name(BSTR *pRetVal) override {
*pRetVal = SysAllocString(TableNames[(unsigned)m_kind]);
return (*pRetVal) ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP get_Count(_Out_ LONG *pRetVal) override {
*pRetVal = m_count;
return S_OK;
}
STDMETHODIMP Item(DWORD index, _COM_Outptr_ IUnknown **table) override {
if (index >= m_count)
return E_INVALIDARG;
return GetItem(index, (TItem **)table);
}
// T implementation (partial).
STDMETHODIMP Clone(_COM_Outptr_ T **ppenum) override {
*ppenum = nullptr;
return ENotImpl();
}
STDMETHODIMP Next(
/* [in] */ ULONG celt,
/* [out] */ TItem **rgelt,
/* [out] */ ULONG *pceltFetched) override {
DxcThreadMalloc TM(m_pMalloc);
ULONG fetched = 0;
while (fetched < celt && m_next < m_count) {
HRESULT hr = GetItem(m_next, &rgelt[fetched]);
if (FAILED(hr)) {
return hr; // TODO: this leaks prior items.
}
++m_next, ++fetched;
}
if (pceltFetched != nullptr)
*pceltFetched = fetched;
return (fetched == celt) ? S_OK : S_FALSE;
}
STDMETHODIMP Item(
/* [in] */ DWORD index,
/* [retval][out] */ TItem **ppItem) override {
DxcThreadMalloc TM(m_pMalloc);
if (index >= m_count)
return E_INVALIDARG;
return GetItem(index, ppItem);
}
virtual HRESULT GetItem(DWORD index, TItem **ppItem) = 0;
};
} // namespace impl
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableFrameData.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableFrameData.h"
#include "DxilDiaSession.h"
dxil_dia::FrameDataTable::FrameDataTable(IMalloc *pMalloc, Session *pSession)
: impl::TableBase<IDiaEnumFrameData, IDiaFrameData>(pMalloc, pSession, Table::Kind::FrameData) {
}
HRESULT dxil_dia::FrameDataTable::GetItem(DWORD index, IDiaFrameData **ppItem) {
*ppItem = nullptr;
return E_FAIL;
}

Просмотреть файл

@ -0,0 +1,43 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableFrameData.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class FrameDataTable : public impl::TableBase<IDiaEnumFrameData, IDiaFrameData> {
public:
FrameDataTable(IMalloc *pMalloc, Session *pSession);
// HLSL inlines functions for a program, so no data to return.
STDMETHODIMP frameByRVA(
/* [in] */ DWORD relativeVirtualAddress,
/* [retval][out] */ IDiaFrameData **frame) override { return ENotImpl(); }
STDMETHODIMP frameByVA(
/* [in] */ ULONGLONG virtualAddress,
/* [retval][out] */ IDiaFrameData **frame) override { return ENotImpl(); }
HRESULT GetItem(DWORD index, IDiaFrameData **ppItem) override;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,102 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableInjectedSources.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableInjectedSources.h"
#include "DxilDia.h"
#include "DxilDiaSession.h"
#include "DxilDiaTable.h"
llvm::MDTuple *dxil_dia::InjectedSource::NameContent() {
return llvm::cast<llvm::MDTuple>(m_pSession->Contents()->getOperand(m_index));
}
llvm::StringRef dxil_dia::InjectedSource::Name() {
return llvm::dyn_cast<llvm::MDString>(NameContent()->getOperand(0))->getString();
}
llvm::StringRef dxil_dia::InjectedSource::Content() {
return llvm::dyn_cast<llvm::MDString>(NameContent()->getOperand(1))->getString();
}
STDMETHODIMP dxil_dia::InjectedSource::get_length(_Out_ ULONGLONG *pRetVal) {
*pRetVal = Content().size();
return S_OK;
}
STDMETHODIMP dxil_dia::InjectedSource::get_filename(BSTR *pRetVal) {
DxcThreadMalloc TM(m_pMalloc);
return StringRefToBSTR(Name(), pRetVal);
}
STDMETHODIMP dxil_dia::InjectedSource::get_objectFilename(BSTR *pRetVal) {
*pRetVal = nullptr;
return S_OK;
}
STDMETHODIMP dxil_dia::InjectedSource::get_virtualFilename(BSTR *pRetVal) {
return get_filename(pRetVal);
}
STDMETHODIMP dxil_dia::InjectedSource::get_source(
/* [in] */ DWORD cbData,
/* [out] */ DWORD *pcbData,
/* [size_is][out] */ BYTE *pbData) {
if (pbData == nullptr) {
if (pcbData != nullptr) {
*pcbData = Content().size();
}
return S_OK;
}
cbData = std::min((DWORD)Content().size(), cbData);
memcpy(pbData, Content().begin(), cbData);
if (pcbData) {
*pcbData = cbData;
}
return S_OK;
}
dxil_dia::InjectedSourcesTable::InjectedSourcesTable(
IMalloc *pMalloc,
Session *pSession)
: impl::TableBase<IDiaEnumInjectedSources,
IDiaInjectedSource>(pMalloc, pSession, Table::Kind::InjectedSource) {
// Count the number of source files available.
// m_count = m_pSession->InfoRef().compile_unit_count();
m_count =
(m_pSession->Contents() == nullptr) ? 0 : m_pSession->Contents()->getNumOperands();
}
HRESULT dxil_dia::InjectedSourcesTable::GetItem(DWORD index, IDiaInjectedSource **ppItem) {
if (index >= m_count)
return E_INVALIDARG;
unsigned itemIndex = index;
if (m_count == m_indexList.size())
itemIndex = m_indexList[index];
*ppItem = CreateOnMalloc<InjectedSource>(m_pMalloc, m_pSession, itemIndex);
if (*ppItem == nullptr)
return E_OUTOFMEMORY;
(*ppItem)->AddRef();
return S_OK;
}
void dxil_dia::InjectedSourcesTable::Init(llvm::StringRef filename) {
for (unsigned i = 0; i < m_pSession->Contents()->getNumOperands(); ++i) {
llvm::StringRef fn =
llvm::dyn_cast<llvm::MDString>(m_pSession->Contents()->getOperand(i)->getOperand(0))
->getString();
if (fn.equals(filename)) {
m_indexList.emplace_back(i);
}
}
m_count = m_indexList.size();
}

Просмотреть файл

@ -0,0 +1,82 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableInjectedSources.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include <vector>
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Metadata.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class InjectedSource : public IDiaInjectedSource {
private:
DXC_MICROCOM_TM_REF_FIELDS()
CComPtr<Session> m_pSession;
DWORD m_index;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaInjectedSource>(this, iid, ppvObject);
}
InjectedSource(IMalloc *pMalloc, Session *pSession, DWORD index)
: m_pMalloc(pMalloc), m_pSession(pSession), m_index(index) {}
llvm::MDTuple *NameContent();
llvm::StringRef Name();
llvm::StringRef Content();
STDMETHODIMP get_crc(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_length(_Out_ ULONGLONG *pRetVal) override;
STDMETHODIMP get_filename(BSTR *pRetVal) override;
STDMETHODIMP get_objectFilename(BSTR *pRetVal) override;
STDMETHODIMP get_virtualFilename(BSTR *pRetVal) override;
STDMETHODIMP get_sourceCompression(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_source(
/* [in] */ DWORD cbData,
/* [out] */ DWORD *pcbData,
/* [size_is][out] */ BYTE *pbData) override;
};
class InjectedSourcesTable : public impl::TableBase<IDiaEnumInjectedSources,
IDiaInjectedSource> {
public:
InjectedSourcesTable(IMalloc *pMalloc, Session *pSession);
HRESULT GetItem(DWORD index, IDiaInjectedSource **ppItem) override;
void Init(llvm::StringRef filename);
private:
std::vector<unsigned> m_indexList;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableInputAssemblyFile.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableInputAssemblyFile.h"
#include "DxilDiaSession.h"
dxil_dia::InputAssemblyFilesTable::InputAssemblyFilesTable(IMalloc *pMalloc, Session *pSession)
: impl::TableBase<IDiaEnumInputAssemblyFiles, IDiaInputAssemblyFile>(pMalloc, pSession, Table::Kind::InputAssemblyFile) {
}
HRESULT dxil_dia::InputAssemblyFilesTable::GetItem(DWORD index, IDiaInputAssemblyFile **ppItem) {
*ppItem = nullptr;
return E_FAIL;
}

Просмотреть файл

@ -0,0 +1,32 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableInputAssemblyFile.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class InputAssemblyFilesTable
: public impl::TableBase<IDiaEnumInputAssemblyFiles, IDiaInputAssemblyFile> {
public:
InputAssemblyFilesTable(IMalloc *pMalloc, Session *pSession);
HRESULT GetItem(DWORD index, IDiaInputAssemblyFile **ppItem) override;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,119 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableLineNumbers.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableLineNumbers.h"
#include <utility>
#include "llvm/IR/DebugInfoMetadata.h"
#include "DxilDiaSession.h"
dxil_dia::LineNumber::LineNumber(
/* [in] */ IMalloc *pMalloc,
/* [in] */ Session *pSession,
/* [in] */ const llvm::Instruction * inst)
: m_pMalloc(pMalloc),
m_pSession(pSession),
m_inst(inst) {
}
const llvm::DebugLoc &dxil_dia::LineNumber::DL() const {
DXASSERT(bool(m_inst->getDebugLoc()), "Trying to read line info from invalid debug location");
return m_inst->getDebugLoc();
}
STDMETHODIMP dxil_dia::LineNumber::get_sourceFile(
/* [retval][out] */ IDiaSourceFile **pRetVal) {
DWORD id;
HRESULT hr = get_sourceFileId(&id);
if (hr != S_OK)
return hr;
return m_pSession->findFileById(id, pRetVal);
}
STDMETHODIMP dxil_dia::LineNumber::get_lineNumber(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = DL().getLine();
return S_OK;
}
STDMETHODIMP dxil_dia::LineNumber::get_lineNumberEnd(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = DL().getLine();
return S_OK;
}
STDMETHODIMP dxil_dia::LineNumber::get_columnNumber(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = DL().getCol();
return S_OK;
}
STDMETHODIMP dxil_dia::LineNumber::get_columnNumberEnd(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = DL().getCol();
return S_OK;
}
STDMETHODIMP dxil_dia::LineNumber::get_relativeVirtualAddress(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = m_pSession->RvaMapRef()[m_inst];
return S_OK;
}
STDMETHODIMP dxil_dia::LineNumber::get_sourceFileId(
/* [retval][out] */ DWORD *pRetVal) {
llvm::MDNode *pScope = DL().getScope();
auto *pBlock = llvm::dyn_cast_or_null<llvm::DILexicalBlock>(pScope);
if (pBlock != nullptr) {
return m_pSession->getSourceFileIdByName(pBlock->getFile()->getFilename(), pRetVal);
}
auto *pSubProgram = llvm::dyn_cast_or_null<llvm::DISubprogram>(pScope);
if (pSubProgram != nullptr) {
return m_pSession->getSourceFileIdByName(pSubProgram->getFile()->getFilename(), pRetVal);
}
*pRetVal = 0;
return S_FALSE;
}
STDMETHODIMP dxil_dia::LineNumber::get_compilandId(
/* [retval][out] */ DWORD *pRetVal) {
// Single compiland for now, so pretty simple.
*pRetVal = HlslCompilandId;
return S_OK;
}
dxil_dia::LineNumbersTable::LineNumbersTable(IMalloc *pMalloc, Session *pSession)
: impl::TableBase<IDiaEnumLineNumbers, IDiaLineNumber>(pMalloc, pSession, Table::Kind::LineNumbers)
, m_instructions(pSession->InstructionLinesRef())
{
m_count = m_instructions.size();
}
dxil_dia::LineNumbersTable::LineNumbersTable(IMalloc *pMalloc, Session *pSession, std::vector<const llvm::Instruction*> &&instructions)
: impl::TableBase<IDiaEnumLineNumbers, IDiaLineNumber>(pMalloc, pSession, Table::Kind::LineNumbers)
, m_instructions(m_instructionsStorage)
, m_instructionsStorage(std::move(instructions))
{
m_count = m_instructions.size();
}
HRESULT dxil_dia::LineNumbersTable::GetItem(DWORD index, IDiaLineNumber **ppItem) {
if (index >= m_instructions.size())
return E_INVALIDARG;
*ppItem = CreateOnMalloc<LineNumber>(m_pMalloc, m_pSession, m_instructions[index]);
if (*ppItem == nullptr)
return E_OUTOFMEMORY;
(*ppItem)->AddRef();
return S_OK;
}

Просмотреть файл

@ -0,0 +1,118 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableLineNumbers.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include <vector>
#include "dia2.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Instruction.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class LineNumber : public IDiaLineNumber {
private:
DXC_MICROCOM_TM_REF_FIELDS()
CComPtr<Session> m_pSession;
const llvm::Instruction *m_inst;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaLineNumber>(this, iid, ppvObject);
}
LineNumber(
/* [in] */ IMalloc *pMalloc,
/* [in] */ Session *pSession,
/* [in] */ const llvm::Instruction * inst);
const llvm::DebugLoc &DL() const;
STDMETHODIMP get_compiland(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_sourceFile(
/* [retval][out] */ IDiaSourceFile **pRetVal) override;
STDMETHODIMP get_lineNumber(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_lineNumberEnd(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_columnNumber(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_columnNumberEnd(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_addressSection(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_addressOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_relativeVirtualAddress(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_virtualAddress(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_length(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_sourceFileId(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_statement(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_compilandId(
/* [retval][out] */ DWORD *pRetVal) override;
};
class LineNumbersTable : public impl::TableBase<IDiaEnumLineNumbers, IDiaLineNumber> {
public:
LineNumbersTable(
/* [in] */ IMalloc *pMalloc,
/* [in] */ Session *pSession);
LineNumbersTable(
/* [in] */ IMalloc *pMalloc,
/* [in] */ Session *pSession,
/* [in] */ std::vector<const llvm::Instruction*> &&instructions);
HRESULT GetItem(
/* [in] */ DWORD index,
/* [out] */ IDiaLineNumber **ppItem) override;
private:
// Keep a reference to the instructions that contain the line numbers.
const std::vector<const llvm::Instruction *> &m_instructions;
// Provide storage space for instructions for when the table contains
// a subset of all instructions.
std::vector<const llvm::Instruction *> m_instructionsStorage;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSections.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableSections.h"
#include "DxilDiaSession.h"
dxil_dia::SectionsTable::SectionsTable(IMalloc *pMalloc, Session *pSession)
: impl::TableBase<IDiaEnumSectionContribs, IDiaSectionContrib>(pMalloc, pSession, Table::Kind::Sections) {
}
HRESULT dxil_dia::SectionsTable::GetItem(DWORD index, IDiaSectionContrib **ppItem) {
*ppItem = nullptr;
return E_FAIL;
}

Просмотреть файл

@ -0,0 +1,33 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSections.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class SectionsTable : public impl::TableBase<IDiaEnumSectionContribs, IDiaSectionContrib> {
public:
SectionsTable(IMalloc *pMalloc, Session *pSession);
HRESULT GetItem(DWORD index, IDiaSectionContrib **ppItem) override;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSegmentMap.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableSegmentMap.h"
#include "DxilDiaSession.h"
dxil_dia::SegmentMapTable::SegmentMapTable(IMalloc *pMalloc, Session *pSession)
: impl::TableBase<IDiaEnumSegments, IDiaSegment>(pMalloc, pSession, Table::Kind::SegmentMap) {
}
HRESULT dxil_dia::SegmentMapTable::GetItem(DWORD index, IDiaSegment **ppItem) {
*ppItem = nullptr;
return E_FAIL;
}

Просмотреть файл

@ -0,0 +1,33 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSegmentMap.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class SegmentMapTable : public impl::TableBase<IDiaEnumSegments, IDiaSegment> {
public:
SegmentMapTable(IMalloc *pMalloc, Session *pSession);
HRESULT GetItem(DWORD index, IDiaSegment **ppItem) override;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSourceFiles.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableSourceFiles.h"
#include "DxilDiaSession.h"
dxil_dia::SourceFile::SourceFile(IMalloc *pMalloc, Session *pSession, DWORD index)
: m_pMalloc(pMalloc), m_pSession(pSession), m_index(index) {}
llvm::MDTuple *dxil_dia::SourceFile::NameContent() const {
return llvm::cast<llvm::MDTuple>(m_pSession->Contents()->getOperand(m_index));
}
llvm::StringRef dxil_dia::SourceFile::Name() const {
return llvm::dyn_cast<llvm::MDString>(NameContent()->getOperand(0))->getString();
}
STDMETHODIMP dxil_dia::SourceFile::get_uniqueId(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = m_index;
return S_OK;
}
STDMETHODIMP dxil_dia::SourceFile::get_fileName(
/* [retval][out] */ BSTR *pRetVal) {
DxcThreadMalloc TM(m_pMalloc);
return StringRefToBSTR(Name(), pRetVal);
}
dxil_dia::SourceFilesTable::SourceFilesTable(
IMalloc *pMalloc,
Session *pSession)
: impl::TableBase<IDiaEnumSourceFiles, IDiaSourceFile>(pMalloc, pSession, Table::Kind::SourceFiles) {
m_count =
(m_pSession->Contents() == nullptr) ? 0 : m_pSession->Contents()->getNumOperands();
m_items.assign(m_count, nullptr);
}
HRESULT dxil_dia::SourceFilesTable::GetItem(DWORD index, IDiaSourceFile **ppItem) {
if (!m_items[index]) {
m_items[index] = CreateOnMalloc<SourceFile>(m_pMalloc, m_pSession, index);
if (m_items[index] == nullptr)
return E_OUTOFMEMORY;
}
m_items[index].p->AddRef();
*ppItem = m_items[index];
(*ppItem)->AddRef();
return S_OK;
}

Просмотреть файл

@ -0,0 +1,79 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSourceFiles.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include <vector>
#include "dia2.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Metadata.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class SourceFile : public IDiaSourceFile {
private:
DXC_MICROCOM_TM_REF_FIELDS()
CComPtr<Session> m_pSession;
DWORD m_index;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaSourceFile>(this, iid, ppvObject);
}
SourceFile(IMalloc *pMalloc, Session *pSession, DWORD index);
llvm::MDTuple *NameContent() const;
llvm::StringRef Name() const;
STDMETHODIMP get_uniqueId(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_fileName(
/* [retval][out] */ BSTR *pRetVal) override;
STDMETHODIMP get_checksumType(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_compilands(
/* [retval][out] */ IDiaEnumSymbols **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_checksum(
/* [in] */ DWORD cbData,
/* [out] */ DWORD *pcbData,
/* [size_is][out] */ BYTE *pbData) override { return ENotImpl(); }
};
class SourceFilesTable : public impl::TableBase<IDiaEnumSourceFiles, IDiaSourceFile> {
public:
SourceFilesTable(IMalloc *pMalloc, Session *pSession);
HRESULT GetItem(DWORD index, IDiaSourceFile **ppItem) override;
private:
std::vector<CComPtr<IDiaSourceFile>> m_items;
};
} // namespace dxil_dia

Просмотреть файл

@ -0,0 +1,165 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSymbols.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. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilDiaTableSymbols.h"
#include <comdef.h>
#include "dxc/Support/Unicode.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Metadata.h"
#include "DxilDiaSession.h"
HRESULT dxil_dia::Symbol::Create(IMalloc *pMalloc, Session *pSession, DWORD index, DWORD symTag, Symbol **pSymbol) {
*pSymbol = Alloc(pMalloc);
if (*pSymbol == nullptr) return E_OUTOFMEMORY;
(*pSymbol)->AddRef();
(*pSymbol)->Init(pSession, index, symTag);
return S_OK;
}
void dxil_dia::Symbol::Init(Session *pSession, DWORD index, DWORD symTag) {
m_pSession = pSession;
m_index = index;
m_symTag = symTag;
}
STDMETHODIMP dxil_dia::Symbol::get_symIndexId(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = m_index;
return S_OK;
}
STDMETHODIMP dxil_dia::Symbol::get_symTag(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = m_symTag;
return S_OK;
}
STDMETHODIMP dxil_dia::Symbol::get_name(
/* [retval][out] */ BSTR *pRetVal) {
return m_name.CopyTo(pRetVal);
}
STDMETHODIMP dxil_dia::Symbol::get_dataKind(
/* [retval][out] */ DWORD *pRetVal) {
*pRetVal = m_dataKind;
return m_dataKind ? S_OK : S_FALSE;
}
STDMETHODIMP dxil_dia::Symbol::get_sourceFileName(
/* [retval][out] */ BSTR *pRetVal) {
if (pRetVal == nullptr) {
return E_INVALIDARG;
}
*pRetVal = m_sourceFileName.Copy();
return S_OK;
}
STDMETHODIMP dxil_dia::Symbol::get_value(
/* [retval][out] */ VARIANT *pRetVal) {
return VariantCopy(pRetVal, &m_value);
}
dxil_dia::SymbolsTable::SymbolsTable(IMalloc *pMalloc, Session *pSession)
: impl::TableBase<IDiaEnumSymbols, IDiaSymbol>(pMalloc, pSession, Table::Kind::Symbols) {
// The count is as follows:
// One symbol for the program.
// One Compiland per compilation unit.
// One CompilandDetails per compilation unit.
// Three CompilandEnv per Compliands: hlslFlags, hlslTarget, hlslEntry, hlslDefines, hlslArguments.
// One Function/Data for each global.
// One symbol for each type.
const size_t SymbolsPerCU = 1 + 1 + 5;
m_count = 1 + pSession->InfoRef().compile_unit_count() * SymbolsPerCU;
}
HRESULT dxil_dia::SymbolsTable::GetItem(DWORD index, IDiaSymbol **ppItem) {
DxcThreadMalloc TM(m_pMalloc);
// Ids are one-based, so adjust the index.
++index;
// Program symbol.
CComPtr<Symbol> item;
if (index == HlslProgramId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagExe, &item));
item->SetName(L"HLSL");
} else if (index == HlslCompilandId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompiland, &item));
item->SetName(L"main");
item->SetLexicalParent(HlslProgramId);
if (m_pSession->MainFileName()) {
llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(m_pSession->MainFileName()->getOperand(0)->getOperand(0))->getString();
std::string str(strRef.begin(), strRef.size()); // To make sure str is null terminated
item->SetSourceFileName(_bstr_t(Unicode::UTF8ToUTF16StringOrThrow(str.data()).c_str()));
}
} else if (index == HlslCompilandDetailsId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandDetails, &item));
item->SetLexicalParent(HlslCompilandId);
// TODO: complete the rest of the compiland details
// platform: 256, language: 16, frontEndMajor: 6, frontEndMinor: 3, value: 0, hasDebugInfo: 1, compilerName: comiler string goes here
} else if (index == HlslCompilandEnvFlagsId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
item->SetLexicalParent(HlslCompilandId);
item->SetName(L"hlslFlags");
item->SetValue(m_pSession->DxilModuleRef().GetGlobalFlags());
} else if (index == HlslCompilandEnvTargetId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
item->SetLexicalParent(HlslCompilandId);
item->SetName(L"hlslTarget");
item->SetValue(m_pSession->DxilModuleRef().GetShaderModel()->GetName());
} else if (index == HlslCompilandEnvEntryId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
item->SetLexicalParent(HlslCompilandId);
item->SetName(L"hlslEntry");
item->SetValue(m_pSession->DxilModuleRef().GetEntryFunctionName().c_str());
} else if (index == HlslCompilandEnvDefinesId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
item->SetLexicalParent(HlslCompilandId);
item->SetName(L"hlslDefines");
llvm::MDNode *definesNode = m_pSession->Defines()->getOperand(0);
// Construct a double null terminated string for defines with L"\0" as a delimiter
CComBSTR pBSTR;
for (llvm::MDNode::op_iterator it = definesNode->op_begin(); it != definesNode->op_end(); ++it) {
llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(*it)->getString();
std::string str(strRef.begin(), strRef.size());
CA2W cv(str.c_str());
pBSTR.Append(cv);
pBSTR.Append(L"\0", 1);
}
pBSTR.Append(L"\0", 1);
VARIANT Variant;
Variant.bstrVal = pBSTR;
Variant.vt = VARENUM::VT_BSTR;
item->SetValue(&Variant);
} else if (index == HlslCompilandEnvArgumentsId) {
IFR(Symbol::Create(m_pMalloc, m_pSession, index, SymTagCompilandEnv, &item));
item->SetLexicalParent(HlslCompilandId);
item->SetName(L"hlslArguments");
auto Arguments = m_pSession->Arguments()->getOperand(0);
auto NumArguments = Arguments->getNumOperands();
std::string args;
for (unsigned i = 0; i < NumArguments; ++i) {
llvm::StringRef strRef = llvm::dyn_cast<llvm::MDString>(Arguments->getOperand(i))->getString();
if (!args.empty())
args.push_back(' ');
args = args + strRef.str();
}
item->SetValue(args.c_str());
}
// TODO: add support for global data and functions as well as types.
*ppItem = item.Detach();
return (*ppItem == nullptr) ? E_FAIL : S_OK;
}

Просмотреть файл

@ -0,0 +1,821 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilDiaTableSymbols.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// DIA API implementation for DXIL modules. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/Support/WinIncludes.h"
#include "dia2.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/microcom.h"
#include "DxilDia.h"
#include "DxilDiaTable.h"
namespace dxil_dia {
class Session;
class Symbol : public IDiaSymbol {
DXC_MICROCOM_TM_REF_FIELDS()
CComPtr<Session> m_pSession;
DWORD m_index;
DWORD m_symTag;
DWORD m_lexicalParent = 0;
DWORD m_dataKind = 0;
CComBSTR m_sourceFileName;
CComBSTR m_name;
CComVariant m_value;
public:
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
DXC_MICROCOM_TM_CTOR(Symbol)
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
return DoBasicQueryInterface<IDiaSymbol>(this, iid, ppvObject);
}
static HRESULT Create(IMalloc *pMalloc, Session *pSession, DWORD index, DWORD symTag, Symbol **pSymbol);
void Init(Session *pSession, DWORD index, DWORD symTag);
void SetDataKind(DWORD value) { m_dataKind = value; }
void SetLexicalParent(DWORD value) { m_lexicalParent = value; }
void SetName(LPCWSTR value) { m_name = value; }
void SetValue(LPCSTR value) { m_value = value; }
void SetValue(VARIANT *pValue) { m_value.Copy(pValue); }
void SetValue(unsigned value) { m_value = value; }
void SetSourceFileName(BSTR value) { m_sourceFileName = value; }
#pragma region IDiaSymbol implementation.
STDMETHODIMP get_symIndexId(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_symTag(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_name(
/* [retval][out] */ BSTR *pRetVal) override;
STDMETHODIMP get_lexicalParent(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_classParent(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_type(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_dataKind(
/* [retval][out] */ DWORD *pRetVal) override;
STDMETHODIMP get_locationType(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_addressSection(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_addressOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_relativeVirtualAddress(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualAddress(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_registerId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_offset(
/* [retval][out] */ LONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_length(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_slot(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_volatileType(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_constType(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_unalignedType(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_access(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_libraryName(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_platform(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_language(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_editAndContinueEnabled(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_frontEndMajor(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_frontEndMinor(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_frontEndBuild(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_backEndMajor(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_backEndMinor(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_backEndBuild(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_sourceFileName(
/* [retval][out] */ BSTR *pRetVal) override;
STDMETHODIMP get_unused(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_thunkOrdinal(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_thisAdjust(
/* [retval][out] */ LONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualBaseOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtual(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_intro(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_pure(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_callingConvention(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_value(
/* [retval][out] */ VARIANT *pRetVal) override;
STDMETHODIMP get_baseType(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_token(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_timeStamp(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_guid(
/* [retval][out] */ GUID *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_symbolsFileName(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_reference(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_count(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_bitPosition(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_arrayIndexType(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_packed(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_constructor(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_overloadedOperator(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_nested(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasNestedTypes(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasAssignmentOperator(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasCastOperator(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_scoped(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualBaseClass(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_indirectVirtualBaseClass(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualBasePointerOffset(
/* [retval][out] */ LONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualTableShape(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_lexicalParentId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_classParentId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_typeId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_arrayIndexTypeId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualTableShapeId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_code(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_function(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_managed(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_msil(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualBaseDispIndex(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_undecoratedName(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_age(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_signature(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_compilerGenerated(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_addressTaken(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_rank(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_lowerBound(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_upperBound(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_lowerBoundId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_upperBoundId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_dataBytes(
/* [in] */ DWORD cbData,
/* [out] */ DWORD *pcbData,
/* [size_is][out] */ BYTE *pbData) override { return ENotImpl(); }
STDMETHODIMP findChildren(
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenEx(
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenExByAddr(
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenExByVA(
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [in] */ ULONGLONG va,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findChildrenExByRVA(
/* [in] */ enum SymTagEnum symtag,
/* [in] */ LPCOLESTR name,
/* [in] */ DWORD compareFlags,
/* [in] */ DWORD rva,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP get_targetSection(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_targetOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_targetRelativeVirtualAddress(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_targetVirtualAddress(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_machineType(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_oemId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_oemSymbolId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_types(
/* [in] */ DWORD cTypes,
/* [out] */ DWORD *pcTypes,
/* [size_is][size_is][out] */ IDiaSymbol **pTypes) override { return ENotImpl(); }
STDMETHODIMP get_typeIds(
/* [in] */ DWORD cTypeIds,
/* [out] */ DWORD *pcTypeIds,
/* [size_is][out] */ DWORD *pdwTypeIds) override { return ENotImpl(); }
STDMETHODIMP get_objectPointerType(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_udtKind(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_undecoratedNameEx(
/* [in] */ DWORD undecorateOptions,
/* [out] */ BSTR *name) override { return ENotImpl(); }
STDMETHODIMP get_noReturn(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_customCallingConvention(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_noInline(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_optimizedCodeDebugInfo(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_notReached(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_interruptReturn(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_farReturn(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isStatic(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasDebugInfo(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isLTCG(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isDataAligned(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasSecurityChecks(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_compilerName(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasAlloca(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasSetJump(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasLongJump(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasInlAsm(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasEH(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasSEH(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasEHa(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isNaked(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isAggregated(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isSplitted(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_container(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_inlSpec(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_noStackOrdering(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_virtualBaseTableType(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasManagedCode(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isHotpatchable(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isCVTCIL(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isMSILNetmodule(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isCTypes(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isStripped(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_frontEndQFE(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_backEndQFE(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_wasInlined(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_strictGSCheck(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isCxxReturnUdt(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isConstructorVirtualBase(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_RValueReference(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_unmodifiedType(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_framePointerPresent(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isSafeBuffers(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_intrinsic(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_sealed(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hfaFloat(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hfaDouble(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_liveRangeStartAddressSection(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_liveRangeStartAddressOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_liveRangeStartRelativeVirtualAddress(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_countLiveRanges(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_liveRangeLength(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_offsetInUdt(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_paramBasePointerRegisterId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_localBasePointerRegisterId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isLocationControlFlowDependent(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_stride(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_numberOfRows(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_numberOfColumns(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isMatrixRowMajor(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_numericProperties(
/* [in] */ DWORD cnt,
/* [out] */ DWORD *pcnt,
/* [size_is][out] */ DWORD *pProperties) override { return ENotImpl(); }
STDMETHODIMP get_modifierValues(
/* [in] */ DWORD cnt,
/* [out] */ DWORD *pcnt,
/* [size_is][out] */ WORD *pModifiers) override { return ENotImpl(); }
STDMETHODIMP get_isReturnValue(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isOptimizedAway(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_builtInKind(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_registerType(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_baseDataSlot(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_baseDataOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_textureSlot(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_samplerSlot(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_uavSlot(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_sizeInUdt(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_memorySpaceKind(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_unmodifiedTypeId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_subTypeId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_subType(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_numberOfModifiers(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_numberOfRegisterIndices(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isHLSLData(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isPointerToDataMember(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isPointerToMemberFunction(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isSingleInheritance(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isMultipleInheritance(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isVirtualInheritance(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_restrictedType(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isPointerBasedOnSymbolValue(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_baseSymbol(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_baseSymbolId(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_objectFileName(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isAcceleratorGroupSharedLocal(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isAcceleratorPointerTagLiveRange(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isAcceleratorStubFunction(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_numberOfAcceleratorPointerTags(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isSdl(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isWinRTPointer(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isRefUdt(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isValueUdt(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isInterfaceUdt(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP findInlineFramesByAddr(
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineFramesByRVA(
/* [in] */ DWORD rva,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineFramesByVA(
/* [in] */ ULONGLONG va,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLines(
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByAddr(
/* [in] */ DWORD isect,
/* [in] */ DWORD offset,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByRVA(
/* [in] */ DWORD rva,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findInlineeLinesByVA(
/* [in] */ ULONGLONG va,
/* [in] */ DWORD length,
/* [out] */ IDiaEnumLineNumbers **ppResult) override { return ENotImpl(); }
STDMETHODIMP findSymbolsForAcceleratorPointerTag(
/* [in] */ DWORD tagValue,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP findSymbolsByRVAForAcceleratorPointerTag(
/* [in] */ DWORD tagValue,
/* [in] */ DWORD rva,
/* [out] */ IDiaEnumSymbols **ppResult) override { return ENotImpl(); }
STDMETHODIMP get_acceleratorPointerTags(
/* [in] */ DWORD cnt,
/* [out] */ DWORD *pcnt,
/* [size_is][out] */ DWORD *pPointerTags) override { return ENotImpl(); }
STDMETHODIMP getSrcLineOnTypeDefn(
/* [out] */ IDiaLineNumber **ppResult) override { return ENotImpl(); }
STDMETHODIMP get_isPGO(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasValidPGOCounts(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_isOptimizedForSpeed(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_PGOEntryCount(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_PGOEdgeCount(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_PGODynamicInstructionCount(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_staticSize(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_finalLiveStaticSize(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_phaseName(
/* [retval][out] */ BSTR *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_hasControlFlowCheck(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_constantExport(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_dataExport(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_privateExport(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_noNameExport(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_exportHasExplicitlyAssignedOrdinal(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_exportIsForwarder(
/* [retval][out] */ BOOL *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_ordinal(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_frameSize(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_exceptionHandlerAddressSection(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_exceptionHandlerAddressOffset(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_exceptionHandlerRelativeVirtualAddress(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_exceptionHandlerVirtualAddress(
/* [retval][out] */ ULONGLONG *pRetVal) override { return ENotImpl(); }
STDMETHODIMP findInputAssemblyFile(
/* [out] */ IDiaInputAssemblyFile **ppResult) override { return ENotImpl(); }
STDMETHODIMP get_characteristics(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_coffGroup(
/* [retval][out] */ IDiaSymbol **pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_bindID(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_bindSpace(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
STDMETHODIMP get_bindSlot(
/* [retval][out] */ DWORD *pRetVal) override { return ENotImpl(); }
#pragma endregion IDiaSymbol implementation.
};
class SymbolsTable : public impl::TableBase<IDiaEnumSymbols, IDiaSymbol> {
public:
SymbolsTable(IMalloc *pMalloc, Session *pSession);
HRESULT GetItem(DWORD index, IDiaSymbol **ppItem) override;
};
} // namespace dxil_dia

16
lib/DxilDia/LLVMBuild.txt Normal file
Просмотреть файл

@ -0,0 +1,16 @@
; Copyright (C) Microsoft Corporation. All rights reserved.
; This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = DxilDia
parent = Libraries
required_libraries = Core DxcSupport Support

Просмотреть файл

@ -2,6 +2,7 @@
# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
add_llvm_library(LLVMDxilPIXPasses
DxilAddPixelHitInstrumentation.cpp
DxilAnnotateWithVirtualRegister.cpp
DxilDebugInstrumentation.cpp
DxilForceEarlyZ.cpp
DxilOutputColorBecomesConstant.cpp
@ -9,6 +10,7 @@ add_llvm_library(LLVMDxilPIXPasses
DxilReduceMSAAToSingleSample.cpp
DxilShaderAccessTracking.cpp
DxilPIXPasses.cpp
DxilPIXVirtualRegisters.cpp
ADDITIONAL_HEADER_DIRS

Просмотреть файл

@ -0,0 +1,211 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilAnnotateWithVirtualRegister.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. //
// //
// Annotates the llvm instructions with a virtual register number to be used //
// during PIX debugging. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
#include <memory>
#include "dxc/DXIL/DxilModule.h"
#include "dxc/Support/Global.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "DxilPIXVirtualRegisters.h"
#define DEBUG_TYPE "dxil-annotate-with-virtual-regs"
namespace {
using namespace pix_dxil;
class DxilAnnotateWithVirtualRegister : public llvm::ModulePass {
public:
static char ID;
DxilAnnotateWithVirtualRegister() : llvm::ModulePass(ID) {}
bool runOnModule(llvm::Module &M) override;
private:
void AnnotateValues(llvm::Instruction *pI);
void AnnotateStore(llvm::Instruction *pI);
bool IsAllocaRegisterWrite(llvm::Value *V, llvm::AllocaInst **pAI, llvm::Value **pIdx);
void AnnotateAlloca(llvm::AllocaInst *pAlloca);
void AnnotateGeneric(llvm::Instruction *pI);
void AssignNewDxilRegister(llvm::Instruction *pI);
void AssignNewAllocaRegister(llvm::AllocaInst *pAlloca, std::uint32_t C);
hlsl::DxilModule *m_DM;
std::uint32_t m_uVReg;
void Init(llvm::Module &M) {
m_DM = &M.GetOrCreateDxilModule();
m_uVReg = 0;
}
};
char DxilAnnotateWithVirtualRegister::ID = 0;
bool DxilAnnotateWithVirtualRegister::runOnModule(llvm::Module &M) {
Init(M);
if (m_DM == nullptr) {
return false;
}
if (OSOverride != nullptr) {
*OSOverride << "\nBegin - dxil values to virtual register mapping\n";
}
std::uint32_t InstNum = 0;
for (llvm::Instruction &I : llvm::inst_range(m_DM->GetEntryFunction())) {
pix_dxil::PixDxilInstNum::AddMD(M.getContext(), &I, ++InstNum);
}
for (llvm::Instruction &I : llvm::inst_range(m_DM->GetEntryFunction())) {
AnnotateValues(&I);
}
for (llvm::Instruction &I : llvm::inst_range(m_DM->GetEntryFunction())) {
AnnotateStore(&I);
}
if (OSOverride != nullptr) {
*OSOverride << "\nEnd - dxil values to virtual register mapping\n";
}
m_DM = nullptr;
return m_uVReg > 0;
}
void DxilAnnotateWithVirtualRegister::AnnotateValues(llvm::Instruction *pI) {
if (auto *pAlloca = llvm::dyn_cast<llvm::AllocaInst>(pI)) {
AnnotateAlloca(pAlloca);
} else if (!pI->getType()->isVoidTy()) {
AnnotateGeneric(pI);
}
}
void DxilAnnotateWithVirtualRegister::AnnotateStore(llvm::Instruction *pI) {
auto *pSt = llvm::dyn_cast<llvm::StoreInst>(pI);
if (pSt == nullptr) {
return;
}
llvm::AllocaInst *Alloca;
llvm::Value *Index;
if (!IsAllocaRegisterWrite(pSt->getPointerOperand(), &Alloca, &Index)) {
return;
}
llvm::MDNode *AllocaReg = Alloca->getMetadata(PixAllocaReg::MDName);
if (AllocaReg == nullptr) {
return;
}
PixAllocaRegWrite::AddMD(m_DM->GetCtx(), pSt, AllocaReg, Index);
}
bool DxilAnnotateWithVirtualRegister::IsAllocaRegisterWrite(llvm::Value *V, llvm::AllocaInst **pAI, llvm::Value **pIdx) {
llvm::IRBuilder<> B(m_DM->GetCtx());
*pAI = nullptr;
*pIdx = nullptr;
if (auto *pGEP = llvm::dyn_cast<llvm::GetElementPtrInst>(V)) {
auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(pGEP->getPointerOperand());
if (Alloca == nullptr) {
return false;
}
llvm::SmallVector<llvm::Value *, 2> Indices(pGEP->idx_begin(), pGEP->idx_end());
if (Indices.size() != 2) {
return false;
}
auto *pIdx0 = llvm::dyn_cast<llvm::ConstantInt>(Indices[0]);
if (pIdx0 == nullptr || pIdx0->getLimitedValue() != 0) {
return false;
}
*pAI = Alloca;
*pIdx = Indices[1];
return true;
}
if (auto *pAlloca = llvm::dyn_cast<llvm::AllocaInst>(V)) {
llvm::Type *pAllocaTy = pAlloca->getType()->getElementType();
if (!pAllocaTy->isFloatTy() && !pAllocaTy->isIntegerTy()) {
return false;
}
*pAI = pAlloca;
*pIdx = B.getInt32(0);
return true;
}
return false;
}
void DxilAnnotateWithVirtualRegister::AnnotateAlloca(llvm::AllocaInst *pAlloca) {
llvm::Type *pAllocaTy = pAlloca->getType()->getElementType();
if (pAllocaTy->isFloatTy() || pAllocaTy->isIntegerTy()) {
AssignNewAllocaRegister(pAlloca, 1);
} else if (auto *AT = llvm::dyn_cast<llvm::ArrayType>(pAllocaTy)) {
AssignNewAllocaRegister(pAlloca, AT->getNumElements());
} else {
DXASSERT_ARGS(false, "Unhandled alloca kind: %d", pAllocaTy->getTypeID());
}
}
void DxilAnnotateWithVirtualRegister::AnnotateGeneric(llvm::Instruction *pI) {
if (!pI->getType()->isFloatTy() && !pI->getType()->isIntegerTy()) {
return;
}
AssignNewDxilRegister(pI);
}
void DxilAnnotateWithVirtualRegister::AssignNewDxilRegister(llvm::Instruction *pI) {
PixDxilReg::AddMD(m_DM->GetCtx(), pI, m_uVReg);
if (OSOverride != nullptr) {
static constexpr bool DontPrintType = false;
pI->printAsOperand(*OSOverride, DontPrintType, m_DM->GetModule());
*OSOverride << " dxil " << m_uVReg << "\n";
}
m_uVReg++;
}
void DxilAnnotateWithVirtualRegister::AssignNewAllocaRegister(llvm::AllocaInst *pAlloca, std::uint32_t C) {
PixAllocaReg::AddMD(m_DM->GetCtx(), pAlloca, m_uVReg, C);
if (OSOverride != nullptr) {
static constexpr bool DontPrintType = false;
pAlloca->printAsOperand(*OSOverride, DontPrintType, m_DM->GetModule());
*OSOverride << " alloca " << m_uVReg << " " << C << "\n";
}
m_uVReg += C;
}
}
using namespace llvm;
INITIALIZE_PASS(DxilAnnotateWithVirtualRegister, DEBUG_TYPE, "Annotates each instruction in the DXIL module with a virtual register number", false, false)
ModulePass *llvm::createDxilAnnotateWithVirtualRegisterPass() {
return new DxilAnnotateWithVirtualRegister();
}

Просмотреть файл

@ -21,6 +21,8 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/ADT/STLExtras.h"
#include "DxilPIXVirtualRegisters.h"
using namespace llvm;
using namespace hlsl;
@ -125,6 +127,13 @@ struct DebugShaderModifierRecordDXILStepBase {
template< typename ReturnType >
struct DebugShaderModifierRecordDXILStep : public DebugShaderModifierRecordDXILStepBase {
ReturnType ReturnValue;
union {
struct {
uint32_t ValueOrdinalBase : 16;
uint32_t ValueOrdinalIndex : 16;
} Details;
uint32_t u32ValueOrdinal;
} ValueOrdinal;
};
template< >
@ -195,8 +204,6 @@ private:
std::map<uint32_t, Value *> m_IncrementInstructionBySize;
unsigned int m_InstructionIndex = 0;
struct BuilderContext {
Module &M;
DxilModule &DM;
@ -226,10 +233,12 @@ private:
void addDebugEntryValue(BuilderContext &BC, Value * TheValue);
void addInvocationStartMarker(BuilderContext &BC);
void reserveDebugEntrySpace(BuilderContext &BC, uint32_t SpaceInDwords);
void addStoreStepDebugEntry(BuilderContext &BC, StoreInst *Inst);
void addStepDebugEntry(BuilderContext &BC, Instruction *Inst);
void addStepDebugEntryValue(BuilderContext &BC, std::uint32_t InstNum, Value *V, std::uint32_t ValueOrdinal, Value *ValueOrdinalIndex);
uint32_t UAVDumpingGroundOffset();
template<typename ReturnType>
void addStepEntryForType(DebugShaderModifierRecordType RecordType, BuilderContext &BC, Instruction *Inst);
void addStepEntryForType(DebugShaderModifierRecordType RecordType, BuilderContext &BC, std::uint32_t InstNum, Value *V, std::uint32_t ValueOrdinal, Value *ValueOrdinalIndex);
};
@ -632,8 +641,7 @@ void DxilDebugInstrumentation::addInvocationStartMarker(BuilderContext &BC) {
}
template<typename ReturnType>
void DxilDebugInstrumentation::addStepEntryForType(DebugShaderModifierRecordType RecordType, BuilderContext &BC, Instruction *Inst) {
void DxilDebugInstrumentation::addStepEntryForType(DebugShaderModifierRecordType RecordType, BuilderContext &BC, std::uint32_t InstNum, Value *V, std::uint32_t ValueOrdinal, Value *ValueOrdinalIndex) {
DebugShaderModifierRecordDXILStep<ReturnType> step = {};
reserveDebugEntrySpace(BC, sizeof(step));
@ -641,41 +649,83 @@ void DxilDebugInstrumentation::addStepEntryForType(DebugShaderModifierRecordType
step.Header.Details.Type = static_cast<uint8_t>(RecordType);
addDebugEntryValue(BC, BC.HlslOP->GetU32Const(step.Header.u32Header));
addDebugEntryValue(BC, m_InvocationId);
addDebugEntryValue(BC, BC.HlslOP->GetU32Const(m_InstructionIndex++));
addDebugEntryValue(BC, BC.HlslOP->GetU32Const(InstNum));
if (RecordType != DebugShaderModifierRecordTypeDXILStepVoid) {
addDebugEntryValue(BC, Inst);
addDebugEntryValue(BC, V);
IRBuilder<> &B = BC.Builder;
Value *VO = BC.HlslOP->GetU32Const(ValueOrdinal << 16);
Value *VOI = B.CreateAnd(ValueOrdinalIndex, BC.HlslOP->GetU32Const(0xFFFF), "ValueOrdinalIndex");
Value *EncodedValueOrdinalAndIndex = BC.Builder.CreateOr(VO, VOI, "ValueOrdinal");
addDebugEntryValue(BC, EncodedValueOrdinalAndIndex);
}
}
void DxilDebugInstrumentation::addStoreStepDebugEntry(BuilderContext &BC, StoreInst *Inst) {
std::uint32_t ValueOrdinalBase;
std::uint32_t UnusedValueOrdinalSize;
llvm::Value *ValueOrdinalIndex;
if (!pix_dxil::PixAllocaRegWrite::FromInst(Inst, &ValueOrdinalBase, &UnusedValueOrdinalSize, &ValueOrdinalIndex)) {
return;
}
std::uint32_t InstNum;
if (!pix_dxil::PixDxilInstNum::FromInst(Inst, &InstNum)) {
return;
}
addStepDebugEntryValue(BC, InstNum, Inst->getValueOperand(), ValueOrdinalBase, ValueOrdinalIndex);
}
void DxilDebugInstrumentation::addStepDebugEntry(BuilderContext &BC, Instruction *Inst) {
if (Inst->getOpcode() == Instruction::OtherOps::PHI) {
return;
}
Type::TypeID ID = Inst->getType()->getTypeID();
if (auto *St = llvm::dyn_cast<llvm::StoreInst>(Inst)) {
addStoreStepDebugEntry(BC, St);
return;
}
std::uint32_t RegNum;
if (!pix_dxil::PixDxilReg::FromInst(Inst, &RegNum)) {
return;
}
std::uint32_t InstNum;
if (!pix_dxil::PixDxilInstNum::FromInst(Inst, &InstNum)) {
return;
}
addStepDebugEntryValue(BC, InstNum, Inst, RegNum, BC.Builder.getInt32(0));
}
void DxilDebugInstrumentation::addStepDebugEntryValue(BuilderContext &BC, std::uint32_t InstNum, Value *V, std::uint32_t ValueOrdinal, Value *ValueOrdinalIndex) {
const Type::TypeID ID = V->getType()->getTypeID();
switch (ID) {
case Type::TypeID::StructTyID:
case Type::TypeID::VoidTyID:
addStepEntryForType<void>(DebugShaderModifierRecordTypeDXILStepVoid, BC, Inst);
addStepEntryForType<void>(DebugShaderModifierRecordTypeDXILStepVoid, BC, InstNum, V, ValueOrdinal, ValueOrdinalIndex);
break;
case Type::TypeID::FloatTyID:
addStepEntryForType<float>(DebugShaderModifierRecordTypeDXILStepFloat, BC, Inst);
addStepEntryForType<float>(DebugShaderModifierRecordTypeDXILStepFloat, BC, InstNum, V, ValueOrdinal, ValueOrdinalIndex);
break;
case Type::TypeID::IntegerTyID:
if (Inst->getType()->getIntegerBitWidth() == 64) {
addStepEntryForType<uint64_t>(DebugShaderModifierRecordTypeDXILStepUint64, BC, Inst);
if (V->getType()->getIntegerBitWidth() == 64) {
addStepEntryForType<uint64_t>(DebugShaderModifierRecordTypeDXILStepUint64, BC, InstNum, V, ValueOrdinal, ValueOrdinalIndex);
}
else {
addStepEntryForType<uint32_t>(DebugShaderModifierRecordTypeDXILStepUint32, BC, Inst);
addStepEntryForType<uint32_t>(DebugShaderModifierRecordTypeDXILStepUint32, BC, InstNum, V, ValueOrdinal, ValueOrdinalIndex);
}
break;
case Type::TypeID::DoubleTyID:
addStepEntryForType<double>(DebugShaderModifierRecordTypeDXILStepDouble, BC, Inst);
addStepEntryForType<double>(DebugShaderModifierRecordTypeDXILStepDouble, BC, InstNum, V, ValueOrdinal, ValueOrdinalIndex);
break;
case Type::TypeID::HalfTyID:
addStepEntryForType<float>(DebugShaderModifierRecordTypeDXILStepFloat, BC, Inst);
addStepEntryForType<float>(DebugShaderModifierRecordTypeDXILStepFloat, BC, InstNum, V, ValueOrdinal, ValueOrdinalIndex);
break;
case Type::TypeID::PointerTyID:
// Skip pointer calculation instructions. They aren't particularly meaningful to the user (being a mere
@ -741,10 +791,9 @@ bool DxilDebugInstrumentation::runOnModule(Module &M) {
// Instrument original instructions:
for (auto & Inst : AllInstructions) {
// Instrumentation goes after the instruction if it has a return value.
// Otherwise, the instruction might be a terminator so we HAVE to put the instrumentation before
if (Inst->getType()->getTypeID() != Type::TypeID::VoidTyID) {
// Has a return type, so can't be a terminator, so start inserting before the next instruction
// Instrumentation goes after the instruction if it is not a terminator. Otherwise,
// Instrumentation goes prior to the instruction.
if (!Inst->isTerminator()) {
IRBuilder<> Builder(Inst->getNextNode());
BuilderContext BC2{ BC.M, BC.DM, BC.Ctx, BC.HlslOP, Builder };
addStepDebugEntry(BC2, Inst);

Просмотреть файл

@ -31,6 +31,7 @@ HRESULT SetupRegistryPassForPIX() {
/* <py::lines('INIT-PASSES')>hctdb_instrhelp.get_init_passes(set(["pix"]))</py>*/
// INIT-PASSES:BEGIN
initializeDxilAddPixelHitInstrumentationPass(Registry);
initializeDxilAnnotateWithVirtualRegisterPass(Registry);
initializeDxilDebugInstrumentationPass(Registry);
initializeDxilForceEarlyZPass(Registry);
initializeDxilOutputColorBecomesConstantPass(Registry);

Просмотреть файл

@ -0,0 +1,169 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilPIXVirtualRegisters.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. //
// //
// Defines functions for dealing with the virtual register annotations in //
// DXIL instructions. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilPIXVirtualRegisters.h"
#include "dxc/Support/Global.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Type.h"
static llvm::Metadata *MetadataForValue(llvm::Value *V) {
if (auto *C = llvm::dyn_cast<llvm::Constant>(V)) {
return llvm::ConstantAsMetadata::get(C);
}
return llvm::ValueAsMetadata::get(V);
}
void pix_dxil::PixDxilInstNum::AddMD(llvm::LLVMContext &Ctx, llvm::Instruction *pI, std::uint32_t InstNum) {
llvm::IRBuilder<> B(Ctx);
pI->setMetadata(
llvm::StringRef(MDName),
llvm::MDNode::get(Ctx, { llvm::ConstantAsMetadata::get(B.getInt32(ID)),
llvm::ConstantAsMetadata::get(B.getInt32(InstNum)) }));
}
bool pix_dxil::PixDxilInstNum::FromInst(llvm::Instruction *pI, std::uint32_t *pInstNum) {
*pInstNum = 0;
auto *mdNodes = pI->getMetadata(MDName);
if (mdNodes == nullptr) {
return false;
}
if (mdNodes->getNumOperands() != 2) {
return false;
}
auto *mdID = llvm::mdconst::dyn_extract<llvm::ConstantInt>(mdNodes->getOperand(0));
if (mdID == nullptr || mdID->getLimitedValue() != ID) {
return false;
}
auto *mdInstNum = llvm::mdconst::dyn_extract<llvm::ConstantInt>(mdNodes->getOperand(1));
if (mdInstNum == nullptr) {
return false;
}
*pInstNum = mdInstNum->getLimitedValue();
return true;
}
void pix_dxil::PixDxilReg::AddMD(llvm::LLVMContext &Ctx, llvm::Instruction *pI, std::uint32_t RegNum) {
llvm::IRBuilder<> B(Ctx);
pI->setMetadata(
llvm::StringRef(MDName),
llvm::MDNode::get(Ctx, { llvm::ConstantAsMetadata::get(B.getInt32(ID)),
llvm::ConstantAsMetadata::get(B.getInt32(RegNum)) }));
}
bool pix_dxil::PixDxilReg::FromInst(llvm::Instruction *pI, std::uint32_t *pRegNum) {
*pRegNum = 0;
auto *mdNodes = pI->getMetadata(MDName);
if (mdNodes == nullptr) {
return false;
}
if (mdNodes->getNumOperands() != 2) {
return false;
}
auto *mdID = llvm::mdconst::dyn_extract<llvm::ConstantInt>(mdNodes->getOperand(0));
if (mdID == nullptr || mdID->getLimitedValue() != ID) {
return false;
}
auto *mdRegNum = llvm::mdconst::dyn_extract<llvm::ConstantInt>(mdNodes->getOperand(1));
if (mdRegNum == nullptr) {
return false;
}
*pRegNum = mdRegNum->getLimitedValue();
return true;
}
static bool ParsePixAllocaReg(llvm::MDNode *MD, std::uint32_t *RegNum, std::uint32_t *Count) {
if (MD->getNumOperands() != 3) {
return false;
}
auto *mdID = llvm::mdconst::dyn_extract<llvm::ConstantInt>(MD->getOperand(0));
if (mdID == nullptr || mdID->getLimitedValue() != pix_dxil::PixAllocaReg::ID) {
return false;
}
auto *mdRegNum = llvm::mdconst::dyn_extract<llvm::ConstantInt>(MD->getOperand(1));
auto *mdCount = llvm::mdconst::dyn_extract<llvm::ConstantInt>(MD->getOperand(2));
if (mdRegNum == nullptr || mdCount == nullptr) {
return false;
}
*RegNum = mdRegNum->getLimitedValue();
*Count = mdCount->getLimitedValue();
return true;
}
void pix_dxil::PixAllocaReg::AddMD(llvm::LLVMContext &Ctx, llvm::AllocaInst *pAlloca, std::uint32_t RegNum, std::uint32_t Count) {
llvm::IRBuilder<> B(Ctx);
pAlloca->setMetadata(
llvm::StringRef(MDName),
llvm::MDNode::get(Ctx, { llvm::ConstantAsMetadata::get(B.getInt32(ID)),
llvm::ConstantAsMetadata::get(B.getInt32(RegNum)),
llvm::ConstantAsMetadata::get(B.getInt32(Count)) }));
}
void pix_dxil::PixAllocaRegWrite::AddMD(llvm::LLVMContext &Ctx, llvm::StoreInst *pSt, llvm::MDNode *pAllocaReg, llvm::Value *Index) {
llvm::IRBuilder<> B(Ctx);
pSt->setMetadata(
llvm::StringRef(MDName),
llvm::MDNode::get(Ctx, { llvm::ConstantAsMetadata::get(B.getInt32(ID)),
pAllocaReg,
MetadataForValue(Index) }));
}
bool pix_dxil::PixAllocaRegWrite::FromInst(llvm::StoreInst *pI, std::uint32_t *pRegBase, std::uint32_t *pRegSize, llvm::Value **pIndex) {
*pRegBase = 0;
*pRegSize = 0;
*pIndex = nullptr;
auto *mdNodes = pI->getMetadata(MDName);
if (mdNodes == nullptr || mdNodes->getNumOperands() != 3) {
return false;
}
auto *mdID = llvm::mdconst::dyn_extract<llvm::ConstantInt>(mdNodes->getOperand(0));
if (mdID == nullptr || mdID->getLimitedValue() != ID) {
return false;
}
auto *mdAllocaReg = llvm::dyn_cast<llvm::MDNode>(mdNodes->getOperand(1));
if (mdAllocaReg == nullptr || !ParsePixAllocaReg(mdAllocaReg, pRegBase, pRegSize)) {
return false;
}
auto *mdIndex = llvm::dyn_cast<llvm::ValueAsMetadata>(mdNodes->getOperand(2));
if (mdIndex == nullptr) {
return false;
}
*pIndex = mdIndex->getValue();
return true;
}

Просмотреть файл

@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilPIXVirtualRegisters.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. //
// //
// Declares functions for dealing with the virtual register annotations in //
// DXIL instructions. //
// //
///////////////////////////////////////////////////////////////////////////////
#include <cstdint>
namespace llvm {
class AllocaInst;
class Instruction;
class LLVMContext;
class MDNode;
class StoreInst;
class Value;
} // namespace llvm
namespace pix_dxil {
namespace PixDxilInstNum {
static constexpr char MDName[] = "pix-dxil-inst-num";
static constexpr uint32_t ID = 3;
void AddMD(llvm::LLVMContext &Ctx, llvm::Instruction *pI, std::uint32_t InstNum);
bool FromInst(llvm::Instruction *pI, std::uint32_t *pInstNum);
} // namespace PixDxilInstNum
namespace PixDxilReg {
static constexpr char MDName[] = "pix-dxil-reg";
static constexpr uint32_t ID = 0;
void AddMD(llvm::LLVMContext &Ctx, llvm::Instruction *pI, std::uint32_t RegNum);
bool FromInst(llvm::Instruction *pI, std::uint32_t *pRegNum);
} // namespace PixDxilReg
namespace PixAllocaReg {
static constexpr char MDName[] = "pix-alloca-reg";
static constexpr uint32_t ID = 1;
void AddMD(llvm::LLVMContext &Ctx, llvm::AllocaInst *pAlloca, std::uint32_t RegNum, std::uint32_t Count);
} // namespace PixAllocaReg
namespace PixAllocaRegWrite {
static constexpr char MDName[] = "pix-alloca-reg-write";
static constexpr uint32_t ID = 2;
void AddMD(llvm::LLVMContext &Ctx, llvm::StoreInst *pSt, llvm::MDNode *pAllocaReg, llvm::Value *Index);
bool FromInst(llvm::StoreInst *pI, std::uint32_t *pRegBase, std::uint32_t *pRegSize, llvm::Value **pIndex);
} // namespace PixAllocaRegWrite
} // namespace pix_dxil

Просмотреть файл

@ -16,6 +16,7 @@ add_llvm_library(LLVMHLSL
DxilPackSignatureElement.cpp
DxilPatchShaderRecordBindings.cpp
DxilPreserveAllOutputs.cpp
DxilSimpleGVNHoist.cpp
DxilSignatureValidation.cpp
DxilTargetLowering.cpp
DxilTargetTransformInfo.cpp

Просмотреть файл

@ -98,11 +98,13 @@ HRESULT SetupRegistryPassForHLSL() {
initializeDxilLegalizeResourcesPass(Registry);
initializeDxilLegalizeSampleOffsetPassPass(Registry);
initializeDxilLoadMetadataPass(Registry);
initializeDxilLoopUnrollPass(Registry);
initializeDxilLowerCreateHandleForLibPass(Registry);
initializeDxilPrecisePropagatePassPass(Registry);
initializeDxilPreserveAllOutputsPass(Registry);
initializeDxilPromoteLocalResourcesPass(Registry);
initializeDxilPromoteStaticResourcesPass(Registry);
initializeDxilSimpleGVNHoistPass(Registry);
initializeDxilTranslateRawBufferPass(Registry);
initializeDynamicIndexingVectorToArrayPass(Registry);
initializeEarlyCSELegacyPassPass(Registry);
@ -203,7 +205,7 @@ static ArrayRef<LPCSTR> GetPassArgNames(LPCSTR passName) {
static const LPCSTR LowerExpectIntrinsicArgs[] = { "likely-branch-weight", "unlikely-branch-weight" };
static const LPCSTR MergeFunctionsArgs[] = { "mergefunc-sanity" };
static const LPCSTR RewriteSymbolsArgs[] = { "DL", "rewrite-map-file" };
static const LPCSTR SROAArgs[] = { "RequiresDomTree", "force-ssa-updater", "sroa-random-shuffle-slices", "sroa-strict-inbounds" };
static const LPCSTR SROAArgs[] = { "RequiresDomTree", "SkipHLSLMat", "force-ssa-updater", "sroa-random-shuffle-slices", "sroa-strict-inbounds" };
static const LPCSTR SROA_DTArgs[] = { "Threshold", "StructMemberThreshold", "ArrayElementThreshold", "ScalarLoadThreshold" };
static const LPCSTR SROA_SSAUpArgs[] = { "Threshold", "StructMemberThreshold", "ArrayElementThreshold", "ScalarLoadThreshold" };
static const LPCSTR SampleProfileLoaderArgs[] = { "sample-profile-file", "sample-profile-max-propagate-iterations" };
@ -276,7 +278,7 @@ static ArrayRef<LPCSTR> GetPassArgDescriptions(LPCSTR passName) {
static const LPCSTR LowerExpectIntrinsicArgs[] = { "Weight of the branch likely to be taken (default = 64)", "Weight of the branch unlikely to be taken (default = 4)" };
static const LPCSTR MergeFunctionsArgs[] = { "How many functions in module could be used for MergeFunctions pass sanity check. '0' disables this check. Works only with '-debug' key." };
static const LPCSTR RewriteSymbolsArgs[] = { "None", "None" };
static const LPCSTR SROAArgs[] = { "None", "Force the pass to not use DomTree and mem2reg, insteadforming SSA values through the SSAUpdater infrastructure.", "Enable randomly shuffling the slices to help uncover instability in their order.", "Experiment with completely strict handling of inbounds GEPs." };
static const LPCSTR SROAArgs[] = { "None", "None", "Force the pass to not use DomTree and mem2reg, insteadforming SSA values through the SSAUpdater infrastructure.", "Enable randomly shuffling the slices to help uncover instability in their order.", "Experiment with completely strict handling of inbounds GEPs." };
static const LPCSTR SROA_DTArgs[] = { "None", "None", "None", "None" };
static const LPCSTR SROA_SSAUpArgs[] = { "None", "None", "None", "None" };
static const LPCSTR SampleProfileLoaderArgs[] = { "None", "None" };
@ -341,6 +343,7 @@ static bool IsPassOptionName(StringRef S) {
|| S.equals("RequiresDomTree")
|| S.equals("Runtime")
|| S.equals("ScalarLoadThreshold")
|| S.equals("SkipHLSLMat")
|| S.equals("StructMemberThreshold")
|| S.equals("TIRA")
|| S.equals("TLIImpl")

Просмотреть файл

@ -1534,7 +1534,7 @@ Type *UpdateFieldTypeForLegacyLayout(Type *Ty, bool IsCBuf,
return Ty;
else
return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
} else if (HLMatrixLower::IsMatrixType(Ty)) {
} else if (dxilutil::IsHLSLMatrixType(Ty)) {
DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
unsigned rows, cols;
Type *EltTy = HLMatrixLower::GetMatrixInfo(Ty, cols, rows);

Просмотреть файл

@ -765,7 +765,7 @@ HRESULT CShaderReflectionType::Initialize(
llvm::Type* elementType = type->getArrayElementType();
// Note: At this point an HLSL matrix type may appear as an ordinary
// array (not wrapped in a `struct`), so `HLMatrixLower::IsMatrixType()`
// array (not wrapped in a `struct`), so `dxilutil::IsHLSLMatrixType()`
// is not sufficient. Instead we need to check the field annotation.
//
// We might have an array of matrices, though, so we only exit if

Просмотреть файл

@ -1412,8 +1412,17 @@ void DxilTranslateRawBuffer::ReplaceRawBufferLoad64Bit(Function *F, Type *EltTy,
for (unsigned i = 0; i < size; i++) {
if (i == 2) {
// Update offset 4 by 4 bytes.
args[DXIL::OperandIndex::kRawBufferLoadElementOffsetOpIdx] =
if (isa<UndefValue>(offset)) {
// [RW]ByteAddressBuffer has undef element offset -> update index
Value *index = CI->getArgOperand(DXIL::OperandIndex::kRawBufferLoadIndexOpIdx);
args[DXIL::OperandIndex::kRawBufferLoadIndexOpIdx] =
Builder.CreateAdd(index, Builder.getInt32(4 * 4));
}
else {
// [RW]StructuredBuffer -> update element offset
args[DXIL::OperandIndex::kRawBufferLoadElementOffsetOpIdx] =
Builder.CreateAdd(offset, Builder.getInt32(4 * 4));
}
args[DXIL::OperandIndex::kRawBufferLoadMaskOpIdx] =
Builder.getInt8(maskHi);
newLd = Builder.CreateCall(bufLd, args);
@ -1531,10 +1540,20 @@ void DxilTranslateRawBuffer::ReplaceRawBufferStore64Bit(Function *F, Type *ETy,
Builder.CreateCall(newFunction, args);
if (maskHi) {
Value *offset = args[DXIL::OperandIndex::kBufferStoreCoord1OpIdx];
// Update offset 4 by 4 bytes.
offset = Builder.CreateAdd(offset, Builder.getInt32(4 * 4));
args[DXIL::OperandIndex::kRawBufferStoreElementOffsetOpIdx] = offset;
Value *offset = args[DXIL::OperandIndex::kBufferStoreCoord1OpIdx];
if (isa<UndefValue>(offset)) {
// [RW]ByteAddressBuffer has element offset == undef -> update index instead
Value *index = args[DXIL::OperandIndex::kBufferStoreCoord0OpIdx];
index = Builder.CreateAdd(index, Builder.getInt32(4 * 4));
args[DXIL::OperandIndex::kRawBufferStoreIndexOpIdx] = index;
}
else {
// [RW]StructuredBuffer -> update element offset
offset = Builder.CreateAdd(offset, Builder.getInt32(4 * 4));
args[DXIL::OperandIndex::kRawBufferStoreElementOffsetOpIdx] = offset;
}
args[DXIL::OperandIndex::kRawBufferStoreMaskOpIdx] =
Builder.getInt8(maskHi);
args[DXIL::OperandIndex::kRawBufferStoreVal0OpIdx] = vals32[4];

Просмотреть файл

@ -1027,7 +1027,7 @@ void DxilLinkJob::RunPreparePass(Module &M) {
PM.add(createDxilDeadFunctionEliminationPass());
// SROA
PM.add(createSROAPass(/*RequiresDomTree*/false));
PM.add(createSROAPass(/*RequiresDomTree*/false, /*SkipHLSLMat*/false));
// Remove MultiDimArray from function call arg.
PM.add(createMultiDimArrayToOneDimArrayPass());

Просмотреть файл

@ -0,0 +1,566 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilSimpleGVNHoist.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. //
// //
// A simple version of GVN hoist for DXIL. //
// Based on GVNHoist in LLVM 6.0. // //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/HLSL/DxilGenerationPass.h"
#include "dxc/DXIL/DxilOperations.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instructions.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/CFG.h"
using namespace llvm;
using namespace hlsl;
///////////////////////////////////////////////////////////////////////////////
namespace {
struct Expression {
uint32_t opcode;
Type *type;
bool commutative = false;
SmallVector<uint32_t, 4> varargs;
Expression(uint32_t o = ~2U) : opcode(o) {}
bool operator==(const Expression &other) const {
if (opcode != other.opcode)
return false;
if (opcode == ~0U || opcode == ~1U)
return true;
if (type != other.type)
return false;
if (varargs != other.varargs)
return false;
return true;
}
friend hash_code hash_value(const Expression &Value) {
return hash_combine(
Value.opcode, Value.type,
hash_combine_range(Value.varargs.begin(), Value.varargs.end()));
}
};
}
namespace llvm {
template <> struct DenseMapInfo<Expression> {
static inline Expression getEmptyKey() { return ~0U; }
static inline Expression getTombstoneKey() { return ~1U; }
static unsigned getHashValue(const Expression &e) {
using llvm::hash_value;
return static_cast<unsigned>(hash_value(e));
}
static bool isEqual(const Expression &LHS, const Expression &RHS) {
return LHS == RHS;
}
};
} // namespace llvm
namespace {
// Simple Value table which support DXIL operation.
class ValueTable {
DenseMap<Value *, uint32_t> valueNumbering;
DenseMap<Expression, uint32_t> expressionNumbering;
// Expressions is the vector of Expression. ExprIdx is the mapping from
// value number to the index of Expression in Expressions. We use it
// instead of a DenseMap because filling such mapping is faster than
// filling a DenseMap and the compile time is a little better.
uint32_t nextExprNumber;
std::vector<Expression> Expressions;
std::vector<uint32_t> ExprIdx;
DominatorTree *DT;
uint32_t nextValueNumber = 1;
Expression createExpr(Instruction *I);
Expression createCmpExpr(unsigned Opcode, CmpInst::Predicate Predicate,
Value *LHS, Value *RHS);
Expression createExtractvalueExpr(ExtractValueInst *EI);
uint32_t lookupOrAddCall(CallInst *C);
std::pair<uint32_t, bool> assignExpNewValueNum(Expression &exp);
public:
ValueTable();
ValueTable(const ValueTable &Arg);
ValueTable(ValueTable &&Arg);
~ValueTable();
uint32_t lookupOrAdd(Value *V);
uint32_t lookup(Value *V, bool Verify = true) const;
uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred, Value *LHS,
Value *RHS);
bool exists(Value *V) const;
void add(Value *V, uint32_t num);
void clear();
void erase(Value *v);
void setDomTree(DominatorTree *D) { DT = D; }
uint32_t getNextUnusedValueNumber() { return nextValueNumber; }
void verifyRemoved(const Value *) const;
};
//===----------------------------------------------------------------------===//
// ValueTable Internal Functions
//===----------------------------------------------------------------------===//
Expression ValueTable::createExpr(Instruction *I) {
Expression e;
e.type = I->getType();
e.opcode = I->getOpcode();
for (Instruction::op_iterator OI = I->op_begin(), OE = I->op_end();
OI != OE; ++OI)
e.varargs.push_back(lookupOrAdd(*OI));
if (I->isCommutative()) {
// Ensure that commutative instructions that only differ by a permutation
// of their operands get the same value number by sorting the operand value
// numbers. Since all commutative instructions have two operands it is more
// efficient to sort by hand rather than using, say, std::sort.
assert(I->getNumOperands() == 2 && "Unsupported commutative instruction!");
if (e.varargs[0] > e.varargs[1])
std::swap(e.varargs[0], e.varargs[1]);
e.commutative = true;
}
if (CmpInst *C = dyn_cast<CmpInst>(I)) {
// Sort the operand value numbers so x<y and y>x get the same value number.
CmpInst::Predicate Predicate = C->getPredicate();
if (e.varargs[0] > e.varargs[1]) {
std::swap(e.varargs[0], e.varargs[1]);
Predicate = CmpInst::getSwappedPredicate(Predicate);
}
e.opcode = (C->getOpcode() << 8) | Predicate;
e.commutative = true;
}
else if (InsertValueInst *E = dyn_cast<InsertValueInst>(I)) {
for (InsertValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end();
II != IE; ++II)
e.varargs.push_back(*II);
}
return e;
}
Expression ValueTable::createCmpExpr(unsigned Opcode,
CmpInst::Predicate Predicate,
Value *LHS, Value *RHS) {
assert((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&
"Not a comparison!");
Expression e;
e.type = CmpInst::makeCmpResultType(LHS->getType());
e.varargs.push_back(lookupOrAdd(LHS));
e.varargs.push_back(lookupOrAdd(RHS));
// Sort the operand value numbers so x<y and y>x get the same value number.
if (e.varargs[0] > e.varargs[1]) {
std::swap(e.varargs[0], e.varargs[1]);
Predicate = CmpInst::getSwappedPredicate(Predicate);
}
e.opcode = (Opcode << 8) | Predicate;
e.commutative = true;
return e;
}
Expression ValueTable::createExtractvalueExpr(ExtractValueInst *EI) {
assert(EI && "Not an ExtractValueInst?");
Expression e;
e.type = EI->getType();
e.opcode = 0;
IntrinsicInst *I = dyn_cast<IntrinsicInst>(EI->getAggregateOperand());
if (I != nullptr && EI->getNumIndices() == 1 && *EI->idx_begin() == 0) {
// EI might be an extract from one of our recognised intrinsics. If it
// is we'll synthesize a semantically equivalent expression instead on
// an extract value expression.
switch (I->getIntrinsicID()) {
case Intrinsic::sadd_with_overflow:
case Intrinsic::uadd_with_overflow:
e.opcode = Instruction::Add;
break;
case Intrinsic::ssub_with_overflow:
case Intrinsic::usub_with_overflow:
e.opcode = Instruction::Sub;
break;
case Intrinsic::smul_with_overflow:
case Intrinsic::umul_with_overflow:
e.opcode = Instruction::Mul;
break;
default:
break;
}
if (e.opcode != 0) {
// Intrinsic recognized. Grab its args to finish building the expression.
assert(I->getNumArgOperands() == 2 &&
"Expect two args for recognised intrinsics.");
e.varargs.push_back(lookupOrAdd(I->getArgOperand(0)));
e.varargs.push_back(lookupOrAdd(I->getArgOperand(1)));
return e;
}
}
// Not a recognised intrinsic. Fall back to producing an extract value
// expression.
e.opcode = EI->getOpcode();
for (Instruction::op_iterator OI = EI->op_begin(), OE = EI->op_end();
OI != OE; ++OI)
e.varargs.push_back(lookupOrAdd(*OI));
for (ExtractValueInst::idx_iterator II = EI->idx_begin(), IE = EI->idx_end();
II != IE; ++II)
e.varargs.push_back(*II);
return e;
}
//===----------------------------------------------------------------------===//
// ValueTable External Functions
//===----------------------------------------------------------------------===//
ValueTable::ValueTable() = default;
ValueTable::ValueTable(const ValueTable &) = default;
ValueTable::ValueTable(ValueTable &&) = default;
ValueTable::~ValueTable() = default;
/// add - Insert a value into the table with a specified value number.
void ValueTable::add(Value *V, uint32_t num) {
valueNumbering.insert(std::make_pair(V, num));
}
uint32_t ValueTable::lookupOrAddCall(CallInst *C) {
Function *F = C->getCalledFunction();
bool bSafe = false;
if (F->hasFnAttribute(Attribute::ReadNone)) {
bSafe = true;
} else if (F->hasFnAttribute(Attribute::ReadOnly)) {
if (hlsl::OP::IsDxilOpFunc(F)) {
DXIL::OpCode Opcode = hlsl::OP::GetDxilOpFuncCallInst(C);
switch (Opcode) {
default:
break;
// TODO: make buffer/texture load on srv safe.
case DXIL::OpCode::CreateHandleForLib:
case DXIL::OpCode::CBufferLoad:
case DXIL::OpCode::CBufferLoadLegacy:
case DXIL::OpCode::Sample:
case DXIL::OpCode::SampleBias:
case DXIL::OpCode::SampleCmp:
case DXIL::OpCode::SampleCmpLevelZero:
case DXIL::OpCode::SampleGrad:
case DXIL::OpCode::CheckAccessFullyMapped:
case DXIL::OpCode::GetDimensions:
case DXIL::OpCode::TextureGather:
case DXIL::OpCode::TextureGatherCmp:
case DXIL::OpCode::Texture2DMSGetSamplePosition:
case DXIL::OpCode::RenderTargetGetSampleCount:
case DXIL::OpCode::RenderTargetGetSamplePosition:
case DXIL::OpCode::CalculateLOD:
bSafe = true;
break;
}
}
}
if (bSafe) {
Expression exp = createExpr(C);
uint32_t e = assignExpNewValueNum(exp).first;
valueNumbering[C] = e;
return e;
} else {
// Not sure safe or not, always use new value number.
valueNumbering[C] = nextValueNumber;
return nextValueNumber++;
}
}
/// Returns true if a value number exists for the specified value.
bool ValueTable::exists(Value *V) const { return valueNumbering.count(V) != 0; }
/// lookup_or_add - Returns the value number for the specified value, assigning
/// it a new number if it did not have one before.
uint32_t ValueTable::lookupOrAdd(Value *V) {
DenseMap<Value*, uint32_t>::iterator VI = valueNumbering.find(V);
if (VI != valueNumbering.end())
return VI->second;
if (!isa<Instruction>(V)) {
valueNumbering[V] = nextValueNumber;
return nextValueNumber++;
}
Instruction* I = cast<Instruction>(V);
Expression exp;
switch (I->getOpcode()) {
case Instruction::Call:
return lookupOrAddCall(cast<CallInst>(I));
case Instruction::Add:
case Instruction::FAdd:
case Instruction::Sub:
case Instruction::FSub:
case Instruction::Mul:
case Instruction::FMul:
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::FDiv:
case Instruction::URem:
case Instruction::SRem:
case Instruction::FRem:
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
case Instruction::ICmp:
case Instruction::FCmp:
case Instruction::Trunc:
case Instruction::ZExt:
case Instruction::SExt:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::UIToFP:
case Instruction::SIToFP:
case Instruction::FPTrunc:
case Instruction::FPExt:
case Instruction::PtrToInt:
case Instruction::IntToPtr:
case Instruction::BitCast:
case Instruction::Select:
case Instruction::ExtractElement:
case Instruction::InsertElement:
case Instruction::ShuffleVector:
case Instruction::InsertValue:
case Instruction::GetElementPtr:
exp = createExpr(I);
break;
case Instruction::ExtractValue:
exp = createExtractvalueExpr(cast<ExtractValueInst>(I));
break;
case Instruction::PHI:
valueNumbering[V] = nextValueNumber;
return nextValueNumber++;
default:
valueNumbering[V] = nextValueNumber;
return nextValueNumber++;
}
uint32_t e = assignExpNewValueNum(exp).first;
valueNumbering[V] = e;
return e;
}
/// Returns the value number of the specified value. Fails if
/// the value has not yet been numbered.
uint32_t ValueTable::lookup(Value *V, bool Verify) const {
DenseMap<Value*, uint32_t>::const_iterator VI = valueNumbering.find(V);
if (Verify) {
assert(VI != valueNumbering.end() && "Value not numbered?");
return VI->second;
}
return (VI != valueNumbering.end()) ? VI->second : 0;
}
/// Returns the value number of the given comparison,
/// assigning it a new number if it did not have one before. Useful when
/// we deduced the result of a comparison, but don't immediately have an
/// instruction realizing that comparison to hand.
uint32_t ValueTable::lookupOrAddCmp(unsigned Opcode,
CmpInst::Predicate Predicate,
Value *LHS, Value *RHS) {
Expression exp = createCmpExpr(Opcode, Predicate, LHS, RHS);
return assignExpNewValueNum(exp).first;
}
/// Remove all entries from the ValueTable.
void ValueTable::clear() {
valueNumbering.clear();
expressionNumbering.clear();
nextValueNumber = 1;
Expressions.clear();
ExprIdx.clear();
nextExprNumber = 0;
}
/// Remove a value from the value numbering.
void ValueTable::erase(Value *V) {
valueNumbering.erase(V);
}
/// verifyRemoved - Verify that the value is removed from all internal data
/// structures.
void ValueTable::verifyRemoved(const Value *V) const {
for (DenseMap<Value*, uint32_t>::const_iterator
I = valueNumbering.begin(), E = valueNumbering.end(); I != E; ++I) {
assert(I->first != V && "Inst still occurs in value numbering map!");
}
}
/// Return a pair the first field showing the value number of \p Exp and the
/// second field showing whether it is a value number newly created.
std::pair<uint32_t, bool>
ValueTable::assignExpNewValueNum(Expression &Exp) {
uint32_t &e = expressionNumbering[Exp];
bool CreateNewValNum = !e;
if (CreateNewValNum) {
Expressions.push_back(Exp);
if (ExprIdx.size() < nextValueNumber + 1)
ExprIdx.resize(nextValueNumber * 2);
e = nextValueNumber;
ExprIdx[nextValueNumber++] = nextExprNumber++;
}
return {e, CreateNewValNum};
}
} // namespace
namespace {
// Reduce code size for pattern like this:
// if (a.x > 0) {
// r = tex.Sample(ss, uv)-1;
// } else {
// if (a.y > 0)
// r = tex.Sample(ss, uv);
// else
// r = tex.Sample(ss, uv) + 3;
// }
class DxilSimpleGVNHoist : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid
explicit DxilSimpleGVNHoist() : FunctionPass(ID) {}
const char *getPassName() const override {
return "DXIL simple GVN hoist";
}
bool runOnFunction(Function &F) override;
private:
bool tryToHoist(BasicBlock *BB, BasicBlock *Succ0, BasicBlock *Succ1);
};
char DxilSimpleGVNHoist::ID = 0;
bool HasOnePred(BasicBlock *BB) {
if (pred_empty(BB))
return false;
auto pred = pred_begin(BB);
pred++;
if (pred != pred_end(BB))
return false;
return true;
}
bool DxilSimpleGVNHoist::tryToHoist(BasicBlock *BB, BasicBlock *Succ0,
BasicBlock *Succ1) {
// ValueNumber Succ0 and Succ1.
ValueTable VT;
DenseMap<uint32_t, SmallVector<Instruction *, 2>> VNtoInsts;
for (Instruction &I : *Succ0) {
uint32_t V = VT.lookupOrAdd(&I);
VNtoInsts[V].emplace_back(&I);
}
std::vector<uint32_t> HoistCandidateVN;
for (Instruction &I : *Succ1) {
uint32_t V = VT.lookupOrAdd(&I);
if (!VNtoInsts.count(V))
continue;
VNtoInsts[V].emplace_back(&I);
HoistCandidateVN.emplace_back(V);
}
if (HoistCandidateVN.empty()) {
return false;
}
DenseSet<uint32_t> ProcessedVN;
Instruction *TI = BB->getTerminator();
// Hoist need to be in order, so operand could hoist before its users.
for (uint32_t VN : HoistCandidateVN) {
// Skip processed VN
if (ProcessedVN.count(VN))
continue;
ProcessedVN.insert(VN);
auto &Insts = VNtoInsts[VN];
if (Insts.size() == 1)
continue;
bool bHoist = false;
for (Instruction *I : Insts) {
if (I->getParent() == Succ1) {
bHoist = true;
break;
}
}
Instruction *FirstI = Insts.front();
if (bHoist) {
// Move FirstI to BB.
FirstI->removeFromParent();
FirstI->insertBefore(TI);
}
// Replace all insts with same value number with firstI.
auto it = Insts.begin();
it++;
for (; it != Insts.end(); it++) {
Instruction *I = *it;
I->replaceAllUsesWith(FirstI);
I->eraseFromParent();
}
Insts.clear();
}
return true;
}
bool DxilSimpleGVNHoist::runOnFunction(Function &F) {
BasicBlock &Entry = F.getEntryBlock();
bool bUpdated = false;
for (auto it = po_begin(&Entry); it != po_end(&Entry); it++) {
BasicBlock *BB = *it;
TerminatorInst *TI = BB->getTerminator();
if (TI->getNumSuccessors() != 2)
continue;
BasicBlock *Succ0 = TI->getSuccessor(0);
BasicBlock *Succ1 = TI->getSuccessor(1);
if (BB == Succ0)
continue;
if (BB == Succ1)
continue;
if (!HasOnePred(Succ0))
continue;
if (!HasOnePred(Succ1))
continue;
bUpdated |= tryToHoist(BB, Succ0, Succ1);
}
return bUpdated;
}
}
FunctionPass *llvm::createDxilSimpleGVNHoistPass() {
return new DxilSimpleGVNHoist();
}
INITIALIZE_PASS(DxilSimpleGVNHoist, "dxil-gvn-hoist",
"DXIL simple gvn hoist", false, false)

Просмотреть файл

@ -36,20 +36,6 @@ using namespace hlsl::HLMatrixLower;
namespace hlsl {
namespace HLMatrixLower {
bool IsMatrixType(Type *Ty) {
if (StructType *ST = dyn_cast<StructType>(Ty)) {
Type *EltTy = ST->getElementType(0);
if (!ST->getName().startswith("class.matrix"))
return false;
bool isVecArray = EltTy->isArrayTy() &&
EltTy->getArrayElementType()->isVectorTy();
return isVecArray && EltTy->getArrayNumElements() <= 4;
}
return false;
}
// If user is function call, return param annotation to get matrix major.
DxilFieldAnnotation *FindAnnotationFromMatUser(Value *Mat,
DxilTypeSystem &typeSys) {
@ -69,7 +55,7 @@ DxilFieldAnnotation *FindAnnotationFromMatUser(Value *Mat,
}
// Translate matrix type to vector type.
Type *LowerMatrixType(Type *Ty) {
Type *LowerMatrixType(Type *Ty, bool forMem) {
// Only translate matrix type and function type which use matrix type.
// Not translate struct has matrix or matrix pointer.
// Struct should be flattened before.
@ -81,9 +67,11 @@ Type *LowerMatrixType(Type *Ty) {
params.emplace_back(LowerMatrixType(param));
}
return FunctionType::get(RetTy, params, false);
} else if (IsMatrixType(Ty)) {
} else if (dxilutil::IsHLSLMatrixType(Ty)) {
unsigned row, col;
Type *EltTy = GetMatrixInfo(Ty, col, row);
if (forMem && EltTy->isIntegerTy(1))
EltTy = Type::getInt32Ty(Ty->getContext());
return VectorType::get(EltTy, row * col);
} else {
return Ty;
@ -92,7 +80,7 @@ Type *LowerMatrixType(Type *Ty) {
// Translate matrix type to array type.
Type *LowerMatrixTypeToOneDimArray(Type *Ty) {
if (IsMatrixType(Ty)) {
if (dxilutil::IsHLSLMatrixType(Ty)) {
unsigned row, col;
Type *EltTy = GetMatrixInfo(Ty, col, row);
return ArrayType::get(EltTy, row * col);
@ -103,7 +91,7 @@ Type *LowerMatrixTypeToOneDimArray(Type *Ty) {
Type *GetMatrixInfo(Type *Ty, unsigned &col, unsigned &row) {
DXASSERT(IsMatrixType(Ty), "not matrix type");
DXASSERT(dxilutil::IsHLSLMatrixType(Ty), "not matrix type");
StructType *ST = cast<StructType>(Ty);
Type *EltTy = ST->getElementType(0);
Type *RowTy = EltTy->getArrayElementType();
@ -120,9 +108,9 @@ bool IsMatrixArrayPointer(llvm::Type *Ty) {
return false;
while (Ty->isArrayTy())
Ty = Ty->getArrayElementType();
return IsMatrixType(Ty);
return dxilutil::IsHLSLMatrixType(Ty);
}
Type *LowerMatrixArrayPointer(Type *Ty) {
Type *LowerMatrixArrayPointer(Type *Ty, bool forMem) {
unsigned addrSpace = Ty->getPointerAddressSpace();
Ty = Ty->getPointerElementType();
std::vector<unsigned> arraySizeList;
@ -130,7 +118,7 @@ Type *LowerMatrixArrayPointer(Type *Ty) {
arraySizeList.push_back(Ty->getArrayNumElements());
Ty = Ty->getArrayElementType();
}
Ty = LowerMatrixType(Ty);
Ty = LowerMatrixType(Ty, forMem);
for (auto arraySize = arraySizeList.rbegin();
arraySize != arraySizeList.rend(); arraySize++)
@ -155,13 +143,69 @@ Type *LowerMatrixArrayPointerToOneDimArray(Type *Ty) {
return PointerType::get(Ty, addrSpace);
}
Value *BuildVector(Type *EltTy, unsigned size, ArrayRef<llvm::Value *> elts,
IRBuilder<> &Builder) {
IRBuilder<> &Builder) {
Value *Vec = UndefValue::get(VectorType::get(EltTy, size));
for (unsigned i = 0; i < size; i++)
Vec = Builder.CreateInsertElement(Vec, elts[i], i);
return Vec;
}
llvm::Value *VecMatrixMemToReg(llvm::Value *VecVal, llvm::Type *MatType,
llvm::IRBuilder<> &Builder)
{
llvm::Type *VecMatRegTy = HLMatrixLower::LowerMatrixType(MatType, /*forMem*/false);
if (VecVal->getType() == VecMatRegTy) {
return VecVal;
}
DXASSERT(VecMatRegTy->getVectorElementType()->isIntegerTy(1),
"Vector matrix mem to reg type mismatch should only happen for bools.");
llvm::Type *VecMatMemTy = HLMatrixLower::LowerMatrixType(MatType, /*forMem*/true);
return Builder.CreateICmpNE(VecVal, Constant::getNullValue(VecMatMemTy));
}
llvm::Value *VecMatrixRegToMem(llvm::Value* VecVal, llvm::Type *MatType,
llvm::IRBuilder<> &Builder)
{
llvm::Type *VecMatMemTy = HLMatrixLower::LowerMatrixType(MatType, /*forMem*/true);
if (VecVal->getType() == VecMatMemTy) {
return VecVal;
}
DXASSERT(VecVal->getType()->getVectorElementType()->isIntegerTy(1),
"Vector matrix reg to mem type mismatch should only happen for bools.");
return Builder.CreateZExt(VecVal, VecMatMemTy);
}
llvm::Instruction *CreateVecMatrixLoad(
llvm::Value *VecPtr, llvm::Type *MatType, llvm::IRBuilder<> &Builder)
{
llvm::Instruction *VecVal = Builder.CreateLoad(VecPtr);
return cast<llvm::Instruction>(VecMatrixMemToReg(VecVal, MatType, Builder));
}
llvm::Instruction *CreateVecMatrixStore(llvm::Value* VecVal, llvm::Value *VecPtr,
llvm::Type *MatType, llvm::IRBuilder<> &Builder)
{
llvm::Type *VecMatMemTy = HLMatrixLower::LowerMatrixType(MatType, /*forMem*/true);
if (VecVal->getType() == VecMatMemTy) {
return Builder.CreateStore(VecVal, VecPtr);
}
// We need to convert to the memory representation, and we want to return
// the conversion instruction rather than the store since that's what
// accepts the register-typed i1 values.
// Do not use VecMatrixRegToMem as it may constant fold the conversion
// instruction, which is what we want to return.
DXASSERT(VecVal->getType()->getVectorElementType()->isIntegerTy(1),
"Vector matrix reg to mem type mismatch should only happen for bools.");
llvm::Instruction *ConvInst = Builder.Insert(new ZExtInst(VecVal, VecMatMemTy));
Builder.CreateStore(ConvInst, VecPtr);
return ConvInst;
}
Value *LowerGEPOnMatIndexListToIndex(
llvm::GetElementPtrInst *GEP, ArrayRef<Value *> IdxList) {
IRBuilder<> Builder(GEP);
@ -353,41 +397,29 @@ INITIALIZE_PASS(HLMatrixLowerPass, "hlmatrixlower", "HLSL High-Level Matrix Lowe
static Instruction *CreateTypeCast(HLCastOpcode castOp, Type *toTy, Value *src,
IRBuilder<> Builder) {
// Cast to bool.
if (toTy->getScalarType()->isIntegerTy() &&
toTy->getScalarType()->getIntegerBitWidth() == 1) {
Type *fromTy = src->getType();
bool isFloat = fromTy->getScalarType()->isFloatingPointTy();
Constant *zero;
if (isFloat)
zero = llvm::ConstantFP::get(fromTy->getScalarType(), 0);
else
zero = llvm::ConstantInt::get(fromTy->getScalarType(), 0);
Type *srcTy = src->getType();
if (toTy->getScalarType() != toTy) {
// Create constant vector.
unsigned size = toTy->getVectorNumElements();
std::vector<Constant *> zeros(size, zero);
zero = llvm::ConstantVector::get(zeros);
}
if (isFloat)
return cast<Instruction>(Builder.CreateFCmpOEQ(src, zero));
else
return cast<Instruction>(Builder.CreateICmpEQ(src, zero));
}
Type *eltToTy = toTy->getScalarType();
Type *eltFromTy = src->getType()->getScalarType();
// Conversions between equivalent types are no-ops,
// even between signed/unsigned variants.
if (srcTy == toTy) return cast<Instruction>(src);
bool fromUnsigned = castOp == HLCastOpcode::FromUnsignedCast ||
castOp == HLCastOpcode::UnsignedUnsignedCast;
bool toUnsigned = castOp == HLCastOpcode::ToUnsignedCast ||
castOp == HLCastOpcode::UnsignedUnsignedCast;
Instruction::CastOps castOps = static_cast<Instruction::CastOps>(
HLModule::FindCastOp(fromUnsigned, toUnsigned, eltFromTy, eltToTy));
// Conversions to bools are comparisons
if (toTy->getScalarSizeInBits() == 1) {
// fcmp une is what regular clang uses in C++ for (bool)f;
return cast<Instruction>(srcTy->isIntOrIntVectorTy()
? Builder.CreateICmpNE(src, llvm::Constant::getNullValue(srcTy), "tobool")
: Builder.CreateFCmpUNE(src, llvm::Constant::getNullValue(srcTy), "tobool"));
}
return cast<Instruction>(Builder.CreateCast(castOps, src, toTy));
// Cast necessary
auto CastOp = static_cast<Instruction::CastOps>(HLModule::GetNumericCastOp(
srcTy, fromUnsigned, toTy, toUnsigned));
return cast<Instruction>(Builder.CreateCast(CastOp, src, toTy));
}
Instruction *HLMatrixLowerPass::MatCastToVec(CallInst *CI) {
@ -395,8 +427,8 @@ Instruction *HLMatrixLowerPass::MatCastToVec(CallInst *CI) {
Value *op = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
HLCastOpcode opcode = static_cast<HLCastOpcode>(GetHLOpcode(CI));
bool ToMat = IsMatrixType(CI->getType());
bool FromMat = IsMatrixType(op->getType());
bool ToMat = dxilutil::IsHLSLMatrixType(CI->getType());
bool FromMat = dxilutil::IsHLSLMatrixType(op->getType());
if (ToMat && !FromMat) {
// Translate OtherToMat here.
// Rest will translated when replace.
@ -468,11 +500,11 @@ Instruction *HLMatrixLowerPass::MatCastToVec(CallInst *CI) {
// UDT alloca must be there for library function args
static GetElementPtrInst *GetIfMatrixGEPOfUDTAlloca(Value *V) {
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
if (IsMatrixType(GEP->getResultElementType())) {
if (dxilutil::IsHLSLMatrixType(GEP->getResultElementType())) {
Value *ptr = GEP->getPointerOperand();
if (AllocaInst *AI = dyn_cast<AllocaInst>(ptr)) {
Type *ATy = AI->getAllocatedType();
if (ATy->isStructTy() && !IsMatrixType(ATy)) {
if (ATy->isStructTy() && !dxilutil::IsHLSLMatrixType(ATy)) {
return GEP;
}
}
@ -485,7 +517,7 @@ static GetElementPtrInst *GetIfMatrixGEPOfUDTAlloca(Value *V) {
// none-graphics functions.
static GetElementPtrInst *GetIfMatrixGEPOfUDTArg(Value *V, HLModule &HM) {
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
if (IsMatrixType(GEP->getResultElementType())) {
if (dxilutil::IsHLSLMatrixType(GEP->getResultElementType())) {
Value *ptr = GEP->getPointerOperand();
if (Argument *Arg = dyn_cast<Argument>(ptr)) {
if (!HM.IsGraphicsShader(Arg->getParent()))
@ -508,7 +540,7 @@ Instruction *HLMatrixLowerPass::MatLdStToVec(CallInst *CI) {
if (isa<AllocaInst>(matPtr) || GetIfMatrixGEPOfUDTAlloca(matPtr) ||
GetIfMatrixGEPOfUDTArg(matPtr, *m_pHLModule)) {
Value *vecPtr = matToVecMap[cast<Instruction>(matPtr)];
result = Builder.CreateLoad(vecPtr);
result = CreateVecMatrixLoad(vecPtr, matPtr->getType()->getPointerElementType(), Builder);
} else
result = MatIntrinsicToVec(CI);
} break;
@ -519,9 +551,8 @@ Instruction *HLMatrixLowerPass::MatLdStToVec(CallInst *CI) {
GetIfMatrixGEPOfUDTArg(matPtr, *m_pHLModule)) {
Value *vecPtr = matToVecMap[cast<Instruction>(matPtr)];
Value *matVal = CI->getArgOperand(HLOperandIndex::kMatStoreValOpIdx);
Value *vecVal =
UndefValue::get(HLMatrixLower::LowerMatrixType(matVal->getType()));
result = Builder.CreateStore(vecVal, vecPtr);
Value *vecVal = UndefValue::get(HLMatrixLower::LowerMatrixType(matVal->getType()));
result = CreateVecMatrixStore(vecVal, vecPtr, matVal->getType(), Builder);
} else
result = MatIntrinsicToVec(CI);
} break;
@ -609,7 +640,7 @@ Instruction *HLMatrixLowerPass::MatIntrinsicToVec(CallInst *CI) {
SmallVector<Value *, 4> argList;
for (Value *arg : CI->arg_operands()) {
Type *Ty = arg->getType();
if (IsMatrixType(Ty)) {
if (dxilutil::IsHLSLMatrixType(Ty)) {
argList.emplace_back(UndefValue::get(LowerMatrixType(Ty)));
} else
argList.emplace_back(arg);
@ -625,47 +656,53 @@ Instruction *HLMatrixLowerPass::TrivialMatUnOpToVec(CallInst *CI) {
HLUnaryOpcode opcode = static_cast<HLUnaryOpcode>(GetHLOpcode(CI));
bool isFloat = ResultTy->getVectorElementType()->isFloatingPointTy();
auto GetVecConst = [&](Type *Ty, int v) -> Constant * {
Constant *val = isFloat ? ConstantFP::get(Ty->getScalarType(), v)
: ConstantInt::get(Ty->getScalarType(), v);
std::vector<Constant *> vals(Ty->getVectorNumElements(), val);
return ConstantVector::get(vals);
};
Constant *one = GetVecConst(ResultTy, 1);
Constant *one = isFloat
? ConstantFP::get(ResultTy->getVectorElementType(), 1)
: ConstantInt::get(ResultTy->getVectorElementType(), 1);
Constant *oneVec = ConstantVector::getSplat(ResultTy->getVectorNumElements(), one);
Instruction *Result = nullptr;
switch (opcode) {
case HLUnaryOpcode::Plus: {
// This is actually a no-op, but the structure of the code here requires
// that we create an instruction.
Constant *zero = Constant::getNullValue(ResultTy);
if (isFloat)
Result = BinaryOperator::CreateFAdd(tmp, zero);
else
Result = BinaryOperator::CreateAdd(tmp, zero);
} break;
case HLUnaryOpcode::Minus: {
Constant *zero = GetVecConst(ResultTy, 0);
Constant *zero = Constant::getNullValue(ResultTy);
if (isFloat)
Result = BinaryOperator::CreateFSub(zero, tmp);
else
Result = BinaryOperator::CreateSub(zero, tmp);
} break;
case HLUnaryOpcode::LNot: {
Constant *zero = GetVecConst(ResultTy, 0);
Constant *zero = Constant::getNullValue(ResultTy);
if (isFloat)
Result = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_UNE, tmp, zero);
Result = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_UEQ, tmp, zero);
else
Result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, tmp, zero);
Result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, tmp, zero);
} break;
case HLUnaryOpcode::Not: {
Constant *allOneBits = Constant::getAllOnesValue(ResultTy);
Result = BinaryOperator::CreateXor(tmp, allOneBits);
} break;
case HLUnaryOpcode::Not:
Result = BinaryOperator::CreateXor(tmp, tmp);
break;
case HLUnaryOpcode::PostInc:
case HLUnaryOpcode::PreInc:
if (isFloat)
Result = BinaryOperator::CreateFAdd(tmp, one);
Result = BinaryOperator::CreateFAdd(tmp, oneVec);
else
Result = BinaryOperator::CreateAdd(tmp, one);
Result = BinaryOperator::CreateAdd(tmp, oneVec);
break;
case HLUnaryOpcode::PostDec:
case HLUnaryOpcode::PreDec:
if (isFloat)
Result = BinaryOperator::CreateFSub(tmp, one);
Result = BinaryOperator::CreateFSub(tmp, oneVec);
else
Result = BinaryOperator::CreateSub(tmp, one);
Result = BinaryOperator::CreateSub(tmp, oneVec);
break;
default:
DXASSERT(0, "not implement");
@ -728,12 +765,14 @@ Instruction *HLMatrixLowerPass::TrivialMatBinOpToVec(CallInst *CI) {
break;
case HLBinaryOpcode::Shl: {
Value *op1 = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc1Idx);
DXASSERT_LOCALVAR(op1, IsMatrixType(op1->getType()), "must be matrix type here");
DXASSERT_LOCALVAR(op1, dxilutil::IsHLSLMatrixType(op1->getType()),
"must be matrix type here");
Result = BinaryOperator::CreateShl(tmp, tmp);
} break;
case HLBinaryOpcode::Shr: {
Value *op1 = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc1Idx);
DXASSERT_LOCALVAR(op1, IsMatrixType(op1->getType()), "must be matrix type here");
DXASSERT_LOCALVAR(op1, dxilutil::IsHLSLMatrixType(op1->getType()),
"must be matrix type here");
Result = BinaryOperator::CreateAShr(tmp, tmp);
} break;
case HLBinaryOpcode::LT:
@ -780,7 +819,8 @@ Instruction *HLMatrixLowerPass::TrivialMatBinOpToVec(CallInst *CI) {
break;
case HLBinaryOpcode::UShr: {
Value *op1 = CI->getArgOperand(HLOperandIndex::kBinaryOpSrc1Idx);
DXASSERT_LOCALVAR(op1, IsMatrixType(op1->getType()), "must be matrix type here");
DXASSERT_LOCALVAR(op1, dxilutil::IsHLSLMatrixType(op1->getType()),
"must be matrix type here");
Result = BinaryOperator::CreateLShr(tmp, tmp);
} break;
case HLBinaryOpcode::ULT:
@ -797,33 +837,25 @@ Instruction *HLMatrixLowerPass::TrivialMatBinOpToVec(CallInst *CI) {
break;
case HLBinaryOpcode::LAnd:
case HLBinaryOpcode::LOr: {
Constant *zero;
if (isFloat)
zero = llvm::ConstantFP::get(ResultTy->getVectorElementType(), 0);
else
zero = llvm::ConstantInt::get(ResultTy->getVectorElementType(), 0);
unsigned size = ResultTy->getVectorNumElements();
std::vector<Constant *> zeros(size, zero);
Value *vecZero = llvm::ConstantVector::get(zeros);
Value *vecZero = Constant::getNullValue(ResultTy);
Instruction *cmpL;
if (isFloat)
cmpL =
CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, tmp, vecZero);
cmpL = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_ONE, tmp, vecZero);
else
cmpL = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, tmp, vecZero);
cmpL = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, tmp, vecZero);
Builder.Insert(cmpL);
Instruction *cmpR;
if (isFloat)
cmpR =
CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, tmp, vecZero);
CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_ONE, tmp, vecZero);
else
cmpR = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, tmp, vecZero);
cmpR = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, tmp, vecZero);
Builder.Insert(cmpR);
// How to map l, r back? Need check opcode
if (opcode == HLBinaryOpcode::LOr)
Result = BinaryOperator::CreateAnd(cmpL, cmpR);
Result = BinaryOperator::CreateOr(cmpL, cmpR);
else
Result = BinaryOperator::CreateAnd(cmpL, cmpR);
break;
@ -905,11 +937,11 @@ void HLMatrixLowerPass::lowerToVec(Instruction *matInst) {
IRBuilder<> AllocaBuilder(AI);
if (Ty->isArrayTy()) {
Type *vecTy = HLMatrixLower::LowerMatrixArrayPointer(AI->getType());
Type *vecTy = HLMatrixLower::LowerMatrixArrayPointer(AI->getType(), /*forMem*/ true);
vecTy = vecTy->getPointerElementType();
vecVal = AllocaBuilder.CreateAlloca(vecTy, nullptr, AI->getName());
} else {
Type *vecTy = HLMatrixLower::LowerMatrixType(matTy);
Type *vecTy = HLMatrixLower::LowerMatrixType(matTy, /*forMem*/ true);
vecVal = AllocaBuilder.CreateAlloca(vecTy, nullptr, AI->getName());
}
// Update debug info.
@ -951,23 +983,23 @@ void HLMatrixLowerPass::TrivialMatUnOpReplace(Value *matVal,
HLUnaryOpcode opcode = static_cast<HLUnaryOpcode>(GetHLOpcode(matUseInst));
Instruction *vecUseInst = cast<Instruction>(matToVecMap[matUseInst]);
switch (opcode) {
case HLUnaryOpcode::Not:
// Not is xor now
vecUseInst->setOperand(0, vecVal);
vecUseInst->setOperand(1, vecVal);
break;
case HLUnaryOpcode::LNot:
case HLUnaryOpcode::Plus: // add(x, 0)
// Ideally we'd get completely rid of the instruction for +mat,
// but matToVecMap needs to point to some instruction.
case HLUnaryOpcode::Not: // xor(x, -1)
case HLUnaryOpcode::LNot: // cmpeq(x, 0)
case HLUnaryOpcode::PostInc:
case HLUnaryOpcode::PreInc:
case HLUnaryOpcode::PostDec:
case HLUnaryOpcode::PreDec:
vecUseInst->setOperand(0, vecVal);
break;
case HLUnaryOpcode::Minus: // sub(0, x)
vecUseInst->setOperand(1, vecVal);
break;
case HLUnaryOpcode::Invalid:
case HLUnaryOpcode::Plus:
case HLUnaryOpcode::Minus:
case HLUnaryOpcode::NumOfUO:
// No VecInst replacements for these.
DXASSERT(false, "Unexpected HL unary opcode.");
break;
}
}
@ -1186,8 +1218,8 @@ void HLMatrixLowerPass::TranslateMul(Value *matVal, Value *vecVal,
Value *LVal = mulInst->getArgOperand(HLOperandIndex::kBinaryOpSrc0Idx);
Value *RVal = mulInst->getArgOperand(HLOperandIndex::kBinaryOpSrc1Idx);
bool LMat = IsMatrixType(LVal->getType());
bool RMat = IsMatrixType(RVal->getType());
bool LMat = dxilutil::IsHLSLMatrixType(LVal->getType());
bool RMat = dxilutil::IsHLSLMatrixType(RVal->getType());
if (LMat && RMat) {
TranslateMatMatMul(matVal, vecVal, mulInst, isSigned);
} else if (LMat) {
@ -1458,8 +1490,8 @@ void HLMatrixLowerPass::TranslateMatCast(Value *matVal,
opcode == HLCastOpcode::RowMatrixToColMatrix,
/*bTranspose*/false);
} else {
bool ToMat = IsMatrixType(castInst->getType());
bool FromMat = IsMatrixType(matVal->getType());
bool ToMat = dxilutil::IsHLSLMatrixType(castInst->getType());
bool FromMat = dxilutil::IsHLSLMatrixType(matVal->getType());
if (ToMat && FromMat) {
TranslateMatMatCast(matVal, vecVal, castInst);
} else if (FromMat)
@ -1903,7 +1935,7 @@ static void IterateInitList(MutableArrayRef<Value *> elts, unsigned &idx,
}
}
Type *valEltTy = val->getType()->getPointerElementType();
if (valEltTy->isVectorTy() || HLMatrixLower::IsMatrixType(valEltTy) ||
if (valEltTy->isVectorTy() || dxilutil::IsHLSLMatrixType(valEltTy) ||
valEltTy->isSingleValueType()) {
Value *ldVal = Builder.CreateLoad(val);
IterateInitList(elts, idx, ldVal, matToVecMap, Builder);
@ -1926,7 +1958,7 @@ static void IterateInitList(MutableArrayRef<Value *> elts, unsigned &idx,
}
}
}
} else if (HLMatrixLower::IsMatrixType(valTy)) {
} else if (dxilutil::IsHLSLMatrixType(valTy)) {
unsigned col, row;
HLMatrixLower::GetMatrixInfo(valTy, col, row);
unsigned matSize = col * row;
@ -2059,7 +2091,8 @@ void HLMatrixLowerPass::TranslateMatArrayGEP(Value *matInst,
// Skip the vector version.
if (useCall->getType()->isVectorTy())
continue;
Value *newLd = Builder.CreateLoad(newGEP);
Type *matTy = useCall->getType();
Value *newLd = CreateVecMatrixLoad(newGEP, matTy, Builder);
DXASSERT(matToVecMap.count(useCall), "must have vec version");
Value *oldLd = matToVecMap[useCall];
// Delete the oldLd.
@ -2082,7 +2115,7 @@ void HLMatrixLowerPass::TranslateMatArrayGEP(Value *matInst,
DXASSERT(matToVecMap.count(matInst), "must have vec version");
Value *vecVal = matToVecMap[matInst];
Builder.CreateStore(vecVal, vecPtr);
CreateVecMatrixStore(vecVal, vecPtr, matVal->getType(), Builder);
} break;
}
} break;
@ -2137,20 +2170,46 @@ void HLMatrixLowerPass::replaceMatWithVec(Value *matVal,
MatIntrinsicReplace(matCI, vecVal, useCall);
} else {
IntrinsicOp opcode = static_cast<IntrinsicOp>(GetHLOpcode(useCall));
DXASSERT_LOCALVAR(opcode, opcode == IntrinsicOp::IOP_frexp,
"otherwise, unexpected opcode with matrix out parameter");
// NOTE: because out param use copy out semantic, so the operand of
// out must be temp alloca.
DXASSERT(isa<AllocaInst>(matVal), "else invalid mat ptr for frexp");
auto it = matToVecMap.find(useCall);
DXASSERT(it != matToVecMap.end(),
"else fail to create vec version of useCall");
CallInst *vecUseInst = cast<CallInst>(it->second);
for (unsigned i = 0; i < vecUseInst->getNumArgOperands(); i++) {
if (useCall->getArgOperand(i) == matVal) {
vecUseInst->setArgOperand(i, vecVal);
if (opcode == IntrinsicOp::MOP_Append) {
// Replace matrix with vector representation and update intrinsic signature
// We don't care about matrix orientation here, since that will need to be
// taken into account anyways when generating the store output calls.
SmallVector<Value *, 4> flatArgs;
SmallVector<Type *, 4> flatParamTys;
for (Value *arg : useCall->arg_operands()) {
Value *flagArg = arg == matVal ? vecVal : arg;
flatArgs.emplace_back(arg == matVal ? vecVal : arg);
flatParamTys.emplace_back(flagArg->getType());
}
// Don't need flat return type for Append.
FunctionType *flatFuncTy =
FunctionType::get(useInst->getType(), flatParamTys, false);
Function *flatF = GetOrCreateHLFunction(*m_pModule, flatFuncTy, group, static_cast<unsigned int>(opcode));
// Append returns void, so the old call should have no users
DXASSERT(useInst->getType()->isVoidTy(), "Unexpected MOP_Append intrinsic return type");
DXASSERT(useInst->use_empty(), "Unexpected users of MOP_Append intrinsic return value");
IRBuilder<> Builder(useCall);
Builder.CreateCall(flatF, flatArgs);
AddToDeadInsts(useCall);
}
else if (opcode == IntrinsicOp::IOP_frexp) {
// NOTE: because out param use copy out semantic, so the operand of
// out must be temp alloca.
DXASSERT(isa<AllocaInst>(matVal), "else invalid mat ptr for frexp");
auto it = matToVecMap.find(useCall);
DXASSERT(it != matToVecMap.end(),
"else fail to create vec version of useCall");
CallInst *vecUseInst = cast<CallInst>(it->second);
for (unsigned i = 0; i < vecUseInst->getNumArgOperands(); i++) {
if (useCall->getArgOperand(i) == matVal) {
vecUseInst->setArgOperand(i, vecVal);
}
}
} else {
DXASSERT(false, "Unexpected matrix user intrinsic.");
}
}
} break;
@ -2174,9 +2233,17 @@ void HLMatrixLowerPass::replaceMatWithVec(Value *matVal,
// Load Already translated in lowerToVec.
// Store val operand will be set by the val use.
// Do nothing here.
} else if (StoreInst *stInst = dyn_cast<StoreInst>(vecUser))
} else if (StoreInst *stInst = dyn_cast<StoreInst>(vecUser)) {
DXASSERT(vecVal->getType() == stInst->getValueOperand()->getType(),
"Mismatched vector matrix store value types.");
stInst->setOperand(0, vecVal);
else
} else if (ZExtInst *zextInst = dyn_cast<ZExtInst>(vecUser)) {
// This happens when storing bool matrices,
// which must first undergo conversion from i1's to i32's.
DXASSERT(vecVal->getType() == zextInst->getOperand(0)->getType(),
"Mismatched vector matrix store value types.");
zextInst->setOperand(0, vecVal);
} else
TrivialMatReplace(matVal, vecVal, useCall);
} break;
@ -2411,7 +2478,7 @@ void HLMatrixLowerPass::runOnGlobal(GlobalVariable *GV) {
}
Type *Ty = GV->getType()->getPointerElementType();
if (!HLMatrixLower::IsMatrixType(Ty))
if (!dxilutil::IsHLSLMatrixType(Ty))
return;
bool onlyLdSt = OnlyUsedByMatrixLdSt(GV);
@ -2507,11 +2574,11 @@ void HLMatrixLowerPass::runOnFunction(Function &F) {
BasicBlock *BB = BBI;
for (auto II = BB->begin(); II != BB->end(); ) {
Instruction &I = *(II++);
if (IsMatrixType(I.getType())) {
if (dxilutil::IsHLSLMatrixType(I.getType())) {
lowerToVec(&I);
} else if (AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
Type *Ty = AI->getAllocatedType();
if (HLMatrixLower::IsMatrixType(Ty)) {
if (dxilutil::IsHLSLMatrixType(Ty)) {
lowerToVec(&I);
} else if (HLMatrixLower::IsMatrixArrayPointer(AI->getType())) {
lowerToVec(&I);
@ -2587,7 +2654,7 @@ Type *TryLowerMatTy(Type *Ty) {
if (HLMatrixLower::IsMatrixArrayPointer(Ty)) {
VecTy = HLMatrixLower::LowerMatrixArrayPointerToOneDimArray(Ty);
} else if (isa<PointerType>(Ty) &&
HLMatrixLower::IsMatrixType(Ty->getPointerElementType())) {
dxilutil::IsHLSLMatrixType(Ty->getPointerElementType())) {
VecTy = HLMatrixLower::LowerMatrixTypeToOneDimArray(
Ty->getPointerElementType());
VecTy = PointerType::get(VecTy, Ty->getPointerAddressSpace());
@ -2649,7 +2716,7 @@ bool MatrixBitcastLowerPass::hasCallUser(Instruction *M) {
User *U = *(it++);
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
Type *EltTy = GEP->getType()->getPointerElementType();
if (HLMatrixLower::IsMatrixType(EltTy)) {
if (dxilutil::IsHLSLMatrixType(EltTy)) {
if (hasCallUser(GEP))
return true;
} else {
@ -2704,7 +2771,7 @@ void MatrixBitcastLowerPass::lowerMatrix(Instruction *M, Value *A) {
User *U = *(it++);
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
Type *EltTy = GEP->getType()->getPointerElementType();
if (HLMatrixLower::IsMatrixType(EltTy)) {
if (dxilutil::IsHLSLMatrixType(EltTy)) {
// Change gep matrixArray, 0, index
// into
// gep oneDimArray, 0, index * matSize

Просмотреть файл

@ -957,6 +957,13 @@ void HLModule::MergeGepUse(Value *V) {
}
}
template
CallInst *HLModule::EmitHLOperationCall(IRBuilder<> &Builder,
HLOpcodeGroup group, unsigned opcode,
Type *RetType,
ArrayRef<Value *> paramList,
llvm::Module &M);
template<typename BuilderTy>
CallInst *HLModule::EmitHLOperationCall(BuilderTy &Builder,
HLOpcodeGroup group, unsigned opcode,
@ -984,54 +991,40 @@ CallInst *HLModule::EmitHLOperationCall(BuilderTy &Builder,
return Builder.CreateCall(opFunc, opcodeParamList);
}
template
CallInst *HLModule::EmitHLOperationCall(IRBuilder<> &Builder,
HLOpcodeGroup group, unsigned opcode,
Type *RetType,
ArrayRef<Value *> paramList,
llvm::Module &M);
unsigned HLModule::FindCastOp(bool fromUnsigned, bool toUnsigned,
llvm::Type *SrcTy, llvm::Type *DstTy) {
Instruction::CastOps castOp = llvm::Instruction::CastOps::BitCast;
if (SrcTy->isAggregateType() || DstTy->isAggregateType())
return llvm::Instruction::CastOps::BitCast;
unsigned HLModule::GetNumericCastOp(
llvm::Type *SrcTy, bool SrcIsUnsigned, llvm::Type *DstTy, bool DstIsUnsigned) {
DXASSERT(SrcTy != DstTy, "No-op conversions are not casts and should have been handled by the callee.");
uint32_t SrcBitSize = SrcTy->getScalarSizeInBits();
uint32_t DstBitSize = DstTy->getScalarSizeInBits();
if (SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy()) {
if (SrcBitSize > DstBitSize)
return Instruction::Trunc;
if (toUnsigned)
return Instruction::ZExt;
else
return Instruction::SExt;
}
bool SrcIsInt = SrcTy->isIntOrIntVectorTy();
bool DstIsInt = DstTy->isIntOrIntVectorTy();
if (SrcTy->isFPOrFPVectorTy() && DstTy->isFPOrFPVectorTy()) {
if (SrcBitSize > DstBitSize)
return Instruction::FPTrunc;
else
return Instruction::FPExt;
}
DXASSERT(DstBitSize != 1, "Conversions to bool are not a cast and should have been handled by the callee.");
if (SrcTy->isIntOrIntVectorTy() && DstTy->isFPOrFPVectorTy()) {
if (fromUnsigned)
return Instruction::UIToFP;
else
return Instruction::SIToFP;
}
// Conversions from bools are like unsigned integer widening
if (SrcBitSize == 1) SrcIsUnsigned = true;
if (SrcTy->isFPOrFPVectorTy() && DstTy->isIntOrIntVectorTy()) {
if (toUnsigned)
return Instruction::FPToUI;
else
return Instruction::FPToSI;
if (SrcIsInt) {
if (DstIsInt) { // int to int
if (SrcBitSize > DstBitSize) return Instruction::Trunc;
// unsigned to unsigned: zext
// unsigned to signed: zext (fully representable)
// signed to signed: sext
// signed to unsigned: sext (like C++)
return SrcIsUnsigned ? Instruction::ZExt : Instruction::SExt;
}
else { // int to float
return SrcIsUnsigned ? Instruction::UIToFP : Instruction::SIToFP;
}
}
else {
if (DstIsInt) { // float to int
return DstIsUnsigned ? Instruction::FPToUI : Instruction::FPToSI;
}
else { // float to float
return SrcBitSize > DstBitSize ? Instruction::FPTrunc : Instruction::FPExt;
}
}
DXASSERT_NOMSG(0);
return castOp;
}
bool HLModule::HasPreciseAttributeWithMetadata(Instruction *I) {

Просмотреть файл

@ -1226,7 +1226,7 @@ Value *TranslateWaveReadLaneFirst(CallInst *CI, IntrinsicOp IOP,
CI->getOperand(1)->getType(), CI, hlslOP);
}
Value *TransalteAbs(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
Value *TranslateAbs(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
hlsl::OP *hlslOP = &helper.hlslOP;
Type *pOverloadTy = CI->getType()->getScalarType();
@ -1243,6 +1243,11 @@ Value *TransalteAbs(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
}
}
Value *TranslateUAbs(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
return CI->getOperand(HLOperandIndex::kUnaryOpSrc0Idx); // No-op
}
Value *GenerateCmpNEZero(Value *val, IRBuilder<> Builder) {
Type *Ty = val->getType();
Type *EltTy = Ty->getScalarType();
@ -2195,30 +2200,26 @@ Value *TranslateSign(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
Value *val = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
Type *Ty = val->getType();
Type *EltTy = Ty->getScalarType();
IRBuilder<> Builder(CI);
bool IsInt = Ty->getScalarType()->isIntegerTy();
if (EltTy->isIntegerTy()) {
Constant *zero = ConstantInt::get(Ty->getScalarType(), 0);
if (Ty != EltTy) {
zero = ConstantVector::getSplat(Ty->getVectorNumElements(), zero);
}
Value *zeroLtVal = Builder.CreateICmpSLT(zero, val);
zeroLtVal = Builder.CreateZExt(zeroLtVal, CI->getType());
Value *valLtZero = Builder.CreateICmpSLT(val, zero);
valLtZero = Builder.CreateZExt(valLtZero, CI->getType());
return Builder.CreateSub(zeroLtVal, valLtZero);
} else {
Constant *zero = ConstantFP::get(Ty->getScalarType(), 0.0);
if (Ty != EltTy) {
zero = ConstantVector::getSplat(Ty->getVectorNumElements(), zero);
}
Value *zeroLtVal = Builder.CreateFCmpOLT(zero, val);
zeroLtVal = Builder.CreateZExt(zeroLtVal, CI->getType());
Value *valLtZero = Builder.CreateFCmpOLT(val, zero);
valLtZero = Builder.CreateZExt(valLtZero, CI->getType());
return Builder.CreateSub(zeroLtVal, valLtZero);
}
IRBuilder<> Builder(CI);
Constant *zero = Constant::getNullValue(Ty);
Value *zeroLtVal = IsInt ? Builder.CreateICmpSLT(zero, val) : Builder.CreateFCmpOLT(zero, val);
Value *valLtZero = IsInt ? Builder.CreateICmpSLT(val, zero) : Builder.CreateFCmpOLT(val, zero);
zeroLtVal = Builder.CreateZExt(zeroLtVal, CI->getType());
valLtZero = Builder.CreateZExt(valLtZero, CI->getType());
return Builder.CreateSub(zeroLtVal, valLtZero);
}
Value *TranslateUSign(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
Value *val = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
Type *Ty = val->getType();
IRBuilder<> Builder(CI);
Constant *zero = Constant::getNullValue(Ty);
Value *nonZero = Builder.CreateICmpNE(val, zero);
return Builder.CreateZExt(nonZero, CI->getType());
}
Value *TranslateStep(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
@ -3299,6 +3300,7 @@ void TranslateLoad(ResLoadHelper &helper, HLResource::Kind RK,
Type *Ty = helper.retVal->getType();
if (Ty->isPointerTy()) {
DXASSERT(!DxilResource::IsAnyTexture(RK), "Textures should not be treated as structured buffers.");
TranslateStructBufSubscript(cast<CallInst>(helper.retVal), helper.handle,
helper.status, OP, DL);
return;
@ -4745,7 +4747,7 @@ IntrinsicLower gLowerTable[static_cast<unsigned>(IntrinsicOp::Num_Intrinsics)] =
{IntrinsicOp::IOP_WorldToObject3x4, TranslateNoArgMatrix3x4Operation, DXIL::OpCode::WorldToObject},
{IntrinsicOp::IOP_WorldToObject4x3, TranslateNoArgTransposedMatrix3x4Operation, DXIL::OpCode::WorldToObject},
{IntrinsicOp::IOP_abort, EmptyLower, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_abs, TransalteAbs, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_abs, TranslateAbs, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_acos, TrivialUnaryOperation, DXIL::OpCode::Acos},
{IntrinsicOp::IOP_all, TranslateAll, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_any, TranslateAny, DXIL::OpCode::NumOpCodes},
@ -4910,12 +4912,14 @@ IntrinsicLower gLowerTable[static_cast<unsigned>(IntrinsicOp::Num_Intrinsics)] =
{ IntrinsicOp::IOP_WaveActiveUSum, TranslateWaveA2A, DXIL::OpCode::WaveActiveOp },
{ IntrinsicOp::IOP_WavePrefixUProduct, TranslateWaveA2A, DXIL::OpCode::WavePrefixOp },
{ IntrinsicOp::IOP_WavePrefixUSum, TranslateWaveA2A, DXIL::OpCode::WavePrefixOp },
{ IntrinsicOp::IOP_uabs, TranslateUAbs, DXIL::OpCode::NumOpCodes },
{ IntrinsicOp::IOP_uclamp, TranslateClamp, DXIL::OpCode::NumOpCodes },
{ IntrinsicOp::IOP_ufirstbithigh, TranslateFirstbitHi, DXIL::OpCode::FirstbitHi },
{ IntrinsicOp::IOP_umad, TranslateFUITrinary, DXIL::OpCode::UMad},
{ IntrinsicOp::IOP_umax, TranslateFUIBinary, DXIL::OpCode::UMax},
{ IntrinsicOp::IOP_umin, TranslateFUIBinary, DXIL::OpCode::UMin },
{ IntrinsicOp::IOP_umul, TranslateFUIBinary, DXIL::OpCode::UMul },
{ IntrinsicOp::IOP_umin, TranslateFUIBinary, DXIL::OpCode::UMin },
{ IntrinsicOp::IOP_umul, TranslateFUIBinary, DXIL::OpCode::UMul },
{ IntrinsicOp::IOP_usign, TranslateUSign, DXIL::OpCode::UMax },
{ IntrinsicOp::MOP_InterlockedUMax, TranslateMopAtomicBinaryOperation, DXIL::OpCode::NumOpCodes },
{ IntrinsicOp::MOP_InterlockedUMin, TranslateMopAtomicBinaryOperation, DXIL::OpCode::NumOpCodes },
};
@ -4969,25 +4973,21 @@ unsigned GetEltTypeByteSizeForConstBuf(Type *EltType, const DataLayout &DL) {
Value *GenerateCBLoad(Value *handle, Value *offset, Type *EltTy, OP *hlslOP,
IRBuilder<> &Builder) {
Constant *OpArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CBufferLoad);
DXASSERT(!EltTy->isIntegerTy(1), "Bools should not be loaded as their register representation.");
// Align to 8 bytes for now.
Constant *align = hlslOP->GetU32Const(8);
Type *i1Ty = Type::getInt1Ty(EltTy->getContext());
if (EltTy != i1Ty) {
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoad, EltTy);
return Builder.CreateCall(CBLoad, {OpArg, handle, offset, align});
} else {
Type *i32Ty = Type::getInt32Ty(EltTy->getContext());
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoad, i32Ty);
Value *Result = Builder.CreateCall(CBLoad, {OpArg, handle, offset, align});
return Builder.CreateICmpEQ(Result, hlslOP->GetU32Const(0));
}
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoad, EltTy);
return Builder.CreateCall(CBLoad, {OpArg, handle, offset, align});
}
Value *TranslateConstBufMatLd(Type *matType, Value *handle, Value *offset,
bool colMajor, OP *OP, const DataLayout &DL,
IRBuilder<> &Builder) {
unsigned col, row;
Type *EltTy = HLMatrixLower::GetMatrixInfo(matType, col, row);
HLMatrixLower::GetMatrixInfo(matType, col, row);
Type *EltTy = HLMatrixLower::LowerMatrixType(matType, /*forMem*/true)->getVectorElementType();
unsigned matSize = col * row;
std::vector<Value *> elts(matSize);
Value *EltByteSize = ConstantInt::get(
@ -5000,7 +5000,9 @@ Value *TranslateConstBufMatLd(Type *matType, Value *handle, Value *offset,
baseOffset = Builder.CreateAdd(baseOffset, EltByteSize);
}
return HLMatrixLower::BuildVector(EltTy, col * row, elts, Builder);
Value* Vec = HLMatrixLower::BuildVector(EltTy, col * row, elts, Builder);
Vec = HLMatrixLower::VecMatrixMemToReg(Vec, matType, Builder);
return Vec;
}
void TranslateCBGep(GetElementPtrInst *GEP, Value *handle, Value *baseOffset,
@ -5309,22 +5311,18 @@ Value *GenerateCBLoadLegacy(Value *handle, Value *legacyIdx,
IRBuilder<> &Builder) {
Constant *OpArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CBufferLoadLegacy);
Type *i1Ty = Type::getInt1Ty(EltTy->getContext());
DXASSERT(!EltTy->isIntegerTy(1), "Bools should not be loaded as their register representation.");
Type *doubleTy = Type::getDoubleTy(EltTy->getContext());
Type *halfTy = Type::getHalfTy(EltTy->getContext());
Type *i64Ty = Type::getInt64Ty(EltTy->getContext());
Type *i16Ty = Type::getInt16Ty(EltTy->getContext());
bool isBool = EltTy == i1Ty;
bool is64 = (EltTy == doubleTy) | (EltTy == i64Ty);
bool is16 = (EltTy == halfTy || EltTy == i16Ty) && !hlslOP->UseMinPrecision();
bool isNormal = !isBool && !is64;
DXASSERT_LOCALVAR(is16, (is16 && channelOffset < 8) || channelOffset < 4,
"legacy cbuffer don't across 16 bytes register.");
if (isNormal) {
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, EltTy);
Value *loadLegacy = Builder.CreateCall(CBLoad, {OpArg, handle, legacyIdx});
return Builder.CreateExtractValue(loadLegacy, channelOffset);
} else if (is64) {
if (is64) {
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, EltTy);
Value *loadLegacy = Builder.CreateCall(CBLoad, {OpArg, handle, legacyIdx});
DXASSERT((channelOffset&1)==0,"channel offset must be even for double");
@ -5332,12 +5330,9 @@ Value *GenerateCBLoadLegacy(Value *handle, Value *legacyIdx,
Value *Result = Builder.CreateExtractValue(loadLegacy, eltIdx);
return Result;
} else {
DXASSERT(isBool, "bool should be i1");
Type *i32Ty = Type::getInt32Ty(EltTy->getContext());
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, i32Ty);
Value *loadLegacy = Builder.CreateCall(CBLoad, {OpArg, handle, legacyIdx});
Value *Result = Builder.CreateExtractValue(loadLegacy, channelOffset);
return Builder.CreateICmpEQ(Result, hlslOP->GetU32Const(0));
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, EltTy);
Value *loadLegacy = Builder.CreateCall(CBLoad, { OpArg, handle, legacyIdx });
return Builder.CreateExtractValue(loadLegacy, channelOffset);
}
}
@ -5347,29 +5342,19 @@ Value *GenerateCBLoadLegacy(Value *handle, Value *legacyIdx,
IRBuilder<> &Builder) {
Constant *OpArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CBufferLoadLegacy);
Type *i1Ty = Type::getInt1Ty(EltTy->getContext());
DXASSERT(!EltTy->isIntegerTy(1), "Bools should not be loaded as their register representation.");
Type *doubleTy = Type::getDoubleTy(EltTy->getContext());
Type *i64Ty = Type::getInt64Ty(EltTy->getContext());
Type *halfTy = Type::getHalfTy(EltTy->getContext());
Type *shortTy = Type::getInt16Ty(EltTy->getContext());
bool isBool = EltTy == i1Ty;
bool is64 = (EltTy == doubleTy) | (EltTy == i64Ty);
bool is16 = (EltTy == shortTy || EltTy == halfTy) && !hlslOP->UseMinPrecision();
bool isNormal = !isBool && !is64 && !is16;
DXASSERT((is16 && channelOffset + vecSize <= 8) ||
(channelOffset + vecSize) <= 4,
"legacy cbuffer don't across 16 bytes register.");
if (isNormal) {
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, EltTy);
Value *loadLegacy = Builder.CreateCall(CBLoad, {OpArg, handle, legacyIdx});
Value *Result = UndefValue::get(VectorType::get(EltTy, vecSize));
for (unsigned i = 0; i < vecSize; ++i) {
Value *NewElt = Builder.CreateExtractValue(loadLegacy, channelOffset+i);
Result = Builder.CreateInsertElement(Result, NewElt, i);
}
return Result;
} else if (is16) {
if (is16) {
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, EltTy);
Value *loadLegacy = Builder.CreateCall(CBLoad, {OpArg, handle, legacyIdx});
Value *Result = UndefValue::get(VectorType::get(EltTy, vecSize));
@ -5401,25 +5386,24 @@ Value *GenerateCBLoadLegacy(Value *handle, Value *legacyIdx,
}
return Result;
} else {
DXASSERT(isBool, "bool should be i1");
Type *i32Ty = Type::getInt32Ty(EltTy->getContext());
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, i32Ty);
Value *loadLegacy = Builder.CreateCall(CBLoad, {OpArg, handle, legacyIdx});
Value *Result = UndefValue::get(VectorType::get(i32Ty, vecSize));
Function *CBLoad = hlslOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, EltTy);
Value *loadLegacy = Builder.CreateCall(CBLoad, { OpArg, handle, legacyIdx });
Value *Result = UndefValue::get(VectorType::get(EltTy, vecSize));
for (unsigned i = 0; i < vecSize; ++i) {
Value *NewElt = Builder.CreateExtractValue(loadLegacy, channelOffset+i);
Value *NewElt = Builder.CreateExtractValue(loadLegacy, channelOffset + i);
Result = Builder.CreateInsertElement(Result, NewElt, i);
}
return Builder.CreateICmpEQ(Result, ConstantAggregateZero::get(Result->getType()));
return Result;
}
}
Value *TranslateConstBufMatLdLegacy(Type *matType, Value *handle,
Value *legacyIdx, bool colMajor, OP *OP,
const DataLayout &DL,
bool memElemRepr, const DataLayout &DL,
IRBuilder<> &Builder) {
unsigned col, row;
Type *EltTy = HLMatrixLower::GetMatrixInfo(matType, col, row);
HLMatrixLower::GetMatrixInfo(matType, col, row);
Type *EltTy = HLMatrixLower::LowerMatrixType(matType, /*forMem*/true)->getVectorElementType();
unsigned matSize = col * row;
std::vector<Value *> elts(matSize);
@ -5453,7 +5437,10 @@ Value *TranslateConstBufMatLdLegacy(Type *matType, Value *handle,
}
}
return HLMatrixLower::BuildVector(EltTy, col * row, elts, Builder);
Value *Vec = HLMatrixLower::BuildVector(EltTy, col * row, elts, Builder);
if (!memElemRepr)
Vec = HLMatrixLower::VecMatrixMemToReg(Vec, matType, Builder);
return Vec;
}
void TranslateCBGepLegacy(GetElementPtrInst *GEP, Value *handle,
@ -5505,8 +5492,9 @@ void TranslateCBAddressUserLegacy(Instruction *user, Value *handle,
Type *matType = CI->getArgOperand(HLOperandIndex::kMatLoadPtrOpIdx)
->getType()
->getPointerElementType();
// This will replace a call, so we should use the register representation of elements
Value *newLd = TranslateConstBufMatLdLegacy(
matType, handle, legacyIdx, colMajor, hlslOP, DL, Builder);
matType, handle, legacyIdx, colMajor, hlslOP, /*memElemRepr*/false, DL, Builder);
CI->replaceAllUsesWith(newLd);
CI->eraseFromParent();
} else if (group == HLOpcodeGroup::HLSubscript) {
@ -5533,8 +5521,9 @@ void TranslateCBAddressUserLegacy(Instruction *user, Value *handle,
Value *ldData = UndefValue::get(resultType);
if (!dynamicIndexing) {
// This will replace a load or GEP, so we should use the memory representation of elements
Value *matLd = TranslateConstBufMatLdLegacy(
matType, handle, legacyIdx, colMajor, hlslOP, DL, Builder);
matType, handle, legacyIdx, colMajor, hlslOP, /*memElemRepr*/true, DL, Builder);
// The matLd is keep original layout, just use the idx calc in
// EmitHLSLMatrixElement and EmitHLSLMatrixSubscript.
switch (subOp) {
@ -5923,8 +5912,8 @@ Value *GEPIdxToOffset(GetElementPtrInst *GEP, IRBuilder<> &Builder,
continue;
}
}
if (GEPIt->isPointerTy()) {
unsigned size = DL.getTypeAllocSize(GEPIt->getPointerElementType());
if (GEPIt->isPointerTy() || GEPIt->isArrayTy() || GEPIt->isVectorTy()) {
unsigned size = DL.getTypeAllocSize(GEPIt->getSequentialElementType());
if (immIdx) {
unsigned tempOffset = size * immIdx;
offset = Builder.CreateAdd(offset, OP->GetU32Const(tempOffset));
@ -5933,29 +5922,9 @@ Value *GEPIdxToOffset(GetElementPtrInst *GEP, IRBuilder<> &Builder,
offset = Builder.CreateAdd(offset, tempOffset);
}
} else if (GEPIt->isStructTy()) {
unsigned structOffset = 0;
for (unsigned i = 0; i < immIdx; i++) {
structOffset += DL.getTypeAllocSize(GEPIt->getStructElementType(i));
}
const StructLayout *Layout = DL.getStructLayout(cast<StructType>(*GEPIt));
unsigned structOffset = Layout->getElementOffset(immIdx);
offset = Builder.CreateAdd(offset, OP->GetU32Const(structOffset));
} else if (GEPIt->isArrayTy()) {
unsigned size = DL.getTypeAllocSize(GEPIt->getArrayElementType());
if (immIdx) {
unsigned tempOffset = size * immIdx;
offset = Builder.CreateAdd(offset, OP->GetU32Const(tempOffset));
} else {
Value *tempOffset = Builder.CreateMul(idx, OP->GetU32Const(size));
offset = Builder.CreateAdd(offset, tempOffset);
}
} else if (GEPIt->isVectorTy()) {
unsigned size = DL.getTypeAllocSize(GEPIt->getVectorElementType());
if (immIdx) {
unsigned tempOffset = size * immIdx;
offset = Builder.CreateAdd(offset, OP->GetU32Const(tempOffset));
} else {
Value *tempOffset = Builder.CreateMul(idx, OP->GetU32Const(size));
offset = Builder.CreateAdd(offset, tempOffset);
}
} else {
gep_type_iterator temp = GEPIt;
temp++;
@ -6019,9 +5988,10 @@ void GenerateStructBufSt(Value *handle, Value *bufIdx, Value *offset,
Value *TranslateStructBufMatLd(Type *matType, IRBuilder<> &Builder,
Value *handle, hlsl::OP *OP, Value *status,
Value *bufIdx, Value *baseOffset,
bool colMajor, const DataLayout &DL) {
const DataLayout &DL) {
unsigned col, row;
Type *EltTy = HLMatrixLower::GetMatrixInfo(matType, col, row);
HLMatrixLower::GetMatrixInfo(matType, col, row);
Type *EltTy = HLMatrixLower::LowerMatrixType(matType, /*forMem*/true)->getVectorElementType();
unsigned EltSize = DL.getTypeAllocSize(EltTy);
Constant* alignment = OP->GetI32Const(EltSize);
@ -6053,14 +6023,20 @@ Value *TranslateStructBufMatLd(Type *matType, IRBuilder<> &Builder,
offset = Builder.CreateAdd(offset, OP->GetU32Const(4 * EltSize));
}
return HLMatrixLower::BuildVector(EltTy, col * row, elts, Builder);
Value *Vec = HLMatrixLower::BuildVector(EltTy, col * row, elts, Builder);
Vec = HLMatrixLower::VecMatrixMemToReg(Vec, matType, Builder);
return Vec;
}
void TranslateStructBufMatSt(Type *matType, IRBuilder<> &Builder, Value *handle,
hlsl::OP *OP, Value *bufIdx, Value *baseOffset,
Value *val, bool colMajor, const DataLayout &DL) {
Value *val, const DataLayout &DL) {
unsigned col, row;
Type *EltTy = HLMatrixLower::GetMatrixInfo(matType, col, row);
HLMatrixLower::GetMatrixInfo(matType, col, row);
Type *EltTy = HLMatrixLower::LowerMatrixType(matType, /*forMem*/true)->getVectorElementType();
val = HLMatrixLower::VecMatrixRegToMem(val, matType, Builder);
unsigned EltSize = DL.getTypeAllocSize(EltTy);
Constant *Alignment = OP->GetI32Const(EltSize);
Value *offset = baseOffset;
@ -6075,18 +6051,8 @@ void TranslateStructBufMatSt(Type *matType, IRBuilder<> &Builder, Value *handle,
storeSize = matSize + 4 - (matSize & 3);
}
std::vector<Value *> elts(storeSize, undefElt);
if (colMajor) {
for (unsigned i = 0; i < matSize; i++)
elts[i] = Builder.CreateExtractElement(val, i);
} else {
for (unsigned r = 0; r < row; r++)
for (unsigned c = 0; c < col; c++) {
unsigned rowMajorIdx = r * col + c;
unsigned colMajorIdx = c * row + r;
elts[rowMajorIdx] = Builder.CreateExtractElement(val, colMajorIdx);
}
}
for (unsigned i = 0; i < matSize; i++)
elts[i] = Builder.CreateExtractElement(val, i);
for (unsigned i = 0; i < matSize; i += 4) {
uint8_t mask = 0;
@ -6111,34 +6077,25 @@ void TranslateStructBufMatLdSt(CallInst *CI, Value *handle, hlsl::OP *OP,
DXASSERT_LOCALVAR(group, group == HLOpcodeGroup::HLMatLoadStore,
"only translate matrix loadStore here.");
HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
// Due to the current way the initial codegen generates matrix
// orientation casts, the in-register vector matrix has already been
// reordered based on the destination's row or column-major packing orientation.
switch (matOp) {
case HLMatLoadStoreOpcode::RowMatLoad:
case HLMatLoadStoreOpcode::ColMatLoad: {
Value *ptr = CI->getArgOperand(HLOperandIndex::kMatLoadPtrOpIdx);
Value *NewLd = TranslateStructBufMatLd(
ptr->getType()->getPointerElementType(), Builder, handle, OP, status,
bufIdx, baseOffset, /*colMajor*/ true, DL);
CI->replaceAllUsesWith(NewLd);
} break;
case HLMatLoadStoreOpcode::RowMatLoad: {
Value *ptr = CI->getArgOperand(HLOperandIndex::kMatLoadPtrOpIdx);
Value *NewLd = TranslateStructBufMatLd(
ptr->getType()->getPointerElementType(), Builder, handle, OP, status,
bufIdx, baseOffset, /*colMajor*/ false, DL);
bufIdx, baseOffset, DL);
CI->replaceAllUsesWith(NewLd);
} break;
case HLMatLoadStoreOpcode::RowMatStore:
case HLMatLoadStoreOpcode::ColMatStore: {
Value *ptr = CI->getArgOperand(HLOperandIndex::kMatStoreDstPtrOpIdx);
Value *val = CI->getArgOperand(HLOperandIndex::kMatStoreValOpIdx);
TranslateStructBufMatSt(ptr->getType()->getPointerElementType(), Builder,
handle, OP, bufIdx, baseOffset, val,
/*colMajor*/ true, DL);
} break;
case HLMatLoadStoreOpcode::RowMatStore: {
Value *ptr = CI->getArgOperand(HLOperandIndex::kMatStoreDstPtrOpIdx);
Value *val = CI->getArgOperand(HLOperandIndex::kMatStoreValOpIdx);
TranslateStructBufMatSt(ptr->getType()->getPointerElementType(), Builder,
handle, OP, bufIdx, baseOffset, val,
/*colMajor*/ false, DL);
DL);
} break;
}

Просмотреть файл

@ -624,14 +624,14 @@ void replaceDirectInputParameter(Value *param, Function *loadInput,
newVec = Builder.CreateInsertElement(newVec, input, col);
}
param->replaceAllUsesWith(newVec);
} else if (!Ty->isArrayTy() && !HLMatrixLower::IsMatrixType(Ty)) {
} else if (!Ty->isArrayTy() && !dxilutil::IsHLSLMatrixType(Ty)) {
DXASSERT(cols == 1, "only support scalar here");
Value *colIdx = hlslOP->GetU8Const(0);
args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
Value *input =
GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
param->replaceAllUsesWith(input);
} else if (HLMatrixLower::IsMatrixType(Ty)) {
} else if (dxilutil::IsHLSLMatrixType(Ty)) {
Value *colIdx = hlslOP->GetU8Const(0);
(void)colIdx;
DXASSERT(param->hasOneUse(),
@ -784,7 +784,7 @@ void collectInputOutputAccessInfo(
vectorIdx = GEPIt.getOperand();
}
}
if (HLMatrixLower::IsMatrixType(*GEPIt)) {
if (dxilutil::IsHLSLMatrixType(*GEPIt)) {
unsigned row, col;
HLMatrixLower::GetMatrixInfo(*GEPIt, col, row);
Constant *arraySize = ConstantInt::get(idxTy, col);
@ -912,80 +912,54 @@ void GenerateInputOutputUserCall(InputOutputAccessInfo &info, Value *undefVertex
DXASSERT_NOMSG(group == HLOpcodeGroup::HLMatLoadStore);
HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
switch (matOp) {
case HLMatLoadStoreOpcode::ColMatLoad: {
IRBuilder<> LocalBuilder(CI);
Type *matTy = CI->getArgOperand(HLOperandIndex::kMatLoadPtrOpIdx)
->getType()
->getPointerElementType();
unsigned col, row;
Type *EltTy = HLMatrixLower::GetMatrixInfo(matTy, col, row);
std::vector<Value *> matElts(col * row);
for (unsigned c = 0; c < col; c++) {
Constant *constRowIdx = LocalBuilder.getInt32(c);
Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
for (unsigned r = 0; r < row; r++) {
SmallVector<Value *, 4> args = {OpArg, ID, rowIdx, columnConsts[r]};
if (vertexID)
args.emplace_back(vertexID);
Value *input = LocalBuilder.CreateCall(ldStFunc, args);
unsigned matIdx = c * row + r;
matElts[matIdx] = input;
}
}
Value *newVec =
HLMatrixLower::BuildVector(EltTy, col * row, matElts, LocalBuilder);
CI->replaceAllUsesWith(newVec);
CI->eraseFromParent();
} break;
case HLMatLoadStoreOpcode::ColMatLoad:
case HLMatLoadStoreOpcode::RowMatLoad: {
IRBuilder<> LocalBuilder(CI);
Type *matTy = CI->getArgOperand(HLOperandIndex::kMatLoadPtrOpIdx)
->getType()
->getPointerElementType();
unsigned col, row;
Type *EltTy = HLMatrixLower::GetMatrixInfo(matTy, col, row);
HLMatrixLower::GetMatrixInfo(matTy, col, row);
std::vector<Value *> matElts(col * row);
for (unsigned r = 0; r < row; r++) {
Constant *constRowIdx = LocalBuilder.getInt32(r);
Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
for (unsigned c = 0; c < col; c++) {
SmallVector<Value *, 4> args = {OpArg, ID, rowIdx, columnConsts[c]};
if (vertexID)
args.emplace_back(vertexID);
Value *input = LocalBuilder.CreateCall(ldStFunc, args);
unsigned matIdx = r * col + c;
matElts[matIdx] = input;
if (matOp == HLMatLoadStoreOpcode::ColMatLoad) {
for (unsigned c = 0; c < col; c++) {
Constant *constRowIdx = LocalBuilder.getInt32(c);
Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
for (unsigned r = 0; r < row; r++) {
SmallVector<Value *, 4> args = { OpArg, ID, rowIdx, columnConsts[r] };
if (vertexID)
args.emplace_back(vertexID);
Value *input = LocalBuilder.CreateCall(ldStFunc, args);
unsigned matIdx = c * row + r;
matElts[matIdx] = input;
}
}
} else {
for (unsigned r = 0; r < row; r++) {
Constant *constRowIdx = LocalBuilder.getInt32(r);
Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
for (unsigned c = 0; c < col; c++) {
SmallVector<Value *, 4> args = { OpArg, ID, rowIdx, columnConsts[c] };
if (vertexID)
args.emplace_back(vertexID);
Value *input = LocalBuilder.CreateCall(ldStFunc, args);
unsigned matIdx = r * col + c;
matElts[matIdx] = input;
}
}
}
Value *newVec =
HLMatrixLower::BuildVector(EltTy, col * row, matElts, LocalBuilder);
HLMatrixLower::BuildVector(matElts[0]->getType(), col * row, matElts, LocalBuilder);
newVec = HLMatrixLower::VecMatrixMemToReg(newVec, matTy, LocalBuilder);
CI->replaceAllUsesWith(newVec);
CI->eraseFromParent();
} break;
case HLMatLoadStoreOpcode::ColMatStore: {
IRBuilder<> LocalBuilder(CI);
Value *Val = CI->getArgOperand(HLOperandIndex::kMatStoreValOpIdx);
Type *matTy = CI->getArgOperand(HLOperandIndex::kMatStoreDstPtrOpIdx)
->getType()
->getPointerElementType();
unsigned col, row;
HLMatrixLower::GetMatrixInfo(matTy, col, row);
for (unsigned c = 0; c < col; c++) {
Constant *constColIdx = LocalBuilder.getInt32(c);
Value *colIdx = LocalBuilder.CreateAdd(idxVal, constColIdx);
for (unsigned r = 0; r < row; r++) {
unsigned matIdx = HLMatrixLower::GetColMajorIdx(r, c, row);
Value *Elt = LocalBuilder.CreateExtractElement(Val, matIdx);
LocalBuilder.CreateCall(ldStFunc,
{OpArg, ID, colIdx, columnConsts[r], Elt});
}
}
CI->eraseFromParent();
} break;
case HLMatLoadStoreOpcode::ColMatStore:
case HLMatLoadStoreOpcode::RowMatStore: {
IRBuilder<> LocalBuilder(CI);
Value *Val = CI->getArgOperand(HLOperandIndex::kMatStoreValOpIdx);
@ -995,14 +969,30 @@ void GenerateInputOutputUserCall(InputOutputAccessInfo &info, Value *undefVertex
unsigned col, row;
HLMatrixLower::GetMatrixInfo(matTy, col, row);
for (unsigned r = 0; r < row; r++) {
Constant *constRowIdx = LocalBuilder.getInt32(r);
Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
Val = HLMatrixLower::VecMatrixRegToMem(Val, matTy, LocalBuilder);
if (matOp == HLMatLoadStoreOpcode::ColMatStore) {
for (unsigned c = 0; c < col; c++) {
unsigned matIdx = HLMatrixLower::GetRowMajorIdx(r, c, col);
Value *Elt = LocalBuilder.CreateExtractElement(Val, matIdx);
LocalBuilder.CreateCall(ldStFunc,
{OpArg, ID, rowIdx, columnConsts[c], Elt});
Constant *constColIdx = LocalBuilder.getInt32(c);
Value *colIdx = LocalBuilder.CreateAdd(idxVal, constColIdx);
for (unsigned r = 0; r < row; r++) {
unsigned matIdx = HLMatrixLower::GetColMajorIdx(r, c, row);
Value *Elt = LocalBuilder.CreateExtractElement(Val, matIdx);
LocalBuilder.CreateCall(ldStFunc,
{ OpArg, ID, colIdx, columnConsts[r], Elt });
}
}
} else {
for (unsigned r = 0; r < row; r++) {
Constant *constRowIdx = LocalBuilder.getInt32(r);
Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
for (unsigned c = 0; c < col; c++) {
unsigned matIdx = HLMatrixLower::GetRowMajorIdx(r, c, col);
Value *Elt = LocalBuilder.CreateExtractElement(Val, matIdx);
LocalBuilder.CreateCall(ldStFunc,
{ OpArg, ID, rowIdx, columnConsts[c], Elt });
}
}
}
CI->eraseFromParent();

Просмотреть файл

@ -41,10 +41,11 @@ subdirectories =
HLSL
DXIL
DxilContainer
DxilDia
DxrFallback
DxilRootSignature
; HLSL Change: remove LibDriver, LineEditor, add HLSL, DxrtFallback, DXIL, DxilContainer, DxilPIXPasses, DxilRootSignature
; HLSL Change: remove LibDriver, LineEditor, add HLSL, DxrtFallback, DXIL, DxilContainer, DxilDia, DxilPIXPasses, DxilRootSignature
[component_0]
type = Group

Просмотреть файл

@ -248,20 +248,24 @@ static void addHLSLPasses(bool HLSLHighLevel, unsigned OptLevel, hlsl::HLSLExten
MPM.add(createDxilConvergentMarkPass());
}
if (OptLevel > 2) {
MPM.add(createLoopRotatePass());
MPM.add(createLoopUnrollPass());
}
if (!NoOpt) {
// Verify no undef resource path before simplify, since that can remove undef
// paths. For NoOpt, resources are unpromoted here, so this will not work.
MPM.add(createFailUndefResourcePass());
}
MPM.add(createSimplifyInstPass());
MPM.add(createCFGSimplificationPass());
// Passes to handle [unroll]
// Needs to happen after SROA since loop count may depend on
// struct members.
// Needs to happen before resources are lowered and before HL
// module is gone.
MPM.add(createLoopRotatePass());
MPM.add(createDxilLoopUnrollPass(/*MaxIterationAttempt*/ 128));
// Default unroll pass. This is purely for optimizing loops without
// attributes.
if (OptLevel > 2) {
MPM.add(createLoopUnrollPass());
}
MPM.add(createDxilPromoteLocalResources());
MPM.add(createDxilPromoteStaticResources());
// Verify no undef resource again after promotion
@ -374,14 +378,11 @@ void PassManagerBuilder::populateModulePassManager(
// Start of function pass.
// Break up aggregate allocas, using SSAUpdater.
// HLSL Change - don't run SROA.
// HLSL uses special SROA added in addHLSLPasses.
if (HLSLHighLevel) { // HLSL Change
if (UseNewSROA)
MPM.add(createSROAPass(/*RequiresDomTree*/ false));
else
MPM.add(createScalarReplAggregatesPass(-1, false));
}
// HLSL Change. MPM.add(createEarlyCSEPass()); // Catch trivial redundancies
// HLSL Change. MPM.add(createJumpThreadingPass()); // Thread jumps.
MPM.add(createCorrelatedValuePropagationPass()); // Propagate conditionals
@ -418,6 +419,8 @@ void PassManagerBuilder::populateModulePassManager(
if (EnableMLSM)
MPM.add(createMergedLoadStoreMotionPass()); // Merge ld/st in diamonds
MPM.add(createGVNPass(DisableGVNLoadPRE)); // Remove redundancies
if (!HLSLResMayAlias)
MPM.add(createDxilSimpleGVNHoistPass()); // HLSL Change - GVN hoist for code size.
}
// HLSL Change Begins.
// HLSL don't allow memcpy and memset.

Просмотреть файл

@ -44,6 +44,7 @@ add_llvm_library(LLVMScalarOpts
Scalar.cpp
ScalarReplAggregates.cpp
ScalarReplAggregatesHLSL.cpp # HLSL Change
DxilLoopUnroll.cpp # HLSL Change
Scalarizer.cpp
SeparateConstOffsetFromGEP.cpp
SimplifyCFGPass.cpp

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -222,7 +222,8 @@ namespace {
class AllocaSlices {
public:
/// \brief Construct the slices of a particular alloca.
AllocaSlices(const DataLayout &DL, AllocaInst &AI);
AllocaSlices(const DataLayout &DL, AllocaInst &AI,
const bool SkipHLSLMat); // HLSL Change - not sroa matrix type.
/// \brief Test whether a pointer to the allocation escapes our analysis.
///
@ -633,6 +634,7 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
friend class InstVisitor<SliceBuilder>;
typedef PtrUseVisitor<SliceBuilder> Base;
const bool SkipHLSLMat; // HLSL Change - not sroa matrix type.
const uint64_t AllocSize;
AllocaSlices &AS;
@ -643,8 +645,10 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
SmallPtrSet<Instruction *, 4> VisitedDeadInsts;
public:
SliceBuilder(const DataLayout &DL, AllocaInst &AI, AllocaSlices &AS)
SliceBuilder(const DataLayout &DL, AllocaInst &AI, AllocaSlices &AS,
const bool SkipHLSLMat)
: PtrUseVisitor<SliceBuilder>(DL),
SkipHLSLMat(SkipHLSLMat), // HLSL Change - not sroa matrix type.
AllocSize(DL.getTypeAllocSize(AI.getAllocatedType())), AS(AS) {}
private:
@ -690,7 +694,24 @@ private:
void visitBitCastInst(BitCastInst &BC) {
if (BC.use_empty())
return markAsDead(BC);
// HLSL Change Begin - not sroa matrix type.
if (PointerType *PT = dyn_cast<PointerType>(BC.getType())) {
Type *EltTy = PT->getElementType();
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(EltTy)) ||
hlsl::dxilutil::IsHLSLObjectType(EltTy)) {
AS.PointerEscapingInstr = &BC;
return;
}
if (PointerType *SrcPT = dyn_cast<PointerType>(BC.getSrcTy())) {
Type *SrcEltTy = SrcPT->getElementType();
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(SrcEltTy)) ||
hlsl::dxilutil::IsHLSLObjectType(SrcEltTy)) {
AS.PointerEscapingInstr = &BC;
return;
}
}
}
// HLSL Change End.
return Base::visitBitCastInst(BC);
}
@ -751,9 +772,15 @@ private:
}
void visitLoadInst(LoadInst &LI) {
// HLSL Change Begin - not sroa matrix type.
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(LI.getType())) ||
hlsl::dxilutil::IsHLSLObjectType(LI.getType()))
return PI.setEscapedAndAborted(&LI);
// HLSL Change End.
assert((!LI.isSimple() || LI.getType()->isSingleValueType()) &&
"All simple FCA loads should have been pre-split");
if (!IsOffsetKnown)
return PI.setAborted(&LI);
@ -766,6 +793,12 @@ private:
Value *ValOp = SI.getValueOperand();
if (ValOp == *U)
return PI.setEscapedAndAborted(&SI);
// HLSL Change Begin - not sroa matrix type.
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(ValOp->getType())) ||
hlsl::dxilutil::IsHLSLObjectType(ValOp->getType()))
return PI.setEscapedAndAborted(&SI);
// HLSL Change End.
if (!IsOffsetKnown)
return PI.setAborted(&SI);
@ -1002,13 +1035,15 @@ private:
void visitInstruction(Instruction &I) { PI.setAborted(&I); }
};
AllocaSlices::AllocaSlices(const DataLayout &DL, AllocaInst &AI)
AllocaSlices::AllocaSlices(
const DataLayout &DL, AllocaInst &AI,
const bool SkipHLSLMat) // HLSL Change - not sroa matrix type.
:
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
AI(AI),
#endif
PointerEscapingInstr(nullptr) {
SliceBuilder PB(DL, AI, *this);
SliceBuilder PB(DL, AI, *this, SkipHLSLMat);
SliceBuilder::PtrInfo PtrI = PB.visitPtr(AI);
if (PtrI.isEscaped() || PtrI.isAborted()) {
// FIXME: We should sink the escape vs. abort info into the caller nicely,
@ -1204,6 +1239,7 @@ namespace {
/// SSA vector values.
class SROA : public FunctionPass {
const bool RequiresDomTree;
const bool SkipHLSLMat; // HLSL Change - not sroa matrix type.
LLVMContext *C;
DominatorTree *DT;
@ -1252,9 +1288,10 @@ class SROA : public FunctionPass {
SetVector<SelectInst *, SmallVector<SelectInst *, 2>> SpeculatableSelects;
public:
SROA(bool RequiresDomTree = true)
: FunctionPass(ID), RequiresDomTree(RequiresDomTree), C(nullptr),
DT(nullptr) {
SROA(bool RequiresDomTree = true, bool SkipHLSLMat = true)
: FunctionPass(ID), RequiresDomTree(RequiresDomTree),
SkipHLSLMat(SkipHLSLMat), // HLSL Change - not sroa matrix type.
C(nullptr), DT(nullptr) {
initializeSROAPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override;
@ -1280,8 +1317,8 @@ private:
char SROA::ID = 0;
FunctionPass *llvm::createSROAPass(bool RequiresDomTree) {
return new SROA(RequiresDomTree);
FunctionPass *llvm::createSROAPass(bool RequiresDomTree, bool SkipHLSLMat) {
return new SROA(RequiresDomTree, SkipHLSLMat);
}
INITIALIZE_PASS_BEGIN(SROA, "sroa", "Scalar Replacement Of Aggregates", false,
@ -3191,6 +3228,7 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
friend class llvm::InstVisitor<AggLoadStoreRewriter, bool>;
const DataLayout &DL;
const bool SkipHLSLMat; // HLSL Change - not sroa matrix type.
/// Queue of pointer uses to analyze and potentially rewrite.
SmallVector<Use *, 8> Queue;
@ -3203,7 +3241,9 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
Use *U;
public:
AggLoadStoreRewriter(const DataLayout &DL) : DL(DL) {}
AggLoadStoreRewriter(const DataLayout &DL, const bool SkipHLSLMat)
// HLSL Change - not sroa matrix type.
: DL(DL), SkipHLSLMat(SkipHLSLMat) {}
/// Rewrite loads and stores through a pointer and all pointers derived from
/// it.
@ -3323,6 +3363,11 @@ private:
assert(LI.getPointerOperand() == *U);
if (!LI.isSimple() || LI.getType()->isSingleValueType())
return false;
// HLSL Change Begin - not sroa matrix type.
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(LI.getType())) ||
hlsl::dxilutil::IsHLSLObjectType(LI.getType()))
return false;
// HLSL Change End.
// We have an aggregate being loaded, split it apart.
DEBUG(dbgs() << " original: " << LI << "\n");
@ -3357,7 +3402,11 @@ private:
Value *V = SI.getValueOperand();
if (V->getType()->isSingleValueType())
return false;
// HLSL Change Begin - not sroa matrix type.
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(V->getType())) ||
hlsl::dxilutil::IsHLSLObjectType(V->getType()))
return false;
// HLSL Change End.
// We have an aggregate being stored, split it apart.
DEBUG(dbgs() << " original: " << SI << "\n");
StoreOpSplitter Splitter(&SI, *U);
@ -3367,6 +3416,20 @@ private:
}
bool visitBitCastInst(BitCastInst &BC) {
// HLSL Change Begin - not sroa matrix type.
if (PointerType *PT = dyn_cast<PointerType>(BC.getType())) {
Type *EltTy = PT->getElementType();
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(EltTy)) ||
hlsl::dxilutil::IsHLSLObjectType(EltTy))
return false;
if (PointerType *SrcPT = dyn_cast<PointerType>(BC.getSrcTy())) {
Type *SrcEltTy = SrcPT->getElementType();
if ((SkipHLSLMat && hlsl::dxilutil::IsHLSLMatrixType(SrcEltTy)) ||
hlsl::dxilutil::IsHLSLObjectType(SrcEltTy))
return false;
}
}
// HLSL Change End.
enqueueUsers(BC);
return false;
}
@ -4310,7 +4373,12 @@ bool SROA::runOnAlloca(AllocaInst &AI) {
// Skip alloca forms that this analysis can't handle.
if (AI.isArrayAllocation() || !AI.getAllocatedType()->isSized() ||
hlsl::dxilutil::IsHLSLObjectType(AI.getAllocatedType()) || // HLSL Change - not sroa resource type.
hlsl::dxilutil::IsHLSLObjectType(
AI.getAllocatedType()) || // HLSL Change - not sroa resource type.
// HLSL Change Begin - not sroa matrix type.
(SkipHLSLMat &&
hlsl::dxilutil::IsHLSLMatrixType(AI.getAllocatedType())) ||
// HLSL Change End.
DL.getTypeAllocSize(AI.getAllocatedType()) == 0)
return false;
@ -4318,11 +4386,11 @@ bool SROA::runOnAlloca(AllocaInst &AI) {
// First, split any FCA loads and stores touching this alloca to promote
// better splitting and promotion opportunities.
AggLoadStoreRewriter AggRewriter(DL);
AggLoadStoreRewriter AggRewriter(DL, SkipHLSLMat);
Changed |= AggRewriter.rewrite(AI);
// Build the slices using a recursive instruction-visiting builder.
AllocaSlices AS(DL, AI);
AllocaSlices AS(DL, AI, SkipHLSLMat);
DEBUG(AS.print(dbgs()));
if (AS.isEscaped())
return Changed;

Просмотреть файл

@ -1639,7 +1639,7 @@ bool SROA_HLSL::performScalarRepl(Function &F, DxilTypeSystem &typeSys) {
Type *Ty = AI->getAllocatedType();
// Skip empty struct parameters.
if (StructType *ST = dyn_cast<StructType>(Ty)) {
if (!HLMatrixLower::IsMatrixType(Ty)) {
if (!dxilutil::IsHLSLMatrixType(Ty)) {
DxilStructAnnotation *SA = typeSys.GetStructAnnotation(ST);
if (SA && SA->IsEmptyStruct()) {
for (User *U : AI->users()) {
@ -1884,7 +1884,7 @@ void SROA_HLSL::isSafeGEP(GetElementPtrInst *GEPI, uint64_t &Offset,
for (;GEPIt != E; ++GEPIt) {
Type *Ty = *GEPIt;
if (Ty->isStructTy() && !HLMatrixLower::IsMatrixType(Ty)) {
if (Ty->isStructTy() && !dxilutil::IsHLSLMatrixType(Ty)) {
// Don't go inside struct when mark hasArrayIndexing and hasVectorIndexing.
// The following level won't affect scalar repl on the struct.
break;
@ -2250,7 +2250,7 @@ static void EltMemCpy(Type *Ty, Value *Dest, Value *Src,
static bool IsMemCpyTy(Type *Ty, DxilTypeSystem &typeSys) {
if (!Ty->isAggregateType())
return false;
if (HLMatrixLower::IsMatrixType(Ty))
if (dxilutil::IsHLSLMatrixType(Ty))
return false;
if (dxilutil::IsHLSLObjectType(Ty))
return false;
@ -2272,7 +2272,7 @@ static bool IsMemCpyTy(Type *Ty, DxilTypeSystem &typeSys) {
static void SplitCpy(Type *Ty, Value *Dest, Value *Src,
SmallVector<Value *, 16> &idxList, IRBuilder<> &Builder,
const DataLayout &DL, DxilTypeSystem &typeSys,
DxilFieldAnnotation *fieldAnnotation, const bool bEltMemCpy = true) {
const DxilFieldAnnotation *fieldAnnotation, const bool bEltMemCpy = true) {
if (PointerType *PT = dyn_cast<PointerType>(Ty)) {
Constant *idx = Constant::getIntegerValue(
IntegerType::get(Ty->getContext(), 32), APInt(32, 0));
@ -2282,7 +2282,7 @@ static void SplitCpy(Type *Ty, Value *Dest, Value *Src,
fieldAnnotation, bEltMemCpy);
idxList.pop_back();
} else if (HLMatrixLower::IsMatrixType(Ty)) {
} else if (dxilutil::IsHLSLMatrixType(Ty)) {
// If no fieldAnnotation, use row major as default.
// Only load then store immediately should be fine.
bool bRowMajor = true;
@ -2293,31 +2293,31 @@ static void SplitCpy(Type *Ty, Value *Dest, Value *Src,
MatrixOrientation::RowMajor;
}
Module *M = Builder.GetInsertPoint()->getModule();
Value *DestGEP = Builder.CreateInBoundsGEP(Dest, idxList);
Value *SrcGEP = Builder.CreateInBoundsGEP(Src, idxList);
if (bRowMajor) {
Value *Load = HLModule::EmitHLOperationCall(
Builder, HLOpcodeGroup::HLMatLoadStore,
static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatLoad), Ty, {SrcGEP},
*M);
// Generate Matrix Store.
HLModule::EmitHLOperationCall(
Builder, HLOpcodeGroup::HLMatLoadStore,
static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatStore), Ty,
{DestGEP, Load}, *M);
} else {
Value *Load = HLModule::EmitHLOperationCall(
Builder, HLOpcodeGroup::HLMatLoadStore,
static_cast<unsigned>(HLMatLoadStoreOpcode::ColMatLoad), Ty, {SrcGEP},
*M);
// Generate Matrix Store.
HLModule::EmitHLOperationCall(
Builder, HLOpcodeGroup::HLMatLoadStore,
static_cast<unsigned>(HLMatLoadStoreOpcode::ColMatStore), Ty,
{DestGEP, Load}, *M);
Value *DestMatPtr;
Value *SrcMatPtr;
if (idxList.size() == 1 && idxList[0] == ConstantInt::get(
IntegerType::get(Ty->getContext(), 32), APInt(32, 0))) {
// Avoid creating GEP(0)
DestMatPtr = Dest;
SrcMatPtr = Src;
}
else {
DestMatPtr = Builder.CreateInBoundsGEP(Dest, idxList);
SrcMatPtr = Builder.CreateInBoundsGEP(Src, idxList);
}
HLMatLoadStoreOpcode loadOp = bRowMajor
? HLMatLoadStoreOpcode::RowMatLoad : HLMatLoadStoreOpcode::ColMatLoad;
HLMatLoadStoreOpcode storeOp = bRowMajor
? HLMatLoadStoreOpcode::RowMatStore : HLMatLoadStoreOpcode::ColMatStore;
Value *Load = HLModule::EmitHLOperationCall(
Builder, HLOpcodeGroup::HLMatLoadStore, static_cast<unsigned>(loadOp),
Ty, { SrcMatPtr }, *M);
HLModule::EmitHLOperationCall(
Builder, HLOpcodeGroup::HLMatLoadStore, static_cast<unsigned>(storeOp),
Ty, { DestMatPtr, Load }, *M);
} else if (StructType *ST = dyn_cast<StructType>(Ty)) {
if (dxilutil::IsHLSLObjectType(ST)) {
// Avoid split HLSL object.
@ -2365,44 +2365,55 @@ static void SplitCpy(Type *Ty, Value *Dest, Value *Src,
}
}
static void SplitPtr(Type *Ty, Value *Ptr, SmallVector<Value *, 16> &idxList,
SmallVector<Value *, 16> &EltPtrList,
IRBuilder<> &Builder) {
// Given a pointer to a value, produces a list of pointers to
// all scalar elements of that value and their field annotations, at any nesting level.
static void SplitPtr(Value *Ptr, // The root value pointer
SmallVectorImpl<Value *> &IdxList, // GEP indices stack during recursion
Type *Ty, // Type at the current GEP indirection level
const DxilFieldAnnotation &Annotation, // Annotation at the current GEP indirection level
SmallVectorImpl<Value *> &EltPtrList, // Accumulates pointers to each element found
SmallVectorImpl<const DxilFieldAnnotation*> &EltAnnotationList, // Accumulates field annotations for each element found
DxilTypeSystem &TypeSys,
IRBuilder<> &Builder) {
if (PointerType *PT = dyn_cast<PointerType>(Ty)) {
Constant *idx = Constant::getIntegerValue(
IntegerType::get(Ty->getContext(), 32), APInt(32, 0));
idxList.emplace_back(idx);
IdxList.emplace_back(idx);
SplitPtr(PT->getElementType(), Ptr, idxList, EltPtrList, Builder);
SplitPtr(Ptr, IdxList, PT->getElementType(), Annotation,
EltPtrList, EltAnnotationList, TypeSys, Builder);
idxList.pop_back();
} else if (HLMatrixLower::IsMatrixType(Ty)) {
Value *GEP = Builder.CreateInBoundsGEP(Ptr, idxList);
EltPtrList.emplace_back(GEP);
} else if (StructType *ST = dyn_cast<StructType>(Ty)) {
if (dxilutil::IsHLSLObjectType(ST)) {
// Avoid split HLSL object.
Value *GEP = Builder.CreateInBoundsGEP(Ptr, idxList);
EltPtrList.emplace_back(GEP);
return;
}
for (uint32_t i = 0; i < ST->getNumElements(); i++) {
llvm::Type *ET = ST->getElementType(i);
IdxList.pop_back();
return;
}
if (StructType *ST = dyn_cast<StructType>(Ty)) {
if (!dxilutil::IsHLSLMatrixType(Ty) && !dxilutil::IsHLSLObjectType(ST)) {
const DxilStructAnnotation* SA = TypeSys.GetStructAnnotation(ST);
Constant *idx = llvm::Constant::getIntegerValue(
for (uint32_t i = 0; i < ST->getNumElements(); i++) {
llvm::Type *EltTy = ST->getElementType(i);
Constant *idx = llvm::Constant::getIntegerValue(
IntegerType::get(Ty->getContext(), 32), APInt(32, i));
idxList.emplace_back(idx);
IdxList.emplace_back(idx);
SplitPtr(ET, Ptr, idxList, EltPtrList, Builder);
SplitPtr(Ptr, IdxList, EltTy, SA->GetFieldAnnotation(i),
EltPtrList, EltAnnotationList, TypeSys, Builder);
idxList.pop_back();
}
} else if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
if (AT->getNumContainedTypes() == 0) {
// Skip case like [0 x %struct].
IdxList.pop_back();
}
return;
}
}
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
if (AT->getArrayNumElements() == 0) {
// Skip cases like [0 x %struct], nothing to copy
return;
}
Type *ElTy = AT->getElementType();
SmallVector<ArrayType *, 4> nestArrayTys;
@ -2414,19 +2425,16 @@ static void SplitPtr(Type *Ty, Value *Ptr, SmallVector<Value *, 16> &idxList,
ElTy = ElAT->getElementType();
}
if (!ElTy->isStructTy() ||
HLMatrixLower::IsMatrixType(ElTy)) {
// Not split array of basic type.
Value *GEP = Builder.CreateInBoundsGEP(Ptr, idxList);
EltPtrList.emplace_back(GEP);
}
else {
if (ElTy->isStructTy() && !dxilutil::IsHLSLMatrixType(ElTy)) {
DXASSERT(0, "Not support array of struct when split pointers.");
return;
}
} else {
Value *GEP = Builder.CreateInBoundsGEP(Ptr, idxList);
EltPtrList.emplace_back(GEP);
}
// Return a pointer to the current element and its annotation
Value *GEP = Builder.CreateInBoundsGEP(Ptr, IdxList);
EltPtrList.emplace_back(GEP);
EltAnnotationList.emplace_back(&Annotation);
}
// Support case when bitcast (gep ptr, 0,0) is transformed into bitcast ptr.
@ -2435,7 +2443,7 @@ static unsigned MatchSizeByCheckElementType(Type *Ty, const DataLayout &DL, unsi
// Size match, return current level.
if (ptrSize == size) {
// Not go deeper for matrix.
if (HLMatrixLower::IsMatrixType(Ty))
if (dxilutil::IsHLSLMatrixType(Ty))
return level;
// For struct, go deeper if size not change.
// This will leave memcpy to deeper level when flatten.
@ -2588,7 +2596,7 @@ void MemcpySplitter::SplitMemCpy(MemCpyInst *MI, const DataLayout &DL,
// Try to find fieldAnnotation from user of Dest/Src.
if (!fieldAnnotation) {
Type *EltTy = dxilutil::GetArrayEltTy(DestTy);
if (HLMatrixLower::IsMatrixType(EltTy)) {
if (dxilutil::IsHLSLMatrixType(EltTy)) {
fieldAnnotation = HLMatrixLower::FindAnnotationFromMatUser(Dest, typeSys);
}
}
@ -2837,7 +2845,7 @@ void SROA_Helper::RewriteForLoad(LoadInst *LI) {
Value *Ptr = NewElts[i];
Type *Ty = Ptr->getType()->getPointerElementType();
Value *Load = nullptr;
if (!HLMatrixLower::IsMatrixType(Ty))
if (!dxilutil::IsHLSLMatrixType(Ty))
Load = Builder.CreateLoad(Ptr, "load");
else {
// Generate Matrix Load.
@ -2922,7 +2930,7 @@ void SROA_Helper::RewriteForStore(StoreInst *SI) {
Module *M = SI->getModule();
for (unsigned i = 0, e = NewElts.size(); i != e; ++i) {
Value *Extract = Builder.CreateExtractValue(Val, i, Val->getName());
if (!HLMatrixLower::IsMatrixType(Extract->getType())) {
if (!dxilutil::IsHLSLMatrixType(Extract->getType())) {
Builder.CreateStore(Extract, NewElts[i]);
} else {
// Generate Matrix Store.
@ -3234,9 +3242,15 @@ void SROA_Helper::RewriteCall(CallInst *CI) {
Function *flatF =
GetOrCreateHLFunction(*F->getParent(), flatFuncTy, group, opcode);
IRBuilder<> Builder(CI);
// Append return void, don't need to replace CI with flatCI.
Builder.CreateCall(flatF, flatArgs);
// Append returns void, so it's not used by other instructions
// and we don't need to replace it with flatCI.
// However, we don't want to visit the same append again
// when SROA'ing other arguments, as that would be O(n^2)
// and we would attempt double-deleting the original call.
for (auto& opit : CI->operands())
opit.set(UndefValue::get(opit->getType()));
DeadInsts.push_back(CI);
} break;
case IntrinsicOp::IOP_TraceRay: {
@ -3379,7 +3393,7 @@ bool SROA_Helper::DoScalarReplacement(Value *V, std::vector<Value *> &Elts,
if (!Ty->isAggregateType())
return false;
// Skip matrix types.
if (HLMatrixLower::IsMatrixType(Ty))
if (dxilutil::IsHLSLMatrixType(Ty))
return false;
IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(Builder.GetInsertPoint()));
@ -3426,7 +3440,7 @@ bool SROA_Helper::DoScalarReplacement(Value *V, std::vector<Value *> &Elts,
if (ElTy->isStructTy() &&
// Skip Matrix type.
!HLMatrixLower::IsMatrixType(ElTy)) {
!dxilutil::IsHLSLMatrixType(ElTy)) {
if (!dxilutil::IsHLSLObjectType(ElTy)) {
// for array of struct
// split into arrays of struct elements
@ -3555,7 +3569,7 @@ bool SROA_Helper::DoScalarReplacement(GlobalVariable *GV,
if (Ty->isSingleValueType() && !Ty->isVectorTy())
return false;
// Skip matrix types.
if (HLMatrixLower::IsMatrixType(Ty))
if (dxilutil::IsHLSLMatrixType(Ty))
return false;
Module *M = GV->getParent();
@ -3624,7 +3638,7 @@ bool SROA_Helper::DoScalarReplacement(GlobalVariable *GV,
if (ElTy->isStructTy() &&
// Skip Matrix type.
!HLMatrixLower::IsMatrixType(ElTy)) {
!dxilutil::IsHLSLMatrixType(ElTy)) {
// for array of struct
// split into arrays of struct elements
StructType *ElST = cast<StructType>(ElTy);
@ -4108,6 +4122,9 @@ bool SROA_Helper::LowerMemcpy(Value *V, DxilFieldAnnotation *annotation,
// For GEP, the ptr could have other GEP read/write.
// Only scan one GEP is not enough.
Value *Ptr = GEP->getPointerOperand();
while (GEPOperator *NestedGEP = dyn_cast<GEPOperator>(Ptr))
Ptr = NestedGEP->getPointerOperand();
if (CallInst *PtrCI = dyn_cast<CallInst>(Ptr)) {
hlsl::HLOpcodeGroup group =
hlsl::GetHLOpcodeGroup(PtrCI->getCalledFunction());
@ -4185,7 +4202,7 @@ bool SROA_Helper::IsEmptyStructType(Type *Ty, DxilTypeSystem &typeSys) {
Ty = Ty->getArrayElementType();
if (StructType *ST = dyn_cast<StructType>(Ty)) {
if (!HLMatrixLower::IsMatrixType(Ty)) {
if (!dxilutil::IsHLSLMatrixType(Ty)) {
DxilStructAnnotation *SA = typeSys.GetStructAnnotation(ST);
if (SA && SA->IsEmptyStruct())
return true;
@ -4343,7 +4360,7 @@ public:
continue;
// Check matrix store.
if (HLMatrixLower::IsMatrixType(
if (dxilutil::IsHLSLMatrixType(
GV->getType()->getPointerElementType())) {
if (CallInst *CI = dyn_cast<CallInst>(user)) {
if (GetHLOpcodeGroupByName(CI->getCalledFunction()) ==
@ -4389,14 +4406,13 @@ private:
DxilParameterAnnotation &paramAnnotation,
std::vector<Value *> &FlatParamList,
std::vector<DxilParameterAnnotation> &FlatRetAnnotationList,
IRBuilder<> &Builder, DbgDeclareInst *DDI);
BasicBlock *EntryBlock, DbgDeclareInst *DDI);
Value *castResourceArgIfRequired(Value *V, Type *Ty, bool bOut,
DxilParamInputQual inputQual,
IRBuilder<> &Builder);
Value *castArgumentIfRequired(Value *V, Type *Ty, bool bOut,
DxilParamInputQual inputQual,
DxilFieldAnnotation &annotation,
std::deque<Value *> &WorkList,
IRBuilder<> &Builder);
// Replace use of parameter which changed type when flatten.
// Also add information to Arg if required.
@ -4422,6 +4438,25 @@ private:
std::unordered_set<Value *> castRowMajorParamMap;
bool m_HasDbgInfo;
};
// When replacing aggregates by its scalar elements,
// the first element will preserve the original semantic,
// and the subsequent ones will temporarily use this value.
// We then run a pass to fix the semantics and properly renumber them
// once the aggregate has been fully expanded.
//
// For example:
// struct Foo { float a; float b; };
// void main(Foo foo : TEXCOORD0, float bar : TEXCOORD0)
//
// Will be expanded to
// void main(float a : TEXCOORD0, float b : *, float bar : TEXCOORD0)
//
// And then fixed up to
// void main(float a : TEXCOORD0, float b : TEXCOORD1, float bar : TEXCOORD0)
//
// (which will later on fail validation due to duplicate semantics).
constexpr const char *ContinuedPseudoSemantic = "*";
}
char SROA_Parameter_HLSL::ID = 0;
@ -4632,7 +4667,7 @@ static DxilFieldAnnotation &GetEltAnnotation(Type *Ty, unsigned idx, DxilFieldAn
while (Ty->isArrayTy())
Ty = Ty->getArrayElementType();
if (StructType *ST = dyn_cast<StructType>(Ty)) {
if (HLMatrixLower::IsMatrixType(Ty))
if (dxilutil::IsHLSLMatrixType(Ty))
return annotation;
DxilStructAnnotation *SA = dxilTypeSys.GetStructAnnotation(ST);
if (SA) {
@ -4700,13 +4735,13 @@ static unsigned AllocateSemanticIndex(
FlatAnnotationList);
}
return updatedArgIdx;
} else if (Ty->isStructTy() && !HLMatrixLower::IsMatrixType(Ty)) {
} else if (Ty->isStructTy() && !dxilutil::IsHLSLMatrixType(Ty)) {
unsigned fieldsCount = Ty->getStructNumElements();
for (unsigned i = 0; i < fieldsCount; i++) {
Type *EltTy = Ty->getStructElementType(i);
argIdx = AllocateSemanticIndex(EltTy, semIndex, argIdx, endArgIdx,
FlatAnnotationList);
if (!(EltTy->isStructTy() && !HLMatrixLower::IsMatrixType(EltTy))) {
if (!(EltTy->isStructTy() && !dxilutil::IsHLSLMatrixType(EltTy))) {
// Update argIdx only when it is a leaf node.
argIdx++;
}
@ -4753,17 +4788,18 @@ void SROA_Parameter_HLSL::allocateSemanticIndex(
if (semantic.empty())
continue;
unsigned semGroupEnd = i + 1;
while (semGroupEnd < endArgIndex &&
FlatAnnotationList[semGroupEnd].GetSemanticString() == semantic) {
++semGroupEnd;
}
StringRef baseSemName; // The 'FOO' in 'FOO1'.
uint32_t semIndex; // The '1' in 'FOO1'
// Split semName and index.
Semantic::DecomposeNameAndIndex(semantic, &baseSemName, &semIndex);
unsigned semGroupEnd = i + 1;
while (semGroupEnd < endArgIndex &&
FlatAnnotationList[semGroupEnd].GetSemanticString() == ContinuedPseudoSemantic) {
FlatAnnotationList[semGroupEnd].SetSemanticString(baseSemName);
++semGroupEnd;
}
DXASSERT(semanticTypeMap.count(semantic) > 0, "Must has semantic type");
Type *semanticTy = semanticTypeMap[semantic];
@ -4945,7 +4981,7 @@ CastCopyArrayMultiDimTo1Dim(Value *FromArray, Value *ToArray, Type *CurFromTy,
Value *Elt = Builder.CreateExtractElement(V, i);
Builder.CreateStore(Elt, ToPtr);
}
} else if (HLMatrixLower::IsMatrixType(CurFromTy)) {
} else if (dxilutil::IsHLSLMatrixType(CurFromTy)) {
// Copy matrix to array.
unsigned col, row;
HLMatrixLower::GetMatrixInfo(CurFromTy, col, row);
@ -4992,7 +5028,7 @@ CastCopyArray1DimToMultiDim(Value *FromArray, Value *ToArray, Type *CurToTy,
V = Builder.CreateInsertElement(V, Elt, i);
}
Builder.CreateStore(V, ToPtr);
} else if (HLMatrixLower::IsMatrixType(CurToTy)) {
} else if (dxilutil::IsHLSLMatrixType(CurToTy)) {
// Copy array to matrix.
unsigned col, row;
HLMatrixLower::GetMatrixInfo(CurToTy, col, row);
@ -5036,7 +5072,7 @@ static void CastCopyOldPtrToNewPtr(Value *OldPtr, Value *NewPtr, HLModule &HLM,
Value *Elt = Builder.CreateExtractElement(V, i);
Builder.CreateStore(Elt, EltPtr);
}
} else if (HLMatrixLower::IsMatrixType(OldTy)) {
} else if (dxilutil::IsHLSLMatrixType(OldTy)) {
CopyMatPtrToArrayPtr(OldPtr, NewPtr, /*arrayBaseIdx*/ 0, HLM, Builder,
bRowMajor);
} else if (OldTy->isArrayTy()) {
@ -5066,7 +5102,7 @@ static void CastCopyNewPtrToOldPtr(Value *NewPtr, Value *OldPtr, HLModule &HLM,
V = Builder.CreateInsertElement(V, Elt, i);
}
Builder.CreateStore(V, OldPtr);
} else if (HLMatrixLower::IsMatrixType(OldTy)) {
} else if (dxilutil::IsHLSLMatrixType(OldTy)) {
CopyArrayPtrToMatPtr(NewPtr, /*arrayBaseIdx*/ 0, OldPtr, HLM, Builder,
bRowMajor);
} else if (OldTy->isArrayTy()) {
@ -5164,7 +5200,7 @@ void SROA_Parameter_HLSL::replaceCastParameter(
// Must be in param.
// Store NewParam to OldParam at entry.
Builder.CreateStore(NewParam, OldParam);
} else if (HLMatrixLower::IsMatrixType(OldTy)) {
} else if (dxilutil::IsHLSLMatrixType(OldTy)) {
bool bRowMajor = castRowMajorParamMap.count(NewParam);
Value *Mat = LoadArrayPtrToMat(NewParam, /*arrayBaseIdx*/ 0, OldTy,
*m_pHLModule, Builder, bRowMajor);
@ -5243,7 +5279,7 @@ Value *SROA_Parameter_HLSL::castResourceArgIfRequired(
Value *SROA_Parameter_HLSL::castArgumentIfRequired(
Value *V, Type *Ty, bool bOut,
DxilParamInputQual inputQual, DxilFieldAnnotation &annotation,
std::deque<Value *> &WorkList, IRBuilder<> &Builder) {
IRBuilder<> &Builder) {
Module &M = *m_pHLModule->GetModule();
IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(Builder.GetInsertPoint()));
@ -5329,26 +5365,25 @@ Value *SROA_Parameter_HLSL::castArgumentIfRequired(
return V;
}
struct AnnotatedValue {
llvm::Value *Value;
DxilFieldAnnotation Annotation;
};
void SROA_Parameter_HLSL::flattenArgument(
Function *F, Value *Arg, bool bForParam,
DxilParameterAnnotation &paramAnnotation,
std::vector<Value *> &FlatParamList,
std::vector<DxilParameterAnnotation> &FlatAnnotationList,
IRBuilder<> &Builder, DbgDeclareInst *DDI) {
IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(Builder.GetInsertPoint()));
std::deque<Value *> WorkList;
WorkList.push_back(Arg);
BasicBlock *EntryBlock, DbgDeclareInst *DDI) {
std::deque<AnnotatedValue> WorkList;
WorkList.push_back({ Arg, paramAnnotation });
unsigned startArgIndex = FlatAnnotationList.size();
// Map from value to annotation.
std::unordered_map<Value *, DxilFieldAnnotation> annotationMap;
annotationMap[Arg] = paramAnnotation;
DxilTypeSystem &dxilTypeSys = m_pHLModule->GetTypeSystem();
const std::string &semantic = paramAnnotation.GetSemanticString();
bool bSemOverride = !semantic.empty();
DxilParamInputQual inputQual = paramAnnotation.GetParamInputQual();
bool bOut = inputQual == DxilParamInputQual::Out ||
@ -5384,15 +5419,20 @@ void SROA_Parameter_HLSL::flattenArgument(
// Process the worklist
while (!WorkList.empty()) {
Value *V = WorkList.front();
AnnotatedValue AV = WorkList.front();
WorkList.pop_front();
// Do not skip unused parameter.
DxilFieldAnnotation &annotation = annotationMap[V];
Value *V = AV.Value;
DxilFieldAnnotation &annotation = AV.Annotation;
const bool bAllowReplace = !bOut;
SROA_Helper::LowerMemcpy(V, &annotation, dxilTypeSys, DL, bAllowReplace);
// Now is safe to create the IRBuilders.
// If we create it before LowerMemcpy, the insertion pointer instruction may get deleted
IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(EntryBlock));
IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(EntryBlock));
std::vector<Value *> Elts;
// Not flat vector for entry function currently.
@ -5409,26 +5449,26 @@ void SROA_Parameter_HLSL::flattenArgument(
continue;
}
// Push Elts into workList.
// Use rbegin to make sure the order not change.
for (auto iter = Elts.rbegin(); iter != Elts.rend(); iter++)
WorkList.push_front(*iter);
bool precise = annotation.IsPrecise();
const std::string &semantic = annotation.GetSemanticString();
hlsl::InterpolationMode interpMode = annotation.GetInterpolationMode();
for (unsigned i=0;i<Elts.size();i++) {
Value *Elt = Elts[i];
// Push Elts into workList from right to left to preserve the order.
for (unsigned ri=0;ri<Elts.size();ri++) {
unsigned i = Elts.size() - ri - 1;
DxilFieldAnnotation EltAnnotation = GetEltAnnotation(Ty, i, annotation, dxilTypeSys);
const std::string &eltSem = EltAnnotation.GetSemanticString();
if (!semantic.empty()) {
if (!eltSem.empty()) {
// TODO: warning for override the semantic in EltAnnotation.
// It doesn't look like we can provide source location information from here
F->getContext().emitWarning(
Twine("semantic '") + eltSem + "' on field overridden by function or enclosing type");
}
// Just save parent semantic here, allocate later.
EltAnnotation.SetSemanticString(semantic);
// Inherit semantic from parent, but only preserve it for the first element.
// Subsequent elements are noted with a special value that gets resolved
// once the argument is completely flattened.
EltAnnotation.SetSemanticString(i == 0 ? semantic : ContinuedPseudoSemantic);
} else if (!eltSem.empty() &&
semanticTypeMap.count(eltSem) == 0) {
Type *EltTy = dxilutil::GetArrayEltTy(Ty);
@ -5442,22 +5482,13 @@ void SROA_Parameter_HLSL::flattenArgument(
if (EltAnnotation.GetInterpolationMode().GetKind() == DXIL::InterpolationMode::Undefined)
EltAnnotation.SetInterpolationMode(interpMode);
annotationMap[Elt] = EltAnnotation;
WorkList.push_front({ Elts[i], EltAnnotation });
}
annotationMap.erase(V);
++NumReplaced;
if (Instruction *I = dyn_cast<Instruction>(V))
deadAllocas.emplace_back(I);
} else {
if (bSemOverride) {
if (!annotation.GetSemanticString().empty()) {
// TODO: warning for override the semantic in EltAnnotation.
}
// Just save parent semantic here, allocate later.
annotation.SetSemanticString(semantic);
}
Type *Ty = V->getType();
if (Ty->isPointerTy())
Ty = Ty->getPointerElementType();
@ -5494,8 +5525,7 @@ void SROA_Parameter_HLSL::flattenArgument(
// Add semantic type.
semanticTypeMap[EltAnnotation.GetSemanticString()] = Ty;
annotationMap[Elt] = EltAnnotation;
WorkList.push_front(Elt);
WorkList.push_front({ Elt, EltAnnotation });
// Copy local target to flattened target.
std::vector<Value*> idxList(arrayLevel+1);
idxList[0] = Builder.getInt32(0);
@ -5529,16 +5559,12 @@ void SROA_Parameter_HLSL::flattenArgument(
arrayIdxList[idx-1] = 0;
}
}
// Don't override flattened SV_Target.
if (V == Arg) {
bSemOverride = false;
}
continue;
}
// Cast vector/matrix/resource parameter.
V = castArgumentIfRequired(V, Ty, bOut, inputQual,
annotation, WorkList, Builder);
annotation, Builder);
// Cannot SROA, save it to final parameter list.
FlatParamList.emplace_back(V);
@ -5583,6 +5609,7 @@ void SROA_Parameter_HLSL::flattenArgument(
// Create a value as output value.
Type *outputType = V->getType()->getPointerElementType()->getStructElementType(0);
Value *outputVal = AllocaBuilder.CreateAlloca(outputType);
// For each stream.Append(data)
// transform into
// d = load data
@ -5592,42 +5619,46 @@ void SROA_Parameter_HLSL::flattenArgument(
if (CallInst *CI = dyn_cast<CallInst>(user)) {
unsigned opcode = GetHLOpcode(CI);
if (opcode == static_cast<unsigned>(IntrinsicOp::MOP_Append)) {
if (CI->getNumArgOperands() == (HLOperandIndex::kStreamAppendDataOpIndex + 1)) {
Value *data =
CI->getArgOperand(HLOperandIndex::kStreamAppendDataOpIndex);
DXASSERT(data->getType()->isPointerTy(),
"Append value must be pointer.");
// At this point, the stream append data argument might or not have been SROA'd
Value *firstDataPtr = CI->getArgOperand(HLOperandIndex::kStreamAppendDataOpIndex);
DXASSERT(firstDataPtr->getType()->isPointerTy(), "Append value must be a pointer.");
if (firstDataPtr->getType()->getPointerElementType() == outputType) {
// The data has not been SROA'd
DXASSERT(CI->getNumArgOperands() == (HLOperandIndex::kStreamAppendDataOpIndex + 1),
"Unexpected number of arguments for non-SROA'd StreamOutput.Append");
IRBuilder<> Builder(CI);
llvm::SmallVector<llvm::Value *, 16> idxList;
SplitCpy(data->getType(), outputVal, data, idxList, Builder, DL,
dxilTypeSys, &flatParamAnnotation);
SplitCpy(firstDataPtr->getType(), outputVal, firstDataPtr, idxList, Builder, DL,
dxilTypeSys, &flatParamAnnotation);
CI->setArgOperand(HLOperandIndex::kStreamAppendDataOpIndex, outputVal);
}
else {
// Append has been flattened.
// Append has been SROA'd, we might be operating on multiple values
// with types differing from the stream output type.
// Flatten store outputVal.
// Must be struct to be flatten.
IRBuilder<> Builder(CI);
llvm::SmallVector<llvm::Value *, 16> idxList;
llvm::SmallVector<llvm::Value *, 16> IdxList;
llvm::SmallVector<llvm::Value *, 16> EltPtrList;
llvm::SmallVector<const DxilFieldAnnotation*, 16> EltAnnotationList;
// split
SplitPtr(outputVal->getType(), outputVal, idxList, EltPtrList,
Builder);
SplitPtr(outputVal, IdxList, outputVal->getType(), flatParamAnnotation,
EltPtrList, EltAnnotationList, dxilTypeSys, Builder);
unsigned eltCount = CI->getNumArgOperands()-2;
DXASSERT_LOCALVAR(eltCount, eltCount == EltPtrList.size(), "invalid element count");
for (unsigned i = HLOperandIndex::kStreamAppendDataOpIndex; i < CI->getNumArgOperands(); i++) {
Value *DataPtr = CI->getArgOperand(i);
Value *EltPtr =
EltPtrList[i - HLOperandIndex::kStreamAppendDataOpIndex];
Value *EltPtr = EltPtrList[i - HLOperandIndex::kStreamAppendDataOpIndex];
const DxilFieldAnnotation *EltAnnotation = EltAnnotationList[i - HLOperandIndex::kStreamAppendDataOpIndex];
llvm::SmallVector<llvm::Value *, 16> idxList;
SplitCpy(DataPtr->getType(), EltPtr, DataPtr, idxList,
Builder, DL, dxilTypeSys, &flatParamAnnotation);
llvm::SmallVector<llvm::Value *, 16> IdxList;
SplitCpy(DataPtr->getType(), EltPtr, DataPtr, IdxList,
Builder, DL, dxilTypeSys, EltAnnotation);
CI->setArgOperand(i, EltPtr);
}
}
@ -5636,7 +5667,7 @@ void SROA_Parameter_HLSL::flattenArgument(
}
// Then split output value to generate ParamQual.
WorkList.push_front(outputVal);
WorkList.push_front({ outputVal, annotation });
}
}
}
@ -5892,7 +5923,7 @@ static void LegalizeDxilInputOutputs(Function *F,
// Skip arg which is not a pointer.
if (!Ty->isPointerTy()) {
if (HLMatrixLower::IsMatrixType(Ty)) {
if (dxilutil::IsHLSLMatrixType(Ty)) {
// Replace matrix arg with cast to vec. It will be lowered in
// DxilGenerationPass.
isColMajor = paramAnnotation.GetMatrixAnnotation().Orientation ==
@ -5920,22 +5951,18 @@ static void LegalizeDxilInputOutputs(Function *F,
bool bStore = false;
CheckArgUsage(&arg, bLoad, bStore);
bool bNeedTemp = false;
bool bStoreInputToTemp = false;
bool bLoadOutputFromTemp = false;
if (qual == DxilParamInputQual::In && bStore) {
bNeedTemp = true;
bStoreInputToTemp = true;
} else if (qual == DxilParamInputQual::Out && bLoad) {
bNeedTemp = true;
bLoadOutputFromTemp = true;
} else if (bLoad && bStore) {
switch (qual) {
case DxilParamInputQual::InputPrimitive:
case DxilParamInputQual::InputPatch:
case DxilParamInputQual::OutputPatch: {
bNeedTemp = true;
bStoreInputToTemp = true;
} break;
case DxilParamInputQual::Inout:
@ -5945,13 +5972,11 @@ static void LegalizeDxilInputOutputs(Function *F,
}
} else if (qual == DxilParamInputQual::Inout) {
// Only replace inout when (bLoad && bStore) == false.
bNeedTemp = true;
bLoadOutputFromTemp = true;
bStoreInputToTemp = true;
}
if (HLMatrixLower::IsMatrixType(Ty)) {
bNeedTemp = true;
if (dxilutil::IsHLSLMatrixType(Ty)) {
if (qual == DxilParamInputQual::In)
bStoreInputToTemp = bLoad;
else if (qual == DxilParamInputQual::Out)
@ -5962,7 +5987,7 @@ static void LegalizeDxilInputOutputs(Function *F,
}
}
if (bNeedTemp) {
if (bStoreInputToTemp || bLoadOutputFromTemp) {
IRBuilder<> AllocaBuilder(EntryBlk.getFirstInsertionPt());
IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(&EntryBlk));
@ -6036,11 +6061,17 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
LLVMContext &Ctx = m_pHLModule->GetCtx();
std::unique_ptr<BasicBlock> TmpBlockForFuncDecl;
BasicBlock *EntryBlock;
if (F->isDeclaration()) {
// We still want to SROA the parameters, so creaty a dummy
// function body block to avoid special cases.
TmpBlockForFuncDecl.reset(BasicBlock::Create(Ctx));
// Create return as terminator.
IRBuilder<> RetBuilder(TmpBlockForFuncDecl.get());
RetBuilder.CreateRetVoid();
EntryBlock = TmpBlockForFuncDecl.get();
} else {
EntryBlock = &F->getEntryBlock();
}
std::vector<Value *> FlatParamList;
@ -6053,13 +6084,6 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
for (Argument &Arg : F->args()) {
// merge GEP use for arg.
HLModule::MergeGepUse(&Arg);
// Insert point may be removed. So recreate builder every time.
IRBuilder<> Builder(Ctx);
if (!F->isDeclaration()) {
Builder.SetInsertPoint(dxilutil::FirstNonAllocaInsertionPt(F));
} else {
Builder.SetInsertPoint(dxilutil::FirstNonAllocaInsertionPt(TmpBlockForFuncDecl.get()));
}
unsigned prevFlatParamCount = FlatParamList.size();
@ -6067,7 +6091,7 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
funcAnnotation->GetParameterAnnotation(Arg.getArgNo());
DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(&Arg);
flattenArgument(F, &Arg, bForParamTrue, paramAnnotation, FlatParamList,
FlatParamAnnotationList, Builder, DDI);
FlatParamAnnotationList, EntryBlock, DDI);
unsigned newFlatParamCount = FlatParamList.size() - prevFlatParamCount;
for (unsigned i = 0; i < newFlatParamCount; i++) {
@ -6081,15 +6105,8 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
std::vector<DxilParameterAnnotation> FlatRetAnnotationList;
// Split and change to out parameter.
if (!retType->isVoidTy()) {
IRBuilder<> Builder(Ctx);
IRBuilder<> AllocaBuilder(Ctx);
if (!F->isDeclaration()) {
Builder.SetInsertPoint(dxilutil::FirstNonAllocaInsertionPt(F));
AllocaBuilder.SetInsertPoint(dxilutil::FindAllocaInsertionPt(F));
} else {
Builder.SetInsertPoint(dxilutil::FirstNonAllocaInsertionPt(TmpBlockForFuncDecl.get()));
AllocaBuilder.SetInsertPoint(TmpBlockForFuncDecl->getFirstInsertionPt());
}
IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(EntryBlock));
IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(EntryBlock));
Value *retValAddr = AllocaBuilder.CreateAlloca(retType);
DxilParameterAnnotation &retAnnotation =
funcAnnotation->GetRetTypeAnnotation();
@ -6143,7 +6160,7 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(retValAddr);
flattenArgument(F, retValAddr, bForParamTrue,
funcAnnotation->GetRetTypeAnnotation(), FlatRetList,
FlatRetAnnotationList, Builder, DDI);
FlatRetAnnotationList, EntryBlock, DDI);
const int kRetArgNo = -1;
for (unsigned i = 0; i < FlatRetList.size(); i++) {
@ -6341,6 +6358,8 @@ void SROA_Parameter_HLSL::createFlattenedFunction(Function *F) {
}
flatArg->replaceAllUsesWith(Arg);
if (isa<Instruction>(flatArg))
DeadInsts.emplace_back(flatArg);
HLModule::MergeGepUse(Arg);
// Flatten store of array parameter.

Просмотреть файл

@ -548,7 +548,10 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT) {
/// in place of the other. Note that we will always choose the non-undef
/// value to keep.
static bool CanMergeValues(Value *First, Value *Second) {
return First == Second || isa<UndefValue>(First) || isa<UndefValue>(Second);
return First == Second;
// HLSL Change Begin -Not merge undef.
// || isa<UndefValue>(First) || isa<UndefValue>(Second);
// HLSL Change End.
}
/// CanPropagatePredecessorsForPHIs - Return true if we can fold BB, an

Просмотреть файл

@ -371,8 +371,10 @@ bool IsHLSLVecMatType(clang::QualType);
bool IsHLSLVecType(clang::QualType type);
bool IsHLSLMatType(clang::QualType type);
clang::QualType GetElementTypeOrType(clang::QualType type);
bool HasHLSLMatOrientation(clang::QualType type, bool *pIsRowMajor);
bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm);
bool HasHLSLMatOrientation(clang::QualType type, bool *pIsRowMajor = nullptr);
bool IsHLSLMatRowMajor(clang::QualType type, bool defaultValue);
bool IsHLSLUnsigned(clang::QualType type);
bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm = nullptr);
bool IsHLSLInputPatchType(clang::QualType type);
bool IsHLSLOutputPatchType(clang::QualType type);
bool IsHLSLPointStreamType(clang::QualType type);
@ -382,6 +384,7 @@ bool IsHLSLStreamOutputType(clang::QualType type);
bool IsHLSLResourceType(clang::QualType type);
bool IsHLSLNumeric(clang::QualType type);
bool IsHLSLNumericUserDefinedType(clang::QualType type);
bool IsHLSLAggregateType(clang::ASTContext& context, clang::QualType type);
clang::QualType GetHLSLResourceResultType(clang::QualType type);
bool IsIncompleteHLSLResourceArrayType(clang::ASTContext& context, clang::QualType type);
clang::QualType GetHLSLInputPatchElementType(clang::QualType type);

Просмотреть файл

@ -7670,8 +7670,8 @@ def err_hlsl_intrinsic_template_arg_unsupported: Error<
"Explicit template arguments on intrinsic %0 are not supported.">;
def err_hlsl_intrinsic_template_arg_requires_2018: Error<
"Explicit template arguments on intrinsic %0 requires HLSL version 2018 or above.">;
def err_hlsl_intrinsic_template_arg_scalar_vector_16: Error<
"Explicit template arguments on intrinsic %0 are limited one to scalar or vector type up to 16 bytes in size.">;
def err_hlsl_intrinsic_template_arg_scalar_vector: Error<
"Explicit template arguments on intrinsic %0 are limited one to scalar or vector type.">;
}
def err_hlsl_no_struct_user_defined_type: Error<
"User defined type intrinsic arg must be struct">;

Просмотреть файл

@ -212,6 +212,8 @@ public:
/// DefaultLinkage Internal, External, or Default. If Default, default
/// function linkage is determined by library target.
hlsl::DXIL::DefaultLinkage DefaultLinkage = hlsl::DXIL::DefaultLinkage::Default;
/// Assume UAVs/SRVs may alias.
bool HLSLResMayAlias = false;
// HLSL Change Ends
// SPIRV Change Starts

Просмотреть файл

@ -431,6 +431,9 @@ public:
/// \brief Decorates the given target <result-id> with nonuniformEXT
void decorateNonUniformEXT(uint32_t targetId);
/// \brief Decorates the given target <result-id> with NoContraction
void decorateNoContraction(uint32_t targetId);
// === Type ===
uint32_t getVoidType();

Просмотреть файл

@ -347,6 +347,15 @@ private:
/*TSCS*/unsigned ThreadStorageClassSpec : 2;
unsigned SCS_extern_in_linkage_spec : 1;
// HLSL Change Start
// Whether the default matrix pack is defined at the point
// of the declaration. This is false when rewriting
// and no #pragma pack_matrix have been encountered yet.
unsigned HasDefaultMatrixPack : 1;
// Default matrix pack at the point of the declaration
unsigned DefaultMatrixPackRowMajor : 1;
// HLSL Change End
// type-specifier
/*TSW*/unsigned TypeSpecWidth : 2;
/*TSC*/unsigned TypeSpecComplex : 2;
@ -431,6 +440,8 @@ public:
: StorageClassSpec(SCS_unspecified),
ThreadStorageClassSpec(TSCS_unspecified),
SCS_extern_in_linkage_spec(false),
HasDefaultMatrixPack(false), // HLSL Change
DefaultMatrixPackRowMajor(false), // HLSL Change
TypeSpecWidth(TSW_unspecified),
TypeSpecComplex(TSC_unspecified),
TypeSpecSign(TSS_unspecified),
@ -463,6 +474,19 @@ public:
SCS_extern_in_linkage_spec = Value;
}
// HLSL changes begin
bool TryGetDefaultMatrixPackRowMajor(bool& rowMajor) const {
if (!HasDefaultMatrixPack) return false;
rowMajor = DefaultMatrixPackRowMajor;
return true;
}
void SetDefaultMatrixPackRowMajor(bool Value) {
HasDefaultMatrixPack = true;
DefaultMatrixPackRowMajor = Value;
}
// HLSL changes end
SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; }
SourceLocation getThreadStorageClassSpecLoc() const {
return ThreadStorageClassSpecLoc;

Просмотреть файл

@ -333,10 +333,12 @@ public:
LangOptions::PragmaMSPointersToMembersKind
MSPointerToMemberRepresentationMethod;
// HLSL Change Begin - pragma pack_matrix.
// Add both row/col to identify the default case which no pragma.
bool PackMatrixRowMajorPragmaOn = false; // True when \#pragma pack_matrix(row_major) on.
bool PackMatrixColMajorPragmaOn = false; // True when \#pragma pack_matrix(column_major) on.
// HLSL Change Begin
// The HLSL rewriter doesn't define a default matrix pack,
// so we must preserve the lack of annotations to avoid changing semantics.
bool HasDefaultMatrixPack = false;
// Uses of #pragma pack_matrix change the default pack.
bool DefaultMatrixPackRowMajor = false;
// HLSL Change End.
enum PragmaVtorDispKind {

Просмотреть файл

@ -1568,7 +1568,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
// Vector align to its element.
if (getLangOpts().HLSL) {
Align = EltInfo.Align;
Width = Align * VT->getNumElements();
}
// HLSL Change Ends.
// If the alignment is not a power of 2, round up to the next power of 2.

Просмотреть файл

@ -7670,6 +7670,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_CopyAndAutoreleaseBlockObject:
case CK_HLSLVectorToScalarCast: // HLSL Change
case CK_HLSLMatrixToScalarCast: // HLSL Change
case CK_FlatConversion: // HLSL Change
return Error(E);
case CK_UserDefinedConversion:

Просмотреть файл

@ -125,6 +125,15 @@ bool IsHLSLNumericUserDefinedType(clang::QualType type) {
return false;
}
bool IsHLSLAggregateType(clang::ASTContext& context, clang::QualType type) {
// Aggregate types are arrays and user-defined structs
if (context.getAsArrayType(type) != nullptr) return true;
const RecordType *Record = dyn_cast<RecordType>(type);
return Record != nullptr
&& !IsHLSLVecMatType(type) && !IsHLSLResourceType(type)
&& !dyn_cast<ClassTemplateSpecializationDecl>(Record->getAsCXXRecordDecl());
}
clang::QualType GetElementTypeOrType(clang::QualType type) {
if (const RecordType *RT = type->getAs<RecordType>()) {
if (const ClassTemplateSpecializationDecl *templateDecl =
@ -160,6 +169,26 @@ bool HasHLSLMatOrientation(clang::QualType type, bool *pIsRowMajor) {
return false;
}
bool IsHLSLMatRowMajor(clang::QualType type, bool defaultValue) {
bool result = defaultValue;
HasHLSLMatOrientation(type, &result);
return result;
}
bool IsHLSLUnsigned(clang::QualType type) {
if (type->getAs<clang::BuiltinType>() == nullptr) {
type = type.getCanonicalType().getNonReferenceType();
if (IsHLSLVecMatType(type))
type = GetElementTypeOrType(type);
if (type->isExtVectorType())
type = type->getAs<clang::ExtVectorType>()->getElementType();
}
return type->isUnsignedIntegerType();
}
bool HasHLSLUNormSNorm(clang::QualType type, bool *pIsSNorm) {
// snorm/unorm can be on outer vector/matrix as well as element type
// in the template form. Outer-most type attribute wins.

Просмотреть файл

@ -278,7 +278,12 @@ namespace clang {
unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
DiagnosticIDs &Diags) {
DiagDesc D(L, Message);
// HLSL Change Starts
// ".str()" is a workaround for a bug in VC++'s STL where std::pair<T,U>::pair<T2,U2>(T2&&,U2&&)
// may cause a conversion operator from U2 to U to be invoked within a noexcept function.
// This would cause a call std::terminate if we ran out of memory and throw std::bad_alloc
DiagDesc D(L, Message.str());
// HLSL Change Ends
// Check to see if it already exists.
std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
if (I != DiagIDs.end() && I->first == D)

Просмотреть файл

@ -6991,9 +6991,7 @@ public:
LongWidth = LongAlign = 32;
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
BoolWidth = 32;
// To avoid member for alignment.
BoolAlign = 8;
BoolWidth = BoolAlign = 32;
// using the Microsoft ABI.
TheCXXABI.set(TargetCXXABI::Microsoft);

Просмотреть файл

@ -324,6 +324,7 @@ void EmitAssemblyHelper::CreatePasses() {
PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
PMBuilder.HLSLHighLevel = CodeGenOpts.HLSLHighLevel; // HLSL Change
PMBuilder.HLSLExtensionsCodeGen = CodeGenOpts.HLSLExtensionsCodegen.get(); // HLSL Change
PMBuilder.HLSLResMayAlias = CodeGenOpts.HLSLResMayAlias; // HLSL Change
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;

Просмотреть файл

@ -1865,11 +1865,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().getDebugInfo()
>= CodeGenOptions::LimitedDebugInfo) {
// HLSL Change Begins.
// Use the Arg directly instead of DeclPtr for HLSL.
// The DeclPtr will be promoted in later pass.
DI->EmitDeclareOfArgVariable(&D, Arg, ArgNo, Builder);
// HLSL Change Ends.
DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
}
}

Просмотреть файл

@ -1082,6 +1082,14 @@ static bool hasBooleanRepresentation(QualType Ty) {
return false;
}
// HLSL Change Begin.
static bool hasBooleanScalarOrVectorRepresentation(QualType Ty) {
if (hlsl::IsHLSLVecType(Ty))
return hasBooleanRepresentation(hlsl::GetElementTypeOrType(Ty));
return hasBooleanRepresentation(Ty);
}
// HLSL Change End.
static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
llvm::APInt &Min, llvm::APInt &End,
bool StrictEnums) {
@ -1233,30 +1241,26 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
}
llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
if (hasBooleanRepresentation(Ty)) {
// This should really always be an i1, but sometimes it's already
// an i8, and it's awkward to track those cases down.
if (Value->getType()->isIntegerTy(1))
// HLSL Change Begin.
// Bool scalar and vectors have a different representation in memory than in registers.
if (hasBooleanScalarOrVectorRepresentation(Ty)) {
if (Value->getType()->getScalarType()->isIntegerTy(1))
return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "frombool");
assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
"wrong value rep of bool");
}
// HLSL Change End.
return Value;
}
llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
if (hasBooleanRepresentation(Ty)) {
assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
"wrong value rep of bool");
// HLSL Change Begin.
// HLSL Change Begin.
// Bool scalar and vectors have a different representation in memory than in registers.
if (hasBooleanScalarOrVectorRepresentation(Ty)) {
// Use ne v, 0 to convert to i1 instead of trunc.
return Builder.CreateICmpNE(
Value, llvm::ConstantInt::get(Value->getType(), 0), "tobool");
// HLSL Change End.
Value, llvm::ConstantVector::getNullValue(Value->getType()), "tobool");
}
// HLSL Change End.
return Value;
}
@ -1392,6 +1396,20 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
return RValue::get(V);
}
}
if (hlsl::IsHLSLAggregateType(getContext(), LV.getType())) {
// We cannot load the value because we don't expect to ever have
// user-defined struct or array-typed llvm registers, only pointers to them.
// To preserve the snapshot semantics of LValue loads, we copy the
// value to a temporary and return a pointer to it.
llvm::Value *Alloca = CreateMemTemp(LV.getType(), "rval");
auto CharSizeAlignPair = getContext().getTypeInfoInChars(LV.getType());
Builder.CreateMemCpy(Alloca, LV.getAddress(),
static_cast<uint64_t>(CharSizeAlignPair.first.getQuantity()),
static_cast<unsigned>(CharSizeAlignPair.second.getQuantity()));
return RValue::get(Alloca);
}
// HLSL Change End.
// Everything needs a load.
@ -1475,6 +1493,8 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
Load->setAlignment(LV.getAlignment().getQuantity());
llvm::Value *Vec = Load;
Vec = EmitFromMemory(Vec, LV.getType()); // HLSL Change
const llvm::Constant *Elts = LV.getExtVectorElts();
// If the result of the expression is a non-vector type, we must be extracting
@ -1748,7 +1768,10 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
const llvm::Constant *Elts = Dst.getExtVectorElts();
llvm::Value *SrcVal = Src.getScalarVal();
// HLSL Change Starts
SrcVal = EmitToMemory(SrcVal, Dst.getType());
const VectorType *VTy = Dst.getType()->getAs<VectorType>();
if (VTy == nullptr && getContext().getLangOpts().HLSL)
VTy =
@ -2918,11 +2941,12 @@ CodeGenFunction::EmitHLSLVectorElementExpr(const HLSLVectorElementExpr *E) {
assert(hlsl::IsHLSLVecType(E->getBase()->getType()) &&
"Result must be a vector");
llvm::Value *Vec = EmitScalarExpr(E->getBase());
Vec = EmitToMemory(Vec, E->getBase()->getType());
// Store the vector to memory (because LValue wants an address).
llvm::Value *VecMem = CreateMemTemp(E->getBase()->getType());
Builder.CreateStore(Vec, VecMem);
Base = MakeAddrLValue(VecMem, E->getBase()->getType());
llvm::Value *VecMemPtr = CreateMemTemp(E->getBase()->getType());
Builder.CreateStore(Vec, VecMemPtr);
Base = MakeAddrLValue(VecMemPtr, E->getBase()->getType());
}
QualType type =

Просмотреть файл

@ -714,12 +714,12 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
if (IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E->getSubExpr())) {
llvm::Value *SrcVal = llvm::ConstantInt::get(CGF.getLLVMContext(), IL->getValue());
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversionToAggregate(
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversion(
CGF, SrcVal, DestPtr, E->getType(), Ty);
} else if (FloatingLiteral *FL =
dyn_cast<FloatingLiteral>(E->getSubExpr())) {
llvm::Value *SrcVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FL->getValue());
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversionToAggregate(
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversion(
CGF, SrcVal, DestPtr, E->getType(), Ty);
} else {
Expr *Src = E->getSubExpr();
@ -744,7 +744,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
} break;
case TEK_Scalar: {
llvm::Value *SrcVal = CGF.EmitScalarExpr(Src);
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversionToAggregate(
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversion(
CGF, SrcVal, DestPtr, E->getType(), Ty);
} break;
default:

Просмотреть файл

@ -1232,7 +1232,7 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
assert(E && "No initializer to emit");
llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
if (C && C->getType()->isIntegerTy(1)) {
if (C && C->getType()->getScalarType()->isIntegerTy(1)) { // HLSL Change
llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
@ -1257,7 +1257,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
else
C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
if (C && C->getType()->isIntegerTy(1)) {
if (C && C->getType()->getScalarType()->isIntegerTy(1)) { // HLSL Change
llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
@ -1472,7 +1472,7 @@ CodeGenModule::EmitConstantValueForMemory(const APValue &Value,
QualType DestType,
CodeGenFunction *CGF) {
llvm::Constant *C = EmitConstantValue(Value, DestType, CGF);
if (C->getType()->isIntegerTy(1)) {
if (C->getType()->getScalarType()->isIntegerTy(1)) { // HLSL Change
llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType);
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}

Просмотреть файл

@ -1507,7 +1507,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
QualType DestTy = CE->getType();
CastKind Kind = CE->getCastKind();
// HLSL Change Begins
if (hlsl::IsHLSLMatType(E->getType()) || hlsl::IsHLSLMatType(CE->getType())) {
if ((hlsl::IsHLSLMatType(E->getType()) || hlsl::IsHLSLMatType(CE->getType()))
&& Kind != CastKind::CK_FlatConversion) {
llvm::Value *V = CGF.EmitScalarExpr(E);
llvm::Type *RetTy = CGF.ConvertType(DestTy);
@ -1817,9 +1818,37 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Builder.CreateExtractElement(Visit(E), (uint64_t)0);
}
case CK_FlatConversion: {
llvm::Value *val = Visit(E);
llvm::Value *elem = Builder.CreateExtractValue(val, (uint64_t)0);
return EmitScalarConversion(elem, E->getType(), DestTy);
llvm::Value *Src = Visit(E);
// We should have an aggregate type (struct or array) on one side,
// and a numeric type (scalar, vector or matrix) on the other.
// If the aggregate type is the cast source, it should be a pointer.
// Aggregate to aggregate casts are handled in CGExprAgg.cpp
auto areCompoundAndNumeric = [this](QualType lhs, QualType rhs) {
return hlsl::IsHLSLAggregateType(CGF.getContext(), lhs)
&& (rhs->isBuiltinType() || hlsl::IsHLSLVecMatType(rhs));
};
assert(Src->getType()->isPointerTy()
? areCompoundAndNumeric(E->getType(), DestTy)
: areCompoundAndNumeric(DestTy, E->getType()));
(void)areCompoundAndNumeric;
llvm::Value *DstPtr = CGF.CreateMemTemp(DestTy, "flatconv");
CGF.CGM.getHLSLRuntime().EmitHLSLFlatConversion(
CGF, Src, DstPtr, DestTy, E->getType());
// Return an rvalue
// Matrices must be loaded with the special function
if (hlsl::IsHLSLMatType(DestTy))
return CGF.CGM.getHLSLRuntime().EmitHLSLMatrixLoad(CGF, DstPtr, DestTy);
// Structs/arrays are pointers to temporaries
if (hlsl::IsHLSLAggregateType(CGF.getContext(), DestTy))
return DstPtr;
// Scalars/vectors are loaded regularly
llvm::Value *Result = Builder.CreateLoad(DstPtr);
return Result = CGF.EmitFromMemory(Result, DestTy);
}
case CK_HLSLCC_IntegralToBoolean:
return EmitIntToBoolConversion(Visit(E));

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -21,23 +21,3 @@ using namespace clang;
using namespace CodeGen;
CGHLSLRuntime::~CGHLSLRuntime() {}
bool CGHLSLRuntime::IsHLSLVecMatType(clang::QualType &type) {
return hlsl::IsHLSLVecMatType(type);
}
const clang::ExtVectorType *CGHLSLRuntime::ConvertHLSLVecMatTypeToExtVectorType(
const clang::ASTContext &context, clang::QualType &type) {
return hlsl::ConvertHLSLVecMatTypeToExtVectorType(context, type);
}
QualType CGHLSLRuntime::GetHLSLVecMatElementType(QualType type) {
const Type *Ty = type.getCanonicalType().getTypePtr();
// TODO: check isVecMatrix
const RecordType *RT = cast<RecordType>(Ty);
const ClassTemplateSpecializationDecl *templateDecl =
cast<ClassTemplateSpecializationDecl>(RT->getDecl());
const TemplateArgumentList &argList = templateDecl->getTemplateArgs();
const TemplateArgument &arg0 = argList[0];
return arg0.getAsType();
}

Просмотреть файл

@ -102,7 +102,7 @@ public:
virtual void EmitHLSLAggregateStore(CodeGenFunction &CGF, llvm::Value *Val,
llvm::Value *DestPtr,
clang::QualType Ty) = 0;
virtual void EmitHLSLFlatConversionToAggregate(CodeGenFunction &CGF, llvm::Value *Val,
virtual void EmitHLSLFlatConversion(CodeGenFunction &CGF, llvm::Value *Val,
llvm::Value *DestPtr,
clang::QualType Ty, clang::QualType SrcTy) = 0;
virtual void EmitHLSLFlatConversionAggregateCopy(CodeGenFunction &CGF, llvm::Value *SrcPtr,
@ -122,11 +122,6 @@ public:
virtual void AddControlFlowHint(CodeGenFunction &CGF, const Stmt &S, llvm::TerminatorInst *TI, llvm::ArrayRef<const Attr *> Attrs) = 0;
virtual void FinishAutoVar(CodeGenFunction &CGF, const VarDecl &D, llvm::Value *V) = 0;
static const clang::ExtVectorType *
ConvertHLSLVecMatTypeToExtVectorType(const clang::ASTContext &context,
clang::QualType &type);
static bool IsHLSLVecMatType(clang::QualType &type);
static clang::QualType GetHLSLVecMatElementType(clang::QualType type);
};
/// Create an instance of a HLSL runtime class.

Просмотреть файл

@ -1122,7 +1122,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
case TEK_Scalar:
// HLSL Change Begins.
if (hlsl::IsHLSLMatType(RV->getType())) {
CGM.getHLSLRuntime().EmitHLSLMatrixStore(*this, EmitScalarExpr(RV), ReturnValue, RV->getType());
CGM.getHLSLRuntime().EmitHLSLMatrixStore(*this, EmitScalarExpr(RV), ReturnValue, FnRetTy);
} else
// HLSL Change Ends.
Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);

Просмотреть файл

@ -612,11 +612,14 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
const auto *ND = cast<NamedDecl>(GD.getDecl());
// HLSL Change Starts
// Entry point doesn't get mangled
if (ND->getKind() == Decl::Function &&
ND->getNameAsString() == CodeGenOpts.HLSLEntryFunction) {
ND->getDeclContext()->getDeclKind() == Decl::Kind::TranslationUnit &&
ND->getNameAsString() == CodeGenOpts.HLSLEntryFunction) {
return CodeGenOpts.HLSLEntryFunction;
}
// HLSL Change Ends
SmallString<256> Buffer;
StringRef Str;
if (getCXXABI().getMangleContext().shouldMangleDeclName(ND)) {

Просмотреть файл

@ -109,15 +109,26 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
/// a type. For example, the scalar representation for _Bool is i1, but the
/// memory representation is usually i8 or i32, depending on the target.
llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
// HLSL Change Starts
if (hlsl::IsHLSLVecType(T)) {
// Vectors of bools in memory should become vectors of
// the memory representation of the elements.
// Clang doesn't do this for plain VectorTypes,
// which is fine otherwise a bool1x1 matrix would become
// [n x <m x i32>] since array elements always have memory representation.
QualType ElemT = hlsl::GetElementTypeOrType(T);
return llvm::VectorType::get(ConvertTypeForMem(ElemT), hlsl::GetHLSLVecSize(T));
}
llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
if (!R->isIntegerTy(1))
return R;
if (R->isIntegerTy(1)) {
// Bools have a different representation in memory
return llvm::IntegerType::get(getLLVMContext(), (unsigned)Context.getTypeSize(T));
}
// Otherwise, return an integer of the target-specified size.
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
return R;
// HLSL Change Ends
}

Просмотреть файл

@ -2054,14 +2054,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
AST.reset(new ASTUnit(false));
// HLSL Change Starts
AST->HlslLangExtensions = HlslLangExtensions;
// Enable -verify on the libclang initialization path.
bool VerifyDiagnostics = false;
for (const char** Arg = ArgBegin; Arg != ArgEnd; ++Arg) {
if (strcmp(*Arg, "-verify") == 0) {
VerifyDiagnostics = true;
break;
}
}
// Enable -verify and -verify-ignore-unexpected on the libclang initialization path.
bool VerifyDiagnostics = CI->getDiagnosticOpts().VerifyDiagnostics;
Diags->getDiagnosticOptions().setVerifyIgnoreUnexpected(
CI->getDiagnosticOpts().getVerifyIgnoreUnexpected());
// HLSL Change Ends
ConfigureDiags(Diags, *AST, CaptureDiagnostics, VerifyDiagnostics); // HLSL Change
AST->Diagnostics = Diags;

Просмотреть файл

@ -3478,6 +3478,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
goto DoneWithDeclSpec;
// HLSL Change Starts
// Remember the current state of the default matrix orientation,
// since it can change between any two tokens with #pragma pack_matrix
if (Parser::Actions.HasDefaultMatrixPack)
DS.SetDefaultMatrixPackRowMajor(Parser::Actions.DefaultMatrixPackRowMajor);
// HLSL Change Ends
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
@ -3588,12 +3595,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
isConstructorDeclarator(/*Unqualified*/true))
goto DoneWithDeclSpec;
// HLSL Change start - modify TypeRep for unsigned vectors/matrix
// HLSL Change Starts
// Modify TypeRep for unsigned vectors/matrix
QualType qt = TypeRep.get();
QualType newType = ApplyTypeSpecSignToParsedType(&Actions, qt, DS.getTypeSpecSign(), Loc);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, ParsedType::make(newType), Policy);
// HLSL Change end
// Remember the current state of the default matrix orientation,
// since it can change between any two tokens with #pragma pack_matrix
if (Parser::Actions.HasDefaultMatrixPack)
DS.SetDefaultMatrixPackRowMajor(Parser::Actions.DefaultMatrixPackRowMajor);
// HLSL Change Ends
if (isInvalid)
break;

Просмотреть файл

@ -16,7 +16,7 @@
namespace clang {
namespace spirv {
static_assert(spv::Version == 0x00010300 && spv::Revision == 1,
static_assert(spv::Version == 0x00010300 && spv::Revision == 6,
"Needs to regenerate outdated InstBuilder");
namespace {

Просмотреть файл

@ -893,6 +893,11 @@ void ModuleBuilder::decorateNonUniformEXT(uint32_t targetId) {
theModule.addDecoration(d, targetId);
}
void ModuleBuilder::decorateNoContraction(uint32_t targetId) {
const Decoration *d = Decoration::getNoContraction(theContext);
theModule.addDecoration(d, targetId);
}
#define IMPL_GET_PRIMITIVE_TYPE(ty) \
\
uint32_t ModuleBuilder::get##ty##Type() { \

Просмотреть файл

@ -3455,12 +3455,14 @@ bool SPIRVEmitter::tryToAssignCounterVar(const DeclaratorDecl *dstDecl,
const auto *srcFields = getIntermediateACSBufferCounter(srcExpr, &srcIndices);
if (dstFields && srcFields) {
if (!dstFields->assign(*srcFields, theBuilder, typeTranslator)) {
emitFatalError("cannot handle associated counter variable assignment",
srcExpr->getExprLoc());
return false;
}
return true;
// The destination is a struct whose fields are directly alias resources.
// But that's not necessarily true for the source, which can be deep
// nested structs. That means they will have different index "prefixes"
// for all their fields; while the "prefix" for destination is effectively
// an empty list (since it is not nested in other structs). We need to
// strip the index prefix from the source.
return dstFields->assign(*srcFields, /*dstIndices=*/{}, srcIndices,
theBuilder, typeTranslator);
}
// AssocCounter#2 and AssocCounter#4 for the lhs cannot happen since the lhs
@ -6574,6 +6576,9 @@ SpirvEvalInfo SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
case hlsl::IntrinsicOp::IOP_lit:
retVal = processIntrinsicLit(callExpr);
break;
case hlsl::IntrinsicOp::IOP_mad:
retVal = processIntrinsicMad(callExpr);
break;
case hlsl::IntrinsicOp::IOP_modf:
retVal = processIntrinsicModf(callExpr);
break;
@ -6747,7 +6752,6 @@ SpirvEvalInfo SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
INTRINSIC_OP_CASE(lerp, FMix, true);
INTRINSIC_OP_CASE(log, Log, true);
INTRINSIC_OP_CASE(log2, Log2, true);
INTRINSIC_OP_CASE(mad, Fma, true);
INTRINSIC_OP_CASE_SINT_UINT_FLOAT(max, SMax, UMax, FMax, true);
INTRINSIC_OP_CASE(umax, UMax, true);
INTRINSIC_OP_CASE_SINT_UINT_FLOAT(min, SMin, UMin, FMin, true);
@ -7425,6 +7429,105 @@ uint32_t SPIRVEmitter::processIntrinsicModf(const CallExpr *callExpr) {
return 0;
}
uint32_t SPIRVEmitter::processIntrinsicMad(const CallExpr *callExpr) {
// Signature is: ret mad(a,b,c)
// All of the above must be a scalar, vector, or matrix with the same
// component types. Component types can be float or int.
// The return value is equal to "a * b + c"
// In the case of float arguments, we can use the GLSL extended instruction
// set's Fma instruction with NoContraction decoration. In the case of integer
// arguments, we'll have to manually perform an OpIMul followed by an OpIAdd
// (We should also apply NoContraction decoration to these two instructions to
// get precise arithmetic).
// TODO: We currently don't propagate the NoContraction decoration.
const Expr *arg0 = callExpr->getArg(0);
const Expr *arg1 = callExpr->getArg(1);
const Expr *arg2 = callExpr->getArg(2);
// All arguments and the return type are the same.
const auto argType = arg0->getType();
const auto argTypeId = typeTranslator.translateType(argType);
const uint32_t arg0Id = doExpr(arg0);
const uint32_t arg1Id = doExpr(arg1);
const uint32_t arg2Id = doExpr(arg2);
// For floating point arguments, we can use the extended instruction set's Fma
// instruction. Sadly we can't simply call processIntrinsicUsingGLSLInst
// because we need to specifically decorate the Fma instruction with
// NoContraction decoration.
if (isFloatOrVecMatOfFloatType(argType)) {
const auto opcode = GLSLstd450::GLSLstd450Fma;
const uint32_t glslInstSetId = theBuilder.getGLSLExtInstSet();
// For matrix cases, operate on each row of the matrix.
if (isMxNMatrix(arg0->getType())) {
const auto actOnEachVec = [this, glslInstSetId, opcode, arg1Id,
arg2Id](uint32_t index, uint32_t vecType,
uint32_t arg0RowId) {
const uint32_t arg1RowId =
theBuilder.createCompositeExtract(vecType, arg1Id, {index});
const uint32_t arg2RowId =
theBuilder.createCompositeExtract(vecType, arg2Id, {index});
const uint32_t fma = theBuilder.createExtInst(
vecType, glslInstSetId, opcode, {arg0RowId, arg1RowId, arg2RowId});
theBuilder.decorateNoContraction(fma);
return fma;
};
return processEachVectorInMatrix(arg0, arg0Id, actOnEachVec);
}
// Non-matrix cases
const uint32_t fma = theBuilder.createExtInst(
argTypeId, glslInstSetId, opcode, {arg0Id, arg1Id, arg2Id});
theBuilder.decorateNoContraction(fma);
return fma;
}
// For scalar and vector argument types.
{
if (isScalarType(argType) || isVectorType(argType)) {
const auto mul =
theBuilder.createBinaryOp(spv::Op::OpIMul, argTypeId, arg0Id, arg1Id);
const auto add =
theBuilder.createBinaryOp(spv::Op::OpIAdd, argTypeId, mul, arg2Id);
theBuilder.decorateNoContraction(mul);
theBuilder.decorateNoContraction(add);
return add;
}
}
// For matrix argument types.
{
uint32_t rowCount = 0, colCount = 0;
QualType elemType = {};
if (isMxNMatrix(argType, &elemType, &rowCount, &colCount)) {
const auto elemTypeId = typeTranslator.translateType(elemType);
const auto colTypeId = theBuilder.getVecType(elemTypeId, colCount);
llvm::SmallVector<uint32_t, 4> resultRows;
for (uint32_t i = 0; i < rowCount; ++i) {
const auto rowArg0 =
theBuilder.createCompositeExtract(colTypeId, arg0Id, {i});
const auto rowArg1 =
theBuilder.createCompositeExtract(colTypeId, arg1Id, {i});
const auto rowArg2 =
theBuilder.createCompositeExtract(colTypeId, arg2Id, {i});
const auto mul = theBuilder.createBinaryOp(spv::Op::OpIMul, colTypeId,
rowArg0, rowArg1);
const auto add =
theBuilder.createBinaryOp(spv::Op::OpIAdd, colTypeId, mul, rowArg2);
theBuilder.decorateNoContraction(mul);
theBuilder.decorateNoContraction(add);
resultRows.push_back(add);
}
return theBuilder.createCompositeConstruct(argTypeId, resultRows);
}
}
emitError("invalid argument type passed to mad intrinsic function",
callExpr->getExprLoc());
return 0;
}
uint32_t SPIRVEmitter::processIntrinsicLit(const CallExpr *callExpr) {
// Signature is: float4 lit(float n_dot_l, float n_dot_h, float m)
//
@ -7763,7 +7866,6 @@ uint32_t SPIRVEmitter::processIntrinsicMemoryBarrier(const CallExpr *callExpr,
spv::MemorySemanticsMask::ImageMemory |
spv::MemorySemanticsMask::UniformMemory |
spv::MemorySemanticsMask::WorkgroupMemory |
spv::MemorySemanticsMask::AtomicCounterMemory |
spv::MemorySemanticsMask::AcquireRelease;
// Get <result-id> for execution scope.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше