HLSLOptions.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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. #ifndef _WIN32
  44. #pragma GCC visibility push(hidden)
  45. #endif
  46. std::error_code hlsl::options::initHlslOptTable() {
  47. DXASSERT(g_HlslOptTable == nullptr, "else double-init");
  48. g_HlslOptTable = new (std::nothrow) HlslOptTable();
  49. if (g_HlslOptTable == nullptr)
  50. return std::error_code(E_OUTOFMEMORY, std::system_category());
  51. return std::error_code();
  52. }
  53. void hlsl::options::cleanupHlslOptTable() {
  54. delete g_HlslOptTable;
  55. g_HlslOptTable = nullptr;
  56. }
  57. const OptTable * hlsl::options::getHlslOptTable() {
  58. return g_HlslOptTable;
  59. }
  60. #ifndef _WIN32
  61. #pragma GCC visibility pop
  62. #endif
  63. void DxcDefines::push_back(llvm::StringRef value) {
  64. // Skip empty defines.
  65. if (value.size() > 0) {
  66. DefineStrings.push_back(value);
  67. }
  68. }
  69. UINT32 DxcDefines::ComputeNumberOfWCharsNeededForDefines() {
  70. UINT32 wcharSize = 0;
  71. for (llvm::StringRef &S : DefineStrings) {
  72. DXASSERT(S.size() > 0,
  73. "else DxcDefines::push_back should not have added this");
  74. const int utf16Length = ::MultiByteToWideChar(
  75. CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(), nullptr, 0);
  76. IFTARG(utf16Length != 0);
  77. wcharSize += utf16Length + 1; // adding null terminated character
  78. }
  79. return wcharSize;
  80. }
  81. void DxcDefines::BuildDefines() {
  82. // Calculate and prepare the size of the backing buffer.
  83. DXASSERT(DefineValues == nullptr, "else DxcDefines is already built");
  84. UINT32 wcharSize = ComputeNumberOfWCharsNeededForDefines();
  85. DefineValues = new wchar_t[wcharSize];
  86. DefineVector.resize(DefineStrings.size());
  87. // Build up the define structures while filling in the backing buffer.
  88. UINT32 remaining = wcharSize;
  89. LPWSTR pWriteCursor = DefineValues;
  90. for (size_t i = 0; i < DefineStrings.size(); ++i) {
  91. llvm::StringRef &S = DefineStrings[i];
  92. DxcDefine &D = DefineVector[i];
  93. const int utf16Length =
  94. ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(),
  95. pWriteCursor, remaining);
  96. DXASSERT(utf16Length > 0,
  97. "else it should have failed during size calculation");
  98. LPWSTR pDefineEnd = pWriteCursor + utf16Length;
  99. D.Name = pWriteCursor;
  100. LPWSTR pEquals = std::find(pWriteCursor, pDefineEnd, L'=');
  101. if (pEquals == pDefineEnd) {
  102. D.Value = nullptr;
  103. } else {
  104. *pEquals = L'\0';
  105. D.Value = pEquals + 1;
  106. }
  107. // Advance past converted characters and include the null terminator.
  108. pWriteCursor += utf16Length;
  109. *pWriteCursor = L'\0';
  110. ++pWriteCursor;
  111. DXASSERT(pWriteCursor <= DefineValues + wcharSize,
  112. "else this function is calculating this incorrectly");
  113. remaining -= (utf16Length + 1);
  114. }
  115. }
  116. bool DxcOpts::IsRootSignatureProfile() {
  117. return TargetProfile == "rootsig_1_0" ||
  118. TargetProfile == "rootsig_1_1";
  119. }
  120. bool DxcOpts::IsLibraryProfile() {
  121. return TargetProfile.startswith("lib_");
  122. }
  123. MainArgs::MainArgs(int argc, const wchar_t **argv, int skipArgCount) {
  124. if (argc > skipArgCount) {
  125. Utf8StringVector.reserve(argc - skipArgCount);
  126. Utf8CharPtrVector.reserve(argc - skipArgCount);
  127. for (int i = skipArgCount; i < argc; ++i) {
  128. Utf8StringVector.emplace_back(Unicode::UTF16ToUTF8StringOrThrow(argv[i]));
  129. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  130. }
  131. }
  132. }
  133. MainArgs::MainArgs(int argc, const char **argv, int skipArgCount) {
  134. if (argc > skipArgCount) {
  135. Utf8StringVector.reserve(argc - skipArgCount);
  136. Utf8CharPtrVector.reserve(argc - skipArgCount);
  137. for (int i = skipArgCount; i < argc; ++i) {
  138. Utf8StringVector.emplace_back(argv[i]);
  139. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  140. }
  141. }
  142. }
  143. MainArgs::MainArgs(llvm::ArrayRef<llvm::StringRef> args) {
  144. Utf8StringVector.reserve(args.size());
  145. Utf8CharPtrVector.reserve(args.size());
  146. for (llvm::StringRef str : args) {
  147. Utf8StringVector.emplace_back(str.str());
  148. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  149. }
  150. }
  151. MainArgs& MainArgs::operator=(const MainArgs &other) {
  152. Utf8StringVector.clear();
  153. Utf8CharPtrVector.clear();
  154. Utf8StringVector.reserve(other.Utf8StringVector.size());
  155. Utf8CharPtrVector.reserve(other.Utf8StringVector.size());
  156. for (const std::string &str : other.Utf8StringVector) {
  157. Utf8StringVector.emplace_back(str);
  158. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  159. }
  160. return *this;
  161. }
  162. StringRefUtf16::StringRefUtf16(llvm::StringRef value) {
  163. if (!value.empty())
  164. m_value = Unicode::UTF8ToUTF16StringOrThrow(value.data());
  165. }
  166. static bool GetTargetVersionFromString(llvm::StringRef ref, unsigned *major, unsigned *minor) {
  167. *major = *minor = -1;
  168. unsigned len = ref.size();
  169. if (len < 6 || len > 11) // length: ps_6_0 to rootsig_1_0
  170. return false;
  171. if (ref[len - 4] != '_' || ref[len - 2] != '_')
  172. return false;
  173. char cMajor = ref[len - 3];
  174. char cMinor = ref[len - 1];
  175. if (cMajor >= '0' && cMajor <= '9')
  176. *major = cMajor - '0';
  177. else
  178. return false;
  179. if (cMinor == 'x')
  180. *minor = 0xF;
  181. else if (cMinor >= '0' && cMinor <= '9')
  182. *minor = cMinor - '0';
  183. else
  184. return false;
  185. return true;
  186. }
  187. // SPIRV Change Starts
  188. #ifdef ENABLE_SPIRV_CODEGEN
  189. /// Checks and collects the arguments for -fvk-{b|s|t|u}-shift into *shifts.
  190. static bool handleVkShiftArgs(const InputArgList &args, OptSpecifier id,
  191. const char *name,
  192. llvm::SmallVectorImpl<int32_t> *shifts,
  193. llvm::raw_ostream &errors) {
  194. const auto values = args.getAllArgValues(id);
  195. if (values.empty())
  196. return true;
  197. if (!args.hasArg(OPT_spirv)) {
  198. errors << "-fvk-" << name << "-shift requires -spirv";
  199. return false;
  200. }
  201. if (!args.getLastArgValue(OPT_fvk_bind_register).empty()) {
  202. errors << "-fvk-" << name
  203. << "-shift cannot be used together with -fvk-bind-register";
  204. return false;
  205. }
  206. shifts->clear();
  207. bool setForAll = false;
  208. for (const auto &val : values) {
  209. int32_t number = 0;
  210. if (val == "all") {
  211. number = -1;
  212. setForAll = true;
  213. } else {
  214. if (llvm::StringRef(val).getAsInteger(10, number)) {
  215. errors << "invalid -fvk-" << name << "-shift argument: " << val;
  216. return false;
  217. }
  218. if (number < 0) {
  219. errors << "negative -fvk-" << name << "-shift argument: " << val;
  220. return false;
  221. }
  222. }
  223. shifts->push_back(number);
  224. }
  225. if (setForAll && shifts->size() > 2) {
  226. errors << "setting all sets via -fvk-" << name
  227. << "-shift argument should be used alone";
  228. return false;
  229. }
  230. return true;
  231. };
  232. #endif
  233. // SPIRV Change Ends
  234. namespace hlsl {
  235. namespace options {
  236. /// Reads all options from the given argument strings, populates opts, and
  237. /// validates reporting errors and warnings.
  238. int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
  239. const MainArgs &argStrings, DxcOpts &opts,
  240. llvm::raw_ostream &errors) {
  241. DXASSERT_NOMSG(optionTable != nullptr);
  242. unsigned missingArgIndex = 0, missingArgCount = 0;
  243. InputArgList Args = optionTable->ParseArgs(
  244. argStrings.getArrayRef(), missingArgIndex, missingArgCount, flagsToInclude);
  245. // Verify consistency for external library support.
  246. opts.ExternalLib = Args.getLastArgValue(OPT_external_lib);
  247. opts.ExternalFn = Args.getLastArgValue(OPT_external_fn);
  248. if (opts.ExternalLib.empty()) {
  249. if (!opts.ExternalFn.empty()) {
  250. errors << "External function cannot be specified without an external "
  251. "library name.";
  252. return 1;
  253. }
  254. }
  255. else {
  256. if (opts.ExternalFn.empty()) {
  257. errors << "External library name requires specifying an external "
  258. "function name.";
  259. return 1;
  260. }
  261. }
  262. opts.ShowHelp = Args.hasFlag(OPT_help, OPT_INVALID, false);
  263. opts.ShowHelp |= (opts.ShowHelpHidden = Args.hasFlag(OPT__help_hidden, OPT_INVALID, false));
  264. if (opts.ShowHelp) {
  265. return 0;
  266. }
  267. if (missingArgCount) {
  268. errors << "Argument to '" << Args.getArgString(missingArgIndex)
  269. << "' is missing.";
  270. return 1;
  271. }
  272. if (!Args.hasArg(hlsl::options::OPT_Qunused_arguments)) {
  273. for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
  274. errors << "Unknown argument: '" << A->getAsString(Args).c_str() << "'";
  275. return 1;
  276. }
  277. }
  278. // Add macros from the command line.
  279. for (const Arg *A : Args.filtered(OPT_D)) {
  280. opts.Defines.push_back(A->getValue());
  281. // If supporting OPT_U and included in filter, handle undefs.
  282. }
  283. opts.Defines.BuildDefines(); // Must be called after all defines are pushed back
  284. DXASSERT(opts.ExternalLib.empty() == opts.ExternalFn.empty(),
  285. "else flow above is incorrect");
  286. // when no-warnings option is present, do not output warnings.
  287. opts.OutputWarnings = Args.hasFlag(OPT_INVALID, OPT_no_warnings, true);
  288. opts.EntryPoint = Args.getLastArgValue(OPT_entrypoint);
  289. // Entry point is required in arguments only for drivers; APIs take this through an argument.
  290. // The value should default to 'main', but we let the caller apply this policy.
  291. if (opts.TargetProfile.empty()) {
  292. opts.TargetProfile = Args.getLastArgValue(OPT_target_profile);
  293. }
  294. if (opts.IsLibraryProfile()) {
  295. if (Args.getLastArg(OPT_entrypoint)) {
  296. errors << "cannot specify entry point for a library";
  297. return 1;
  298. } else {
  299. // Set entry point to impossible name.
  300. opts.EntryPoint = "lib.no::entry";
  301. }
  302. } else {
  303. if (Args.getLastArg(OPT_exports)) {
  304. errors << "library profile required when using -exports option";
  305. return 1;
  306. } else if (Args.hasFlag(OPT_export_shaders_only, OPT_INVALID, false)) {
  307. errors << "library profile required when using -export-shaders-only option";
  308. return 1;
  309. } else if (Args.getLastArg(OPT_default_linkage)) {
  310. errors << "library profile required when using -default-linkage option";
  311. return 1;
  312. }
  313. }
  314. opts.EnableDX9CompatMode = Args.hasFlag(OPT_Gec, OPT_INVALID, false);
  315. llvm::StringRef ver = Args.getLastArgValue(OPT_hlsl_version);
  316. if (ver.empty()) {
  317. if (opts.EnableDX9CompatMode)
  318. opts.HLSLVersion = 2016; // Default to max supported version with /Gec flag
  319. else
  320. opts.HLSLVersion = 2018; // Default to latest version
  321. } else {
  322. try {
  323. opts.HLSLVersion = std::stoul(std::string(ver));
  324. if (opts.HLSLVersion < 2015 || opts.HLSLVersion > 2018) {
  325. errors << "Unknown HLSL version: " << opts.HLSLVersion;
  326. return 1;
  327. }
  328. }
  329. catch (const std::invalid_argument &) {
  330. errors << "Invalid HLSL Version";
  331. return 1;
  332. }
  333. catch (const std::out_of_range &) {
  334. errors << "Invalid HLSL Version";
  335. return 1;
  336. }
  337. }
  338. if (opts.HLSLVersion == 2015 && !(flagsToInclude & HlslFlags::ISenseOption)) {
  339. errors << "HLSL Version 2015 is only supported for language services";
  340. return 1;
  341. }
  342. if (opts.EnableDX9CompatMode && opts.HLSLVersion > 2016) {
  343. errors << "/Gec is not supported with HLSLVersion " << opts.HLSLVersion;
  344. return 1;
  345. }
  346. if (opts.HLSLVersion <= 2016) {
  347. opts.EnableFXCCompatMode = true;
  348. }
  349. // AssemblyCodeHex not supported (Fx)
  350. // OutputLibrary not supported (Fl)
  351. opts.AssemblyCode = Args.getLastArgValue(OPT_Fc);
  352. opts.DebugFile = Args.getLastArgValue(OPT_Fd);
  353. opts.ExtractPrivateFile = Args.getLastArgValue(OPT_getprivate);
  354. opts.Enable16BitTypes = Args.hasFlag(OPT_enable_16bit_types, OPT_INVALID, false);
  355. opts.OutputObject = Args.getLastArgValue(OPT_Fo);
  356. opts.OutputHeader = Args.getLastArgValue(OPT_Fh);
  357. opts.OutputWarningsFile = Args.getLastArgValue(OPT_Fe);
  358. opts.UseColor = Args.hasFlag(OPT_Cc, OPT_INVALID);
  359. opts.UseInstructionNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID);
  360. opts.UseInstructionByteOffsets = Args.hasFlag(OPT_No, OPT_INVALID);
  361. opts.UseHexLiterals = Args.hasFlag(OPT_Lx, OPT_INVALID);
  362. opts.Preprocess = Args.getLastArgValue(OPT_P);
  363. opts.AstDump = Args.hasFlag(OPT_ast_dump, OPT_INVALID, false);
  364. opts.CodeGenHighLevel = Args.hasFlag(OPT_fcgl, OPT_INVALID, false);
  365. opts.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, OPT_INVALID, false);
  366. opts.DebugNameForBinary = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
  367. opts.DebugNameForSource = Args.hasFlag(OPT_Zss, OPT_INVALID, false);
  368. opts.VariableName = Args.getLastArgValue(OPT_Vn);
  369. opts.InputFile = Args.getLastArgValue(OPT_INPUT);
  370. opts.ForceRootSigVer = Args.getLastArgValue(OPT_force_rootsig_ver);
  371. opts.PrivateSource = Args.getLastArgValue(OPT_setprivate);
  372. opts.RootSignatureSource = Args.getLastArgValue(OPT_setrootsignature);
  373. opts.VerifyRootSignatureSource = Args.getLastArgValue(OPT_verifyrootsignature);
  374. opts.RootSignatureDefine = Args.getLastArgValue(OPT_rootsig_define);
  375. if (!opts.ForceRootSigVer.empty() && opts.ForceRootSigVer != "rootsig_1_0" &&
  376. opts.ForceRootSigVer != "rootsig_1_1") {
  377. errors << "Unsupported value '" << opts.ForceRootSigVer
  378. << "' for root signature profile.";
  379. return 1;
  380. }
  381. opts.IEEEStrict = Args.hasFlag(OPT_Gis, OPT_INVALID, false);
  382. opts.IgnoreLineDirectives = Args.hasFlag(OPT_ignore_line_directives, OPT_INVALID, false);
  383. opts.FloatDenormalMode = Args.getLastArgValue(OPT_denorm);
  384. // Check if a given denormalized value is valid
  385. if (!opts.FloatDenormalMode.empty()) {
  386. if (!(opts.FloatDenormalMode.equals_lower("preserve") ||
  387. opts.FloatDenormalMode.equals_lower("ftz") ||
  388. opts.FloatDenormalMode.equals_lower("any"))) {
  389. errors << "Unsupported value '" << opts.FloatDenormalMode
  390. << "' for denorm option.";
  391. return 1;
  392. }
  393. }
  394. llvm::StringRef auto_binding_space = Args.getLastArgValue(OPT_auto_binding_space);
  395. if (!auto_binding_space.empty()) {
  396. if (auto_binding_space.getAsInteger(10, opts.AutoBindingSpace)) {
  397. errors << "Unsupported value '" << auto_binding_space << "' for auto binding space.";
  398. return 1;
  399. }
  400. }
  401. opts.Exports = Args.getAllArgValues(OPT_exports);
  402. opts.DefaultLinkage = Args.getLastArgValue(OPT_default_linkage);
  403. if (!opts.DefaultLinkage.empty()) {
  404. if (!(opts.DefaultLinkage.equals_lower("internal") ||
  405. opts.DefaultLinkage.equals_lower("external"))) {
  406. errors << "Unsupported value '" << opts.DefaultLinkage
  407. << "for -default-linkage option.";
  408. return 1;
  409. }
  410. }
  411. // Check options only allowed in shader model >= 6.2FPDenormalMode
  412. unsigned Major = 0;
  413. unsigned Minor = 0;
  414. if (!opts.TargetProfile.empty()) {
  415. if (!GetTargetVersionFromString(opts.TargetProfile, &Major, &Minor)) {
  416. errors << "unable to parse shader model.";
  417. return 1;
  418. }
  419. }
  420. if (opts.TargetProfile.empty() || Major < 6 || (Major == 6 && Minor < 2)) {
  421. if (!opts.FloatDenormalMode.empty()) {
  422. errors << "denorm option is only allowed for shader model 6.2 and above.";
  423. return 1;
  424. }
  425. }
  426. // /enable-16bit-types only allowed for HLSL 2018 and shader model 6.2
  427. if (opts.Enable16BitTypes) {
  428. if (opts.TargetProfile.empty() || opts.HLSLVersion < 2018
  429. || Major < 6 || (Major == 6 && Minor < 2)) {
  430. errors << "enable-16bit-types is only allowed for shader model >= 6.2 and HLSL Language >= 2018.";
  431. return 1;
  432. }
  433. }
  434. opts.DisableOptimizations = false;
  435. if (Arg *A = Args.getLastArg(OPT_O0, OPT_O1, OPT_O2, OPT_O3, OPT_Od)) {
  436. if (A->getOption().matches(OPT_O0))
  437. opts.OptLevel = 0;
  438. if (A->getOption().matches(OPT_O1))
  439. opts.OptLevel = 1;
  440. if (A->getOption().matches(OPT_O2))
  441. opts.OptLevel = 2;
  442. if (A->getOption().matches(OPT_O3))
  443. opts.OptLevel = 3;
  444. if (A->getOption().matches(OPT_Od)) {
  445. opts.DisableOptimizations = true;
  446. opts.OptLevel = 0;
  447. }
  448. }
  449. else
  450. opts.OptLevel = 3;
  451. opts.OptDump = Args.hasFlag(OPT_Odump, OPT_INVALID, false);
  452. opts.DisableValidation = Args.hasFlag(OPT_VD, OPT_INVALID, false);
  453. opts.AllResourcesBound = Args.hasFlag(OPT_all_resources_bound, OPT_INVALID, false);
  454. opts.ColorCodeAssembly = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
  455. opts.DefaultRowMajor = Args.hasFlag(OPT_Zpr, OPT_INVALID, false);
  456. opts.DefaultColMajor = Args.hasFlag(OPT_Zpc, OPT_INVALID, false);
  457. opts.DumpBin = Args.hasFlag(OPT_dumpbin, OPT_INVALID, false);
  458. opts.NotUseLegacyCBufLoad = Args.hasFlag(OPT_not_use_legacy_cbuf_load, OPT_INVALID, false);
  459. opts.PackPrefixStable = Args.hasFlag(OPT_pack_prefix_stable, OPT_INVALID, false);
  460. opts.PackOptimized = Args.hasFlag(OPT_pack_optimized, OPT_INVALID, false);
  461. opts.DisplayIncludeProcess = Args.hasFlag(OPT_H, OPT_INVALID, false);
  462. opts.WarningAsError = Args.hasFlag(OPT__SLASH_WX, OPT_INVALID, false);
  463. opts.AvoidFlowControl = Args.hasFlag(OPT_Gfa, OPT_INVALID, false);
  464. opts.PreferFlowControl = Args.hasFlag(OPT_Gfp, OPT_INVALID, false);
  465. opts.RecompileFromBinary = Args.hasFlag(OPT_recompile, OPT_INVALID, false);
  466. opts.StripDebug = Args.hasFlag(OPT_Qstrip_debug, OPT_INVALID, false);
  467. opts.StripRootSignature = Args.hasFlag(OPT_Qstrip_rootsignature, OPT_INVALID, false);
  468. opts.StripPrivate = Args.hasFlag(OPT_Qstrip_priv, OPT_INVALID, false);
  469. opts.StripReflection = Args.hasFlag(OPT_Qstrip_reflect, OPT_INVALID, false);
  470. opts.ExtractRootSignature = Args.hasFlag(OPT_extractrootsignature, OPT_INVALID, false);
  471. opts.DisassembleColorCoded = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
  472. opts.DisassembleInstNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID, false);
  473. opts.DisassembleByteOffset = Args.hasFlag(OPT_No, OPT_INVALID, false);
  474. opts.DisaseembleHex = Args.hasFlag(OPT_Lx, OPT_INVALID, false);
  475. opts.LegacyMacroExpansion = Args.hasFlag(OPT_flegacy_macro_expansion, OPT_INVALID, false);
  476. opts.ExportShadersOnly = Args.hasFlag(OPT_export_shaders_only, OPT_INVALID, false);
  477. if (opts.DefaultColMajor && opts.DefaultRowMajor) {
  478. errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
  479. return 1;
  480. }
  481. if (opts.AvoidFlowControl && opts.PreferFlowControl) {
  482. errors << "Cannot specify /Gfa and /Gfp together, use /? to get usage information";
  483. return 1;
  484. }
  485. if (opts.PackPrefixStable && opts.PackOptimized) {
  486. errors << "Cannot specify /pack_prefix_stable and /pack_optimized together, use /? to get usage information";
  487. return 1;
  488. }
  489. // TODO: more fxc option check.
  490. // ERR_RES_MAY_ALIAS_ONLY_IN_CS_5
  491. // ERR_NOT_ABLE_TO_FLATTEN on if that contain side effects
  492. // TODO: other front-end error.
  493. // ERR_RESOURCE_NOT_IN_TEMPLATE
  494. // ERR_COMPLEX_TEMPLATE_RESOURCE
  495. // ERR_RESOURCE_BIND_CONFLICT
  496. // ERR_TEMPLATE_VAR_CONFLICT
  497. // ERR_ATTRIBUTE_PARAM_SIDE_EFFECT
  498. if ((flagsToInclude & hlsl::options::DriverOption) && opts.InputFile.empty()) {
  499. // Input file is required in arguments only for drivers; APIs take this through an argument.
  500. errors << "Required input file argument is missing. use -help to get more information.";
  501. return 1;
  502. }
  503. if (opts.OutputHeader.empty() && !opts.VariableName.empty()) {
  504. errors << "Cannot specify a header variable name when not writing a header.";
  505. return 1;
  506. }
  507. if (!opts.Preprocess.empty() &&
  508. (!opts.OutputHeader.empty() || !opts.OutputObject.empty() ||
  509. !opts.OutputWarnings || !opts.OutputWarningsFile.empty())) {
  510. errors << "Preprocess cannot be specified with other options.";
  511. return 1;
  512. }
  513. if (opts.DumpBin) {
  514. if (opts.DisplayIncludeProcess || opts.AstDump) {
  515. errors << "Cannot perform actions related to sources from a binary file.";
  516. return 1;
  517. }
  518. if (opts.AllResourcesBound || opts.AvoidFlowControl ||
  519. opts.CodeGenHighLevel || opts.DebugInfo || opts.DefaultColMajor ||
  520. opts.DefaultRowMajor || opts.Defines.size() != 0 ||
  521. opts.DisableOptimizations ||
  522. !opts.EntryPoint.empty() || !opts.ForceRootSigVer.empty() ||
  523. opts.PreferFlowControl || !opts.TargetProfile.empty()) {
  524. errors << "Cannot specify compilation options when reading a binary file.";
  525. return 1;
  526. }
  527. }
  528. if ((flagsToInclude & hlsl::options::DriverOption) &&
  529. opts.TargetProfile.empty() && !opts.DumpBin && opts.Preprocess.empty() && !opts.RecompileFromBinary) {
  530. // Target profile is required in arguments only for drivers when compiling;
  531. // APIs take this through an argument.
  532. errors << "Target profile argument is missing";
  533. return 1;
  534. }
  535. if (!opts.DebugNameForBinary && !opts.DebugNameForSource) {
  536. opts.DebugNameForSource = true;
  537. }
  538. else if (opts.DebugNameForBinary && opts.DebugNameForSource) {
  539. errors << "Cannot specify both /Zss and /Zsb";
  540. return 1;
  541. }
  542. if (opts.IsLibraryProfile() && Minor == 0xF) {
  543. // Disable validation for offline link only target
  544. opts.DisableValidation = true;
  545. }
  546. // Disable lib_6_1 and lib_6_2 if /Vd is not present
  547. if (opts.IsLibraryProfile() && (Major < 6 || (Major == 6 && Minor < 3))) {
  548. if (!opts.DisableValidation) {
  549. errors << "Must disable validation for unsupported lib_6_1 or lib_6_2 "
  550. "targets.";
  551. return 1;
  552. }
  553. }
  554. // SPIRV Change Starts
  555. #ifdef ENABLE_SPIRV_CODEGEN
  556. opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
  557. opts.SpirvOptions.invertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
  558. opts.SpirvOptions.invertW = Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false);
  559. opts.SpirvOptions.useGlLayout = Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false);
  560. opts.SpirvOptions.useDxLayout = Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false);
  561. opts.SpirvOptions.enableReflect = Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false);
  562. opts.SpirvOptions.noWarnIgnoredFeatures = Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false);
  563. opts.SpirvOptions.noWarnEmulatedFeatures = Args.hasFlag(OPT_Wno_vk_emulated_features, OPT_INVALID, false);
  564. if (!handleVkShiftArgs(Args, OPT_fvk_b_shift, "b", &opts.SpirvOptions.bShift, errors) ||
  565. !handleVkShiftArgs(Args, OPT_fvk_t_shift, "t", &opts.SpirvOptions.tShift, errors) ||
  566. !handleVkShiftArgs(Args, OPT_fvk_s_shift, "s", &opts.SpirvOptions.sShift, errors) ||
  567. !handleVkShiftArgs(Args, OPT_fvk_u_shift, "u", &opts.SpirvOptions.uShift, errors))
  568. return 1;
  569. opts.SpirvOptions.bindRegister = Args.getAllArgValues(OPT_fvk_bind_register);
  570. opts.SpirvOptions.stageIoOrder = Args.getLastArgValue(OPT_fvk_stage_io_order_EQ, "decl");
  571. if (opts.SpirvOptions.stageIoOrder != "alpha" && opts.SpirvOptions.stageIoOrder != "decl") {
  572. errors << "unknown Vulkan stage I/O location assignment order: "
  573. << opts.SpirvOptions.stageIoOrder;
  574. return 1;
  575. }
  576. for (const Arg *A : Args.filtered(OPT_fspv_extension_EQ)) {
  577. opts.SpirvOptions.allowedExtensions.push_back(A->getValue());
  578. }
  579. opts.SpirvOptions.debugInfoFile = opts.SpirvOptions.debugInfoSource = false;
  580. opts.SpirvOptions.debugInfoLine = opts.SpirvOptions.debugInfoTool = false;
  581. if (Args.hasArg(OPT_fspv_debug_EQ)) {
  582. opts.DebugInfo = true;
  583. for (const Arg *A : Args.filtered(OPT_fspv_debug_EQ)) {
  584. const llvm::StringRef v = A->getValue();
  585. if (v == "file") {
  586. opts.SpirvOptions.debugInfoFile = true;
  587. } else if (v == "source") {
  588. opts.SpirvOptions.debugInfoFile = true;
  589. opts.SpirvOptions.debugInfoSource = true;
  590. } else if (v == "line") {
  591. opts.SpirvOptions.debugInfoFile = true;
  592. opts.SpirvOptions.debugInfoSource = true;
  593. opts.SpirvOptions.debugInfoLine = true;
  594. } else if (v == "tool") {
  595. opts.SpirvOptions.debugInfoTool = true;
  596. } else {
  597. errors << "unknown SPIR-V debug info control parameter: " << v;
  598. return 1;
  599. }
  600. }
  601. } else if (opts.DebugInfo) {
  602. // By default turn on all categories
  603. opts.SpirvOptions.debugInfoFile = opts.SpirvOptions.debugInfoSource = true;
  604. opts.SpirvOptions.debugInfoLine = opts.SpirvOptions.debugInfoTool = true;
  605. }
  606. opts.SpirvOptions.targetEnv = Args.getLastArgValue(OPT_fspv_target_env_EQ, "vulkan1.0");
  607. // Handle -Oconfig=<comma-separated-list> option.
  608. uint32_t numOconfigs = 0;
  609. for (const Arg *A : Args.filtered(OPT_Oconfig)) {
  610. ++numOconfigs;
  611. if (numOconfigs > 1) {
  612. errors << "-Oconfig should not be specified more than once";
  613. return 1;
  614. }
  615. if (Args.getLastArg(OPT_O0, OPT_O1, OPT_O2, OPT_O3, OPT_O4)) {
  616. errors << "-Oconfig should not be used together with -O";
  617. return 1;
  618. }
  619. for (const auto v : A->getValues()) {
  620. opts.SpirvOptions.optConfig.push_back(v);
  621. }
  622. }
  623. #else
  624. if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
  625. Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
  626. Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false) ||
  627. Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false) ||
  628. Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false) ||
  629. Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
  630. Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
  631. Args.hasFlag(OPT_Wno_vk_emulated_features, OPT_INVALID, false) ||
  632. !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
  633. !Args.getLastArgValue(OPT_fspv_debug_EQ).empty() ||
  634. !Args.getLastArgValue(OPT_fspv_extension_EQ).empty() ||
  635. !Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
  636. !Args.getLastArgValue(OPT_Oconfig).empty() ||
  637. !Args.getLastArgValue(OPT_fvk_bind_register).empty() ||
  638. !Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
  639. !Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
  640. !Args.getLastArgValue(OPT_fvk_s_shift).empty() ||
  641. !Args.getLastArgValue(OPT_fvk_u_shift).empty()) {
  642. errors << "SPIR-V CodeGen not available. "
  643. "Please recompile with -DENABLE_SPIRV_CODEGEN=ON.";
  644. return 1;
  645. }
  646. #endif // ENABLE_SPIRV_CODEGEN
  647. // SPIRV Change Ends
  648. opts.Args = std::move(Args);
  649. return 0;
  650. }
  651. /// Sets up the specified DxcDllSupport instance as per the given options.
  652. int SetupDxcDllSupport(const DxcOpts &opts, dxc::DxcDllSupport &dxcSupport,
  653. llvm::raw_ostream &errors) {
  654. if (!opts.ExternalLib.empty()) {
  655. DXASSERT(!opts.ExternalFn.empty(), "else ReadDxcOpts should have failed");
  656. StringRefUtf16 externalLib(opts.ExternalLib);
  657. HRESULT hrLoad =
  658. dxcSupport.InitializeForDll(externalLib, opts.ExternalFn.data());
  659. if (DXC_FAILED(hrLoad)) {
  660. errors << "Unable to load support for external DLL " << opts.ExternalLib
  661. << " with function " << opts.ExternalFn << " - error 0x";
  662. errors.write_hex(hrLoad);
  663. return 1;
  664. }
  665. }
  666. return 0;
  667. }
  668. void CopyArgsToWStrings(const InputArgList &inArgs, unsigned flagsToInclude,
  669. std::vector<std::wstring> &outArgs) {
  670. ArgStringList stringList;
  671. for (const Arg *A : inArgs) {
  672. if (A->getOption().hasFlag(flagsToInclude)) {
  673. A->renderAsInput(inArgs, stringList);
  674. }
  675. }
  676. for (const char *argText : stringList) {
  677. outArgs.emplace_back(Unicode::UTF8ToUTF16StringOrThrow(argText));
  678. }
  679. }
  680. } } // hlsl::options