Mutate resource to handle for shader model 6.6+. (#3374)
* Mutate resource to handle for sm_6_6+. * Use bitcast to save global symbol and HLSL type for DxilResourceBase.
This commit is contained in:
Родитель
0ec5839e5e
Коммит
797d4b8adc
|
@ -18,6 +18,7 @@
|
|||
namespace llvm {
|
||||
class Value;
|
||||
class Constant;
|
||||
class Type;
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,6 +42,7 @@ public:
|
|||
unsigned GetUpperBound() const;
|
||||
unsigned GetRangeSize() const;
|
||||
llvm::Constant *GetGlobalSymbol() const;
|
||||
llvm::Type *GetHLSLType() const;
|
||||
const std::string &GetGlobalName() const;
|
||||
llvm::Value *GetHandle() const;
|
||||
bool IsAllocated() const;
|
||||
|
@ -53,6 +55,7 @@ public:
|
|||
void SetGlobalSymbol(llvm::Constant *pGV);
|
||||
void SetGlobalName(const std::string &Name);
|
||||
void SetHandle(llvm::Value *pHandle);
|
||||
void SetHLSLType(llvm::Type *Ty);
|
||||
|
||||
// TODO: check whether we can make this a protected method.
|
||||
void SetID(unsigned ID);
|
||||
|
@ -76,6 +79,7 @@ private:
|
|||
llvm::Constant *m_pSymbol; // Global variable.
|
||||
std::string m_Name; // Unmangled name of the global variable.
|
||||
llvm::Value *m_pHandle; // Cached resource handle for SM5.0- (and maybe SM5.1).
|
||||
llvm::Type *m_pHLSLTy; // The original hlsl type for reflection.
|
||||
};
|
||||
|
||||
const char *GetResourceKindName(DXIL::ResourceKind K);
|
||||
|
|
|
@ -131,4 +131,7 @@ void initializeDxilNoOptLegalizePass(llvm::PassRegistry&);
|
|||
ModulePass *createDxilNoOptSimplifyInstructionsPass();
|
||||
void initializeDxilNoOptSimplifyInstructionsPass(llvm::PassRegistry&);
|
||||
|
||||
ModulePass *createDxilMutateResourceToHandlePass();
|
||||
void initializeDxilMutateResourceToHandlePass(llvm::PassRegistry&);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include <array>
|
||||
|
@ -594,7 +595,16 @@ void DxilMDHelper::GetDxilResources(const MDOperand &MDO, const MDTuple *&pSRVs,
|
|||
|
||||
void DxilMDHelper::EmitDxilResourceBase(const DxilResourceBase &R, Metadata *ppMDVals[]) {
|
||||
ppMDVals[kDxilResourceBaseID ] = Uint32ToConstMD(R.GetID());
|
||||
ppMDVals[kDxilResourceBaseVariable ] = ValueAsMetadata::get(R.GetGlobalSymbol());
|
||||
Constant *GlobalSymbol = R.GetGlobalSymbol();
|
||||
// For sm66+, global symbol will be mutated into handle type.
|
||||
// Save hlsl type by generate bitcast on global symbol.
|
||||
if (m_pSM->IsSM66Plus()) {
|
||||
Type *HLSLTy = R.GetHLSLType();
|
||||
if (HLSLTy && HLSLTy != GlobalSymbol->getType())
|
||||
GlobalSymbol = cast<Constant>(
|
||||
ConstantExpr::getCast(Instruction::BitCast, GlobalSymbol, HLSLTy));
|
||||
}
|
||||
ppMDVals[kDxilResourceBaseVariable ] = ValueAsMetadata::get(GlobalSymbol);
|
||||
ppMDVals[kDxilResourceBaseName ] = MDString::get(m_Ctx, R.GetGlobalName());
|
||||
ppMDVals[kDxilResourceBaseSpaceID ] = Uint32ToConstMD(R.GetSpaceID());
|
||||
ppMDVals[kDxilResourceBaseLowerBound] = Uint32ToConstMD(R.GetLowerBound());
|
||||
|
@ -608,7 +618,20 @@ void DxilMDHelper::LoadDxilResourceBase(const MDOperand &MDO, DxilResourceBase &
|
|||
IFTBOOL(pTupleMD->getNumOperands() >= kDxilResourceBaseNumFields, DXC_E_INCORRECT_DXIL_METADATA);
|
||||
|
||||
R.SetID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID)));
|
||||
R.SetGlobalSymbol(dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable))));
|
||||
Constant *GlobalSymbol = dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable)));
|
||||
// For sm66+, global symbol will be mutated into handle type.
|
||||
// Read hlsl type and global symbol from bitcast.
|
||||
if (m_pSM->IsSM66Plus()) {
|
||||
// Before mutate, there's no bitcast. After GlobalSymbol changed into undef,
|
||||
// there's no bitcast too. Bitcast will only exist when global symbol is
|
||||
// mutated into handle and not changed into undef for lib linking.
|
||||
if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(GlobalSymbol)) {
|
||||
GlobalSymbol = cast<Constant>(BCO->getOperand(0));
|
||||
R.SetHLSLType(BCO->getType());
|
||||
}
|
||||
}
|
||||
R.SetGlobalSymbol(GlobalSymbol);
|
||||
|
||||
R.SetGlobalName(StringMDToString(pTupleMD->getOperand(kDxilResourceBaseName)));
|
||||
R.SetSpaceID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseSpaceID)));
|
||||
R.SetLowerBound(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseLowerBound)));
|
||||
|
|
|
@ -49,7 +49,7 @@ void DxilResource::SetCompType(const CompType CT) {
|
|||
}
|
||||
|
||||
Type *DxilResource::GetRetType() const {
|
||||
Type *Ty = GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty = GetHLSLType()->getPointerElementType();
|
||||
// For resource array, use element type.
|
||||
while (Ty->isArrayTy())
|
||||
Ty = Ty->getArrayElementType();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "dxc/DXIL/DxilResourceBase.h"
|
||||
#include "dxc/Support/Global.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
|
||||
|
||||
namespace hlsl {
|
||||
|
@ -26,7 +27,8 @@ DxilResourceBase::DxilResourceBase(Class C)
|
|||
, m_LowerBound(0)
|
||||
, m_RangeSize(0)
|
||||
, m_pSymbol(nullptr)
|
||||
, m_pHandle(nullptr) {
|
||||
, m_pHandle(nullptr)
|
||||
, m_pHLSLTy(nullptr) {
|
||||
}
|
||||
|
||||
DxilResourceBase::Class DxilResourceBase::GetClass() const { return m_Class; }
|
||||
|
@ -43,7 +45,13 @@ unsigned DxilResourceBase::GetUpperBound() const { return m_RangeSize != UINT_M
|
|||
unsigned DxilResourceBase::GetRangeSize() const { return m_RangeSize; }
|
||||
llvm::Constant *DxilResourceBase::GetGlobalSymbol() const { return m_pSymbol; }
|
||||
const std::string &DxilResourceBase::GetGlobalName() const { return m_Name; }
|
||||
llvm::Value *DxilResourceBase::GetHandle() const { return m_pHandle; }
|
||||
llvm::Value *DxilResourceBase::GetHandle() const { return m_pHandle; }
|
||||
// If m_pHLSLTy is nullptr, HLSL type is the type of m_pSymbol.
|
||||
// In sm6.6, type of m_pSymbol will be mutated to handleTy, m_pHLSLTy will save
|
||||
// the original HLSL type.
|
||||
llvm::Type *DxilResourceBase::GetHLSLType() const {
|
||||
return m_pHLSLTy == nullptr ? m_pSymbol->getType() : m_pHLSLTy;
|
||||
}
|
||||
bool DxilResourceBase::IsAllocated() const { return m_LowerBound != UINT_MAX; }
|
||||
bool DxilResourceBase::IsUnbounded() const { return m_RangeSize == UINT_MAX; }
|
||||
|
||||
|
@ -55,6 +63,7 @@ void DxilResourceBase::SetRangeSize(unsigned RangeSize) { m_RangeSize
|
|||
void DxilResourceBase::SetGlobalSymbol(llvm::Constant *pGV) { m_pSymbol = pGV; }
|
||||
void DxilResourceBase::SetGlobalName(const std::string &Name) { m_Name = Name; }
|
||||
void DxilResourceBase::SetHandle(llvm::Value *pHandle) { m_pHandle = pHandle; }
|
||||
void DxilResourceBase::SetHLSLType(llvm::Type *pTy) { m_pHLSLTy = pTy; }
|
||||
|
||||
static const char *s_ResourceClassNames[] = {
|
||||
"texture", "UAV", "cbuffer", "sampler"
|
||||
|
|
|
@ -109,6 +109,7 @@ HRESULT SetupRegistryPassForHLSL() {
|
|||
initializeDxilLoopDeletionPass(Registry);
|
||||
initializeDxilLoopUnrollPass(Registry);
|
||||
initializeDxilLowerCreateHandleForLibPass(Registry);
|
||||
initializeDxilMutateResourceToHandlePass(Registry);
|
||||
initializeDxilNoOptLegalizePass(Registry);
|
||||
initializeDxilNoOptSimplifyInstructionsPass(Registry);
|
||||
initializeDxilPrecisePropagatePassPass(Registry);
|
||||
|
|
|
@ -1893,7 +1893,7 @@ StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
|
|||
void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
|
||||
DxilTypeSystem &TypeSys, Module &M) {
|
||||
Constant *Symbol = Res.GetGlobalSymbol();
|
||||
Type *ElemTy = Symbol->getType()->getPointerElementType();
|
||||
Type *ElemTy = Res.GetHLSLType()->getPointerElementType();
|
||||
// Support Array of ConstantBuffer/StructuredBuffer.
|
||||
llvm::SmallVector<unsigned, 4> arrayDims;
|
||||
ElemTy = dxilutil::StripArrayTypes(ElemTy, &arrayDims);
|
||||
|
@ -2307,6 +2307,7 @@ void InitTBuffer(const DxilCBuffer *pSource, DxilResource *pDest) {
|
|||
pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
|
||||
pDest->SetGlobalName(pSource->GetGlobalName());
|
||||
pDest->SetHandle(pSource->GetHandle());
|
||||
pDest->SetHLSLType(pSource->GetHLSLType());
|
||||
}
|
||||
|
||||
void PatchTBufferLoad(CallInst *handle, DxilModule &DM,
|
||||
|
|
|
@ -1228,7 +1228,7 @@ void CShaderReflectionConstantBuffer::Initialize(
|
|||
// For ConstantBuffer<> buf[2], the array size is in Resource binding count
|
||||
// part.
|
||||
Type *Ty = dxilutil::StripArrayTypes(
|
||||
CB.GetGlobalSymbol()->getType()->getPointerElementType());
|
||||
CB.GetHLSLType()->getPointerElementType());
|
||||
|
||||
DxilTypeSystem &typeSys = M.GetTypeSystem();
|
||||
StructType *ST = cast<StructType>(Ty);
|
||||
|
@ -1265,8 +1265,7 @@ void CShaderReflectionConstantBuffer::Initialize(
|
|||
DXASSERT(pVarType->m_Desc.Elements == 0,
|
||||
"otherwise, assumption is wrong");
|
||||
pVarType->m_Desc.Elements = 1;
|
||||
} else if (CB.GetGlobalSymbol()
|
||||
->getType()
|
||||
} else if (CB.GetHLSLType()
|
||||
->getPointerElementType()
|
||||
->isArrayTy() &&
|
||||
CB.GetRangeSize() == 1) {
|
||||
|
@ -1315,7 +1314,7 @@ static unsigned CalcTypeSize(Type *Ty, unsigned &alignment) {
|
|||
|
||||
static unsigned CalcResTypeSize(DxilModule &M, DxilResource &R) {
|
||||
UNREFERENCED_PARAMETER(M);
|
||||
Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty = R.GetHLSLType()->getPointerElementType();
|
||||
if (R.IsStructuredBuffer()) {
|
||||
Ty = dxilutil::StripArrayTypes(Ty);
|
||||
}
|
||||
|
@ -1351,7 +1350,7 @@ void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
|
|||
// Create reflection type, if we have the necessary annotation info
|
||||
|
||||
// Extract the `struct` that wraps element type of the buffer resource
|
||||
Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty = R.GetHLSLType()->getPointerElementType();
|
||||
SmallVector<unsigned, 4> arrayDims;
|
||||
Ty = dxilutil::StripArrayTypes(Ty, &arrayDims);
|
||||
for (unsigned i = 0; i < arrayDims.size(); ++i) {
|
||||
|
@ -1396,7 +1395,7 @@ void CShaderReflectionConstantBuffer::InitializeTBuffer(
|
|||
m_Desc.Type = D3D11_CT_TBUFFER;
|
||||
m_Desc.uFlags = 0;
|
||||
|
||||
Type *Ty = R.GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty = R.GetHLSLType()->getPointerElementType();
|
||||
|
||||
DxilTypeSystem &typeSys = M.GetTypeSystem();
|
||||
StructType *ST = cast<StructType>(Ty);
|
||||
|
|
|
@ -76,6 +76,7 @@ void InitResourceBase(const DxilResourceBase *pSource,
|
|||
pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
|
||||
pDest->SetGlobalName(pSource->GetGlobalName());
|
||||
pDest->SetHandle(pSource->GetHandle());
|
||||
pDest->SetHLSLType(pSource->GetHLSLType());
|
||||
|
||||
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(pSource->GetGlobalSymbol()))
|
||||
SimplifyGlobalSymbol(GV);
|
||||
|
|
|
@ -481,8 +481,8 @@ bool IsMatchedType(Type *Ty0, Type *Ty) {
|
|||
bool DxilLinkJob::AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV) {
|
||||
if (m_resourceMap.count(res->GetGlobalName())) {
|
||||
DxilResourceBase *res0 = m_resourceMap[res->GetGlobalName()].first;
|
||||
Type *Ty0 = res0->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty = res->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty0 = res0->GetHLSLType()->getPointerElementType();
|
||||
Type *Ty = res->GetHLSLType()->getPointerElementType();
|
||||
// Make sure res0 match res.
|
||||
bool bMatch = IsMatchedType(Ty0, Ty);
|
||||
if (!bMatch) {
|
||||
|
@ -1217,6 +1217,10 @@ void DxilLinkJob::FixShaderModelMismatch(llvm::Module &M) {
|
|||
void DxilLinkJob::RunPreparePass(Module &M) {
|
||||
StripDeadDebugInfo(M);
|
||||
FixShaderModelMismatch(M);
|
||||
|
||||
DxilModule &DM = M.GetDxilModule();
|
||||
const ShaderModel *pSM = DM.GetShaderModel();
|
||||
|
||||
legacy::PassManager PM;
|
||||
PM.add(createAlwaysInlinerPass(/*InsertLifeTime*/ false));
|
||||
|
||||
|
@ -1247,6 +1251,9 @@ void DxilLinkJob::RunPreparePass(Module &M) {
|
|||
PM.add(createDeadCodeEliminationPass());
|
||||
PM.add(createGlobalDCEPass());
|
||||
|
||||
if (pSM->IsSM66Plus() && pSM->IsLib())
|
||||
PM.add(createDxilMutateResourceToHandlePass());
|
||||
|
||||
PM.add(createDxilLowerCreateHandleForLibPass());
|
||||
PM.add(createDxilTranslateRawBuffer());
|
||||
PM.add(createDxilFinalizeModulePass());
|
||||
|
|
|
@ -777,7 +777,7 @@ bool DxilPatchShaderRecordBindings::GetHandleInfo(
|
|||
shaderRegister = Resource->GetLowerBound();
|
||||
kind = Resource->GetKind();
|
||||
resClass = Resource->GetClass();
|
||||
resType = Resource->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
resType = Resource->GetHLSLType()->getPointerElementType();
|
||||
}
|
||||
return Resource != nullptr;
|
||||
}
|
||||
|
|
|
@ -10,15 +10,25 @@
|
|||
#include "dxc/DXIL/DxilUtil.h"
|
||||
#include "dxc/HLSL/DxilGenerationPass.h"
|
||||
#include "dxc/HLSL/HLModule.h"
|
||||
#include "dxc/DXIL/DxilResourceBase.h"
|
||||
#include "dxc/DXIL/DxilResource.h"
|
||||
#include "dxc/DXIL/DxilCBuffer.h"
|
||||
#include "dxc/DXIL/DxilOperations.h"
|
||||
#include "dxc/DXIL/DxilModule.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Attributes.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
|
||||
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
||||
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
||||
#include <unordered_set>
|
||||
|
@ -223,3 +233,474 @@ ModulePass *llvm::createDxilPromoteStaticResources() {
|
|||
INITIALIZE_PASS(DxilPromoteStaticResources,
|
||||
"hlsl-dxil-promote-static-resources",
|
||||
"DXIL promote static resource use", false, false)
|
||||
|
||||
// Mutate high-level resource type into handle.
|
||||
// This is used for SM 6.6+, on libraries only, where
|
||||
// CreateHandleForLib is eliminated, and high-level resource
|
||||
// types are only preserved in metadata for reflection purposes.
|
||||
namespace {
|
||||
// Overview
|
||||
// 1. collectCandidates - collect to MutateValSet
|
||||
// Start from resource global variable, function parameter/ret, alloca.
|
||||
// Propagate to all insts, GEP/ld/st/phi/select/called functions.
|
||||
// 2. mutateCandidates
|
||||
// Mutate all non-function value types.
|
||||
// Mutate functions by creating new function with new type, then
|
||||
// splice original function blocks into new function, and
|
||||
// replace old argument uses with new function's arguments.
|
||||
class DxilMutateResourceToHandle : public ModulePass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
explicit DxilMutateResourceToHandle() : ModulePass(ID) {}
|
||||
|
||||
const char *getPassName() const override {
|
||||
return "DXIL Mutate resource to handle";
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
if (M.HasHLModule()) {
|
||||
auto &HLM = M.GetHLModule();
|
||||
if (!HLM.GetShaderModel()->IsSM66Plus())
|
||||
return false;
|
||||
|
||||
hdlTy = HLM.GetOP()->GetHandleType();
|
||||
pTypeSys = &HLM.GetTypeSystem();
|
||||
} else if (M.HasDxilModule()) {
|
||||
auto &DM = M.GetDxilModule();
|
||||
if (!DM.GetShaderModel()->IsSM66Plus())
|
||||
return false;
|
||||
|
||||
hdlTy = DM.GetOP()->GetHandleType();
|
||||
pTypeSys = &DM.GetTypeSystem();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
collectCandidates(M);
|
||||
mutateCandidates(M);
|
||||
// Remvoe cast to handle.
|
||||
return !MutateValSet.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
Type *mutateToHandleTy(Type *Ty);
|
||||
bool mutateTypesToHandleTy(SmallVector<Type *, 4> &Tys);
|
||||
|
||||
void collectGlobalResource(DxilResourceBase *Res,
|
||||
SmallVector<Value *, 8> &WorkList);
|
||||
void collectAlloca(Function &F, SmallVector<Value *, 8> &WorkList);
|
||||
|
||||
SmallVector<Value *, 8> collectHlslObjects(Module &M);
|
||||
|
||||
void collectCandidates(Module &M);
|
||||
void mutateCandidates(Module &M);
|
||||
|
||||
Type *hdlTy;
|
||||
DxilTypeSystem *pTypeSys;
|
||||
DenseSet<Value *> MutateValSet;
|
||||
DenseMap<Type *, Type *> MutateTypeMap;
|
||||
};
|
||||
|
||||
char DxilMutateResourceToHandle::ID = 0;
|
||||
|
||||
Type *DxilMutateResourceToHandle::mutateToHandleTy(Type *Ty) {
|
||||
auto it = MutateTypeMap.find(Ty);
|
||||
if (it != MutateTypeMap.end())
|
||||
return it->second;
|
||||
|
||||
Type *ResultTy = nullptr;
|
||||
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
|
||||
SmallVector<unsigned, 2> nestedSize;
|
||||
Type *EltTy = Ty;
|
||||
while (ArrayType *NestAT = dyn_cast<ArrayType>(EltTy)) {
|
||||
nestedSize.emplace_back(NestAT->getNumElements());
|
||||
EltTy = NestAT->getElementType();
|
||||
}
|
||||
Type *mutatedTy = mutateToHandleTy(EltTy);
|
||||
if (mutatedTy == EltTy) {
|
||||
ResultTy = Ty;
|
||||
} else {
|
||||
Type *newAT = mutatedTy;
|
||||
for (auto it = nestedSize.rbegin(), E = nestedSize.rend(); it != E; ++it)
|
||||
newAT = ArrayType::get(newAT, *it);
|
||||
ResultTy = newAT;
|
||||
}
|
||||
} else if (PointerType *PT = dyn_cast<PointerType>(Ty)) {
|
||||
Type *EltTy = PT->getElementType();
|
||||
Type *mutatedTy = mutateToHandleTy(EltTy);
|
||||
if (mutatedTy == EltTy)
|
||||
ResultTy = Ty;
|
||||
else
|
||||
ResultTy = mutatedTy->getPointerTo(PT->getAddressSpace());
|
||||
} else if (dxilutil::IsHLSLResourceType(Ty)) {
|
||||
ResultTy = hdlTy;
|
||||
} else if (StructType *ST = dyn_cast<StructType>(Ty)) {
|
||||
if (!ST->isOpaque()) {
|
||||
SmallVector<Type *, 4> Elts(ST->element_begin(), ST->element_end());
|
||||
if (!mutateTypesToHandleTy(Elts)) {
|
||||
ResultTy = Ty;
|
||||
} else {
|
||||
ResultTy = StructType::create(Elts, ST->getName().str() + ".hdl");
|
||||
}
|
||||
} else {
|
||||
if (ST->getName() == "ConstantBuffer")
|
||||
ResultTy = hdlTy;
|
||||
else
|
||||
ResultTy = Ty;
|
||||
}
|
||||
} else if (FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
|
||||
Type *RetTy = FT->getReturnType();
|
||||
SmallVector<Type *, 4> Args(FT->param_begin(), FT->param_end());
|
||||
Type *mutatedRetTy = mutateToHandleTy(RetTy);
|
||||
if (!mutateTypesToHandleTy(Args) && RetTy == mutatedRetTy) {
|
||||
ResultTy = Ty;
|
||||
} else {
|
||||
ResultTy = FunctionType::get(mutatedRetTy, Args, FT->isVarArg());
|
||||
}
|
||||
} else {
|
||||
ResultTy = Ty;
|
||||
}
|
||||
MutateTypeMap[Ty] = ResultTy;
|
||||
return ResultTy;
|
||||
}
|
||||
|
||||
bool DxilMutateResourceToHandle::mutateTypesToHandleTy(
|
||||
SmallVector<Type *, 4> &Tys) {
|
||||
bool bMutated = false;
|
||||
for (size_t i = 0; i < Tys.size(); i++) {
|
||||
Type *Ty = Tys[i];
|
||||
Type *mutatedTy = mutateToHandleTy(Ty);
|
||||
if (Ty != mutatedTy) {
|
||||
Tys[i] = mutatedTy;
|
||||
bMutated = true;
|
||||
}
|
||||
}
|
||||
return bMutated;
|
||||
}
|
||||
|
||||
void DxilMutateResourceToHandle::collectGlobalResource(
|
||||
DxilResourceBase *Res, SmallVector<Value *, 8> &WorkList) {
|
||||
Value *GV = Res->GetGlobalSymbol();
|
||||
// Save hlsl type before mutate to handle.
|
||||
Res->SetHLSLType(GV->getType());
|
||||
mutateToHandleTy(GV->getType());
|
||||
WorkList.emplace_back(GV);
|
||||
}
|
||||
void DxilMutateResourceToHandle::collectAlloca(
|
||||
Function &F, SmallVector<Value *, 8> &WorkList) {
|
||||
if (F.isDeclaration())
|
||||
return;
|
||||
for (Instruction &I : F.getEntryBlock()) {
|
||||
AllocaInst *AI = dyn_cast<AllocaInst>(&I);
|
||||
if (!AI)
|
||||
continue;
|
||||
Type *Ty = AI->getType();
|
||||
Type *MTy = mutateToHandleTy(Ty);
|
||||
if (Ty == MTy)
|
||||
continue;
|
||||
WorkList.emplace_back(AI);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SmallVector<Value *, 8>
|
||||
DxilMutateResourceToHandle::collectHlslObjects(Module &M) {
|
||||
// Add all global/function/argument/alloca has resource type.
|
||||
SmallVector<Value *, 8> WorkList;
|
||||
|
||||
// Assume this is after SROA so no struct for global/alloca.
|
||||
|
||||
// Functions.
|
||||
for (Function &F : M) {
|
||||
collectAlloca(F, WorkList);
|
||||
FunctionType *FT = F.getFunctionType();
|
||||
FunctionType *MFT = cast<FunctionType>(mutateToHandleTy(FT));
|
||||
if (FT == MFT)
|
||||
continue;
|
||||
WorkList.emplace_back(&F);
|
||||
// Check args.
|
||||
for (Argument &Arg : F.args()) {
|
||||
Type *Ty = Arg.getType();
|
||||
Type *MTy = mutateToHandleTy(Ty);
|
||||
if (Ty == MTy)
|
||||
continue;
|
||||
WorkList.emplace_back(&Arg);
|
||||
}
|
||||
}
|
||||
|
||||
// Static globals.
|
||||
for (GlobalVariable &GV : M.globals()) {
|
||||
if (!dxilutil::IsStaticGlobal(&GV))
|
||||
continue;
|
||||
Type *Ty = dxilutil::GetArrayEltTy(GV.getValueType());
|
||||
if (!dxilutil::IsHLSLObjectType(Ty))
|
||||
continue;
|
||||
WorkList.emplace_back(&GV);
|
||||
}
|
||||
|
||||
// Global resources.
|
||||
if (M.HasHLModule()) {
|
||||
auto &HLM = M.GetHLModule();
|
||||
for (auto &Res : HLM.GetCBuffers()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
for (auto &Res : HLM.GetSRVs()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
for (auto &Res : HLM.GetUAVs()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
for (auto &Res : HLM.GetSamplers()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
} else {
|
||||
auto &DM = M.GetDxilModule();
|
||||
for (auto &Res : DM.GetCBuffers()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
for (auto &Res : DM.GetSRVs()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
for (auto &Res : DM.GetUAVs()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
for (auto &Res : DM.GetSamplers()) {
|
||||
collectGlobalResource(Res.get(), WorkList);
|
||||
}
|
||||
}
|
||||
return WorkList;
|
||||
}
|
||||
|
||||
void DxilMutateResourceToHandle::collectCandidates(Module &M) {
|
||||
SmallVector<Value *, 8> WorkList = collectHlslObjects(M);
|
||||
|
||||
// Propagate candidates.
|
||||
while (!WorkList.empty()) {
|
||||
Value *V = WorkList.pop_back_val();
|
||||
MutateValSet.insert(V);
|
||||
|
||||
for (User *U : V->users()) {
|
||||
// collect in a user.
|
||||
SmallVector<Value *, 2> newCandidates;
|
||||
// Should only used by ld/st/sel/phi/gep/call.
|
||||
if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
|
||||
newCandidates.emplace_back(LI);
|
||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
|
||||
Value *Ptr = SI->getPointerOperand();
|
||||
Value *Val = SI->getValueOperand();
|
||||
if (V == Ptr)
|
||||
newCandidates.emplace_back(Val);
|
||||
else
|
||||
newCandidates.emplace_back(Ptr);
|
||||
} else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
|
||||
// If result type of GEP not related to resource type, skip.
|
||||
Type *Ty = GEP->getType();
|
||||
Type *MTy = mutateToHandleTy(Ty);
|
||||
if (MTy == Ty)
|
||||
continue;
|
||||
newCandidates.emplace_back(GEP);
|
||||
} else if (PHINode *Phi = dyn_cast<PHINode>(U)) {
|
||||
// Propagate all operands.
|
||||
newCandidates.emplace_back(Phi);
|
||||
for (Use &PhiOp : Phi->incoming_values()) {
|
||||
if (V == PhiOp)
|
||||
continue;
|
||||
newCandidates.emplace_back(PhiOp);
|
||||
}
|
||||
} else if (SelectInst *Sel = dyn_cast<SelectInst>(U)) {
|
||||
// Propagate other result.
|
||||
newCandidates.emplace_back(Sel);
|
||||
Value *TrueV = Sel->getTrueValue();
|
||||
Value *FalseV = Sel->getFalseValue();
|
||||
if (TrueV == V)
|
||||
newCandidates.emplace_back(FalseV);
|
||||
else
|
||||
newCandidates.emplace_back(TrueV);
|
||||
} else if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(U)) {
|
||||
// Make sure only used for lifetime intrinsic.
|
||||
for (User *BCUser : BCO->users()) {
|
||||
if (ConstantArray *CA = dyn_cast<ConstantArray>(BCUser)) {
|
||||
// For llvm.used.
|
||||
if (CA->hasOneUse()) {
|
||||
Value *CAUser = CA->user_back();
|
||||
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CAUser)) {
|
||||
if (GV->getName() == "llvm.used")
|
||||
continue;
|
||||
}
|
||||
} else if (CA->user_empty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CallInst *CI = cast<CallInst>(BCUser);
|
||||
Function *F = CI->getCalledFunction();
|
||||
Intrinsic::ID ID = F->getIntrinsicID();
|
||||
if (ID != Intrinsic::lifetime_start &&
|
||||
ID != Intrinsic::lifetime_end) {
|
||||
DXASSERT(false, "unexpected resource object user");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CallInst *CI = cast<CallInst>(U);
|
||||
Type *Ty = CI->getType();
|
||||
Type *MTy = mutateToHandleTy(Ty);
|
||||
if (Ty != MTy)
|
||||
newCandidates.emplace_back(CI);
|
||||
|
||||
SmallVector<Value *, 4> Args(CI->arg_operands().begin(),
|
||||
CI->arg_operands().end());
|
||||
for (Value *Arg : Args) {
|
||||
if (Arg == V)
|
||||
continue;
|
||||
Type *Ty = Arg->getType();
|
||||
Type *MTy = mutateToHandleTy(Ty);
|
||||
if (Ty == MTy)
|
||||
continue;
|
||||
newCandidates.emplace_back(Arg);
|
||||
}
|
||||
}
|
||||
|
||||
for (Value *Val : newCandidates) {
|
||||
// New candidate find.
|
||||
if (MutateValSet.insert(Val).second) {
|
||||
WorkList.emplace_back(Val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DxilMutateResourceToHandle::mutateCandidates(Module &M) {
|
||||
SmallVector<Function *, 2> CandidateFns;
|
||||
for (Value *V : MutateValSet) {
|
||||
if (Function *F = dyn_cast<Function>(V)) {
|
||||
CandidateFns.emplace_back(F);
|
||||
continue;
|
||||
}
|
||||
Type *Ty = V->getType();
|
||||
V->dump();
|
||||
Type *MTy = mutateToHandleTy(Ty);
|
||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
|
||||
AI->setAllocatedType(MTy->getPointerElementType());
|
||||
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
|
||||
Type *MResultEltTy = mutateToHandleTy(GEP->getResultElementType());
|
||||
GEP->setResultElementType(MResultEltTy);
|
||||
Type *MSrcEltTy = mutateToHandleTy(GEP->getSourceElementType());
|
||||
GEP->setSourceElementType(MSrcEltTy);
|
||||
} else if (GEPOperator *GEPO = dyn_cast<GEPOperator>(V)) {
|
||||
// GEP operator not support setSourceElementType.
|
||||
// Create a new GEP here.
|
||||
Constant *C = cast<Constant>(GEPO->getPointerOperand());
|
||||
IRBuilder<> B(C->getContext());
|
||||
// Make sure C is mutated so the GEP get correct sourceElementType.
|
||||
C->mutateType(mutateToHandleTy(C->getType()));
|
||||
|
||||
// Collect user of GEPs, then replace all use with undef.
|
||||
SmallVector<Use *, 2> Uses;
|
||||
for (Use &U : GEPO->uses()) {
|
||||
Uses.emplace_back(&U);
|
||||
}
|
||||
|
||||
SmallVector<Value *, 2> idxList(GEPO->idx_begin(), GEPO->idx_end());
|
||||
Type *Ty = GEPO->getType();
|
||||
GEPO->replaceAllUsesWith(UndefValue::get(Ty));
|
||||
StringRef Name = GEPO->getName();
|
||||
|
||||
// GO and newGO will be same constant except has different
|
||||
// sourceElementType. ConstantMap think they're the same constant. Have to
|
||||
// remove GO first before create newGO.
|
||||
C->removeDeadConstantUsers();
|
||||
|
||||
Value *newGO = B.CreateGEP(C, idxList, Name);
|
||||
// update uses.
|
||||
for (Use *U : Uses) {
|
||||
U->set(newGO);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
V->mutateType(MTy);
|
||||
V->dump();
|
||||
}
|
||||
|
||||
Function *createHandleForLibOnHandle = nullptr;
|
||||
hlsl::OP *hlslOP = nullptr;
|
||||
if (M.HasDxilModule()) {
|
||||
auto &DM = M.GetDxilModule();
|
||||
hlslOP = DM.GetOP();
|
||||
if (hlslOP->IsDxilOpUsed(DXIL::OpCode::CreateHandleForLib)) {
|
||||
createHandleForLibOnHandle =
|
||||
hlslOP->GetOpFunc(DXIL::OpCode::CreateHandleForLib, hdlTy);
|
||||
}
|
||||
}
|
||||
|
||||
// Mutate functions.
|
||||
for (Function *F : CandidateFns) {
|
||||
Function *MF = nullptr;
|
||||
if (hlslOP) {
|
||||
if (hlslOP->IsDxilOpFunc(F)) {
|
||||
DXIL::OpCodeClass OpcodeClass;
|
||||
if (hlslOP->GetOpCodeClass(F, OpcodeClass)) {
|
||||
if (OpcodeClass == DXIL::OpCodeClass::CreateHandleForLib) {
|
||||
MF = createHandleForLibOnHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MF) {
|
||||
FunctionType *FT = F->getFunctionType();
|
||||
FunctionType *MFT = cast<FunctionType>(MutateTypeMap[FT]);
|
||||
|
||||
MF = Function::Create(MFT, F->getLinkage(), "", &M);
|
||||
MF->takeName(F);
|
||||
|
||||
// Copy calling conv.
|
||||
MF->setCallingConv(F->getCallingConv());
|
||||
// Copy attributes.
|
||||
AttributeSet AS = F->getAttributes();
|
||||
MF->setAttributes(AS);
|
||||
// Annotation.
|
||||
if (DxilFunctionAnnotation *FnAnnot =
|
||||
pTypeSys->GetFunctionAnnotation(F)) {
|
||||
DxilFunctionAnnotation *newFnAnnot =
|
||||
pTypeSys->AddFunctionAnnotation(MF);
|
||||
DxilParameterAnnotation &RetAnnot = newFnAnnot->GetRetTypeAnnotation();
|
||||
RetAnnot = FnAnnot->GetRetTypeAnnotation();
|
||||
for (unsigned i = 0; i < FnAnnot->GetNumParameters(); i++) {
|
||||
newFnAnnot->GetParameterAnnotation(i) =
|
||||
FnAnnot->GetParameterAnnotation(i);
|
||||
}
|
||||
}
|
||||
// Update function debug info.
|
||||
if (DISubprogram *funcDI = getDISubprogram(F))
|
||||
funcDI->replaceFunction(MF);
|
||||
}
|
||||
|
||||
for (auto it = F->user_begin(); it != F->user_end();) {
|
||||
CallInst *CI = cast<CallInst>(*(it++));
|
||||
CI->setCalledFunction(MF);
|
||||
}
|
||||
|
||||
if (F->isDeclaration()) {
|
||||
F->eraseFromParent();
|
||||
continue;
|
||||
}
|
||||
// Take body of F.
|
||||
// Splice the body of the old function right into the new function.
|
||||
MF->getBasicBlockList().splice(MF->begin(), F->getBasicBlockList());
|
||||
// Replace use of arg.
|
||||
auto argIt = F->arg_begin();
|
||||
for (auto MArgIt = MF->arg_begin(); MArgIt != MF->arg_end();) {
|
||||
Argument *Arg = (argIt++);
|
||||
Argument *MArg = (MArgIt++);
|
||||
Arg->replaceAllUsesWith(MArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModulePass *llvm::createDxilMutateResourceToHandlePass() {
|
||||
return new DxilMutateResourceToHandle();
|
||||
}
|
||||
|
||||
INITIALIZE_PASS(DxilMutateResourceToHandle,
|
||||
"hlsl-dxil-resources-to-handle",
|
||||
"Mutate resource to handle", false, false)
|
||||
|
|
|
@ -388,6 +388,7 @@ struct ValidationContext {
|
|||
Module &M;
|
||||
Module *pDebugModule;
|
||||
DxilModule &DxilMod;
|
||||
const Type *HandleTy;
|
||||
const DataLayout &DL;
|
||||
DebugLoc LastDebugLocEmit;
|
||||
ValidationRule LastRuleEmit;
|
||||
|
@ -421,6 +422,7 @@ struct ValidationContext {
|
|||
kLLVMLoopMDKind(llvmModule.getContext().getMDKindID("llvm.loop")),
|
||||
slotTracker(&llvmModule, true) {
|
||||
DxilMod.GetDxilVersion(m_DxilMajor, m_DxilMinor);
|
||||
HandleTy = DxilMod.GetOP()->GetHandleType();
|
||||
|
||||
for (Function &F : llvmModule.functions()) {
|
||||
if (DxilMod.HasDxilEntryProps(&F)) {
|
||||
|
@ -481,6 +483,9 @@ struct ValidationContext {
|
|||
}
|
||||
} else if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
|
||||
PropagateResMap(U, Res);
|
||||
} else if (isa<BitCastOperator>(U) && U->user_empty()) {
|
||||
// For hlsl type.
|
||||
continue;
|
||||
} else {
|
||||
EmitResourceError(Res, ValidationRule::InstrResourceUser);
|
||||
}
|
||||
|
@ -570,8 +575,7 @@ struct ValidationContext {
|
|||
}
|
||||
|
||||
ConstantInt *cIndex = dyn_cast<ConstantInt>(hdl.get_index());
|
||||
if (!Res->GetGlobalSymbol()
|
||||
->getType()
|
||||
if (!Res->GetHLSLType()
|
||||
->getPointerElementType()
|
||||
->isArrayTy()) {
|
||||
if (!cIndex) {
|
||||
|
@ -2722,6 +2726,9 @@ static bool ValidateType(Type *Ty, ValidationContext &ValCtx, bool bInner = fals
|
|||
|
||||
StringRef Name = ST->getName();
|
||||
if (Name.startswith("dx.")) {
|
||||
// Allow handle type.
|
||||
if (ValCtx.HandleTy == Ty)
|
||||
return true;
|
||||
hlsl::OP *hlslOP = ValCtx.DxilMod.GetOP();
|
||||
if (IsDxilBuiltinStructType(ST, hlslOP)) {
|
||||
ValCtx.EmitTypeError(Ty, ValidationRule::InstrDxilStructUser);
|
||||
|
@ -4128,7 +4135,7 @@ CollectCBufferRanges(DxilStructAnnotation *annotation,
|
|||
}
|
||||
|
||||
static void ValidateCBuffer(DxilCBuffer &cb, ValidationContext &ValCtx) {
|
||||
Type *Ty = cb.GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
Type *Ty = cb.GetHLSLType()->getPointerElementType();
|
||||
if (cb.GetRangeSize() != 1 || Ty->isArrayTy()) {
|
||||
Ty = Ty->getArrayElementType();
|
||||
}
|
||||
|
|
|
@ -278,6 +278,7 @@ static void addHLSLPasses(bool HLSLHighLevel, unsigned OptLevel, bool OnlyWarnOn
|
|||
|
||||
MPM.add(createDxilPromoteLocalResources());
|
||||
MPM.add(createDxilPromoteStaticResources());
|
||||
|
||||
// Verify no undef resource again after promotion
|
||||
MPM.add(createInvalidateUndefResourcesPass());
|
||||
|
||||
|
@ -374,6 +375,7 @@ void PassManagerBuilder::populateModulePassManager(
|
|||
MPM.add(createMultiDimArrayToOneDimArrayPass());
|
||||
MPM.add(createDeadCodeEliminationPass());
|
||||
MPM.add(createGlobalDCEPass());
|
||||
MPM.add(createDxilMutateResourceToHandlePass());
|
||||
MPM.add(createDxilLowerCreateHandleForLibPass());
|
||||
MPM.add(createDxilTranslateRawBuffer());
|
||||
MPM.add(createDxilLegalizeSampleOffsetPass());
|
||||
|
@ -675,6 +677,7 @@ void PassManagerBuilder::populateModulePassManager(
|
|||
MPM.add(createDxilRemoveDeadBlocksPass());
|
||||
MPM.add(createDeadCodeEliminationPass());
|
||||
MPM.add(createGlobalDCEPass());
|
||||
MPM.add(createDxilMutateResourceToHandlePass());
|
||||
MPM.add(createDxilLowerCreateHandleForLibPass());
|
||||
MPM.add(createDxilTranslateRawBuffer());
|
||||
// Always try to legalize sample offsets as loop unrolling
|
||||
|
|
|
@ -1805,7 +1805,7 @@ unsigned AllocateDxilConstantBuffer(
|
|||
continue;
|
||||
|
||||
unsigned size = C->GetRangeSize();
|
||||
llvm::Type *Ty = C->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
llvm::Type *Ty = C->GetHLSLType()->getPointerElementType();
|
||||
auto fieldAnnotation = constVarAnnotationMap.at(C->GetGlobalSymbol());
|
||||
bool bRowMajor = HLMatrixType::isa(Ty)
|
||||
? fieldAnnotation.GetMatrixAnnotation().Orientation ==
|
||||
|
@ -1906,7 +1906,7 @@ bool CreateCBufferVariable(HLCBuffer &CB, HLModule &HLM, llvm::Type *HandleTy) {
|
|||
if (!GV->use_empty())
|
||||
bUsed = true;
|
||||
// Global variable must be pointer type.
|
||||
llvm::Type *Ty = GV->getType()->getPointerElementType();
|
||||
llvm::Type *Ty = C->GetHLSLType()->getPointerElementType();
|
||||
Elements.emplace_back(Ty);
|
||||
}
|
||||
// Don't create CBuffer variable for unused cbuffer.
|
||||
|
@ -1942,9 +1942,8 @@ bool CreateCBufferVariable(HLCBuffer &CB, HLModule &HLM, llvm::Type *HandleTy) {
|
|||
// array.
|
||||
DXASSERT(CB.GetConstants().size() == 1,
|
||||
"ConstantBuffer should have 1 constant");
|
||||
Value *GV = CB.GetConstants()[0]->GetGlobalSymbol();
|
||||
llvm::Type *CBEltTy =
|
||||
GV->getType()->getPointerElementType()->getArrayElementType();
|
||||
CB.GetConstants()[0]->GetHLSLType()->getPointerElementType()->getArrayElementType();
|
||||
cbIndexDepth = 1;
|
||||
while (CBEltTy->isArrayTy()) {
|
||||
CBEltTy = CBEltTy->getArrayElementType();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
|
||||
|
||||
// lib_6_x does not reduce phi/select of resource or handle in lib.
|
||||
// CHECK: phi %"class.RWBuffer
|
||||
// CHECK: select i1 %{{[^,]+}}, %"class.
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: ret <4 x float>
|
||||
|
||||
RWBuffer<float4> BufArray[2][2][3];
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
// phi/select of handle should not be produced in this case, but would be allowed if it were.
|
||||
|
||||
// CHECK: define <4 x float> @"\01?test@@YA?AV?$vector@M$03@@HHH@Z"(i32 %i, i32 %j, i32 %m)
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %"class.
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %"class.
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
|
||||
// CHECK: ret <4 x float>
|
||||
|
||||
RWBuffer<float4> BufArray[2][2][3];
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
// phi/select of handle should not be produced in this case, but would be allowed if it were.
|
||||
|
||||
// CHECK: define i32 @"\01?test@@YAIHHH@Z"(i32 %i, i32 %j, i32 %m)
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %"class.
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %"class.
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
|
||||
// Make sure get dimensions returns 24
|
||||
// CHECK: ret i32 24
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
// phi/select of handle should not be produced in this case, but would be allowed if it were.
|
||||
|
||||
// CHECK: define i32 @"\01?test@@YAIHHH@Z"(i32 %i, i32 %j, i32 %m)
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %"class.
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %"class.
|
||||
// CHECK-NOT: phi %dx.types.Handle
|
||||
// CHECK-NOT: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
// CHECK: phi %dx.types.Handle
|
||||
// CHECK: select i1 %{{[^,]+}}, %dx.types.Handle
|
||||
|
||||
// Make sure get dimensions returns 24
|
||||
// CHECK: ret i32 24
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
// RUN: %dxc -T lib_6_x %s | FileCheck %s
|
||||
|
||||
// resources in return/params allowed for lib_6_x
|
||||
// CHECK: alloca %struct.T
|
||||
// CHECK: store %struct.RWByteAddressBuffer
|
||||
// CHECK: call void @"\01?resStruct@@YA?AUT2@@UT@@V?$vector@I$01@@@Z"(%struct.T2
|
||||
// CHECK: %[[ptr:[^, ]+]] = getelementptr inbounds %struct.T2
|
||||
// CHECK: %[[val:[^, ]+]] = load %"class.RWStructuredBuffer<D>", %"class.RWStructuredBuffer<D>"* %[[ptr]]
|
||||
// CHECK: call %dx.types.Handle @"dx.op.createHandleForLib.class.RWStructuredBuffer<D>"(i32 160, %"class.RWStructuredBuffer<D>" %[[val]])
|
||||
// CHECK: alloca %struct.T.hdl
|
||||
// CHECK: store %dx.types.Handle
|
||||
// CHECK: call void @"\01?resStruct@@YA?AUT2@@UT@@V?$vector@I$01@@@Z"(%struct.T2.hdl
|
||||
// CHECK: %[[ptr:[^, ]+]] = getelementptr inbounds %struct.T2.hdl
|
||||
// CHECK: %[[val:[^, ]+]] = load %dx.types.Handle, %dx.types.Handle* %[[ptr]]
|
||||
// CHECK: call %dx.types.Handle @dx.op.createHandleForLib.dx.types.Handle(i32 160, %dx.types.Handle %[[val]])
|
||||
|
||||
// Make sure save bitcast for global symbol and HLSL type.
|
||||
// CHECK:i32 0, %struct.RWByteAddressBuffer* bitcast (%dx.types.Handle* @"\01?outputBuffer@@3URWByteAddressBuffer@@A" to %struct.RWByteAddressBuffer*), !"outputBuffer"
|
||||
// CHECK:i32 1, %struct.RWByteAddressBuffer* bitcast (%dx.types.Handle* @"\01?outputBuffer2@@3URWByteAddressBuffer@@A" to %struct.RWByteAddressBuffer*), !"outputBuffer2"
|
||||
|
||||
|
||||
struct T {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %dxc -T lib_6_x -Od %s | FileCheck %s
|
||||
|
||||
// lib_6_x allows phi on resource, targeting offline linking only.
|
||||
// CHECK: phi %struct.ByteAddressBuffer
|
||||
// CHECK: phi %dx.types.Handle
|
||||
|
||||
ByteAddressBuffer firstBuffer, secondBuffer;
|
||||
uint firstBufferSize;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %dxc -T lib_6_x -auto-binding-space 11 %s | FileCheck %s
|
||||
|
||||
// lib_6_x allows select on resource, targeting offline linking only.
|
||||
// CHECK: select i1 %{{[^, ]+}}, %struct.ByteAddressBuffer
|
||||
// CHECK: select i1 %{{[^, ]+}}, %dx.types.Handle
|
||||
|
||||
RWByteAddressBuffer outputBuffer : register(u0);
|
||||
ByteAddressBuffer ReadBuffer : register(t0);
|
||||
|
|
|
@ -954,7 +954,7 @@ void PrintStructBufferDefinition(DxilResource *buf,
|
|||
llvm::Type *RetTy = buf->GetRetType();
|
||||
// Skip none struct type.
|
||||
if (!RetTy->isStructTy() || HLMatrixType::isa(RetTy)) {
|
||||
llvm::Type *Ty = buf->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
llvm::Type *Ty = buf->GetHLSLType()->getPointerElementType();
|
||||
// For resource array, use element type.
|
||||
if (Ty->isArrayTy())
|
||||
Ty = Ty->getArrayElementType();
|
||||
|
@ -993,7 +993,7 @@ void PrintStructBufferDefinition(DxilResource *buf,
|
|||
void PrintTBufferDefinition(DxilResource *buf, DxilTypeSystem &typeSys,
|
||||
raw_string_ostream &OS, StringRef comment) {
|
||||
const unsigned offsetIndent = 50;
|
||||
llvm::Type *Ty = buf->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
llvm::Type *Ty = buf->GetHLSLType()->getPointerElementType();
|
||||
// For TextureBuffer<> buf[2], the array size is in Resource binding count
|
||||
// part.
|
||||
if (Ty->isArrayTy())
|
||||
|
@ -1019,7 +1019,7 @@ void PrintTBufferDefinition(DxilResource *buf, DxilTypeSystem &typeSys,
|
|||
void PrintCBufferDefinition(DxilCBuffer *buf, DxilTypeSystem &typeSys,
|
||||
raw_string_ostream &OS, StringRef comment) {
|
||||
const unsigned offsetIndent = 50;
|
||||
llvm::Type *Ty = buf->GetGlobalSymbol()->getType()->getPointerElementType();
|
||||
llvm::Type *Ty = buf->GetHLSLType()->getPointerElementType();
|
||||
// For ConstantBuffer<> buf[2], the array size is in Resource binding count
|
||||
// part.
|
||||
if (Ty->isArrayTy())
|
||||
|
|
|
@ -307,14 +307,15 @@ TEST_F(LinkerTest, RunLinkGlobalInit) {
|
|||
}
|
||||
|
||||
TEST_F(LinkerTest, RunLinkFailReDefineGlobal) {
|
||||
LPCWSTR option[] = { L"-default-linkage", L"external" };
|
||||
CComPtr<IDxcBlob> pEntryLib;
|
||||
CompileLib(L"..\\CodeGenHLSL\\lib_global2.hlsl", &pEntryLib);
|
||||
CompileLib(L"..\\CodeGenHLSL\\lib_global2.hlsl", &pEntryLib, option, L"lib_6_3");
|
||||
|
||||
CComPtr<IDxcBlob> pLib0;
|
||||
CompileLib(L"..\\CodeGenHLSL\\lib_global3.hlsl", &pLib0);
|
||||
CompileLib(L"..\\CodeGenHLSL\\lib_global3.hlsl", &pLib0, option, L"lib_6_3");
|
||||
|
||||
CComPtr<IDxcBlob> pLib1;
|
||||
CompileLib(L"..\\CodeGenHLSL\\lib_global4.hlsl", &pLib1);
|
||||
CompileLib(L"..\\CodeGenHLSL\\lib_global4.hlsl", &pLib1, option, L"lib_6_3");
|
||||
|
||||
CComPtr<IDxcLinker> pLinker;
|
||||
CreateLinker(&pLinker);
|
||||
|
@ -688,14 +689,14 @@ TEST_F(LinkerTest, RunLinkToLibWithNoExports) {
|
|||
}
|
||||
|
||||
TEST_F(LinkerTest, RunLinkWithPotentialIntrinsicNameCollisions) {
|
||||
LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
|
||||
LPCWSTR option[] = { L"-Zi", L"-Qembed_debug", L"-default-linkage", L"external" };
|
||||
|
||||
CComPtr<IDxcBlob> pLib1;
|
||||
CompileLib(L"..\\CodeGenHLSL\\linker\\createHandle_multi.hlsl",
|
||||
&pLib1, option);
|
||||
&pLib1, option, L"lib_6_3");
|
||||
CComPtr<IDxcBlob> pLib2;
|
||||
CompileLib(L"..\\CodeGenHLSL\\linker\\createHandle_multi2.hlsl",
|
||||
&pLib2, option);
|
||||
&pLib2, option, L"lib_6_3");
|
||||
|
||||
CComPtr<IDxcLinker> pLinker;
|
||||
CreateLinker(&pLinker);
|
||||
|
|
|
@ -2136,6 +2136,7 @@ class db_dxil(object):
|
|||
{'n':'from-binding', 'i':'FromBinding', 't':'bool', 'c':1, 'd':'Append binding to name when bound'},
|
||||
{'n':'keep-name', 'i':'KeepName', 't':'bool', 'c':1, 'd':'Keep name when appending binding'},
|
||||
])
|
||||
add_pass('hlsl-dxil-resources-to-handle', 'DxilMutateResourceToHandle', 'Mutate resource to handle',[])
|
||||
|
||||
category_lib="llvm"
|
||||
add_pass('ipsccp', 'IPSCCP', 'Interprocedural Sparse Conditional Constant Propagation', [])
|
||||
|
|
Загрузка…
Ссылка в новой задаче