HLSignatureLower.cpp 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // HLSignatureLower.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. // Lower signatures of entry function to DXIL LoadInput/StoreOutput. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "HLSignatureLower.h"
  12. #include "dxc/DXIL/DxilOperations.h"
  13. #include "dxc/DXIL/DxilSignatureElement.h"
  14. #include "dxc/DXIL/DxilSigPoint.h"
  15. #include "dxc/Support/Global.h"
  16. #include "dxc/DXIL/DxilTypeSystem.h"
  17. #include "dxc/DXIL/DxilSemantic.h"
  18. #include "dxc/HLSL/HLModule.h"
  19. #include "dxc/HLSL/HLMatrixLowerHelper.h"
  20. #include "dxc/HLSL/HLMatrixType.h"
  21. #include "dxc/HlslIntrinsicOp.h"
  22. #include "dxc/DXIL/DxilUtil.h"
  23. #include "dxc/HLSL/DxilPackSignatureElement.h"
  24. #include "llvm/IR/IRBuilder.h"
  25. #include "llvm/IR/DebugInfo.h"
  26. #include "llvm/IR/IntrinsicInst.h"
  27. #include "llvm/IR/Module.h"
  28. #include "llvm/Transforms/Utils/Local.h"
  29. using namespace llvm;
  30. using namespace hlsl;
  31. namespace {
  32. // Decompose semantic name (eg FOO1=>FOO,1), change interp mode for SV_Position.
  33. // Return semantic index.
  34. unsigned UpdateSemanticAndInterpMode(StringRef &semName,
  35. DXIL::InterpolationMode &mode,
  36. DXIL::SigPointKind kind,
  37. LLVMContext &Context) {
  38. llvm::StringRef baseSemName; // The 'FOO' in 'FOO1'.
  39. uint32_t semIndex; // The '1' in 'FOO1'
  40. // Split semName and index.
  41. Semantic::DecomposeNameAndIndex(semName, &baseSemName, &semIndex);
  42. semName = baseSemName;
  43. const Semantic *semantic = Semantic::GetByName(semName, kind);
  44. if (semantic && semantic->GetKind() == Semantic::Kind::Position) {
  45. // Update interp mode to no_perspective version for SV_Position.
  46. switch (mode) {
  47. case InterpolationMode::Kind::LinearCentroid:
  48. mode = InterpolationMode::Kind::LinearNoperspectiveCentroid;
  49. break;
  50. case InterpolationMode::Kind::LinearSample:
  51. mode = InterpolationMode::Kind::LinearNoperspectiveSample;
  52. break;
  53. case InterpolationMode::Kind::Linear:
  54. mode = InterpolationMode::Kind::LinearNoperspective;
  55. break;
  56. case InterpolationMode::Kind::Constant:
  57. case InterpolationMode::Kind::Undefined:
  58. case InterpolationMode::Kind::Invalid: {
  59. Context.emitError("invalid interpolation mode for SV_Position");
  60. } break;
  61. case InterpolationMode::Kind::LinearNoperspective:
  62. case InterpolationMode::Kind::LinearNoperspectiveCentroid:
  63. case InterpolationMode::Kind::LinearNoperspectiveSample:
  64. // Already Noperspective modes.
  65. break;
  66. }
  67. }
  68. return semIndex;
  69. }
  70. DxilSignatureElement *FindArgInSignature(Argument &arg,
  71. llvm::StringRef semantic,
  72. DXIL::InterpolationMode interpMode,
  73. DXIL::SigPointKind kind,
  74. DxilSignature &sig) {
  75. // Match output ID.
  76. unsigned semIndex =
  77. UpdateSemanticAndInterpMode(semantic, interpMode, kind, arg.getContext());
  78. for (uint32_t i = 0; i < sig.GetElements().size(); i++) {
  79. DxilSignatureElement &SE = sig.GetElement(i);
  80. bool semNameMatch = semantic.equals_lower(SE.GetName());
  81. bool semIndexMatch = semIndex == SE.GetSemanticIndexVec()[0];
  82. if (semNameMatch && semIndexMatch) {
  83. // Find a match.
  84. return &SE;
  85. }
  86. }
  87. return nullptr;
  88. }
  89. } // namespace
  90. namespace {
  91. void replaceInputOutputWithIntrinsic(DXIL::SemanticKind semKind, Value *GV,
  92. OP *hlslOP, IRBuilder<> &Builder) {
  93. Type *Ty = GV->getType();
  94. if (Ty->isPointerTy())
  95. Ty = Ty->getPointerElementType();
  96. OP::OpCode opcode;
  97. switch (semKind) {
  98. case Semantic::Kind::DomainLocation:
  99. opcode = OP::OpCode::DomainLocation;
  100. break;
  101. case Semantic::Kind::OutputControlPointID:
  102. opcode = OP::OpCode::OutputControlPointID;
  103. break;
  104. case Semantic::Kind::GSInstanceID:
  105. opcode = OP::OpCode::GSInstanceID;
  106. break;
  107. case Semantic::Kind::PrimitiveID:
  108. opcode = OP::OpCode::PrimitiveID;
  109. break;
  110. case Semantic::Kind::SampleIndex:
  111. opcode = OP::OpCode::SampleIndex;
  112. break;
  113. case Semantic::Kind::Coverage:
  114. opcode = OP::OpCode::Coverage;
  115. break;
  116. case Semantic::Kind::InnerCoverage:
  117. opcode = OP::OpCode::InnerCoverage;
  118. break;
  119. case Semantic::Kind::ViewID:
  120. opcode = OP::OpCode::ViewID;
  121. break;
  122. case Semantic::Kind::GroupThreadID:
  123. opcode = OP::OpCode::ThreadIdInGroup;
  124. break;
  125. case Semantic::Kind::GroupID:
  126. opcode = OP::OpCode::GroupId;
  127. break;
  128. case Semantic::Kind::DispatchThreadID:
  129. opcode = OP::OpCode::ThreadId;
  130. break;
  131. case Semantic::Kind::GroupIndex:
  132. opcode = OP::OpCode::FlattenedThreadIdInGroup;
  133. break;
  134. case Semantic::Kind::CullPrimitive: {
  135. GV->replaceAllUsesWith(ConstantInt::get(Ty, (uint64_t)0));
  136. return;
  137. } break;
  138. default:
  139. DXASSERT(0, "invalid semantic");
  140. return;
  141. }
  142. Function *dxilFunc = hlslOP->GetOpFunc(opcode, Ty->getScalarType());
  143. Constant *OpArg = hlslOP->GetU32Const((unsigned)opcode);
  144. Value *newArg = nullptr;
  145. if (semKind == Semantic::Kind::DomainLocation ||
  146. semKind == Semantic::Kind::GroupThreadID ||
  147. semKind == Semantic::Kind::GroupID ||
  148. semKind == Semantic::Kind::DispatchThreadID) {
  149. unsigned vecSize = 1;
  150. if (Ty->isVectorTy())
  151. vecSize = Ty->getVectorNumElements();
  152. newArg = Builder.CreateCall(dxilFunc, { OpArg,
  153. semKind == Semantic::Kind::DomainLocation ? hlslOP->GetU8Const(0) : hlslOP->GetU32Const(0) });
  154. if (vecSize > 1) {
  155. Value *result = UndefValue::get(Ty);
  156. result = Builder.CreateInsertElement(result, newArg, (uint64_t)0);
  157. for (unsigned i = 1; i < vecSize; i++) {
  158. Value *newElt =
  159. Builder.CreateCall(dxilFunc, { OpArg,
  160. semKind == Semantic::Kind::DomainLocation ? hlslOP->GetU8Const(i)
  161. : hlslOP->GetU32Const(i) });
  162. result = Builder.CreateInsertElement(result, newElt, i);
  163. }
  164. newArg = result;
  165. }
  166. } else {
  167. newArg = Builder.CreateCall(dxilFunc, {OpArg});
  168. }
  169. if (newArg->getType() != GV->getType()) {
  170. DXASSERT_NOMSG(GV->getType()->isPointerTy());
  171. for (User *U : GV->users()) {
  172. if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
  173. LI->replaceAllUsesWith(newArg);
  174. }
  175. }
  176. } else {
  177. GV->replaceAllUsesWith(newArg);
  178. }
  179. }
  180. } // namespace
  181. void HLSignatureLower::ProcessArgument(Function *func,
  182. DxilFunctionAnnotation *funcAnnotation,
  183. Argument &arg, DxilFunctionProps &props,
  184. const ShaderModel *pSM,
  185. bool isPatchConstantFunction,
  186. bool forceOut, bool &hasClipPlane) {
  187. Type *Ty = arg.getType();
  188. DxilParameterAnnotation &paramAnnotation =
  189. funcAnnotation->GetParameterAnnotation(arg.getArgNo());
  190. hlsl::DxilParamInputQual qual =
  191. forceOut ? DxilParamInputQual::Out : paramAnnotation.GetParamInputQual();
  192. bool isInout = qual == DxilParamInputQual::Inout;
  193. // If this was an inout param, do the output side first
  194. if (isInout) {
  195. DXASSERT(!isPatchConstantFunction,
  196. "Patch Constant function should not have inout param");
  197. m_inoutArgSet.insert(&arg);
  198. const bool bForceOutTrue = true;
  199. ProcessArgument(func, funcAnnotation, arg, props, pSM,
  200. isPatchConstantFunction, bForceOutTrue, hasClipPlane);
  201. qual = DxilParamInputQual::In;
  202. }
  203. // Get stream index
  204. unsigned streamIdx = 0;
  205. switch (qual) {
  206. case DxilParamInputQual::OutStream1:
  207. streamIdx = 1;
  208. break;
  209. case DxilParamInputQual::OutStream2:
  210. streamIdx = 2;
  211. break;
  212. case DxilParamInputQual::OutStream3:
  213. streamIdx = 3;
  214. break;
  215. default:
  216. // Use streamIdx = 0 by default.
  217. break;
  218. }
  219. const SigPoint *sigPoint = SigPoint::GetSigPoint(
  220. SigPointFromInputQual(qual, props.shaderKind, isPatchConstantFunction));
  221. unsigned rows, cols;
  222. HLModule::GetParameterRowsAndCols(Ty, rows, cols, paramAnnotation);
  223. CompType EltTy = paramAnnotation.GetCompType();
  224. DXIL::InterpolationMode interpMode =
  225. paramAnnotation.GetInterpolationMode().GetKind();
  226. // Set undefined interpMode.
  227. if (sigPoint->GetKind() == DXIL::SigPointKind::MSPOut) {
  228. if (interpMode != InterpolationMode::Kind::Undefined &&
  229. interpMode != InterpolationMode::Kind::Constant) {
  230. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), func,
  231. "Mesh shader's primitive outputs' interpolation mode must be constant or undefined.");
  232. }
  233. interpMode = InterpolationMode::Kind::Constant;
  234. }
  235. else if (!sigPoint->NeedsInterpMode())
  236. interpMode = InterpolationMode::Kind::Undefined;
  237. else if (interpMode == InterpolationMode::Kind::Undefined) {
  238. // Type-based default: linear for floats, constant for others.
  239. if (EltTy.IsFloatTy())
  240. interpMode = InterpolationMode::Kind::Linear;
  241. else
  242. interpMode = InterpolationMode::Kind::Constant;
  243. }
  244. // back-compat mode - remap obsolete semantics
  245. if (HLM.GetHLOptions().bDX9CompatMode && paramAnnotation.HasSemanticString()) {
  246. hlsl::RemapObsoleteSemantic(paramAnnotation, sigPoint->GetKind(), HLM.GetCtx());
  247. }
  248. llvm::StringRef semanticStr = paramAnnotation.GetSemanticString();
  249. if (semanticStr.empty()) {
  250. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), func,
  251. "Semantic must be defined for all parameters of an entry function or "
  252. "patch constant function");
  253. return;
  254. }
  255. UpdateSemanticAndInterpMode(semanticStr, interpMode, sigPoint->GetKind(),
  256. arg.getContext());
  257. // Get Semantic interpretation, skipping if not in signature
  258. const Semantic *pSemantic = Semantic::GetByName(semanticStr);
  259. DXIL::SemanticInterpretationKind interpretation =
  260. SigPoint::GetInterpretation(pSemantic->GetKind(), sigPoint->GetKind(),
  261. pSM->GetMajor(), pSM->GetMinor());
  262. // Verify system value semantics do not overlap.
  263. // Note: Arbitrary are always in the signature and will be verified with a
  264. // different mechanism. For patch constant function, only validate patch
  265. // constant elements (others already validated on hull function)
  266. if (pSemantic->GetKind() != DXIL::SemanticKind::Arbitrary &&
  267. (!isPatchConstantFunction ||
  268. (!sigPoint->IsInput() && !sigPoint->IsOutput()))) {
  269. auto &SemanticUseMap =
  270. sigPoint->IsInput()
  271. ? m_InputSemanticsUsed
  272. : (sigPoint->IsOutput()
  273. ? m_OutputSemanticsUsed[streamIdx]
  274. : (sigPoint->IsPatchConstOrPrim() ? m_PatchConstantSemanticsUsed
  275. : m_OtherSemanticsUsed));
  276. if (SemanticUseMap.count((unsigned)pSemantic->GetKind()) > 0) {
  277. auto &SemanticIndexSet = SemanticUseMap[(unsigned)pSemantic->GetKind()];
  278. for (unsigned idx : paramAnnotation.GetSemanticIndexVec()) {
  279. if (SemanticIndexSet.count(idx) > 0) {
  280. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), func, "Parameter with semantic " + semanticStr +
  281. " has overlapping semantic index at " + std::to_string(idx) + ".");
  282. return;
  283. }
  284. }
  285. }
  286. auto &SemanticIndexSet = SemanticUseMap[(unsigned)pSemantic->GetKind()];
  287. for (unsigned idx : paramAnnotation.GetSemanticIndexVec()) {
  288. SemanticIndexSet.emplace(idx);
  289. }
  290. // Enforce Coverage and InnerCoverage input mutual exclusivity
  291. if (sigPoint->IsInput()) {
  292. if ((pSemantic->GetKind() == DXIL::SemanticKind::Coverage &&
  293. SemanticUseMap.count((unsigned)DXIL::SemanticKind::InnerCoverage) >
  294. 0) ||
  295. (pSemantic->GetKind() == DXIL::SemanticKind::InnerCoverage &&
  296. SemanticUseMap.count((unsigned)DXIL::SemanticKind::Coverage) > 0)) {
  297. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), func,
  298. "Pixel shader inputs SV_Coverage and SV_InnerCoverage are mutually "
  299. "exclusive.");
  300. return;
  301. }
  302. }
  303. }
  304. // Validate interpretation and replace argument usage with load/store
  305. // intrinsics
  306. {
  307. switch (interpretation) {
  308. case DXIL::SemanticInterpretationKind::NA: {
  309. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), func, Twine("Semantic ") + semanticStr +
  310. Twine(" is invalid for shader model: ") +
  311. ShaderModel::GetKindName(props.shaderKind));
  312. return;
  313. }
  314. case DXIL::SemanticInterpretationKind::NotInSig:
  315. case DXIL::SemanticInterpretationKind::Shadow: {
  316. IRBuilder<> funcBuilder(func->getEntryBlock().getFirstInsertionPt());
  317. if (DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(&arg)) {
  318. funcBuilder.SetCurrentDebugLocation(DDI->getDebugLoc());
  319. }
  320. replaceInputOutputWithIntrinsic(pSemantic->GetKind(), &arg, HLM.GetOP(),
  321. funcBuilder);
  322. if (interpretation == DXIL::SemanticInterpretationKind::NotInSig)
  323. return; // This argument should not be included in the signature
  324. break;
  325. }
  326. case DXIL::SemanticInterpretationKind::SV:
  327. case DXIL::SemanticInterpretationKind::SGV:
  328. case DXIL::SemanticInterpretationKind::Arb:
  329. case DXIL::SemanticInterpretationKind::Target:
  330. case DXIL::SemanticInterpretationKind::TessFactor:
  331. case DXIL::SemanticInterpretationKind::NotPacked:
  332. case DXIL::SemanticInterpretationKind::ClipCull:
  333. // Will be replaced with load/store intrinsics in
  334. // GenerateDxilInputsOutputs
  335. break;
  336. default:
  337. DXASSERT(false, "Unexpected SemanticInterpretationKind");
  338. return;
  339. }
  340. }
  341. // Determine signature this argument belongs in, if any
  342. DxilSignature *pSig = nullptr;
  343. DXIL::SignatureKind sigKind = sigPoint->GetSignatureKindWithFallback();
  344. switch (sigKind) {
  345. case DXIL::SignatureKind::Input:
  346. pSig = &EntrySig.InputSignature;
  347. break;
  348. case DXIL::SignatureKind::Output:
  349. pSig = &EntrySig.OutputSignature;
  350. break;
  351. case DXIL::SignatureKind::PatchConstOrPrim:
  352. pSig = &EntrySig.PatchConstOrPrimSignature;
  353. break;
  354. default:
  355. DXASSERT(false, "Expected real signature kind at this point");
  356. return; // No corresponding signature
  357. }
  358. // Create and add element to signature
  359. DxilSignatureElement *pSE = nullptr;
  360. {
  361. // Add signature element to appropriate maps
  362. if (isPatchConstantFunction &&
  363. sigKind != DXIL::SignatureKind::PatchConstOrPrim) {
  364. pSE = FindArgInSignature(arg, paramAnnotation.GetSemanticString(),
  365. interpMode, sigPoint->GetKind(), *pSig);
  366. if (!pSE) {
  367. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), func, Twine("Signature element ") + semanticStr +
  368. Twine(", referred to by patch constant function, is not found in "
  369. "corresponding hull shader ") +
  370. (sigKind == DXIL::SignatureKind::Input ? "input." : "output."));
  371. return;
  372. }
  373. m_patchConstantInputsSigMap[arg.getArgNo()] = pSE;
  374. } else {
  375. std::unique_ptr<DxilSignatureElement> SE = pSig->CreateElement();
  376. pSE = SE.get();
  377. pSig->AppendElement(std::move(SE));
  378. pSE->SetSigPointKind(sigPoint->GetKind());
  379. pSE->Initialize(semanticStr, EltTy, interpMode, rows, cols,
  380. Semantic::kUndefinedRow, Semantic::kUndefinedCol,
  381. pSE->GetID(), paramAnnotation.GetSemanticIndexVec());
  382. m_sigValueMap[pSE] = &arg;
  383. }
  384. }
  385. if (paramAnnotation.IsPrecise())
  386. m_preciseSigSet.insert(pSE);
  387. if (sigKind == DXIL::SignatureKind::Output &&
  388. pSemantic->GetKind() == Semantic::Kind::Position && hasClipPlane) {
  389. GenerateClipPlanesForVS(&arg);
  390. hasClipPlane = false;
  391. }
  392. // Set Output Stream.
  393. if (streamIdx > 0)
  394. pSE->SetOutputStream(streamIdx);
  395. }
  396. void HLSignatureLower::CreateDxilSignatures() {
  397. DxilFunctionProps &props = HLM.GetDxilFunctionProps(Entry);
  398. const ShaderModel *pSM = HLM.GetShaderModel();
  399. DXASSERT(Entry->getReturnType()->isVoidTy(),
  400. "Should changed in SROA_Parameter_HLSL");
  401. DxilFunctionAnnotation *EntryAnnotation = HLM.GetFunctionAnnotation(Entry);
  402. DXASSERT(EntryAnnotation, "must have function annotation for entry function");
  403. bool bHasClipPlane =
  404. props.shaderKind == DXIL::ShaderKind::Vertex ? HasClipPlanes() : false;
  405. const bool isPatchConstantFunctionFalse = false;
  406. const bool bForOutFasle = false;
  407. for (Argument &arg : Entry->getArgumentList()) {
  408. Type *Ty = arg.getType();
  409. // Skip streamout obj.
  410. if (HLModule::IsStreamOutputPtrType(Ty))
  411. continue;
  412. // Skip OutIndices and InPayload
  413. DxilParameterAnnotation &paramAnnotation =
  414. EntryAnnotation->GetParameterAnnotation(arg.getArgNo());
  415. hlsl::DxilParamInputQual qual = paramAnnotation.GetParamInputQual();
  416. if (qual == hlsl::DxilParamInputQual::OutIndices ||
  417. qual == hlsl::DxilParamInputQual::InPayload)
  418. continue;
  419. ProcessArgument(Entry, EntryAnnotation, arg, props, pSM,
  420. isPatchConstantFunctionFalse, bForOutFasle, bHasClipPlane);
  421. }
  422. if (bHasClipPlane) {
  423. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry, "Cannot use clipplanes attribute without "
  424. "specifying a 4-component SV_Position "
  425. "output");
  426. }
  427. m_OtherSemanticsUsed.clear();
  428. if (props.shaderKind == DXIL::ShaderKind::Hull) {
  429. Function *patchConstantFunc = props.ShaderProps.HS.patchConstantFunc;
  430. if (patchConstantFunc == nullptr) {
  431. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry,
  432. "Patch constant function is not specified.");
  433. }
  434. DxilFunctionAnnotation *patchFuncAnnotation =
  435. HLM.GetFunctionAnnotation(patchConstantFunc);
  436. DXASSERT(patchFuncAnnotation,
  437. "must have function annotation for patch constant function");
  438. const bool isPatchConstantFunctionTrue = true;
  439. for (Argument &arg : patchConstantFunc->getArgumentList()) {
  440. ProcessArgument(patchConstantFunc, patchFuncAnnotation, arg, props, pSM,
  441. isPatchConstantFunctionTrue, bForOutFasle, bHasClipPlane);
  442. }
  443. }
  444. }
  445. // Allocate input/output slots
  446. void HLSignatureLower::AllocateDxilInputOutputs() {
  447. DxilFunctionProps &props = HLM.GetDxilFunctionProps(Entry);
  448. const ShaderModel *pSM = HLM.GetShaderModel();
  449. const HLOptions &opts = HLM.GetHLOptions();
  450. DXASSERT_NOMSG(opts.PackingStrategy <
  451. (unsigned)DXIL::PackingStrategy::Invalid);
  452. DXIL::PackingStrategy packing = (DXIL::PackingStrategy)opts.PackingStrategy;
  453. if (packing == DXIL::PackingStrategy::Default)
  454. packing = pSM->GetDefaultPackingStrategy();
  455. hlsl::PackDxilSignature(EntrySig.InputSignature, packing);
  456. if (!EntrySig.InputSignature.IsFullyAllocated()) {
  457. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry,
  458. "Failed to allocate all input signature elements in available space.");
  459. }
  460. if (props.shaderKind != DXIL::ShaderKind::Amplification) {
  461. hlsl::PackDxilSignature(EntrySig.OutputSignature, packing);
  462. if (!EntrySig.OutputSignature.IsFullyAllocated()) {
  463. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry,
  464. "Failed to allocate all output signature elements in available space.");
  465. }
  466. }
  467. if (props.shaderKind == DXIL::ShaderKind::Hull ||
  468. props.shaderKind == DXIL::ShaderKind::Domain ||
  469. props.shaderKind == DXIL::ShaderKind::Mesh) {
  470. hlsl::PackDxilSignature(EntrySig.PatchConstOrPrimSignature, packing);
  471. if (!EntrySig.PatchConstOrPrimSignature.IsFullyAllocated()) {
  472. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry,
  473. "Failed to allocate all patch constant signature "
  474. "elements in available space.");
  475. }
  476. }
  477. }
  478. namespace {
  479. // Helper functions and class for lower signature.
  480. void GenerateStOutput(Function *stOutput, MutableArrayRef<Value *> args,
  481. IRBuilder<> &Builder, bool cast) {
  482. if (cast) {
  483. Value *value = args[DXIL::OperandIndex::kStoreOutputValOpIdx];
  484. args[DXIL::OperandIndex::kStoreOutputValOpIdx] =
  485. Builder.CreateZExt(value, Builder.getInt32Ty());
  486. }
  487. Builder.CreateCall(stOutput, args);
  488. }
  489. void replaceStWithStOutput(Function *stOutput, StoreInst *stInst,
  490. Constant *OpArg, Constant *outputID, Value *idx,
  491. unsigned cols, Value *vertexOrPrimID, bool bI1Cast) {
  492. IRBuilder<> Builder(stInst);
  493. Value *val = stInst->getValueOperand();
  494. if (VectorType *VT = dyn_cast<VectorType>(val->getType())) {
  495. DXASSERT_LOCALVAR(VT, cols == VT->getNumElements(), "vec size must match");
  496. for (unsigned col = 0; col < cols; col++) {
  497. Value *subVal = Builder.CreateExtractElement(val, col);
  498. Value *colIdx = Builder.getInt8(col);
  499. SmallVector<Value *, 4> args = {OpArg, outputID, idx, colIdx, subVal};
  500. if (vertexOrPrimID)
  501. args.emplace_back(vertexOrPrimID);
  502. GenerateStOutput(stOutput, args, Builder, bI1Cast);
  503. }
  504. // remove stInst
  505. stInst->eraseFromParent();
  506. } else if (!val->getType()->isArrayTy()) {
  507. // TODO: support case cols not 1
  508. DXASSERT(cols == 1, "only support scalar here");
  509. Value *colIdx = Builder.getInt8(0);
  510. SmallVector<Value *, 4> args = {OpArg, outputID, idx, colIdx, val};
  511. if (vertexOrPrimID)
  512. args.emplace_back(vertexOrPrimID);
  513. GenerateStOutput(stOutput, args, Builder, bI1Cast);
  514. // remove stInst
  515. stInst->eraseFromParent();
  516. } else {
  517. DXASSERT(0, "not support array yet");
  518. // TODO: support array.
  519. Value *colIdx = Builder.getInt8(0);
  520. ArrayType *AT = cast<ArrayType>(val->getType());
  521. Value *args[] = {OpArg, outputID, idx, colIdx, /*val*/ nullptr};
  522. (void)args;
  523. (void)AT;
  524. }
  525. }
  526. Value *GenerateLdInput(Function *loadInput, ArrayRef<Value *> args,
  527. IRBuilder<> &Builder, Value *zero, bool bCast,
  528. Type *Ty) {
  529. Value *input = Builder.CreateCall(loadInput, args);
  530. if (!bCast)
  531. return input;
  532. else {
  533. Value *bVal = Builder.CreateICmpNE(input, zero);
  534. IntegerType *IT = cast<IntegerType>(Ty);
  535. if (IT->getBitWidth() == 1)
  536. return bVal;
  537. else
  538. return Builder.CreateZExt(bVal, Ty);
  539. }
  540. }
  541. Value *replaceLdWithLdInput(Function *loadInput, LoadInst *ldInst,
  542. unsigned cols, MutableArrayRef<Value *> args,
  543. bool bCast) {
  544. IRBuilder<> Builder(ldInst);
  545. IRBuilder<> AllocaBuilder(dxilutil::FindAllocaInsertionPt(ldInst));
  546. Type *Ty = ldInst->getType();
  547. Type *EltTy = Ty->getScalarType();
  548. // Change i1 to i32 for load input.
  549. Value *zero = Builder.getInt32(0);
  550. if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
  551. Value *newVec = llvm::UndefValue::get(VT);
  552. DXASSERT(cols == VT->getNumElements(), "vec size must match");
  553. for (unsigned col = 0; col < cols; col++) {
  554. Value *colIdx = Builder.getInt8(col);
  555. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  556. Value *input =
  557. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  558. newVec = Builder.CreateInsertElement(newVec, input, col);
  559. }
  560. ldInst->replaceAllUsesWith(newVec);
  561. ldInst->eraseFromParent();
  562. return newVec;
  563. } else {
  564. Value *colIdx = args[DXIL::OperandIndex::kLoadInputColOpIdx];
  565. if (colIdx == nullptr) {
  566. DXASSERT(cols == 1, "only support scalar here");
  567. colIdx = Builder.getInt8(0);
  568. } else {
  569. if (colIdx->getType() == Builder.getInt32Ty()) {
  570. colIdx = Builder.CreateTrunc(colIdx, Builder.getInt8Ty());
  571. }
  572. }
  573. if (isa<ConstantInt>(colIdx)) {
  574. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  575. Value *input =
  576. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  577. ldInst->replaceAllUsesWith(input);
  578. ldInst->eraseFromParent();
  579. return input;
  580. } else {
  581. // Vector indexing.
  582. // Load to array.
  583. ArrayType *AT = ArrayType::get(ldInst->getType(), cols);
  584. Value *arrayVec = AllocaBuilder.CreateAlloca(AT);
  585. Value *zeroIdx = Builder.getInt32(0);
  586. for (unsigned col = 0; col < cols; col++) {
  587. Value *colIdx = Builder.getInt8(col);
  588. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  589. Value *input =
  590. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  591. Value *GEP = Builder.CreateInBoundsGEP(arrayVec, {zeroIdx, colIdx});
  592. Builder.CreateStore(input, GEP);
  593. }
  594. Value *vecIndexingPtr =
  595. Builder.CreateInBoundsGEP(arrayVec, {zeroIdx, colIdx});
  596. Value *input = Builder.CreateLoad(vecIndexingPtr);
  597. ldInst->replaceAllUsesWith(input);
  598. ldInst->eraseFromParent();
  599. return input;
  600. }
  601. }
  602. }
  603. void replaceMatStWithStOutputs(CallInst *CI, HLMatLoadStoreOpcode matOp,
  604. Function *ldStFunc, Constant *OpArg, Constant *ID,
  605. Constant *columnConsts[],Value *vertexOrPrimID,
  606. Value *idxVal) {
  607. IRBuilder<> LocalBuilder(CI);
  608. Value *Val = CI->getArgOperand(HLOperandIndex::kMatStoreValOpIdx);
  609. HLMatrixType MatTy = HLMatrixType::cast(
  610. CI->getArgOperand(HLOperandIndex::kMatStoreDstPtrOpIdx)
  611. ->getType()->getPointerElementType());
  612. Val = MatTy.emitLoweredRegToMem(Val, LocalBuilder);
  613. if (matOp == HLMatLoadStoreOpcode::ColMatStore) {
  614. for (unsigned c = 0; c < MatTy.getNumColumns(); c++) {
  615. Constant *constColIdx = LocalBuilder.getInt32(c);
  616. Value *colIdx = LocalBuilder.CreateAdd(idxVal, constColIdx);
  617. for (unsigned r = 0; r < MatTy.getNumRows(); r++) {
  618. unsigned matIdx = MatTy.getColumnMajorIndex(r, c);
  619. Value *Elt = LocalBuilder.CreateExtractElement(Val, matIdx);
  620. SmallVector<Value*, 6> argList = {OpArg, ID, colIdx, columnConsts[r], Elt};
  621. if (vertexOrPrimID)
  622. argList.emplace_back(vertexOrPrimID);
  623. LocalBuilder.CreateCall(ldStFunc, argList);
  624. }
  625. }
  626. } else {
  627. for (unsigned r = 0; r < MatTy.getNumRows(); r++) {
  628. Constant *constRowIdx = LocalBuilder.getInt32(r);
  629. Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
  630. for (unsigned c = 0; c < MatTy.getNumColumns(); c++) {
  631. unsigned matIdx = MatTy.getRowMajorIndex(r, c);
  632. Value *Elt = LocalBuilder.CreateExtractElement(Val, matIdx);
  633. SmallVector<Value*, 6> argList = {OpArg, ID, rowIdx, columnConsts[c], Elt};
  634. if (vertexOrPrimID)
  635. argList.emplace_back(vertexOrPrimID);
  636. LocalBuilder.CreateCall(ldStFunc, argList);
  637. }
  638. }
  639. }
  640. CI->eraseFromParent();
  641. }
  642. void replaceMatLdWithLdInputs(CallInst *CI, HLMatLoadStoreOpcode matOp,
  643. Function *ldStFunc, Constant *OpArg, Constant *ID,
  644. Constant *columnConsts[],Value *vertexOrPrimID,
  645. Value *idxVal) {
  646. IRBuilder<> LocalBuilder(CI);
  647. HLMatrixType MatTy = HLMatrixType::cast(
  648. CI->getArgOperand(HLOperandIndex::kMatLoadPtrOpIdx)
  649. ->getType()->getPointerElementType());
  650. std::vector<Value *> matElts(MatTy.getNumElements());
  651. if (matOp == HLMatLoadStoreOpcode::ColMatLoad) {
  652. for (unsigned c = 0; c < MatTy.getNumColumns(); c++) {
  653. Constant *constRowIdx = LocalBuilder.getInt32(c);
  654. Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
  655. for (unsigned r = 0; r < MatTy.getNumRows(); r++) {
  656. SmallVector<Value *, 4> args = { OpArg, ID, rowIdx, columnConsts[r] };
  657. if (vertexOrPrimID)
  658. args.emplace_back(vertexOrPrimID);
  659. Value *input = LocalBuilder.CreateCall(ldStFunc, args);
  660. unsigned matIdx = MatTy.getColumnMajorIndex(r, c);
  661. matElts[matIdx] = input;
  662. }
  663. }
  664. } else {
  665. for (unsigned r = 0; r < MatTy.getNumRows(); r++) {
  666. Constant *constRowIdx = LocalBuilder.getInt32(r);
  667. Value *rowIdx = LocalBuilder.CreateAdd(idxVal, constRowIdx);
  668. for (unsigned c = 0; c < MatTy.getNumColumns(); c++) {
  669. SmallVector<Value *, 4> args = { OpArg, ID, rowIdx, columnConsts[c] };
  670. if (vertexOrPrimID)
  671. args.emplace_back(vertexOrPrimID);
  672. Value *input = LocalBuilder.CreateCall(ldStFunc, args);
  673. unsigned matIdx = MatTy.getRowMajorIndex(r, c);
  674. matElts[matIdx] = input;
  675. }
  676. }
  677. }
  678. Value *newVec =
  679. HLMatrixLower::BuildVector(matElts[0]->getType(), matElts, LocalBuilder);
  680. newVec = MatTy.emitLoweredMemToReg(newVec, LocalBuilder);
  681. CI->replaceAllUsesWith(newVec);
  682. CI->eraseFromParent();
  683. }
  684. void replaceDirectInputParameter(Value *param, Function *loadInput,
  685. unsigned cols, MutableArrayRef<Value *> args,
  686. bool bCast, OP *hlslOP, IRBuilder<> &Builder) {
  687. Value *zero = hlslOP->GetU32Const(0);
  688. Type *Ty = param->getType();
  689. Type *EltTy = Ty->getScalarType();
  690. if (VectorType *VT = dyn_cast<VectorType>(Ty)) {
  691. Value *newVec = llvm::UndefValue::get(VT);
  692. DXASSERT(cols == VT->getNumElements(), "vec size must match");
  693. for (unsigned col = 0; col < cols; col++) {
  694. Value *colIdx = hlslOP->GetU8Const(col);
  695. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  696. Value *input =
  697. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  698. newVec = Builder.CreateInsertElement(newVec, input, col);
  699. }
  700. param->replaceAllUsesWith(newVec);
  701. // THe individual loadInputs are the authoritative source of values for the vector.
  702. dxilutil::TryScatterDebugValueToVectorElements(newVec);
  703. } else if (!Ty->isArrayTy() && !HLMatrixType::isa(Ty)) {
  704. DXASSERT(cols == 1, "only support scalar here");
  705. Value *colIdx = hlslOP->GetU8Const(0);
  706. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  707. Value *input =
  708. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  709. param->replaceAllUsesWith(input); // Will properly relocate any DbgValueInst
  710. } else if (HLMatrixType::isa(Ty)) {
  711. if (param->use_empty()) return;
  712. DXASSERT(param->hasOneUse(),
  713. "matrix arg should only has one use as matrix to vec");
  714. CallInst *CI = cast<CallInst>(param->user_back());
  715. HLOpcodeGroup group = GetHLOpcodeGroupByName(CI->getCalledFunction());
  716. DXASSERT_LOCALVAR(group, group == HLOpcodeGroup::HLCast,
  717. "must be hlcast here");
  718. unsigned opcode = GetHLOpcode(CI);
  719. HLCastOpcode matOp = static_cast<HLCastOpcode>(opcode);
  720. switch (matOp) {
  721. case HLCastOpcode::ColMatrixToVecCast: {
  722. IRBuilder<> LocalBuilder(CI);
  723. HLMatrixType MatTy = HLMatrixType::cast(
  724. CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx)->getType());
  725. Type *EltTy = MatTy.getElementTypeForReg();
  726. std::vector<Value *> matElts(MatTy.getNumElements());
  727. for (unsigned c = 0; c < MatTy.getNumColumns(); c++) {
  728. Value *rowIdx = hlslOP->GetI32Const(c);
  729. args[DXIL::OperandIndex::kLoadInputRowOpIdx] = rowIdx;
  730. for (unsigned r = 0; r < MatTy.getNumRows(); r++) {
  731. Value *colIdx = hlslOP->GetU8Const(r);
  732. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  733. Value *input =
  734. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  735. matElts[MatTy.getColumnMajorIndex(r, c)] = input;
  736. }
  737. }
  738. Value *newVec =
  739. HLMatrixLower::BuildVector(EltTy, matElts, LocalBuilder);
  740. CI->replaceAllUsesWith(newVec);
  741. CI->eraseFromParent();
  742. } break;
  743. case HLCastOpcode::RowMatrixToVecCast: {
  744. IRBuilder<> LocalBuilder(CI);
  745. HLMatrixType MatTy = HLMatrixType::cast(
  746. CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx)->getType());
  747. Type *EltTy = MatTy.getElementTypeForReg();
  748. std::vector<Value *> matElts(MatTy.getNumElements());
  749. for (unsigned r = 0; r < MatTy.getNumRows(); r++) {
  750. Value *rowIdx = hlslOP->GetI32Const(r);
  751. args[DXIL::OperandIndex::kLoadInputRowOpIdx] = rowIdx;
  752. for (unsigned c = 0; c < MatTy.getNumColumns(); c++) {
  753. Value *colIdx = hlslOP->GetU8Const(c);
  754. args[DXIL::OperandIndex::kLoadInputColOpIdx] = colIdx;
  755. Value *input =
  756. GenerateLdInput(loadInput, args, Builder, zero, bCast, EltTy);
  757. matElts[MatTy.getRowMajorIndex(r, c)] = input;
  758. }
  759. }
  760. Value *newVec =
  761. HLMatrixLower::BuildVector(EltTy, matElts, LocalBuilder);
  762. CI->replaceAllUsesWith(newVec);
  763. CI->eraseFromParent();
  764. } break;
  765. default:
  766. // Only matrix to vector casts are valid.
  767. break;
  768. }
  769. } else {
  770. DXASSERT(0, "invalid type for direct input");
  771. }
  772. }
  773. struct InputOutputAccessInfo {
  774. // For input output which has only 1 row, idx is 0.
  775. Value *idx;
  776. // VertexID for HS/DS/GS input, MS vertex output. PrimitiveID for MS primitive output
  777. Value *vertexOrPrimID;
  778. // Vector index.
  779. Value *vectorIdx;
  780. // Load/Store/LoadMat/StoreMat on input/output.
  781. Instruction *user;
  782. InputOutputAccessInfo(Value *index, Instruction *I)
  783. : idx(index), vertexOrPrimID(nullptr), vectorIdx(nullptr), user(I) {}
  784. InputOutputAccessInfo(Value *index, Instruction *I, Value *ID, Value *vecIdx)
  785. : idx(index), vertexOrPrimID(ID), vectorIdx(vecIdx), user(I) {}
  786. };
  787. void collectInputOutputAccessInfo(
  788. Value *GV, Constant *constZero,
  789. std::vector<InputOutputAccessInfo> &accessInfoList, bool hasVertexOrPrimID,
  790. bool bInput, bool bRowMajor, bool isMS) {
  791. // merge GEP use for input output.
  792. HLModule::MergeGepUse(GV);
  793. for (auto User = GV->user_begin(); User != GV->user_end();) {
  794. Value *I = *(User++);
  795. if (LoadInst *ldInst = dyn_cast<LoadInst>(I)) {
  796. if (bInput) {
  797. InputOutputAccessInfo info = {constZero, ldInst};
  798. accessInfoList.push_back(info);
  799. }
  800. } else if (StoreInst *stInst = dyn_cast<StoreInst>(I)) {
  801. if (!bInput) {
  802. InputOutputAccessInfo info = {constZero, stInst};
  803. accessInfoList.push_back(info);
  804. }
  805. } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I)) {
  806. // Vector indexing may has more indices.
  807. // Vector indexing changed to array indexing in SROA_HLSL.
  808. auto idx = GEP->idx_begin();
  809. DXASSERT_LOCALVAR(idx, idx->get() == constZero,
  810. "only support 0 offset for input pointer");
  811. Value *vertexOrPrimID = nullptr;
  812. Value *vectorIdx = nullptr;
  813. gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
  814. // Skip first pointer idx which must be 0.
  815. GEPIt++;
  816. if (hasVertexOrPrimID) {
  817. // Save vertexOrPrimID.
  818. vertexOrPrimID = GEPIt.getOperand();
  819. GEPIt++;
  820. }
  821. // Start from first index.
  822. Value *rowIdx = GEPIt.getOperand();
  823. if (GEPIt != E) {
  824. if ((*GEPIt)->isVectorTy()) {
  825. // Vector indexing.
  826. rowIdx = constZero;
  827. vectorIdx = GEPIt.getOperand();
  828. DXASSERT_NOMSG((++GEPIt) == E);
  829. } else {
  830. // Array which may have vector indexing.
  831. // Highest dim index is saved in rowIdx,
  832. // array size for highest dim not affect index.
  833. GEPIt++;
  834. IRBuilder<> Builder(GEP);
  835. Type *idxTy = rowIdx->getType();
  836. for (; GEPIt != E; ++GEPIt) {
  837. DXASSERT(!GEPIt->isStructTy(),
  838. "Struct should be flattened SROA_Parameter_HLSL");
  839. DXASSERT(!GEPIt->isPointerTy(),
  840. "not support pointer type in middle of GEP");
  841. if (GEPIt->isArrayTy()) {
  842. Constant *arraySize =
  843. ConstantInt::get(idxTy, GEPIt->getArrayNumElements());
  844. rowIdx = Builder.CreateMul(rowIdx, arraySize);
  845. rowIdx = Builder.CreateAdd(rowIdx, GEPIt.getOperand());
  846. } else {
  847. Type *Ty = *GEPIt;
  848. DXASSERT_LOCALVAR(Ty, Ty->isVectorTy(),
  849. "must be vector type here to index");
  850. // Save vector idx.
  851. vectorIdx = GEPIt.getOperand();
  852. }
  853. }
  854. if (HLMatrixType MatTy = HLMatrixType::dyn_cast(*GEPIt)) {
  855. Constant *arraySize = ConstantInt::get(idxTy, MatTy.getNumColumns());
  856. if (bRowMajor) {
  857. arraySize = ConstantInt::get(idxTy, MatTy.getNumRows());
  858. }
  859. rowIdx = Builder.CreateMul(rowIdx, arraySize);
  860. }
  861. }
  862. } else
  863. rowIdx = constZero;
  864. auto GepUser = GEP->user_begin();
  865. auto GepUserE = GEP->user_end();
  866. Value *idxVal = rowIdx;
  867. for (; GepUser != GepUserE;) {
  868. auto GepUserIt = GepUser++;
  869. if (LoadInst *ldInst = dyn_cast<LoadInst>(*GepUserIt)) {
  870. if (bInput) {
  871. InputOutputAccessInfo info = {idxVal, ldInst, vertexOrPrimID, vectorIdx};
  872. accessInfoList.push_back(info);
  873. }
  874. } else if (StoreInst *stInst = dyn_cast<StoreInst>(*GepUserIt)) {
  875. if (!bInput) {
  876. InputOutputAccessInfo info = {idxVal, stInst, vertexOrPrimID, vectorIdx};
  877. accessInfoList.push_back(info);
  878. }
  879. } else if (CallInst *CI = dyn_cast<CallInst>(*GepUserIt)) {
  880. HLOpcodeGroup group = GetHLOpcodeGroupByName(CI->getCalledFunction());
  881. DXASSERT_LOCALVAR(group, group == HLOpcodeGroup::HLMatLoadStore,
  882. "input/output should only used by ld/st");
  883. HLMatLoadStoreOpcode opcode = (HLMatLoadStoreOpcode)GetHLOpcode(CI);
  884. if ((opcode == HLMatLoadStoreOpcode::ColMatLoad ||
  885. opcode == HLMatLoadStoreOpcode::RowMatLoad)
  886. ? bInput
  887. : !bInput) {
  888. InputOutputAccessInfo info = {idxVal, CI, vertexOrPrimID, vectorIdx};
  889. accessInfoList.push_back(info);
  890. }
  891. } else {
  892. DXASSERT(0, "input output should only used by ld/st");
  893. }
  894. }
  895. } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
  896. InputOutputAccessInfo info = {constZero, CI};
  897. accessInfoList.push_back(info);
  898. } else {
  899. DXASSERT(0, "input output should only used by ld/st");
  900. }
  901. }
  902. }
  903. void GenerateInputOutputUserCall(InputOutputAccessInfo &info, Value *undefVertexIdx,
  904. Function *ldStFunc, Constant *OpArg, Constant *ID, unsigned cols, bool bI1Cast,
  905. Constant *columnConsts[],
  906. bool bNeedVertexOrPrimID, bool isArrayTy, bool bInput, bool bIsInout) {
  907. Value *idxVal = info.idx;
  908. Value *vertexOrPrimID = undefVertexIdx;
  909. if (bNeedVertexOrPrimID && isArrayTy) {
  910. vertexOrPrimID = info.vertexOrPrimID;
  911. }
  912. if (LoadInst *ldInst = dyn_cast<LoadInst>(info.user)) {
  913. SmallVector<Value *, 4> args = {OpArg, ID, idxVal, info.vectorIdx};
  914. if (vertexOrPrimID)
  915. args.emplace_back(vertexOrPrimID);
  916. replaceLdWithLdInput(ldStFunc, ldInst, cols, args, bI1Cast);
  917. } else if (StoreInst *stInst = dyn_cast<StoreInst>(info.user)) {
  918. if (bInput) {
  919. DXASSERT_LOCALVAR(bIsInout, bIsInout, "input should not have store use.");
  920. } else {
  921. if (!info.vectorIdx) {
  922. replaceStWithStOutput(ldStFunc, stInst, OpArg, ID, idxVal, cols,
  923. vertexOrPrimID, bI1Cast);
  924. } else {
  925. Value *V = stInst->getValueOperand();
  926. Type *Ty = V->getType();
  927. DXASSERT_LOCALVAR(Ty == Ty->getScalarType() && !Ty->isAggregateType(),
  928. Ty, "only support scalar here");
  929. if (ConstantInt *ColIdx = dyn_cast<ConstantInt>(info.vectorIdx)) {
  930. IRBuilder<> Builder(stInst);
  931. if (ColIdx->getType()->getBitWidth() != 8) {
  932. ColIdx = Builder.getInt8(ColIdx->getValue().getLimitedValue());
  933. }
  934. SmallVector<Value *, 6> args = {OpArg, ID, idxVal, ColIdx, V};
  935. if (vertexOrPrimID)
  936. args.emplace_back(vertexOrPrimID);
  937. GenerateStOutput(ldStFunc, args, Builder, bI1Cast);
  938. } else {
  939. BasicBlock *BB = stInst->getParent();
  940. BasicBlock *EndBB = BB->splitBasicBlock(stInst);
  941. TerminatorInst *TI = BB->getTerminator();
  942. IRBuilder<> SwitchBuilder(TI);
  943. LLVMContext &Ctx = stInst->getContext();
  944. SwitchInst *Switch =
  945. SwitchBuilder.CreateSwitch(info.vectorIdx, EndBB, cols);
  946. TI->eraseFromParent();
  947. Function *F = EndBB->getParent();
  948. for (unsigned i = 0; i < cols; i++) {
  949. BasicBlock *CaseBB = BasicBlock::Create(Ctx, "case", F, EndBB);
  950. Switch->addCase(SwitchBuilder.getInt32(i), CaseBB);
  951. IRBuilder<> CaseBuilder(CaseBB);
  952. ConstantInt *CaseIdx = SwitchBuilder.getInt8(i);
  953. SmallVector<Value *, 6> args = {OpArg, ID, idxVal, CaseIdx, V};
  954. if (vertexOrPrimID)
  955. args.emplace_back(vertexOrPrimID);
  956. GenerateStOutput(ldStFunc, args, CaseBuilder, bI1Cast);
  957. CaseBuilder.CreateBr(EndBB);
  958. }
  959. }
  960. // remove stInst
  961. stInst->eraseFromParent();
  962. }
  963. }
  964. } else if (CallInst *CI = dyn_cast<CallInst>(info.user)) {
  965. HLOpcodeGroup group = GetHLOpcodeGroupByName(CI->getCalledFunction());
  966. // Intrinsic will be translated later.
  967. if (group == HLOpcodeGroup::HLIntrinsic || group == HLOpcodeGroup::NotHL)
  968. return;
  969. unsigned opcode = GetHLOpcode(CI);
  970. DXASSERT_NOMSG(group == HLOpcodeGroup::HLMatLoadStore);
  971. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  972. switch (matOp) {
  973. case HLMatLoadStoreOpcode::ColMatLoad:
  974. case HLMatLoadStoreOpcode::RowMatLoad: {
  975. replaceMatLdWithLdInputs(CI, matOp, ldStFunc, OpArg, ID, columnConsts, vertexOrPrimID, idxVal);
  976. } break;
  977. case HLMatLoadStoreOpcode::ColMatStore:
  978. case HLMatLoadStoreOpcode::RowMatStore: {
  979. replaceMatStWithStOutputs(CI, matOp, ldStFunc, OpArg, ID, columnConsts, vertexOrPrimID, idxVal);
  980. } break;
  981. }
  982. } else {
  983. DXASSERT(0, "invalid operation on input output");
  984. }
  985. }
  986. } // namespace
  987. void HLSignatureLower::GenerateDxilInputs() {
  988. GenerateDxilInputsOutputs(DXIL::SignatureKind::Input);
  989. }
  990. void HLSignatureLower::GenerateDxilOutputs() {
  991. GenerateDxilInputsOutputs(DXIL::SignatureKind::Output);
  992. }
  993. void HLSignatureLower::GenerateDxilPrimOutputs() {
  994. GenerateDxilInputsOutputs(DXIL::SignatureKind::PatchConstOrPrim);
  995. }
  996. void HLSignatureLower::GenerateDxilInputsOutputs(DXIL::SignatureKind SK) {
  997. OP *hlslOP = HLM.GetOP();
  998. DxilFunctionProps &props = HLM.GetDxilFunctionProps(Entry);
  999. Module &M = *(HLM.GetModule());
  1000. OP::OpCode opcode = (OP::OpCode)-1;
  1001. switch (SK) {
  1002. case DXIL::SignatureKind::Input:
  1003. opcode = OP::OpCode::LoadInput;
  1004. break;
  1005. case DXIL::SignatureKind::Output:
  1006. opcode = props.IsMS() ? OP::OpCode::StoreVertexOutput : OP::OpCode::StoreOutput;
  1007. break;
  1008. case DXIL::SignatureKind::PatchConstOrPrim:
  1009. opcode = OP::OpCode::StorePrimitiveOutput;
  1010. break;
  1011. default:
  1012. DXASSERT_NOMSG(0);
  1013. }
  1014. bool bInput = SK == DXIL::SignatureKind::Input;
  1015. bool bNeedVertexOrPrimID = bInput && (props.IsGS() || props.IsDS() || props.IsHS());
  1016. bNeedVertexOrPrimID |= !bInput && props.IsMS();
  1017. Constant *OpArg = hlslOP->GetU32Const((unsigned)opcode);
  1018. Constant *columnConsts[] = {
  1019. hlslOP->GetU8Const(0), hlslOP->GetU8Const(1), hlslOP->GetU8Const(2),
  1020. hlslOP->GetU8Const(3), hlslOP->GetU8Const(4), hlslOP->GetU8Const(5),
  1021. hlslOP->GetU8Const(6), hlslOP->GetU8Const(7), hlslOP->GetU8Const(8),
  1022. hlslOP->GetU8Const(9), hlslOP->GetU8Const(10), hlslOP->GetU8Const(11),
  1023. hlslOP->GetU8Const(12), hlslOP->GetU8Const(13), hlslOP->GetU8Const(14),
  1024. hlslOP->GetU8Const(15)};
  1025. Constant *constZero = hlslOP->GetU32Const(0);
  1026. Value *undefVertexIdx = props.IsMS() || !bInput ? nullptr : UndefValue::get(Type::getInt32Ty(HLM.GetCtx()));
  1027. DxilSignature &Sig =
  1028. bInput ? EntrySig.InputSignature :
  1029. SK == DXIL::SignatureKind::Output ? EntrySig.OutputSignature :
  1030. EntrySig.PatchConstOrPrimSignature;
  1031. DxilTypeSystem &typeSys = HLM.GetTypeSystem();
  1032. DxilFunctionAnnotation *pFuncAnnot = typeSys.GetFunctionAnnotation(Entry);
  1033. Type *i1Ty = Type::getInt1Ty(constZero->getContext());
  1034. Type *i32Ty = constZero->getType();
  1035. llvm::SmallVector<unsigned, 8> removeIndices;
  1036. for (unsigned i = 0; i < Sig.GetElements().size(); i++) {
  1037. DxilSignatureElement *SE = &Sig.GetElement(i);
  1038. llvm::Type *Ty = SE->GetCompType().GetLLVMType(HLM.GetCtx());
  1039. // Cast i1 to i32 for load input.
  1040. bool bI1Cast = false;
  1041. if (Ty == i1Ty) {
  1042. bI1Cast = true;
  1043. Ty = i32Ty;
  1044. }
  1045. if (!hlslOP->IsOverloadLegal(opcode, Ty)) {
  1046. std::string O;
  1047. raw_string_ostream OSS(O);
  1048. Ty->print(OSS);
  1049. OSS << "(type for " << SE->GetName() << ")";
  1050. OSS << " cannot be used as shader inputs or outputs.";
  1051. OSS.flush();
  1052. dxilutil::EmitErrorOnFunction(M.getContext(), Entry, O);
  1053. continue;
  1054. }
  1055. Function *dxilFunc = hlslOP->GetOpFunc(opcode, Ty);
  1056. Constant *ID = hlslOP->GetU32Const(i);
  1057. unsigned cols = SE->GetCols();
  1058. Value *GV = m_sigValueMap[SE];
  1059. bool bIsInout = m_inoutArgSet.count(GV) > 0;
  1060. IRBuilder<> EntryBuilder(Entry->getEntryBlock().getFirstInsertionPt());
  1061. if (DbgDeclareInst *DDI = llvm::FindAllocaDbgDeclare(GV)) {
  1062. EntryBuilder.SetCurrentDebugLocation(DDI->getDebugLoc());
  1063. }
  1064. DXIL::SemanticInterpretationKind SI = SE->GetInterpretation();
  1065. DXASSERT_NOMSG(SI < DXIL::SemanticInterpretationKind::Invalid);
  1066. DXASSERT_NOMSG(SI != DXIL::SemanticInterpretationKind::NA);
  1067. DXASSERT_NOMSG(SI != DXIL::SemanticInterpretationKind::NotInSig);
  1068. if (SI == DXIL::SemanticInterpretationKind::Shadow)
  1069. continue; // Handled in ProcessArgument
  1070. if (!GV->getType()->isPointerTy()) {
  1071. DXASSERT(bInput, "direct parameter must be input");
  1072. Value *vertexOrPrimID = undefVertexIdx;
  1073. Value *args[] = {OpArg, ID, /*rowIdx*/ constZero, /*colIdx*/ nullptr,
  1074. vertexOrPrimID};
  1075. replaceDirectInputParameter(GV, dxilFunc, cols, args, bI1Cast, hlslOP,
  1076. EntryBuilder);
  1077. continue;
  1078. }
  1079. bool bIsArrayTy = GV->getType()->getPointerElementType()->isArrayTy();
  1080. bool bIsPrecise = m_preciseSigSet.count(SE);
  1081. if (bIsPrecise)
  1082. HLModule::MarkPreciseAttributeOnPtrWithFunctionCall(GV, M);
  1083. bool bRowMajor = false;
  1084. if (Argument *Arg = dyn_cast<Argument>(GV)) {
  1085. if (pFuncAnnot) {
  1086. auto &paramAnnot = pFuncAnnot->GetParameterAnnotation(Arg->getArgNo());
  1087. if (paramAnnot.HasMatrixAnnotation())
  1088. bRowMajor = paramAnnot.GetMatrixAnnotation().Orientation ==
  1089. MatrixOrientation::RowMajor;
  1090. }
  1091. }
  1092. std::vector<InputOutputAccessInfo> accessInfoList;
  1093. collectInputOutputAccessInfo(GV, constZero, accessInfoList,
  1094. bNeedVertexOrPrimID && bIsArrayTy, bInput, bRowMajor, props.IsMS());
  1095. for (InputOutputAccessInfo &info : accessInfoList) {
  1096. GenerateInputOutputUserCall(info, undefVertexIdx, dxilFunc, OpArg, ID,
  1097. cols, bI1Cast, columnConsts, bNeedVertexOrPrimID,
  1098. bIsArrayTy, bInput, bIsInout);
  1099. }
  1100. }
  1101. }
  1102. void HLSignatureLower::GenerateDxilCSInputs() {
  1103. OP *hlslOP = HLM.GetOP();
  1104. DxilFunctionAnnotation *funcAnnotation = HLM.GetFunctionAnnotation(Entry);
  1105. DXASSERT(funcAnnotation, "must find annotation for entry function");
  1106. IRBuilder<> Builder(Entry->getEntryBlock().getFirstInsertionPt());
  1107. for (Argument &arg : Entry->args()) {
  1108. DxilParameterAnnotation &paramAnnotation =
  1109. funcAnnotation->GetParameterAnnotation(arg.getArgNo());
  1110. llvm::StringRef semanticStr = paramAnnotation.GetSemanticString();
  1111. if (semanticStr.empty()) {
  1112. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry, "Semantic must be defined for all "
  1113. "parameters of an entry function or patch "
  1114. "constant function.");
  1115. return;
  1116. }
  1117. const Semantic *semantic =
  1118. Semantic::GetByName(semanticStr, DXIL::SigPointKind::CSIn);
  1119. OP::OpCode opcode;
  1120. switch (semantic->GetKind()) {
  1121. case Semantic::Kind::GroupThreadID:
  1122. opcode = OP::OpCode::ThreadIdInGroup;
  1123. break;
  1124. case Semantic::Kind::GroupID:
  1125. opcode = OP::OpCode::GroupId;
  1126. break;
  1127. case Semantic::Kind::DispatchThreadID:
  1128. opcode = OP::OpCode::ThreadId;
  1129. break;
  1130. case Semantic::Kind::GroupIndex:
  1131. opcode = OP::OpCode::FlattenedThreadIdInGroup;
  1132. break;
  1133. default:
  1134. DXASSERT(semantic->IsInvalid(),
  1135. "else compute shader semantics out-of-date");
  1136. dxilutil::EmitErrorOnFunction(HLM.GetModule()->getContext(), Entry, "invalid semantic found in CS");
  1137. return;
  1138. }
  1139. Constant *OpArg = hlslOP->GetU32Const((unsigned)opcode);
  1140. Type *NumTy = arg.getType();
  1141. DXASSERT(!NumTy->isPointerTy(), "Unexpected byref value for CS SV_***ID semantic.");
  1142. DXASSERT(NumTy->getScalarType()->isIntegerTy(), "Unexpected non-integer value for CS SV_***ID semantic.");
  1143. // Always use the i32 overload of those intrinsics, and then cast as needed
  1144. Function *dxilFunc = hlslOP->GetOpFunc(opcode, Builder.getInt32Ty());
  1145. Value *newArg = nullptr;
  1146. if (opcode == OP::OpCode::FlattenedThreadIdInGroup) {
  1147. newArg = Builder.CreateCall(dxilFunc, {OpArg});
  1148. } else {
  1149. unsigned vecSize = 1;
  1150. if (NumTy->isVectorTy())
  1151. vecSize = NumTy->getVectorNumElements();
  1152. newArg = Builder.CreateCall(dxilFunc, {OpArg, hlslOP->GetU32Const(0)});
  1153. if (vecSize > 1) {
  1154. Value *result = UndefValue::get(VectorType::get(Builder.getInt32Ty(), vecSize));
  1155. result = Builder.CreateInsertElement(result, newArg, (uint64_t)0);
  1156. for (unsigned i = 1; i < vecSize; i++) {
  1157. Value *newElt =
  1158. Builder.CreateCall(dxilFunc, {OpArg, hlslOP->GetU32Const(i)});
  1159. result = Builder.CreateInsertElement(result, newElt, i);
  1160. }
  1161. newArg = result;
  1162. }
  1163. }
  1164. // If the argument is of non-i32 type, convert here
  1165. if (newArg->getType() != NumTy)
  1166. newArg = Builder.CreateZExtOrTrunc(newArg, NumTy);
  1167. if (newArg->getType() != arg.getType()) {
  1168. DXASSERT_NOMSG(arg.getType()->isPointerTy());
  1169. for (User *U : arg.users()) {
  1170. LoadInst *LI = cast<LoadInst>(U);
  1171. LI->replaceAllUsesWith(newArg);
  1172. }
  1173. } else {
  1174. arg.replaceAllUsesWith(newArg);
  1175. }
  1176. }
  1177. }
  1178. void HLSignatureLower::GenerateDxilPatchConstantLdSt() {
  1179. OP *hlslOP = HLM.GetOP();
  1180. DxilFunctionProps &props = HLM.GetDxilFunctionProps(Entry);
  1181. Module &M = *(HLM.GetModule());
  1182. Constant *constZero = hlslOP->GetU32Const(0);
  1183. DxilSignature &Sig = EntrySig.PatchConstOrPrimSignature;
  1184. DxilTypeSystem &typeSys = HLM.GetTypeSystem();
  1185. DxilFunctionAnnotation *pFuncAnnot = typeSys.GetFunctionAnnotation(Entry);
  1186. auto InsertPt = Entry->getEntryBlock().getFirstInsertionPt();
  1187. const bool bIsHs = props.IsHS();
  1188. const bool bIsInput = !bIsHs;
  1189. const bool bIsInout = false;
  1190. const bool bNeedVertexOrPrimID = false;
  1191. if (bIsHs) {
  1192. DxilFunctionProps &EntryQual = HLM.GetDxilFunctionProps(Entry);
  1193. Function *patchConstantFunc = EntryQual.ShaderProps.HS.patchConstantFunc;
  1194. InsertPt = patchConstantFunc->getEntryBlock().getFirstInsertionPt();
  1195. pFuncAnnot = typeSys.GetFunctionAnnotation(patchConstantFunc);
  1196. }
  1197. IRBuilder<> Builder(InsertPt);
  1198. Type *i1Ty = Builder.getInt1Ty();
  1199. Type *i32Ty = Builder.getInt32Ty();
  1200. // LoadPatchConst don't have vertexIdx operand.
  1201. Value *undefVertexIdx = nullptr;
  1202. Constant *columnConsts[] = {
  1203. hlslOP->GetU8Const(0), hlslOP->GetU8Const(1), hlslOP->GetU8Const(2),
  1204. hlslOP->GetU8Const(3), hlslOP->GetU8Const(4), hlslOP->GetU8Const(5),
  1205. hlslOP->GetU8Const(6), hlslOP->GetU8Const(7), hlslOP->GetU8Const(8),
  1206. hlslOP->GetU8Const(9), hlslOP->GetU8Const(10), hlslOP->GetU8Const(11),
  1207. hlslOP->GetU8Const(12), hlslOP->GetU8Const(13), hlslOP->GetU8Const(14),
  1208. hlslOP->GetU8Const(15)};
  1209. OP::OpCode opcode =
  1210. bIsInput ? OP::OpCode::LoadPatchConstant : OP::OpCode::StorePatchConstant;
  1211. Constant *OpArg = hlslOP->GetU32Const((unsigned)opcode);
  1212. for (unsigned i = 0; i < Sig.GetElements().size(); i++) {
  1213. DxilSignatureElement *SE = &Sig.GetElement(i);
  1214. Value *GV = m_sigValueMap[SE];
  1215. DXIL::SemanticInterpretationKind SI = SE->GetInterpretation();
  1216. DXASSERT_NOMSG(SI < DXIL::SemanticInterpretationKind::Invalid);
  1217. DXASSERT_NOMSG(SI != DXIL::SemanticInterpretationKind::NA);
  1218. DXASSERT_NOMSG(SI != DXIL::SemanticInterpretationKind::NotInSig);
  1219. if (SI == DXIL::SemanticInterpretationKind::Shadow)
  1220. continue; // Handled in ProcessArgument
  1221. Constant *ID = hlslOP->GetU32Const(i);
  1222. // Generate LoadPatchConstant.
  1223. Type *Ty = SE->GetCompType().GetLLVMType(HLM.GetCtx());
  1224. // Cast i1 to i32 for load input.
  1225. bool bI1Cast = false;
  1226. if (Ty == i1Ty) {
  1227. bI1Cast = true;
  1228. Ty = i32Ty;
  1229. }
  1230. unsigned cols = SE->GetCols();
  1231. Function *dxilFunc = hlslOP->GetOpFunc(opcode, Ty);
  1232. if (!GV->getType()->isPointerTy()) {
  1233. DXASSERT(bIsInput, "Must be DS input.");
  1234. Constant *OpArg = hlslOP->GetU32Const(
  1235. static_cast<unsigned>(OP::OpCode::LoadPatchConstant));
  1236. Value *args[] = {OpArg, ID, /*rowIdx*/ constZero, /*colIdx*/ nullptr};
  1237. replaceDirectInputParameter(GV, dxilFunc, cols, args, bI1Cast, hlslOP,
  1238. Builder);
  1239. continue;
  1240. }
  1241. bool bRowMajor = false;
  1242. if (Argument *Arg = dyn_cast<Argument>(GV)) {
  1243. if (pFuncAnnot) {
  1244. auto &paramAnnot = pFuncAnnot->GetParameterAnnotation(Arg->getArgNo());
  1245. if (paramAnnot.HasMatrixAnnotation())
  1246. bRowMajor = paramAnnot.GetMatrixAnnotation().Orientation ==
  1247. MatrixOrientation::RowMajor;
  1248. }
  1249. }
  1250. std::vector<InputOutputAccessInfo> accessInfoList;
  1251. collectInputOutputAccessInfo(GV, constZero, accessInfoList, bNeedVertexOrPrimID,
  1252. bIsInput, bRowMajor, false);
  1253. bool bIsArrayTy = GV->getType()->getPointerElementType()->isArrayTy();
  1254. bool isPrecise = m_preciseSigSet.count(SE);
  1255. if (isPrecise)
  1256. HLModule::MarkPreciseAttributeOnPtrWithFunctionCall(GV, M);
  1257. for (InputOutputAccessInfo &info : accessInfoList) {
  1258. GenerateInputOutputUserCall(info, undefVertexIdx, dxilFunc, OpArg, ID,
  1259. cols, bI1Cast, columnConsts, bNeedVertexOrPrimID,
  1260. bIsArrayTy, bIsInput, bIsInout);
  1261. }
  1262. }
  1263. }
  1264. void HLSignatureLower::GenerateDxilPatchConstantFunctionInputs() {
  1265. // Map input patch, to input sig
  1266. // LoadOutputControlPoint for output patch .
  1267. OP *hlslOP = HLM.GetOP();
  1268. Constant *constZero = hlslOP->GetU32Const(0);
  1269. DxilFunctionProps &EntryQual = HLM.GetDxilFunctionProps(Entry);
  1270. Function *patchConstantFunc = EntryQual.ShaderProps.HS.patchConstantFunc;
  1271. DxilFunctionAnnotation *patchFuncAnnotation =
  1272. HLM.GetFunctionAnnotation(patchConstantFunc);
  1273. DXASSERT(patchFuncAnnotation,
  1274. "must find annotation for patch constant function");
  1275. Type *i1Ty = Type::getInt1Ty(constZero->getContext());
  1276. Type *i32Ty = constZero->getType();
  1277. Constant *columnConsts[] = {
  1278. hlslOP->GetU8Const(0), hlslOP->GetU8Const(1), hlslOP->GetU8Const(2),
  1279. hlslOP->GetU8Const(3), hlslOP->GetU8Const(4), hlslOP->GetU8Const(5),
  1280. hlslOP->GetU8Const(6), hlslOP->GetU8Const(7), hlslOP->GetU8Const(8),
  1281. hlslOP->GetU8Const(9), hlslOP->GetU8Const(10), hlslOP->GetU8Const(11),
  1282. hlslOP->GetU8Const(12), hlslOP->GetU8Const(13), hlslOP->GetU8Const(14),
  1283. hlslOP->GetU8Const(15)};
  1284. for (Argument &arg : patchConstantFunc->args()) {
  1285. DxilParameterAnnotation &paramAnnotation =
  1286. patchFuncAnnotation->GetParameterAnnotation(arg.getArgNo());
  1287. DxilParamInputQual inputQual = paramAnnotation.GetParamInputQual();
  1288. if (inputQual == DxilParamInputQual::InputPatch ||
  1289. inputQual == DxilParamInputQual::OutputPatch) {
  1290. DxilSignatureElement *SE = m_patchConstantInputsSigMap[arg.getArgNo()];
  1291. if (!SE) // Error should have been reported at an earlier stage.
  1292. continue;
  1293. Constant *inputID = hlslOP->GetU32Const(SE->GetID());
  1294. unsigned cols = SE->GetCols();
  1295. Type *Ty = SE->GetCompType().GetLLVMType(HLM.GetCtx());
  1296. // Cast i1 to i32 for load input.
  1297. bool bI1Cast = false;
  1298. if (Ty == i1Ty) {
  1299. bI1Cast = true;
  1300. Ty = i32Ty;
  1301. }
  1302. OP::OpCode opcode = inputQual == DxilParamInputQual::InputPatch
  1303. ? OP::OpCode::LoadInput
  1304. : OP::OpCode::LoadOutputControlPoint;
  1305. Function *dxilLdFunc = hlslOP->GetOpFunc(opcode, Ty);
  1306. bool bRowMajor = false;
  1307. if (Argument *Arg = dyn_cast<Argument>(&arg)) {
  1308. if (patchFuncAnnotation) {
  1309. auto &paramAnnot = patchFuncAnnotation->GetParameterAnnotation(Arg->getArgNo());
  1310. if (paramAnnot.HasMatrixAnnotation())
  1311. bRowMajor = paramAnnot.GetMatrixAnnotation().Orientation ==
  1312. MatrixOrientation::RowMajor;
  1313. }
  1314. }
  1315. std::vector<InputOutputAccessInfo> accessInfoList;
  1316. collectInputOutputAccessInfo(&arg, constZero, accessInfoList,
  1317. /*hasVertexOrPrimID*/ true, true, bRowMajor, false);
  1318. for (InputOutputAccessInfo &info : accessInfoList) {
  1319. Constant *OpArg = hlslOP->GetU32Const((unsigned)opcode);
  1320. if (LoadInst *ldInst = dyn_cast<LoadInst>(info.user)) {
  1321. Value *args[] = {OpArg, inputID, info.idx, info.vectorIdx,
  1322. info.vertexOrPrimID};
  1323. replaceLdWithLdInput(dxilLdFunc, ldInst, cols, args, bI1Cast);
  1324. } else if (CallInst *CI = dyn_cast<CallInst>(info.user)) {
  1325. HLOpcodeGroup group = GetHLOpcodeGroupByName(CI->getCalledFunction());
  1326. // Intrinsic will be translated later.
  1327. if (group == HLOpcodeGroup::HLIntrinsic || group == HLOpcodeGroup::NotHL)
  1328. return;
  1329. unsigned opcode = GetHLOpcode(CI);
  1330. DXASSERT_NOMSG(group == HLOpcodeGroup::HLMatLoadStore);
  1331. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  1332. if (matOp == HLMatLoadStoreOpcode::ColMatLoad || matOp == HLMatLoadStoreOpcode::RowMatLoad)
  1333. replaceMatLdWithLdInputs(CI, matOp, dxilLdFunc, OpArg, inputID, columnConsts, info.vertexOrPrimID, info.idx);
  1334. } else {
  1335. DXASSERT(0, "input should only be ld");
  1336. }
  1337. }
  1338. }
  1339. }
  1340. }
  1341. bool HLSignatureLower::HasClipPlanes() {
  1342. if (!HLM.HasDxilFunctionProps(Entry))
  1343. return false;
  1344. DxilFunctionProps &EntryQual = HLM.GetDxilFunctionProps(Entry);
  1345. auto &VS = EntryQual.ShaderProps.VS;
  1346. unsigned numClipPlanes = 0;
  1347. for (unsigned i = 0; i < DXIL::kNumClipPlanes; i++) {
  1348. if (!VS.clipPlanes[i])
  1349. break;
  1350. numClipPlanes++;
  1351. }
  1352. return numClipPlanes != 0;
  1353. }
  1354. void HLSignatureLower::GenerateClipPlanesForVS(Value *outPosition) {
  1355. DxilFunctionProps &EntryQual = HLM.GetDxilFunctionProps(Entry);
  1356. auto &VS = EntryQual.ShaderProps.VS;
  1357. unsigned numClipPlanes = 0;
  1358. for (unsigned i = 0; i < DXIL::kNumClipPlanes; i++) {
  1359. if (!VS.clipPlanes[i])
  1360. break;
  1361. numClipPlanes++;
  1362. }
  1363. if (!numClipPlanes)
  1364. return;
  1365. LLVMContext &Ctx = HLM.GetCtx();
  1366. Function *dp4 =
  1367. HLM.GetOP()->GetOpFunc(DXIL::OpCode::Dot4, Type::getFloatTy(Ctx));
  1368. Value *dp4Args[] = {
  1369. ConstantInt::get(Type::getInt32Ty(Ctx),
  1370. static_cast<unsigned>(DXIL::OpCode::Dot4)),
  1371. nullptr,
  1372. nullptr,
  1373. nullptr,
  1374. nullptr,
  1375. nullptr,
  1376. nullptr,
  1377. nullptr,
  1378. nullptr,
  1379. };
  1380. // out SV_Position should only have StoreInst use.
  1381. // Done by LegalizeDxilInputOutputs in ScalarReplAggregatesHLSL.cpp
  1382. for (User *U : outPosition->users()) {
  1383. StoreInst *ST = cast<StoreInst>(U);
  1384. Value *posVal = ST->getValueOperand();
  1385. DXASSERT(posVal->getType()->isVectorTy(), "SV_Position must be a vector");
  1386. IRBuilder<> Builder(ST);
  1387. // Put position to args.
  1388. for (unsigned i = 0; i < 4; i++)
  1389. dp4Args[i + 1] = Builder.CreateExtractElement(posVal, i);
  1390. // For each clip plane.
  1391. // clipDistance = dp4 position, clipPlane.
  1392. auto argIt = Entry->getArgumentList().rbegin();
  1393. for (int clipIdx = numClipPlanes - 1; clipIdx >= 0; clipIdx--) {
  1394. Constant *GV = VS.clipPlanes[clipIdx];
  1395. DXASSERT_NOMSG(GV->hasOneUse());
  1396. StoreInst *ST = cast<StoreInst>(GV->user_back());
  1397. Value *clipPlane = ST->getValueOperand();
  1398. ST->eraseFromParent();
  1399. Argument &arg = *(argIt++);
  1400. // Put clipPlane to args.
  1401. for (unsigned i = 0; i < 4; i++)
  1402. dp4Args[i + 5] = Builder.CreateExtractElement(clipPlane, i);
  1403. Value *clipDistance = Builder.CreateCall(dp4, dp4Args);
  1404. Builder.CreateStore(clipDistance, &arg);
  1405. }
  1406. }
  1407. }
  1408. namespace {
  1409. Value *TranslateStreamAppend(CallInst *CI, unsigned ID, hlsl::OP *OP) {
  1410. Function *DxilFunc = OP->GetOpFunc(OP::OpCode::EmitStream, CI->getType());
  1411. // TODO: generate a emit which has the data being emited as its argment.
  1412. // Value *data = CI->getArgOperand(HLOperandIndex::kStreamAppendDataOpIndex);
  1413. Constant *opArg = OP->GetU32Const((unsigned)OP::OpCode::EmitStream);
  1414. IRBuilder<> Builder(CI);
  1415. Constant *streamID = OP->GetU8Const(ID);
  1416. Value *args[] = {opArg, streamID};
  1417. return Builder.CreateCall(DxilFunc, args);
  1418. }
  1419. Value *TranslateStreamCut(CallInst *CI, unsigned ID, hlsl::OP *OP) {
  1420. Function *DxilFunc = OP->GetOpFunc(OP::OpCode::CutStream, CI->getType());
  1421. // TODO: generate a emit which has the data being emited as its argment.
  1422. // Value *data = CI->getArgOperand(HLOperandIndex::kStreamAppendDataOpIndex);
  1423. Constant *opArg = OP->GetU32Const((unsigned)OP::OpCode::CutStream);
  1424. IRBuilder<> Builder(CI);
  1425. Constant *streamID = OP->GetU8Const(ID);
  1426. Value *args[] = {opArg, streamID};
  1427. return Builder.CreateCall(DxilFunc, args);
  1428. }
  1429. } // namespace
  1430. // Generate DXIL stream output operation.
  1431. void HLSignatureLower::GenerateStreamOutputOperation(Value *streamVal, unsigned ID) {
  1432. OP * hlslOP = HLM.GetOP();
  1433. for (auto U = streamVal->user_begin(); U != streamVal->user_end();) {
  1434. Value *user = *(U++);
  1435. // Should only used by append, restartStrip .
  1436. CallInst *CI = cast<CallInst>(user);
  1437. HLOpcodeGroup group = GetHLOpcodeGroupByName(CI->getCalledFunction());
  1438. // Ignore user functions.
  1439. if (group == HLOpcodeGroup::NotHL)
  1440. continue;
  1441. unsigned opcode = GetHLOpcode(CI);
  1442. DXASSERT_LOCALVAR(group, group == HLOpcodeGroup::HLIntrinsic, "Must be HLIntrinsic here");
  1443. IntrinsicOp IOP = static_cast<IntrinsicOp>(opcode);
  1444. switch (IOP) {
  1445. case IntrinsicOp::MOP_Append:
  1446. TranslateStreamAppend(CI, ID, hlslOP);
  1447. break;
  1448. case IntrinsicOp::MOP_RestartStrip:
  1449. TranslateStreamCut(CI, ID, hlslOP);
  1450. break;
  1451. default:
  1452. DXASSERT(0, "invalid operation on stream");
  1453. }
  1454. CI->eraseFromParent();
  1455. }
  1456. }
  1457. // Generate DXIL stream output operations.
  1458. void HLSignatureLower::GenerateStreamOutputOperations() {
  1459. DxilFunctionAnnotation *EntryAnnotation = HLM.GetFunctionAnnotation(Entry);
  1460. DXASSERT(EntryAnnotation, "must find annotation for entry function");
  1461. for (Argument &arg : Entry->getArgumentList()) {
  1462. if (HLModule::IsStreamOutputPtrType(arg.getType())) {
  1463. unsigned streamID = 0;
  1464. DxilParameterAnnotation &paramAnnotation =
  1465. EntryAnnotation->GetParameterAnnotation(arg.getArgNo());
  1466. DxilParamInputQual inputQual = paramAnnotation.GetParamInputQual();
  1467. switch (inputQual) {
  1468. case DxilParamInputQual::OutStream0:
  1469. streamID = 0;
  1470. break;
  1471. case DxilParamInputQual::OutStream1:
  1472. streamID = 1;
  1473. break;
  1474. case DxilParamInputQual::OutStream2:
  1475. streamID = 2;
  1476. break;
  1477. case DxilParamInputQual::OutStream3:
  1478. default:
  1479. DXASSERT(inputQual == DxilParamInputQual::OutStream3,
  1480. "invalid input qual.");
  1481. streamID = 3;
  1482. break;
  1483. }
  1484. GenerateStreamOutputOperation(&arg, streamID);
  1485. }
  1486. }
  1487. }
  1488. // Generate DXIL EmitIndices operation.
  1489. void HLSignatureLower::GenerateEmitIndicesOperation(Value *indicesOutput) {
  1490. OP * hlslOP = HLM.GetOP();
  1491. Function *DxilFunc = hlslOP->GetOpFunc(OP::OpCode::EmitIndices, Type::getVoidTy(indicesOutput->getContext()));
  1492. Constant *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::EmitIndices);
  1493. for (auto U = indicesOutput->user_begin(); U != indicesOutput->user_end();) {
  1494. Value *user = *(U++);
  1495. GetElementPtrInst *GEP = cast<GetElementPtrInst>(user);
  1496. auto idx = GEP->idx_begin();
  1497. DXASSERT_LOCALVAR(idx, idx->get() == hlslOP->GetU32Const(0),
  1498. "only support 0 offset for input pointer");
  1499. gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
  1500. // Skip first pointer idx which must be 0.
  1501. GEPIt++;
  1502. Value *primIdx = GEPIt.getOperand();
  1503. DXASSERT(++GEPIt == E, "invalid GEP here"); (void)E;
  1504. auto GepUser = GEP->user_begin();
  1505. auto GepUserE = GEP->user_end();
  1506. for (; GepUser != GepUserE;) {
  1507. auto GepUserIt = GepUser++;
  1508. StoreInst *stInst = cast<StoreInst>(*GepUserIt);
  1509. Value *stVal = stInst->getValueOperand();
  1510. VectorType *VT = cast<VectorType>(stVal->getType());
  1511. unsigned eleCount = VT->getNumElements();
  1512. IRBuilder<> Builder(stInst);
  1513. Value *subVal0 = Builder.CreateExtractElement(stVal, hlslOP->GetU32Const(0));
  1514. Value *subVal1 = Builder.CreateExtractElement(stVal, hlslOP->GetU32Const(1));
  1515. Value *subVal2 = eleCount == 3 ?
  1516. Builder.CreateExtractElement(stVal, hlslOP->GetU32Const(2)) : hlslOP->GetU32Const(0);
  1517. Value *args[] = { opArg, primIdx, subVal0, subVal1, subVal2 };
  1518. Builder.CreateCall(DxilFunc, args);
  1519. stInst->eraseFromParent();
  1520. }
  1521. GEP->eraseFromParent();
  1522. }
  1523. }
  1524. // Generate DXIL EmitIndices operations.
  1525. void HLSignatureLower::GenerateEmitIndicesOperations() {
  1526. DxilFunctionAnnotation *EntryAnnotation = HLM.GetFunctionAnnotation(Entry);
  1527. DXASSERT(EntryAnnotation, "must find annotation for entry function");
  1528. for (Argument &arg : Entry->getArgumentList()) {
  1529. DxilParameterAnnotation &paramAnnotation =
  1530. EntryAnnotation->GetParameterAnnotation(arg.getArgNo());
  1531. DxilParamInputQual inputQual = paramAnnotation.GetParamInputQual();
  1532. if (inputQual == DxilParamInputQual::OutIndices) {
  1533. GenerateEmitIndicesOperation(&arg);
  1534. }
  1535. }
  1536. }
  1537. // Generate DXIL GetMeshPayload operation.
  1538. void HLSignatureLower::GenerateGetMeshPayloadOperation() {
  1539. DxilFunctionAnnotation *EntryAnnotation = HLM.GetFunctionAnnotation(Entry);
  1540. DXASSERT(EntryAnnotation, "must find annotation for entry function");
  1541. for (Argument &arg : Entry->getArgumentList()) {
  1542. DxilParameterAnnotation &paramAnnotation =
  1543. EntryAnnotation->GetParameterAnnotation(arg.getArgNo());
  1544. DxilParamInputQual inputQual = paramAnnotation.GetParamInputQual();
  1545. if (inputQual == DxilParamInputQual::InPayload) {
  1546. OP * hlslOP = HLM.GetOP();
  1547. Function *DxilFunc = hlslOP->GetOpFunc(OP::OpCode::GetMeshPayload, arg.getType());
  1548. Constant *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::GetMeshPayload);
  1549. IRBuilder<> Builder(arg.getParent()->getEntryBlock().getFirstInsertionPt());
  1550. Value *args[] = { opArg };
  1551. Value *payload = Builder.CreateCall(DxilFunc, args);
  1552. arg.replaceAllUsesWith(payload);
  1553. }
  1554. }
  1555. }
  1556. // Lower signatures.
  1557. void HLSignatureLower::Run() {
  1558. DxilFunctionProps &props = HLM.GetDxilFunctionProps(Entry);
  1559. if (props.IsGraphics()) {
  1560. if (props.IsMS()) {
  1561. GenerateEmitIndicesOperations();
  1562. GenerateGetMeshPayloadOperation();
  1563. }
  1564. CreateDxilSignatures();
  1565. // Allocate input output.
  1566. AllocateDxilInputOutputs();
  1567. GenerateDxilInputs();
  1568. GenerateDxilOutputs();
  1569. if (props.IsMS()) {
  1570. GenerateDxilPrimOutputs();
  1571. }
  1572. } else if (props.IsCS()) {
  1573. GenerateDxilCSInputs();
  1574. }
  1575. if (props.IsDS() || props.IsHS())
  1576. GenerateDxilPatchConstantLdSt();
  1577. if (props.IsHS())
  1578. GenerateDxilPatchConstantFunctionInputs();
  1579. if (props.IsGS())
  1580. GenerateStreamOutputOperations();
  1581. }