DxilShaderFlags.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilShaderFlags.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "dxc/DXIL/DxilModule.h"
  10. #include "dxc/DXIL/DxilShaderFlags.h"
  11. #include "dxc/DXIL/DxilOperations.h"
  12. #include "dxc/DXIL/DxilResource.h"
  13. #include "dxc/DXIL/DxilResourceBinding.h"
  14. #include "dxc/Support/Global.h"
  15. #include "llvm/IR/LLVMContext.h"
  16. #include "llvm/IR/Instructions.h"
  17. #include "llvm/IR/Constants.h"
  18. #include "llvm/Support/Casting.h"
  19. #include "dxc/DXIL/DxilEntryProps.h"
  20. #include "dxc/DXIL/DxilInstructions.h"
  21. #include "dxc/DXIL/DxilResourceProperties.h"
  22. #include "dxc/DXIL/DxilUtil.h"
  23. using namespace hlsl;
  24. using namespace llvm;
  25. ShaderFlags::ShaderFlags():
  26. m_bDisableOptimizations(false)
  27. , m_bDisableMathRefactoring(false)
  28. , m_bEnableDoublePrecision(false)
  29. , m_bForceEarlyDepthStencil(false)
  30. , m_bEnableRawAndStructuredBuffers(false)
  31. , m_bLowPrecisionPresent(false)
  32. , m_bEnableDoubleExtensions(false)
  33. , m_bEnableMSAD(false)
  34. , m_bAllResourcesBound(false)
  35. , m_bViewportAndRTArrayIndex(false)
  36. , m_bInnerCoverage(false)
  37. , m_bStencilRef(false)
  38. , m_bTiledResources(false)
  39. , m_bUAVLoadAdditionalFormats(false)
  40. , m_bLevel9ComparisonFiltering(false)
  41. , m_b64UAVs(false)
  42. , m_UAVsAtEveryStage(false)
  43. , m_bCSRawAndStructuredViaShader4X(false)
  44. , m_bROVS(false)
  45. , m_bWaveOps(false)
  46. , m_bInt64Ops(false)
  47. , m_bViewID(false)
  48. , m_bBarycentrics(false)
  49. , m_bUseNativeLowPrecision(false)
  50. , m_bShadingRate(false)
  51. , m_bRaytracingTier1_1(false)
  52. , m_bSamplerFeedback(false)
  53. , m_bAtomicInt64OnTypedResource(false)
  54. , m_bAtomicInt64OnGroupShared(false)
  55. , m_bDerivativesInMeshAndAmpShaders(false)
  56. , m_bResourceDescriptorHeapIndexing(false)
  57. , m_bSamplerDescriptorHeapIndexing(false)
  58. , m_bAtomicInt64OnHeapResource(false)
  59. , m_align1(0)
  60. {
  61. // Silence unused field warnings
  62. (void)m_align1;
  63. }
  64. uint64_t ShaderFlags::GetFeatureInfo() const {
  65. uint64_t Flags = 0;
  66. Flags |= m_bEnableDoublePrecision ? hlsl::DXIL::ShaderFeatureInfo_Doubles : 0;
  67. Flags |= m_bLowPrecisionPresent && !m_bUseNativeLowPrecision
  68. ? hlsl::DXIL::ShaderFeatureInfo_MinimumPrecision
  69. : 0;
  70. Flags |= m_bLowPrecisionPresent && m_bUseNativeLowPrecision
  71. ? hlsl::DXIL::ShaderFeatureInfo_NativeLowPrecision
  72. : 0;
  73. Flags |= m_bEnableDoubleExtensions
  74. ? hlsl::DXIL::ShaderFeatureInfo_11_1_DoubleExtensions
  75. : 0;
  76. Flags |= m_bWaveOps ? hlsl::DXIL::ShaderFeatureInfo_WaveOps : 0;
  77. Flags |= m_bInt64Ops ? hlsl::DXIL::ShaderFeatureInfo_Int64Ops : 0;
  78. Flags |= m_bROVS ? hlsl::DXIL::ShaderFeatureInfo_ROVs : 0;
  79. Flags |=
  80. m_bViewportAndRTArrayIndex
  81. ? hlsl::DXIL::
  82. ShaderFeatureInfo_ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer
  83. : 0;
  84. Flags |= m_bInnerCoverage ? hlsl::DXIL::ShaderFeatureInfo_InnerCoverage : 0;
  85. Flags |= m_bStencilRef ? hlsl::DXIL::ShaderFeatureInfo_StencilRef : 0;
  86. Flags |= m_bTiledResources ? hlsl::DXIL::ShaderFeatureInfo_TiledResources : 0;
  87. Flags |=
  88. m_bEnableMSAD ? hlsl::DXIL::ShaderFeatureInfo_11_1_ShaderExtensions : 0;
  89. Flags |=
  90. m_bCSRawAndStructuredViaShader4X
  91. ? hlsl::DXIL::
  92. ShaderFeatureInfo_ComputeShadersPlusRawAndStructuredBuffersViaShader4X
  93. : 0;
  94. Flags |=
  95. m_UAVsAtEveryStage ? hlsl::DXIL::ShaderFeatureInfo_UAVsAtEveryStage : 0;
  96. Flags |= m_b64UAVs ? hlsl::DXIL::ShaderFeatureInfo_64UAVs : 0;
  97. Flags |= m_bLevel9ComparisonFiltering
  98. ? hlsl::DXIL::ShaderFeatureInfo_LEVEL9ComparisonFiltering
  99. : 0;
  100. Flags |= m_bUAVLoadAdditionalFormats
  101. ? hlsl::DXIL::ShaderFeatureInfo_TypedUAVLoadAdditionalFormats
  102. : 0;
  103. Flags |= m_bViewID ? hlsl::DXIL::ShaderFeatureInfo_ViewID : 0;
  104. Flags |= m_bBarycentrics ? hlsl::DXIL::ShaderFeatureInfo_Barycentrics : 0;
  105. Flags |= m_bShadingRate ? hlsl::DXIL::ShaderFeatureInfo_ShadingRate : 0;
  106. Flags |= m_bRaytracingTier1_1 ? hlsl::DXIL::ShaderFeatureInfo_Raytracing_Tier_1_1 : 0;
  107. Flags |= m_bSamplerFeedback ? hlsl::DXIL::ShaderFeatureInfo_SamplerFeedback : 0;
  108. Flags |= m_bAtomicInt64OnTypedResource ? hlsl::DXIL::ShaderFeatureInfo_AtomicInt64OnTypedResource : 0;
  109. Flags |= m_bAtomicInt64OnGroupShared ? hlsl::DXIL::ShaderFeatureInfo_AtomicInt64OnGroupShared : 0;
  110. Flags |= m_bDerivativesInMeshAndAmpShaders ? hlsl::DXIL::ShaderFeatureInfo_DerivativesInMeshAndAmpShaders : 0;
  111. Flags |= m_bResourceDescriptorHeapIndexing ? hlsl::DXIL::ShaderFeatureInfo_ResourceDescriptorHeapIndexing : 0;
  112. Flags |= m_bSamplerDescriptorHeapIndexing ? hlsl::DXIL::ShaderFeatureInfo_SamplerDescriptorHeapIndexing : 0;
  113. Flags |= m_bAtomicInt64OnHeapResource ? hlsl::DXIL::ShaderFeatureInfo_AtomicInt64OnHeapResource : 0;
  114. return Flags;
  115. }
  116. uint64_t ShaderFlags::GetShaderFlagsRaw() const {
  117. union Cast {
  118. Cast(const ShaderFlags &flags) {
  119. shaderFlags = flags;
  120. }
  121. ShaderFlags shaderFlags;
  122. uint64_t rawData;
  123. };
  124. static_assert(sizeof(uint64_t) == sizeof(ShaderFlags),
  125. "size must match to make sure no undefined bits when cast");
  126. Cast rawCast(*this);
  127. return rawCast.rawData;
  128. }
  129. void ShaderFlags::SetShaderFlagsRaw(uint64_t data) {
  130. union Cast {
  131. Cast(uint64_t data) {
  132. rawData = data;
  133. }
  134. ShaderFlags shaderFlags;
  135. uint64_t rawData;
  136. };
  137. Cast rawCast(data);
  138. *this = rawCast.shaderFlags;
  139. }
  140. uint64_t ShaderFlags::GetShaderFlagsRawForCollection() {
  141. // This should be all the flags that can be set by DxilModule::CollectShaderFlags.
  142. ShaderFlags Flags;
  143. Flags.SetEnableDoublePrecision(true);
  144. Flags.SetInt64Ops(true);
  145. Flags.SetLowPrecisionPresent(true);
  146. Flags.SetEnableDoubleExtensions(true);
  147. Flags.SetWaveOps(true);
  148. Flags.SetTiledResources(true);
  149. Flags.SetEnableMSAD(true);
  150. Flags.SetUAVLoadAdditionalFormats(true);
  151. Flags.SetStencilRef(true);
  152. Flags.SetInnerCoverage(true);
  153. Flags.SetViewportAndRTArrayIndex(true);
  154. Flags.Set64UAVs(true);
  155. Flags.SetUAVsAtEveryStage(true);
  156. Flags.SetEnableRawAndStructuredBuffers(true);
  157. Flags.SetCSRawAndStructuredViaShader4X(true);
  158. Flags.SetViewID(true);
  159. Flags.SetBarycentrics(true);
  160. Flags.SetShadingRate(true);
  161. Flags.SetRaytracingTier1_1(true);
  162. Flags.SetSamplerFeedback(true);
  163. Flags.SetAtomicInt64OnTypedResource(true);
  164. Flags.SetAtomicInt64OnGroupShared(true);
  165. Flags.SetDerivativesInMeshAndAmpShaders(true);
  166. Flags.SetResourceDescriptorHeapIndexing(true);
  167. Flags.SetSamplerDescriptorHeapIndexing(true);
  168. Flags.SetAtomicInt64OnHeapResource(true);
  169. return Flags.GetShaderFlagsRaw();
  170. }
  171. unsigned ShaderFlags::GetGlobalFlags() const {
  172. unsigned Flags = 0;
  173. Flags |= m_bDisableOptimizations ? DXIL::kDisableOptimizations : 0;
  174. Flags |= m_bDisableMathRefactoring ? DXIL::kDisableMathRefactoring : 0;
  175. Flags |= m_bEnableDoublePrecision ? DXIL::kEnableDoublePrecision : 0;
  176. Flags |= m_bForceEarlyDepthStencil ? DXIL::kForceEarlyDepthStencil : 0;
  177. Flags |= m_bEnableRawAndStructuredBuffers ? DXIL::kEnableRawAndStructuredBuffers : 0;
  178. Flags |= m_bLowPrecisionPresent && !m_bUseNativeLowPrecision? DXIL::kEnableMinPrecision : 0;
  179. Flags |= m_bEnableDoubleExtensions ? DXIL::kEnableDoubleExtensions : 0;
  180. Flags |= m_bEnableMSAD ? DXIL::kEnableMSAD : 0;
  181. Flags |= m_bAllResourcesBound ? DXIL::kAllResourcesBound : 0;
  182. return Flags;
  183. }
  184. // Given a CreateHandle call, returns arbitrary ConstantInt rangeID
  185. // Note: HLSL is currently assuming that rangeID is a constant value, but this code is assuming
  186. // that it can be either constant, phi node, or select instruction
  187. static ConstantInt *GetArbitraryConstantRangeID(CallInst *handleCall) {
  188. Value *rangeID =
  189. handleCall->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
  190. ConstantInt *ConstantRangeID = dyn_cast<ConstantInt>(rangeID);
  191. while (ConstantRangeID == nullptr) {
  192. if (ConstantInt *CI = dyn_cast<ConstantInt>(rangeID)) {
  193. ConstantRangeID = CI;
  194. } else if (PHINode *PN = dyn_cast<PHINode>(rangeID)) {
  195. rangeID = PN->getIncomingValue(0);
  196. } else if (SelectInst *SI = dyn_cast<SelectInst>(rangeID)) {
  197. rangeID = SI->getTrueValue();
  198. } else {
  199. return nullptr;
  200. }
  201. }
  202. return ConstantRangeID;
  203. }
  204. // Given a handle type, find an arbitrary call instructions to create handle
  205. static CallInst *FindCallToCreateHandle(Value *handleType) {
  206. Value *curVal = handleType;
  207. CallInst *CI = dyn_cast<CallInst>(handleType);
  208. while (CI == nullptr) {
  209. if (PHINode *PN = dyn_cast<PHINode>(curVal)) {
  210. curVal = PN->getIncomingValue(0);
  211. }
  212. else if (SelectInst *SI = dyn_cast<SelectInst>(curVal)) {
  213. curVal = SI->getTrueValue();
  214. }
  215. else {
  216. return nullptr;
  217. }
  218. CI = dyn_cast<CallInst>(curVal);
  219. }
  220. return CI;
  221. }
  222. DxilResourceProperties GetResourcePropertyFromHandleCall(const hlsl::DxilModule *M, CallInst *handleCall) {
  223. DxilResourceProperties RP;
  224. ConstantInt *HandleOpCodeConst = cast<ConstantInt>(
  225. handleCall->getArgOperand(DXIL::OperandIndex::kOpcodeIdx));
  226. DXIL::OpCode handleOp = static_cast<DXIL::OpCode>(HandleOpCodeConst->getLimitedValue());
  227. if (handleOp == DXIL::OpCode::CreateHandle) {
  228. if (ConstantInt *resClassArg =
  229. dyn_cast<ConstantInt>(handleCall->getArgOperand(
  230. DXIL::OperandIndex::kCreateHandleResClassOpIdx))) {
  231. DXIL::ResourceClass resClass = static_cast<DXIL::ResourceClass>(
  232. resClassArg->getLimitedValue());
  233. ConstantInt *rangeID = GetArbitraryConstantRangeID(handleCall);
  234. if (rangeID) {
  235. DxilResource resource;
  236. if (resClass == DXIL::ResourceClass::UAV)
  237. resource = M->GetUAV(rangeID->getLimitedValue());
  238. else if (resClass == DXIL::ResourceClass::SRV)
  239. resource = M->GetSRV(rangeID->getLimitedValue());
  240. RP = resource_helper::loadPropsFromResourceBase(&resource);
  241. }
  242. }
  243. }
  244. else if (handleOp == DXIL::OpCode::CreateHandleForLib) {
  245. // If library handle, find DxilResource by checking the name
  246. if (LoadInst *LI = dyn_cast<LoadInst>(handleCall->getArgOperand(
  247. DXIL::OperandIndex::kCreateHandleForLibResOpIdx))) {
  248. Value *resType = LI->getOperand(0);
  249. for (auto &&res : M->GetUAVs()) {
  250. if (res->GetGlobalSymbol() == resType) {
  251. RP = resource_helper::loadPropsFromResourceBase(res.get());
  252. }
  253. }
  254. }
  255. } else if (handleOp == DXIL::OpCode::AnnotateHandle) {
  256. DxilInst_AnnotateHandle annotateHandle(cast<Instruction>(handleCall));
  257. RP = resource_helper::loadPropsFromAnnotateHandle(annotateHandle, *M->GetShaderModel());
  258. }
  259. return RP;
  260. }
  261. struct ResourceKey {
  262. uint8_t Class;
  263. uint32_t Space;
  264. uint32_t LowerBound;
  265. uint32_t UpperBound;
  266. };
  267. struct ResKeyEq {
  268. bool operator()(const ResourceKey& k1, const ResourceKey& k2) const {
  269. return k1.Class == k2.Class && k1.Space == k2.Space &&
  270. k1.LowerBound == k2.LowerBound && k1.UpperBound == k2.UpperBound;
  271. }
  272. };
  273. struct ResKeyHash {
  274. std::size_t operator()(const ResourceKey& k) const {
  275. return std::hash<uint32_t>()(k.LowerBound) ^ (std::hash<uint32_t>()(k.UpperBound)<<1) ^
  276. (std::hash<uint32_t>()(k.Space)<<2) ^ (std::hash<uint8_t>()(k.Class)<<3);
  277. }
  278. };
  279. // Limited to retrieving handles created by CreateHandleFromBinding and CreateHandleForLib. returns null otherwise
  280. // map should contain resources indexed by space, class, lower, and upper bounds
  281. DxilResource *GetResourceFromAnnotateHandle(const hlsl::DxilModule *M, CallInst *handleCall,
  282. std::unordered_map<ResourceKey, DxilResource *, ResKeyHash, ResKeyEq> resMap) {
  283. DxilResource *resource = nullptr;
  284. ConstantInt *HandleOpCodeConst = cast<ConstantInt>(
  285. handleCall->getArgOperand(DXIL::OperandIndex::kOpcodeIdx));
  286. DXIL::OpCode handleOp = static_cast<DXIL::OpCode>(HandleOpCodeConst->getLimitedValue());
  287. if (handleOp == DXIL::OpCode::AnnotateHandle) {
  288. DxilInst_AnnotateHandle annotateHandle(cast<Instruction>(handleCall));
  289. CallInst *createCall = cast<CallInst>(annotateHandle.get_res());
  290. ConstantInt *HandleOpCodeConst = cast<ConstantInt>(
  291. createCall->getArgOperand(DXIL::OperandIndex::kOpcodeIdx));
  292. DXIL::OpCode handleOp = static_cast<DXIL::OpCode>(HandleOpCodeConst->getLimitedValue());
  293. if (handleOp == DXIL::OpCode::CreateHandleFromBinding) {
  294. DxilInst_CreateHandleFromBinding fromBind(createCall);
  295. DxilResourceBinding B = resource_helper::loadBindingFromConstant(*cast<Constant>(fromBind.get_bind()));
  296. ResourceKey key = {B.resourceClass, B.spaceID, B.rangeLowerBound, B.rangeUpperBound};
  297. resource = resMap[key];
  298. } else if (handleOp == DXIL::OpCode::CreateHandleForLib) {
  299. // If library handle, find DxilResource by checking the name
  300. if (LoadInst *LI = dyn_cast<LoadInst>(createCall->getArgOperand(
  301. DXIL::OperandIndex::kCreateHandleForLibResOpIdx))) {
  302. Value *resType = LI->getOperand(0);
  303. for (auto &&res : M->GetUAVs()) {
  304. if (res->GetGlobalSymbol() == resType) {
  305. return resource = res.get();
  306. }
  307. }
  308. }
  309. }
  310. }
  311. return resource;
  312. }
  313. ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
  314. const hlsl::DxilModule *M) {
  315. ShaderFlags flag;
  316. // Module level options
  317. flag.SetUseNativeLowPrecision(!M->GetUseMinPrecision());
  318. flag.SetDisableOptimizations(M->GetDisableOptimization());
  319. flag.SetAllResourcesBound(M->GetAllResourcesBound());
  320. bool hasDouble = false;
  321. // ddiv dfma drcp d2i d2u i2d u2d.
  322. // fma has dxil op. Others should check IR instruction div/cast.
  323. bool hasDoubleExtension = false;
  324. bool has64Int = false;
  325. bool has16 = false;
  326. bool hasWaveOps = false;
  327. bool hasCheckAccessFully = false;
  328. bool hasMSAD = false;
  329. bool hasStencilRef = false;
  330. bool hasInnerCoverage = false;
  331. bool hasViewID = false;
  332. bool hasMulticomponentUAVLoads = false;
  333. bool hasViewportOrRTArrayIndex = false;
  334. bool hasShadingRate = false;
  335. bool hasBarycentrics = false;
  336. bool hasSamplerFeedback = false;
  337. bool hasRaytracingTier1_1 = false;
  338. bool hasAtomicInt64OnTypedResource = false;
  339. bool hasAtomicInt64OnGroupShared = false;
  340. bool hasDerivativesInMeshAndAmpShaders = false;
  341. bool hasResourceDescriptorHeapIndexing = false;
  342. bool hasSamplerDescriptorHeapIndexing = false;
  343. bool hasAtomicInt64OnHeapResource = false;
  344. // Try to maintain compatibility with a v1.0 validator if that's what we have.
  345. uint32_t valMajor, valMinor;
  346. M->GetValidatorVersion(valMajor, valMinor);
  347. bool hasMulticomponentUAVLoadsBackCompat = valMajor == 1 && valMinor == 0;
  348. bool hasViewportOrRTArrayIndexBackCombat = valMajor == 1 && valMinor < 4;
  349. bool hasBarycentricsBackCompat = valMajor == 1 && valMinor < 6;
  350. Type *int16Ty = Type::getInt16Ty(F->getContext());
  351. Type *int64Ty = Type::getInt64Ty(F->getContext());
  352. // Set up resource to binding handle map for 64-bit atomics usage
  353. std::unordered_map<ResourceKey, DxilResource *, ResKeyHash, ResKeyEq> resMap;
  354. for (auto &res : M->GetUAVs()) {
  355. ResourceKey key = {(uint8_t)res->GetClass(), res->GetSpaceID(),
  356. res->GetLowerBound(), res->GetUpperBound()};
  357. resMap.insert({key, res.get()});
  358. }
  359. for (const BasicBlock &BB : F->getBasicBlockList()) {
  360. for (const Instruction &I : BB.getInstList()) {
  361. // Skip none dxil function call.
  362. if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
  363. if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
  364. continue;
  365. }
  366. Type *Ty = I.getType();
  367. bool isDouble = Ty->isDoubleTy();
  368. bool isHalf = Ty->isHalfTy();
  369. bool isInt16 = Ty == int16Ty;
  370. bool isInt64 = Ty == int64Ty;
  371. if (isa<ExtractElementInst>(&I) ||
  372. isa<InsertElementInst>(&I))
  373. continue;
  374. for (Value *operand : I.operands()) {
  375. Type *Ty = operand->getType();
  376. isDouble |= Ty->isDoubleTy();
  377. isHalf |= Ty->isHalfTy();
  378. isInt16 |= Ty == int16Ty;
  379. isInt64 |= Ty == int64Ty;
  380. }
  381. if (isDouble) {
  382. hasDouble = true;
  383. switch (I.getOpcode()) {
  384. case Instruction::FDiv:
  385. case Instruction::UIToFP:
  386. case Instruction::SIToFP:
  387. case Instruction::FPToUI:
  388. case Instruction::FPToSI:
  389. hasDoubleExtension = true;
  390. break;
  391. }
  392. }
  393. if (isInt64) {
  394. has64Int = true;
  395. switch (I.getOpcode()) {
  396. case Instruction::AtomicCmpXchg:
  397. case Instruction::AtomicRMW:
  398. hasAtomicInt64OnGroupShared = true;
  399. break;
  400. }
  401. }
  402. has16 |= isHalf;
  403. has16 |= isInt16;
  404. if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
  405. if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
  406. continue;
  407. Value *opcodeArg = CI->getArgOperand(DXIL::OperandIndex::kOpcodeIdx);
  408. ConstantInt *opcodeConst = dyn_cast<ConstantInt>(opcodeArg);
  409. DXASSERT(opcodeConst, "DXIL opcode arg must be immediate");
  410. unsigned opcode = opcodeConst->getLimitedValue();
  411. DXASSERT(opcode < static_cast<unsigned>(DXIL::OpCode::NumOpCodes),
  412. "invalid DXIL opcode");
  413. DXIL::OpCode dxilOp = static_cast<DXIL::OpCode>(opcode);
  414. if (hlsl::OP::IsDxilOpWave(dxilOp))
  415. hasWaveOps = true;
  416. switch (dxilOp) {
  417. case DXIL::OpCode::CheckAccessFullyMapped:
  418. hasCheckAccessFully = true;
  419. break;
  420. case DXIL::OpCode::Msad:
  421. hasMSAD = true;
  422. break;
  423. case DXIL::OpCode::BufferLoad:
  424. case DXIL::OpCode::TextureLoad: {
  425. if (hasMulticomponentUAVLoads) continue;
  426. // This is the old-style computation (overestimating requirements).
  427. Value *resHandle = CI->getArgOperand(DXIL::OperandIndex::kBufferStoreHandleOpIdx);
  428. CallInst *handleCall = FindCallToCreateHandle(resHandle);
  429. // Check if this is a library handle or general create handle
  430. if (handleCall) {
  431. DxilResourceProperties RP = GetResourcePropertyFromHandleCall(M, handleCall);
  432. if (RP.isUAV()) {
  433. // Validator 1.0 assumes that all uav load is multi component load.
  434. if (hasMulticomponentUAVLoadsBackCompat) {
  435. hasMulticomponentUAVLoads = true;
  436. continue;
  437. } else {
  438. if (DXIL::IsTyped(RP.getResourceKind()) &&
  439. RP.Typed.CompCount > 1)
  440. hasMulticomponentUAVLoads = true;
  441. }
  442. }
  443. }
  444. } break;
  445. case DXIL::OpCode::Fma:
  446. hasDoubleExtension |= isDouble;
  447. break;
  448. case DXIL::OpCode::InnerCoverage:
  449. hasInnerCoverage = true;
  450. break;
  451. case DXIL::OpCode::ViewID:
  452. hasViewID = true;
  453. break;
  454. case DXIL::OpCode::AllocateRayQuery:
  455. case DXIL::OpCode::GeometryIndex:
  456. hasRaytracingTier1_1 = true;
  457. break;
  458. case DXIL::OpCode::AttributeAtVertex:
  459. hasBarycentrics = true;
  460. break;
  461. case DXIL::OpCode::AtomicBinOp:
  462. case DXIL::OpCode::AtomicCompareExchange:
  463. if (isInt64) {
  464. Value *resHandle = CI->getArgOperand(DXIL::OperandIndex::kAtomicBinOpHandleOpIdx);
  465. CallInst *handleCall = FindCallToCreateHandle(resHandle);
  466. DxilResourceProperties RP = GetResourcePropertyFromHandleCall(M, handleCall);
  467. if (DXIL::IsTyped(RP.getResourceKind()))
  468. hasAtomicInt64OnTypedResource = true;
  469. // set uses 64-bit flag if relevant
  470. if (DxilResource *res = GetResourceFromAnnotateHandle(M, handleCall, resMap)) {
  471. res->SetHasAtomic64Use(true);
  472. } else {
  473. // Assuming CreateHandleFromHeap, which indicates a descriptor
  474. hasAtomicInt64OnHeapResource = true;
  475. }
  476. }
  477. break;
  478. case DXIL::OpCode::DerivFineX:
  479. case DXIL::OpCode::DerivFineY:
  480. case DXIL::OpCode::DerivCoarseX:
  481. case DXIL::OpCode::DerivCoarseY:
  482. case DXIL::OpCode::CalculateLOD:
  483. case DXIL::OpCode::Sample:
  484. case DXIL::OpCode::SampleBias:
  485. case DXIL::OpCode::SampleCmp: {
  486. const ShaderModel *pSM = M->GetShaderModel();
  487. if (pSM->IsAS() || pSM->IsMS())
  488. hasDerivativesInMeshAndAmpShaders = true;
  489. } break;
  490. case DXIL::OpCode::CreateHandleFromHeap: {
  491. ConstantInt *isSamplerVal = dyn_cast<ConstantInt>(
  492. CI->getArgOperand(DXIL::OperandIndex::kCreateHandleFromHeapSamplerHeapOpIdx));
  493. if (isSamplerVal->getLimitedValue())
  494. hasSamplerDescriptorHeapIndexing = true;
  495. else
  496. hasResourceDescriptorHeapIndexing = true;
  497. }
  498. default:
  499. // Normal opcodes.
  500. break;
  501. }
  502. }
  503. }
  504. }
  505. // If this function is a shader, add flags based on signatures
  506. if (M->HasDxilEntryProps(F)) {
  507. const DxilEntryProps &entryProps = M->GetDxilEntryProps(F);
  508. // Val ver < 1.4 has a bug where input case was always clobbered by the
  509. // output check. The only case where it made a difference such that an
  510. // incorrect flag would be set was for the HS and DS input cases.
  511. // It was also checking PS input and output, but PS output could not have
  512. // the semantic, and since it was clobbering the result, it would always
  513. // clear it. Since this flag should not be set for PS at all,
  514. // it produced the correct result for PS by accident.
  515. bool checkInputRTArrayIndex = entryProps.props.IsGS();
  516. if (!hasViewportOrRTArrayIndexBackCombat)
  517. checkInputRTArrayIndex |= entryProps.props.IsDS() ||
  518. entryProps.props.IsHS();
  519. bool checkOutputRTArrayIndex =
  520. entryProps.props.IsVS() || entryProps.props.IsDS() ||
  521. entryProps.props.IsHS();
  522. for (auto &&E : entryProps.sig.InputSignature.GetElements()) {
  523. switch (E->GetKind()) {
  524. case Semantic::Kind::ViewPortArrayIndex:
  525. case Semantic::Kind::RenderTargetArrayIndex:
  526. if (checkInputRTArrayIndex)
  527. hasViewportOrRTArrayIndex = true;
  528. break;
  529. case Semantic::Kind::ShadingRate:
  530. hasShadingRate = true;
  531. break;
  532. case Semantic::Kind::Barycentrics:
  533. hasBarycentrics = true;
  534. break;
  535. default:
  536. break;
  537. }
  538. }
  539. for (auto &&E : entryProps.sig.OutputSignature.GetElements()) {
  540. switch (E->GetKind()) {
  541. case Semantic::Kind::ViewPortArrayIndex:
  542. case Semantic::Kind::RenderTargetArrayIndex:
  543. if (checkOutputRTArrayIndex)
  544. hasViewportOrRTArrayIndex = true;
  545. break;
  546. case Semantic::Kind::StencilRef:
  547. if (entryProps.props.IsPS())
  548. hasStencilRef = true;
  549. break;
  550. case Semantic::Kind::InnerCoverage:
  551. if (entryProps.props.IsPS())
  552. hasInnerCoverage = true;
  553. break;
  554. case Semantic::Kind::ShadingRate:
  555. hasShadingRate = true;
  556. break;
  557. default:
  558. break;
  559. }
  560. }
  561. }
  562. if (!hasRaytracingTier1_1) {
  563. if (const DxilSubobjects *pSubobjects = M->GetSubobjects()) {
  564. for (const auto &it : pSubobjects->GetSubobjects()) {
  565. switch (it.second->GetKind()) {
  566. case DXIL::SubobjectKind::RaytracingPipelineConfig1:
  567. hasRaytracingTier1_1 = true;
  568. break;
  569. case DXIL::SubobjectKind::StateObjectConfig: {
  570. uint32_t Flags;
  571. if (it.second->GetStateObjectConfig(Flags) &&
  572. ((Flags & ~(unsigned)DXIL::StateObjectFlags::ValidMask_1_4) != 0))
  573. hasRaytracingTier1_1 = true;
  574. } break;
  575. default:
  576. break;
  577. }
  578. if (hasRaytracingTier1_1)
  579. break;
  580. }
  581. }
  582. }
  583. flag.SetEnableDoublePrecision(hasDouble);
  584. flag.SetStencilRef(hasStencilRef);
  585. flag.SetInnerCoverage(hasInnerCoverage);
  586. flag.SetInt64Ops(has64Int);
  587. flag.SetLowPrecisionPresent(has16);
  588. flag.SetEnableDoubleExtensions(hasDoubleExtension);
  589. flag.SetWaveOps(hasWaveOps);
  590. flag.SetTiledResources(hasCheckAccessFully);
  591. flag.SetEnableMSAD(hasMSAD);
  592. flag.SetUAVLoadAdditionalFormats(hasMulticomponentUAVLoads);
  593. flag.SetViewID(hasViewID);
  594. flag.SetViewportAndRTArrayIndex(hasViewportOrRTArrayIndex);
  595. flag.SetShadingRate(hasShadingRate);
  596. flag.SetBarycentrics(hasBarycentricsBackCompat ? false : hasBarycentrics);
  597. flag.SetSamplerFeedback(hasSamplerFeedback);
  598. flag.SetRaytracingTier1_1(hasRaytracingTier1_1);
  599. flag.SetAtomicInt64OnTypedResource(hasAtomicInt64OnTypedResource);
  600. flag.SetAtomicInt64OnGroupShared(hasAtomicInt64OnGroupShared);
  601. flag.SetDerivativesInMeshAndAmpShaders(hasDerivativesInMeshAndAmpShaders);
  602. flag.SetResourceDescriptorHeapIndexing(hasResourceDescriptorHeapIndexing);
  603. flag.SetSamplerDescriptorHeapIndexing(hasSamplerDescriptorHeapIndexing);
  604. flag.SetAtomicInt64OnHeapResource(hasAtomicInt64OnHeapResource);
  605. return flag;
  606. }
  607. void ShaderFlags::CombineShaderFlags(const ShaderFlags &other) {
  608. SetShaderFlagsRaw(GetShaderFlagsRaw() | other.GetShaderFlagsRaw());
  609. }