|
@@ -312,16 +312,25 @@ static bool IsResourceSingleComponent(llvm::Type *Ty) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-bool DxilModule::ModuleHasMulticomponentUAVLoads() {
|
|
|
- for (const auto &uav : GetUAVs()) {
|
|
|
- const DxilResource *res = uav.get();
|
|
|
- if (res->IsTypedBuffer() || res->IsAnyTexture()) {
|
|
|
- if (!IsResourceSingleComponent(res->GetRetType())) {
|
|
|
- return true;
|
|
|
- }
|
|
|
+// Given a CreateHandle call, returns arbitrary ConstantInt rangeID
|
|
|
+// Note: HLSL is currently assuming that rangeID is a constant value, but this code is assuming
|
|
|
+// that it can be either constant, phi node, or select instruction
|
|
|
+static ConstantInt *GetArbitraryConstantRangeID(CallInst *handleCall) {
|
|
|
+ Value *rangeID =
|
|
|
+ handleCall->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
|
|
|
+ ConstantInt *ConstantRangeID = dyn_cast<ConstantInt>(rangeID);
|
|
|
+ while (ConstantRangeID == nullptr) {
|
|
|
+ if (ConstantInt *CI = dyn_cast<ConstantInt>(rangeID)) {
|
|
|
+ ConstantRangeID = CI;
|
|
|
+ } else if (PHINode *PN = dyn_cast<PHINode>(rangeID)) {
|
|
|
+ rangeID = PN->getIncomingValue(0);
|
|
|
+ } else if (SelectInst *SI = dyn_cast<SelectInst>(rangeID)) {
|
|
|
+ rangeID = SI->getTrueValue();
|
|
|
+ } else {
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
}
|
|
|
- return false;
|
|
|
+ return ConstantRangeID;
|
|
|
}
|
|
|
|
|
|
void DxilModule::CollectShaderFlags(ShaderFlags &Flags) {
|
|
@@ -336,7 +345,15 @@ void DxilModule::CollectShaderFlags(ShaderFlags &Flags) {
|
|
|
bool hasMSAD = false;
|
|
|
bool hasInnerCoverage = false;
|
|
|
bool hasViewID = false;
|
|
|
- bool hasMulticomponentUAVLoads = ModuleHasMulticomponentUAVLoads();
|
|
|
+ bool hasMulticomponentUAVLoads = false;
|
|
|
+ bool hasMulticomponentUAVLoadsBackCompat = false;
|
|
|
+
|
|
|
+ // Try to maintain compatibility with a v1.0 validator if that's what we have.
|
|
|
+ {
|
|
|
+ unsigned valMajor, valMinor;
|
|
|
+ GetValidatorVersion(valMajor, valMinor);
|
|
|
+ hasMulticomponentUAVLoadsBackCompat = valMajor <= 1 && valMinor == 0;
|
|
|
+ }
|
|
|
|
|
|
Type *int16Ty = Type::getInt16Ty(GetCtx());
|
|
|
Type *int64Ty = Type::getInt64Ty(GetCtx());
|
|
@@ -401,6 +418,39 @@ void DxilModule::CollectShaderFlags(ShaderFlags &Flags) {
|
|
|
case DXIL::OpCode::Msad:
|
|
|
hasMSAD = true;
|
|
|
break;
|
|
|
+ case DXIL::OpCode::BufferLoad:
|
|
|
+ case DXIL::OpCode::TextureLoad: {
|
|
|
+ if (hasMulticomponentUAVLoads) continue;
|
|
|
+ // This is the old-style computation (overestimating requirements).
|
|
|
+ Value *resHandle = CI->getArgOperand(DXIL::OperandIndex::kBufferStoreHandleOpIdx);
|
|
|
+ CallInst *handleCall = cast<CallInst>(resHandle);
|
|
|
+
|
|
|
+ if (ConstantInt *resClassArg =
|
|
|
+ dyn_cast<ConstantInt>(handleCall->getArgOperand(
|
|
|
+ DXIL::OperandIndex::kCreateHandleResClassOpIdx))) {
|
|
|
+ DXIL::ResourceClass resClass = static_cast<DXIL::ResourceClass>(
|
|
|
+ resClassArg->getLimitedValue());
|
|
|
+ if (resClass == DXIL::ResourceClass::UAV) {
|
|
|
+ // Validator 1.0 assumes that all uav load is multi component load.
|
|
|
+ if (hasMulticomponentUAVLoadsBackCompat) {
|
|
|
+ hasMulticomponentUAVLoads = true;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ConstantInt *rangeID = GetArbitraryConstantRangeID(handleCall);
|
|
|
+ if (rangeID) {
|
|
|
+ DxilResource resource = GetUAV(rangeID->getLimitedValue());
|
|
|
+ if (!IsResourceSingleComponent(resource.GetRetType())) {
|
|
|
+ hasMulticomponentUAVLoads = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ DXASSERT(false, "Resource class must be constant.");
|
|
|
+ }
|
|
|
+ } break;
|
|
|
case DXIL::OpCode::Fma:
|
|
|
hasDoubleExtension |= isDouble;
|
|
|
break;
|
|
@@ -793,12 +843,12 @@ static void CollectUsedResource(Value *resID,
|
|
|
} else if (SelectInst *SI = dyn_cast<SelectInst>(resID)) {
|
|
|
CollectUsedResource(SI->getTrueValue(), usedResID);
|
|
|
CollectUsedResource(SI->getFalseValue(), usedResID);
|
|
|
- } else {
|
|
|
- PHINode *Phi = cast<PHINode>(resID);
|
|
|
+ } else if (PHINode *Phi = dyn_cast<PHINode>(resID)) {
|
|
|
for (Use &U : Phi->incoming_values()) {
|
|
|
CollectUsedResource(U.get(), usedResID);
|
|
|
}
|
|
|
}
|
|
|
+ // TODO: resID could be other types of instructions depending on the compiler optimization.
|
|
|
}
|
|
|
|
|
|
static void ConvertUsedResource(std::unordered_set<unsigned> &immResID,
|