HLSLOptions.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. //===--- HLSLOptions.cpp - Driver Options Table ---------------------------===//
  2. ///////////////////////////////////////////////////////////////////////////////
  3. // //
  4. // HLSLOptions.cpp //
  5. // Copyright (C) Microsoft Corporation. All rights reserved. //
  6. // This file is distributed under the University of Illinois Open Source //
  7. // License. See LICENSE.TXT for details. //
  8. // //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "llvm/ADT/STLExtras.h"
  11. #include "llvm/Option/OptTable.h"
  12. #include "llvm/Option/Option.h"
  13. #include "llvm/Support/raw_ostream.h"
  14. #include "dxc/Support/Global.h"
  15. #include "dxc/Support/WinIncludes.h"
  16. #include "dxc/Support/HLSLOptions.h"
  17. #include "dxc/Support/Unicode.h"
  18. #include "dxc/Support/dxcapi.use.h"
  19. #include "dxc/HLSL/DxilShaderModel.h"
  20. using namespace llvm::opt;
  21. using namespace dxc;
  22. using namespace hlsl;
  23. using namespace hlsl::options;
  24. #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
  25. #include "dxc/Support/HLSLOptions.inc"
  26. #undef PREFIX
  27. static const OptTable::Info HlslInfoTable[] = {
  28. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  29. HELPTEXT, METAVAR) \
  30. { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
  31. FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
  32. #include "dxc/Support/HLSLOptions.inc"
  33. #undef OPTION
  34. };
  35. namespace {
  36. class HlslOptTable : public OptTable {
  37. public:
  38. HlslOptTable()
  39. : OptTable(HlslInfoTable, llvm::array_lengthof(HlslInfoTable)) {}
  40. };
  41. }
  42. static HlslOptTable *g_HlslOptTable;
  43. std::error_code hlsl::options::initHlslOptTable() {
  44. DXASSERT(g_HlslOptTable == nullptr, "else double-init");
  45. g_HlslOptTable = new (std::nothrow) HlslOptTable();
  46. if (g_HlslOptTable == nullptr)
  47. return std::error_code(E_OUTOFMEMORY, std::system_category());
  48. return std::error_code();
  49. }
  50. void hlsl::options::cleanupHlslOptTable() {
  51. delete g_HlslOptTable;
  52. g_HlslOptTable = nullptr;
  53. }
  54. const OptTable * hlsl::options::getHlslOptTable() {
  55. return g_HlslOptTable;
  56. }
  57. void DxcDefines::push_back(llvm::StringRef value) {
  58. // Skip empty defines.
  59. if (value.size() > 0) {
  60. DefineStrings.push_back(value);
  61. }
  62. }
  63. UINT32 DxcDefines::ComputeNumberOfWCharsNeededForDefines() {
  64. UINT32 wcharSize = 0;
  65. for (llvm::StringRef &S : DefineStrings) {
  66. DXASSERT(S.size() > 0,
  67. "else DxcDefines::push_back should not have added this");
  68. const int utf16Length = ::MultiByteToWideChar(
  69. CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(), nullptr, 0);
  70. IFTARG(utf16Length != 0);
  71. wcharSize += utf16Length + 1; // adding null terminated character
  72. }
  73. return wcharSize;
  74. }
  75. void DxcDefines::BuildDefines() {
  76. // Calculate and prepare the size of the backing buffer.
  77. DXASSERT(DefineValues == nullptr, "else DxcDefines is already built");
  78. UINT32 wcharSize = ComputeNumberOfWCharsNeededForDefines();
  79. DefineValues = new wchar_t[wcharSize];
  80. DefineVector.resize(DefineStrings.size());
  81. // Build up the define structures while filling in the backing buffer.
  82. UINT32 remaining = wcharSize;
  83. LPWSTR pWriteCursor = DefineValues;
  84. for (size_t i = 0; i < DefineStrings.size(); ++i) {
  85. llvm::StringRef &S = DefineStrings[i];
  86. DxcDefine &D = DefineVector[i];
  87. const int utf16Length =
  88. ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(),
  89. pWriteCursor, remaining);
  90. DXASSERT(utf16Length > 0,
  91. "else it should have failed during size calculation");
  92. LPWSTR pDefineEnd = pWriteCursor + utf16Length;
  93. D.Name = pWriteCursor;
  94. LPWSTR pEquals = std::find(pWriteCursor, pDefineEnd, L'=');
  95. if (pEquals == pDefineEnd) {
  96. D.Value = nullptr;
  97. } else {
  98. *pEquals = L'\0';
  99. D.Value = pEquals + 1;
  100. }
  101. // Advance past converted characters and include the null terminator.
  102. pWriteCursor += utf16Length;
  103. *pWriteCursor = L'\0';
  104. ++pWriteCursor;
  105. DXASSERT(pWriteCursor <= DefineValues + wcharSize,
  106. "else this function is calculating this incorrectly");
  107. remaining -= (utf16Length + 1);
  108. }
  109. }
  110. bool DxcOpts::IsRootSignatureProfile() {
  111. return TargetProfile == "rootsig_1_0" ||
  112. TargetProfile == "rootsig_1_1";
  113. }
  114. bool DxcOpts::IsLibraryProfile() {
  115. return TargetProfile.startswith("lib_");
  116. }
  117. MainArgs::MainArgs(int argc, const wchar_t **argv, int skipArgCount) {
  118. if (argc > skipArgCount) {
  119. Utf8StringVector.reserve(argc - skipArgCount);
  120. Utf8CharPtrVector.reserve(argc - skipArgCount);
  121. for (int i = skipArgCount; i < argc; ++i) {
  122. Utf8StringVector.emplace_back(Unicode::UTF16ToUTF8StringOrThrow(argv[i]));
  123. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  124. }
  125. }
  126. }
  127. MainArgs::MainArgs(llvm::ArrayRef<llvm::StringRef> args) {
  128. Utf8StringVector.reserve(args.size());
  129. Utf8CharPtrVector.reserve(args.size());
  130. for (llvm::StringRef str : args) {
  131. Utf8StringVector.emplace_back(str.str());
  132. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  133. }
  134. }
  135. MainArgs& MainArgs::operator=(const MainArgs &other) {
  136. Utf8StringVector.clear();
  137. Utf8CharPtrVector.clear();
  138. for (const std::string &str : other.Utf8StringVector) {
  139. Utf8StringVector.emplace_back(str);
  140. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  141. }
  142. return *this;
  143. }
  144. StringRefUtf16::StringRefUtf16(llvm::StringRef value) {
  145. if (!value.empty())
  146. m_value = Unicode::UTF8ToUTF16StringOrThrow(value.data());
  147. }
  148. static bool GetTargetVersionFromString(llvm::StringRef ref, unsigned *major, unsigned *minor) {
  149. try {
  150. *major = (unsigned)std::stoul(std::string(1, ref[ref.size() - 3]));
  151. *minor = (unsigned)std::stoul(std::string(1, ref[ref.size() - 1]));
  152. return true;
  153. }
  154. catch (std::invalid_argument &) {
  155. return false;
  156. }
  157. catch (std::out_of_range &) {
  158. return false;
  159. }
  160. }
  161. namespace hlsl {
  162. namespace options {
  163. /// Reads all options from the given argument strings, populates opts, and
  164. /// validates reporting errors and warnings.
  165. int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
  166. const MainArgs &argStrings, DxcOpts &opts,
  167. llvm::raw_ostream &errors) {
  168. DXASSERT_NOMSG(optionTable != nullptr);
  169. unsigned missingArgIndex = 0, missingArgCount = 0;
  170. InputArgList Args = optionTable->ParseArgs(
  171. argStrings.getArrayRef(), missingArgIndex, missingArgCount, flagsToInclude);
  172. // Verify consistency for external library support.
  173. opts.ExternalLib = Args.getLastArgValue(OPT_external_lib);
  174. opts.ExternalFn = Args.getLastArgValue(OPT_external_fn);
  175. if (opts.ExternalLib.empty()) {
  176. if (!opts.ExternalFn.empty()) {
  177. errors << "External function cannot be specified without an external "
  178. "library name.";
  179. return 1;
  180. }
  181. }
  182. else {
  183. if (opts.ExternalFn.empty()) {
  184. errors << "External library name requires specifying an external "
  185. "function name.";
  186. return 1;
  187. }
  188. }
  189. opts.ShowHelp = Args.hasFlag(OPT_help, OPT_INVALID, false);
  190. if (opts.ShowHelp) {
  191. return 0;
  192. }
  193. if (missingArgCount) {
  194. errors << "Argument to '" << Args.getArgString(missingArgIndex)
  195. << "' is missing.";
  196. return 1;
  197. }
  198. if (!Args.hasArg(hlsl::options::OPT_Qunused_arguments)) {
  199. for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
  200. errors << "Unknown argument: '" << A->getAsString(Args).c_str() << "'";
  201. return 1;
  202. }
  203. }
  204. // Add macros from the command line.
  205. for (const Arg *A : Args.filtered(OPT_D)) {
  206. opts.Defines.push_back(A->getValue());
  207. // If supporting OPT_U and included in filter, handle undefs.
  208. }
  209. opts.Defines.BuildDefines(); // Must be called after all defines are pushed back
  210. DXASSERT(opts.ExternalLib.empty() == opts.ExternalFn.empty(),
  211. "else flow above is incorrect");
  212. // when no-warnings option is present, do not output warnings.
  213. opts.OutputWarnings = Args.hasFlag(OPT_INVALID, OPT_no_warnings, true);
  214. opts.EntryPoint = Args.getLastArgValue(OPT_entrypoint);
  215. // Entry point is required in arguments only for drivers; APIs take this through an argument.
  216. // The value should default to 'main', but we let the caller apply this policy.
  217. if (opts.TargetProfile.empty()) {
  218. opts.TargetProfile = Args.getLastArgValue(OPT_target_profile);
  219. }
  220. if (opts.IsLibraryProfile()) {
  221. if (Args.getLastArg(OPT_entrypoint)) {
  222. errors << "cannot specify entry point for a library";
  223. return 1;
  224. } else {
  225. // Set entry point to impossible name.
  226. opts.EntryPoint = "lib.no::entry";
  227. }
  228. }
  229. llvm::StringRef ver = Args.getLastArgValue(OPT_hlsl_version);
  230. if (ver.empty()) { opts.HLSLVersion = 2018; } // Default to latest version
  231. else {
  232. try {
  233. opts.HLSLVersion = std::stoul(std::string(ver));
  234. if (opts.HLSLVersion < 2015 || opts.HLSLVersion > 2018) {
  235. errors << "Unknown HLSL version: " << opts.HLSLVersion;
  236. return 1;
  237. }
  238. }
  239. catch (const std::invalid_argument &) {
  240. errors << "Invalid HLSL Version";
  241. return 1;
  242. }
  243. catch (const std::out_of_range &) {
  244. errors << "Invalid HLSL Version";
  245. return 1;
  246. }
  247. }
  248. if (opts.HLSLVersion == 2015 && !(flagsToInclude & HlslFlags::ISenseOption)) {
  249. errors << "HLSL Version 2015 is only supported for language services";
  250. return 1;
  251. }
  252. // AssemblyCodeHex not supported (Fx)
  253. // OutputLibrary not supported (Fl)
  254. opts.AssemblyCode = Args.getLastArgValue(OPT_Fc);
  255. opts.DebugFile = Args.getLastArgValue(OPT_Fd);
  256. opts.ExtractPrivateFile = Args.getLastArgValue(OPT_getprivate);
  257. opts.Enable16BitTypes = Args.hasFlag(OPT_enable_16bit_types, OPT_INVALID, false);
  258. opts.OutputObject = Args.getLastArgValue(OPT_Fo);
  259. opts.OutputHeader = Args.getLastArgValue(OPT_Fh);
  260. opts.OutputWarningsFile = Args.getLastArgValue(OPT_Fe);
  261. opts.UseColor = Args.hasFlag(OPT_Cc, OPT_INVALID);
  262. opts.UseInstructionNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID);
  263. opts.UseInstructionByteOffsets = Args.hasFlag(OPT_No, OPT_INVALID);
  264. opts.UseHexLiterals = Args.hasFlag(OPT_Lx, OPT_INVALID);
  265. opts.Preprocess = Args.getLastArgValue(OPT_P);
  266. opts.AstDump = Args.hasFlag(OPT_ast_dump, OPT_INVALID, false);
  267. opts.CodeGenHighLevel = Args.hasFlag(OPT_fcgl, OPT_INVALID, false);
  268. opts.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, OPT_INVALID, false);
  269. opts.DebugNameForBinary = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
  270. opts.DebugNameForSource = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
  271. opts.VariableName = Args.getLastArgValue(OPT_Vn);
  272. opts.InputFile = Args.getLastArgValue(OPT_INPUT);
  273. opts.ForceRootSigVer = Args.getLastArgValue(OPT_force_rootsig_ver);
  274. opts.PrivateSource = Args.getLastArgValue(OPT_setprivate);
  275. opts.RootSignatureSource = Args.getLastArgValue(OPT_setrootsignature);
  276. opts.VerifyRootSignatureSource = Args.getLastArgValue(OPT_verifyrootsignature);
  277. opts.RootSignatureDefine = Args.getLastArgValue(OPT_rootsig_define);
  278. if (!opts.ForceRootSigVer.empty() && opts.ForceRootSigVer != "rootsig_1_0" &&
  279. opts.ForceRootSigVer != "rootsig_1_1") {
  280. errors << "Unsupported value '" << opts.ForceRootSigVer
  281. << "' for root signature profile.";
  282. return 1;
  283. }
  284. opts.IEEEStrict = Args.hasFlag(OPT_Gis, OPT_INVALID, false);
  285. opts.IgnoreLineDirectives = Args.hasFlag(OPT_ignore_line_directives, OPT_INVALID, false);
  286. opts.FloatDenormalMode = Args.getLastArgValue(OPT_denorm);
  287. // Check if a given denormalized value is valid
  288. if (!opts.FloatDenormalMode.empty()) {
  289. if (!(opts.FloatDenormalMode.equals_lower("preserve") ||
  290. opts.FloatDenormalMode.equals_lower("ftz") ||
  291. opts.FloatDenormalMode.equals_lower("any"))) {
  292. errors << "Unsupported value '" << opts.FloatDenormalMode
  293. << "' for denorm option.";
  294. return 1;
  295. }
  296. }
  297. // Check options only allowed in shader model >= 6.2FPDenormalMode
  298. unsigned Major = 0;
  299. unsigned Minor = 0;
  300. if (!opts.TargetProfile.empty()) {
  301. GetTargetVersionFromString(opts.TargetProfile, &Major, &Minor);
  302. }
  303. if (opts.TargetProfile.empty() || Major < 6 || (Major == 6 && Minor < 2)) {
  304. if (!opts.FloatDenormalMode.empty()) {
  305. errors << "denorm option is only allowed for shader model 6.2 and above.";
  306. return 1;
  307. }
  308. }
  309. // /enable-16bit-types only allowed for HLSL 2018 and shader model 6.2
  310. if (opts.Enable16BitTypes) {
  311. if (opts.TargetProfile.empty() || opts.HLSLVersion < 2018
  312. || Major < 6 || (Major == 6 && Minor < 2)) {
  313. errors << "enable-16bit-types is only allowed for shader model >= 6.2 and HLSL Language >= 2018.";
  314. return 1;
  315. }
  316. }
  317. opts.DisableOptimizations = false;
  318. if (Arg *A = Args.getLastArg(OPT_O0, OPT_O1, OPT_O2, OPT_O3, OPT_Od)) {
  319. if (A->getOption().matches(OPT_O0))
  320. opts.OptLevel = 0;
  321. if (A->getOption().matches(OPT_O1))
  322. opts.OptLevel = 1;
  323. if (A->getOption().matches(OPT_O2))
  324. opts.OptLevel = 2;
  325. if (A->getOption().matches(OPT_O3))
  326. opts.OptLevel = 3;
  327. if (A->getOption().matches(OPT_Od)) {
  328. opts.DisableOptimizations = true;
  329. opts.OptLevel = 0;
  330. }
  331. }
  332. else
  333. opts.OptLevel = 3;
  334. opts.OptDump = Args.hasFlag(OPT_Odump, OPT_INVALID, false);
  335. opts.DisableValidation = Args.hasFlag(OPT_VD, OPT_INVALID, false);
  336. opts.AllResourcesBound = Args.hasFlag(OPT_all_resources_bound, OPT_INVALID, false);
  337. opts.ColorCodeAssembly = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
  338. opts.DefaultRowMajor = Args.hasFlag(OPT_Zpr, OPT_INVALID, false);
  339. opts.DefaultColMajor = Args.hasFlag(OPT_Zpc, OPT_INVALID, false);
  340. opts.DumpBin = Args.hasFlag(OPT_dumpbin, OPT_INVALID, false);
  341. opts.NotUseLegacyCBufLoad = Args.hasFlag(OPT_not_use_legacy_cbuf_load, OPT_INVALID, false);
  342. opts.PackPrefixStable = Args.hasFlag(OPT_pack_prefix_stable, OPT_INVALID, false);
  343. opts.PackOptimized = Args.hasFlag(OPT_pack_optimized, OPT_INVALID, false);
  344. opts.DisplayIncludeProcess = Args.hasFlag(OPT_H, OPT_INVALID, false);
  345. opts.WarningAsError = Args.hasFlag(OPT__SLASH_WX, OPT_INVALID, false);
  346. opts.AvoidFlowControl = Args.hasFlag(OPT_Gfa, OPT_INVALID, false);
  347. opts.PreferFlowControl = Args.hasFlag(OPT_Gfp, OPT_INVALID, false);
  348. opts.RecompileFromBinary = Args.hasFlag(OPT_recompile, OPT_INVALID, false);
  349. opts.StripDebug = Args.hasFlag(OPT_Qstrip_debug, OPT_INVALID, false);
  350. opts.StripRootSignature = Args.hasFlag(OPT_Qstrip_rootsignature, OPT_INVALID, false);
  351. opts.StripPrivate = Args.hasFlag(OPT_Qstrip_priv, OPT_INVALID, false);
  352. opts.StripReflection = Args.hasFlag(OPT_Qstrip_reflect, OPT_INVALID, false);
  353. opts.ExtractRootSignature = Args.hasFlag(OPT_extractrootsignature, OPT_INVALID, false);
  354. opts.DisassembleColorCoded = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
  355. opts.DisassembleInstNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID, false);
  356. opts.DisassembleByteOffset = Args.hasFlag(OPT_No, OPT_INVALID, false);
  357. opts.DisaseembleHex = Args.hasFlag(OPT_Lx, OPT_INVALID, false);
  358. if (opts.DefaultColMajor && opts.DefaultRowMajor) {
  359. errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
  360. return 1;
  361. }
  362. if (opts.AvoidFlowControl && opts.PreferFlowControl) {
  363. errors << "Cannot specify /Gfa and /Gfp together, use /? to get usage information";
  364. return 1;
  365. }
  366. if (opts.PackPrefixStable && opts.PackOptimized) {
  367. errors << "Cannot specify /pack_prefix_stable and /pack_optimized together, use /? to get usage information";
  368. return 1;
  369. }
  370. // TODO: more fxc option check.
  371. // ERR_RES_MAY_ALIAS_ONLY_IN_CS_5
  372. // ERR_NOT_ABLE_TO_FLATTEN on if that contain side effects
  373. // TODO: other front-end error.
  374. // ERR_RESOURCE_NOT_IN_TEMPLATE
  375. // ERR_COMPLEX_TEMPLATE_RESOURCE
  376. // ERR_RESOURCE_BIND_CONFLICT
  377. // ERR_TEMPLATE_VAR_CONFLICT
  378. // ERR_ATTRIBUTE_PARAM_SIDE_EFFECT
  379. if ((flagsToInclude & hlsl::options::DriverOption) && opts.InputFile.empty()) {
  380. // Input file is required in arguments only for drivers; APIs take this through an argument.
  381. errors << "Required input file argument is missing. use -help to get more information.";
  382. return 1;
  383. }
  384. if (opts.OutputHeader.empty() && !opts.VariableName.empty()) {
  385. errors << "Cannot specify a header variable name when not writing a header.";
  386. return 1;
  387. }
  388. if (!opts.Preprocess.empty() &&
  389. (!opts.OutputHeader.empty() || !opts.OutputObject.empty() ||
  390. !opts.OutputWarnings || !opts.OutputWarningsFile.empty())) {
  391. errors << "Preprocess cannot be specified with other options.";
  392. return 1;
  393. }
  394. if (opts.DumpBin) {
  395. if (opts.DisplayIncludeProcess || opts.AstDump) {
  396. errors << "Cannot perform actions related to sources from a binary file.";
  397. return 1;
  398. }
  399. if (opts.AllResourcesBound || opts.AvoidFlowControl ||
  400. opts.CodeGenHighLevel || opts.DebugInfo || opts.DefaultColMajor ||
  401. opts.DefaultRowMajor || opts.Defines.size() != 0 ||
  402. opts.DisableOptimizations ||
  403. !opts.EntryPoint.empty() || !opts.ForceRootSigVer.empty() ||
  404. opts.PreferFlowControl || !opts.TargetProfile.empty()) {
  405. errors << "Cannot specify compilation options when reading a binary file.";
  406. return 1;
  407. }
  408. }
  409. if ((flagsToInclude & hlsl::options::DriverOption) &&
  410. opts.TargetProfile.empty() && !opts.DumpBin && opts.Preprocess.empty() && !opts.RecompileFromBinary) {
  411. // Target profile is required in arguments only for drivers when compiling;
  412. // APIs take this through an argument.
  413. errors << "Target profile argument is missing";
  414. return 1;
  415. }
  416. if (!opts.DebugNameForBinary && !opts.DebugNameForSource) {
  417. opts.DebugNameForSource = true;
  418. }
  419. else if (opts.DebugNameForBinary && opts.DebugNameForSource) {
  420. errors << "Cannot specify both /Zss and /Zsb";
  421. return 1;
  422. }
  423. // SPIRV Change Starts
  424. #ifdef ENABLE_SPIRV_CODEGEN
  425. const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
  426. opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
  427. opts.VkIgnoreUnusedResources = Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false);
  428. // Collects the arguments for -fvk-{b|s|t|u}-shift.
  429. const auto handleVkShiftArgs = [genSpirv, &Args, &errors](
  430. OptSpecifier id, const char* name, llvm::SmallVectorImpl<uint32_t>* shifts) {
  431. const auto values = Args.getAllArgValues(id);
  432. if (!genSpirv && !values.empty()) {
  433. errors << "-fvk-" << name << "-shift requires -spirv";
  434. return false;
  435. }
  436. shifts->clear();
  437. for (const auto& val : values) {
  438. uint32_t number = 0;
  439. if (llvm::StringRef(val).getAsInteger(10, number)) {
  440. errors << "invalid -fvk-" << name << "-shift argument: " << val;
  441. return false;
  442. }
  443. shifts->push_back(number);
  444. }
  445. return true;
  446. };
  447. if (!handleVkShiftArgs(OPT_fvk_b_shift, "b", &opts.VkBShift) ||
  448. !handleVkShiftArgs(OPT_fvk_t_shift, "t", &opts.VkTShift) ||
  449. !handleVkShiftArgs(OPT_fvk_s_shift, "s", &opts.VkSShift) ||
  450. !handleVkShiftArgs(OPT_fvk_u_shift, "u", &opts.VkUShift))
  451. return 1;
  452. opts.VkStageIoOrder = Args.getLastArgValue(OPT_fvk_stage_io_order_EQ, "decl");
  453. if (opts.VkStageIoOrder != "alpha" && opts.VkStageIoOrder != "decl") {
  454. errors << "unknown Vulkan stage I/O location assignment order: "
  455. << opts.VkStageIoOrder;
  456. return 1;
  457. }
  458. #else
  459. if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
  460. Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
  461. Args.hasFlag(OPT_fvk_ignore_unused_resources, OPT_INVALID, false) ||
  462. !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
  463. !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
  464. !Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
  465. !Args.getLastArgValue(OPT_fvk_s_shift).empty() ||
  466. !Args.getLastArgValue(OPT_fvk_u_shift).empty()
  467. ) {
  468. errors << "SPIR-V CodeGen not available. "
  469. "Please recompile with -DENABLE_SPIRV_CODEGEN=ON.";
  470. return 1;
  471. }
  472. #endif
  473. // SPIRV Change Ends
  474. opts.Args = std::move(Args);
  475. return 0;
  476. }
  477. /// Sets up the specified DxcDllSupport instance as per the given options.
  478. int SetupDxcDllSupport(const DxcOpts &opts, dxc::DxcDllSupport &dxcSupport,
  479. llvm::raw_ostream &errors) {
  480. if (!opts.ExternalLib.empty()) {
  481. DXASSERT(!opts.ExternalFn.empty(), "else ReadDxcOpts should have failed");
  482. StringRefUtf16 externalLib(opts.ExternalLib);
  483. HRESULT hrLoad =
  484. dxcSupport.InitializeForDll(externalLib, opts.ExternalFn.data());
  485. if (DXC_FAILED(hrLoad)) {
  486. errors << "Unable to load support for external DLL " << opts.ExternalLib
  487. << " with function " << opts.ExternalFn << " - error 0x";
  488. errors.write_hex(hrLoad);
  489. return 1;
  490. }
  491. }
  492. return 0;
  493. }
  494. void CopyArgsToWStrings(const InputArgList &inArgs, unsigned flagsToInclude,
  495. std::vector<std::wstring> &outArgs) {
  496. ArgStringList stringList;
  497. for (const Arg *A : inArgs) {
  498. if (A->getOption().hasFlag(flagsToInclude)) {
  499. A->renderAsInput(inArgs, stringList);
  500. }
  501. }
  502. for (const char *argText : stringList) {
  503. outArgs.emplace_back(Unicode::UTF8ToUTF16StringOrThrow(argText));
  504. }
  505. }
  506. } } // hlsl::options