HLSLOptions.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. using namespace llvm::opt;
  20. using namespace dxc;
  21. using namespace hlsl;
  22. using namespace hlsl::options;
  23. #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
  24. #include "dxc/Support/HLSLOptions.inc"
  25. #undef PREFIX
  26. static const OptTable::Info HlslInfoTable[] = {
  27. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  28. HELPTEXT, METAVAR) \
  29. { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
  30. FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
  31. #include "dxc/Support/HLSLOptions.inc"
  32. #undef OPTION
  33. };
  34. namespace {
  35. class HlslOptTable : public OptTable {
  36. public:
  37. HlslOptTable()
  38. : OptTable(HlslInfoTable, llvm::array_lengthof(HlslInfoTable)) {}
  39. };
  40. }
  41. static HlslOptTable g_HlslOptTable;
  42. const OptTable * hlsl::options::getHlslOptTable() {
  43. return &g_HlslOptTable;
  44. }
  45. void DxcDefines::push_back(llvm::StringRef value) {
  46. // Skip empty defines.
  47. if (value.size() > 0) {
  48. DefineStrings.push_back(value);
  49. }
  50. }
  51. UINT32 DxcDefines::ComputeNumberOfWCharsNeededForDefines() {
  52. UINT32 wcharSize = 0;
  53. for (llvm::StringRef &S : DefineStrings) {
  54. DXASSERT(S.size() > 0,
  55. "else DxcDefines::push_back should not have added this");
  56. const int utf16Length = ::MultiByteToWideChar(
  57. CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(), nullptr, 0);
  58. IFTARG(utf16Length != 0);
  59. wcharSize += utf16Length + 1; // adding null terminated character
  60. }
  61. return wcharSize;
  62. }
  63. void DxcDefines::BuildDefines() {
  64. // Calculate and prepare the size of the backing buffer.
  65. DXASSERT(DefineValues == nullptr, "else DxcDefines is already built");
  66. UINT32 wcharSize = ComputeNumberOfWCharsNeededForDefines();
  67. DefineValues = new wchar_t[wcharSize];
  68. DefineVector.resize(DefineStrings.size());
  69. // Build up the define structures while filling in the backing buffer.
  70. UINT32 remaining = wcharSize;
  71. LPWSTR pWriteCursor = DefineValues;
  72. for (size_t i = 0; i < DefineStrings.size(); ++i) {
  73. llvm::StringRef &S = DefineStrings[i];
  74. DxcDefine &D = DefineVector[i];
  75. const int utf16Length =
  76. ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(),
  77. pWriteCursor, remaining);
  78. DXASSERT(utf16Length > 0,
  79. "else it should have failed during size calculation");
  80. LPWSTR pDefineEnd = pWriteCursor + utf16Length;
  81. D.Name = pWriteCursor;
  82. LPWSTR pEquals = std::find(pWriteCursor, pDefineEnd, L'=');
  83. if (pEquals == pDefineEnd) {
  84. D.Value = nullptr;
  85. } else {
  86. *pEquals = L'\0';
  87. D.Value = pEquals + 1;
  88. }
  89. // Advance past converted characters and include the null terminator.
  90. pWriteCursor += utf16Length;
  91. *pWriteCursor = L'\0';
  92. ++pWriteCursor;
  93. DXASSERT(pWriteCursor <= DefineValues + wcharSize,
  94. "else this function is calculating this incorrectly");
  95. remaining -= (utf16Length + 1);
  96. }
  97. }
  98. bool DxcOpts::IsRootSignatureProfile() {
  99. return TargetProfile == "rootsig_1_0" ||
  100. TargetProfile == "rootsig_1_1";
  101. }
  102. MainArgs::MainArgs(int argc, const wchar_t **argv, int skipArgCount) {
  103. if (argc > skipArgCount) {
  104. Utf8StringVector.reserve(argc - skipArgCount);
  105. Utf8CharPtrVector.reserve(argc - skipArgCount);
  106. for (int i = skipArgCount; i < argc; ++i) {
  107. Utf8StringVector.emplace_back(Unicode::UTF16ToUTF8StringOrThrow(argv[i]));
  108. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  109. }
  110. }
  111. }
  112. MainArgs::MainArgs(llvm::ArrayRef<llvm::StringRef> args) {
  113. Utf8StringVector.reserve(args.size());
  114. Utf8CharPtrVector.reserve(args.size());
  115. for (llvm::StringRef str : args) {
  116. Utf8StringVector.emplace_back(str.str());
  117. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  118. }
  119. }
  120. MainArgs& MainArgs::operator=(const MainArgs &other) {
  121. Utf8StringVector.clear();
  122. Utf8CharPtrVector.clear();
  123. for (const std::string &str : other.Utf8StringVector) {
  124. Utf8StringVector.emplace_back(str);
  125. Utf8CharPtrVector.push_back(Utf8StringVector.back().data());
  126. }
  127. return *this;
  128. }
  129. StringRefUtf16::StringRefUtf16(llvm::StringRef value) {
  130. if (!value.empty())
  131. m_value = Unicode::UTF8ToUTF16StringOrThrow(value.data());
  132. }
  133. namespace hlsl {
  134. namespace options {
  135. /// Reads all options from the given argument strings, populates opts, and
  136. /// validates reporting errors and warnings.
  137. int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
  138. const MainArgs &argStrings, DxcOpts &opts,
  139. llvm::raw_ostream &errors) {
  140. DXASSERT_NOMSG(optionTable != nullptr);
  141. unsigned missingArgIndex = 0, missingArgCount = 0;
  142. InputArgList Args = optionTable->ParseArgs(
  143. argStrings.getArrayRef(), missingArgIndex, missingArgCount, flagsToInclude);
  144. opts.ShowHelp = Args.hasFlag(OPT_help, OPT_INVALID, false);
  145. if (opts.ShowHelp) {
  146. return 0;
  147. }
  148. if (missingArgCount) {
  149. errors << "Argument to '" << Args.getArgString(missingArgIndex)
  150. << "' is missing.";
  151. return 1;
  152. }
  153. if (!Args.hasArg(hlsl::options::OPT_Qunused_arguments)) {
  154. for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
  155. errors << "Unknown argument: '" << A->getAsString(Args).c_str() << "'";
  156. return 1;
  157. }
  158. }
  159. // Add macros from the command line.
  160. for (const Arg *A : Args.filtered(OPT_D)) {
  161. opts.Defines.push_back(A->getValue());
  162. // If supporting OPT_U and included in filter, handle undefs.
  163. }
  164. opts.Defines.BuildDefines(); // Must be called after all defines are pushed back
  165. opts.ExternalLib = Args.getLastArgValue(OPT_external_lib);
  166. opts.ExternalFn = Args.getLastArgValue(OPT_external_fn);
  167. // Verify consistency for external library support.
  168. if (opts.ExternalLib.empty()) {
  169. if (!opts.ExternalFn.empty()) {
  170. errors << "External function cannot be specified without an external "
  171. "library name.";
  172. return 1;
  173. }
  174. }
  175. else {
  176. if (opts.ExternalFn.empty()) {
  177. errors << "External library name requires specifying an external "
  178. "function name.";
  179. return 1;
  180. }
  181. }
  182. DXASSERT(opts.ExternalLib.empty() == opts.ExternalFn.empty(),
  183. "else flow above is incorrect");
  184. // when no-warnings option is present, do not output warnings.
  185. opts.OutputWarnings = Args.hasFlag(OPT_INVALID, OPT_no_warnings, true);
  186. opts.EntryPoint = Args.getLastArgValue(OPT_entrypoint);
  187. // Entry point is required in arguments only for drivers; APIs take this through an argument.
  188. // The value should default to 'main', but we let the caller apply this policy.
  189. opts.TargetProfile = Args.getLastArgValue(OPT_target_profile);
  190. llvm::StringRef ver = Args.getLastArgValue(OPT_hlsl_version);
  191. opts.HLSL2015 = opts.HLSL2016 = opts.HLSL2017 = false;
  192. if (ver.empty() || ver == "2016") { opts.HLSL2016 = true; } // Default to 2016
  193. else if (ver == "2015") { opts.HLSL2015 = true; }
  194. else if (ver == "2017") { opts.HLSL2017 = true; }
  195. else {
  196. errors << "Unknown HLSL version";
  197. return 1;
  198. }
  199. if (opts.HLSL2015 && !(flagsToInclude & HlslFlags::ISenseOption)) {
  200. errors << "HLSL Version 2015 is only supported for language services";
  201. return 1;
  202. }
  203. // AssemblyCodeHex not supported (Fx)
  204. // OutputLibrary not supported (Fl)
  205. opts.AssemblyCode = Args.getLastArgValue(OPT_Fc);
  206. opts.DebugFile = Args.getLastArgValue(OPT_Fd);
  207. opts.ExtractPrivateFile = Args.getLastArgValue(OPT_getprivate);
  208. opts.OutputObject = Args.getLastArgValue(OPT_Fo);
  209. opts.OutputHeader = Args.getLastArgValue(OPT_Fh);
  210. opts.OutputWarningsFile = Args.getLastArgValue(OPT_Fe);
  211. opts.UseColor = Args.hasFlag(OPT_Cc, OPT_INVALID);
  212. opts.UseInstructionNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID);
  213. opts.UseInstructionByteOffsets = Args.hasFlag(OPT_No, OPT_INVALID);
  214. opts.UseHexLiterals = Args.hasFlag(OPT_Lx, OPT_INVALID);
  215. opts.Preprocess = Args.getLastArgValue(OPT_P);
  216. opts.AstDump = Args.hasFlag(OPT_ast_dump, OPT_INVALID, false);
  217. opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false); // SPIRV change
  218. opts.CodeGenHighLevel = Args.hasFlag(OPT_fcgl, OPT_INVALID, false);
  219. opts.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, OPT_INVALID, false);
  220. opts.DebugNameForBinary = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
  221. opts.DebugNameForSource = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
  222. opts.VariableName = Args.getLastArgValue(OPT_Vn);
  223. opts.InputFile = Args.getLastArgValue(OPT_INPUT);
  224. opts.ForceRootSigVer = Args.getLastArgValue(OPT_force_rootsig_ver);
  225. opts.PrivateSource = Args.getLastArgValue(OPT_setprivate);
  226. opts.RootSignatureSource = Args.getLastArgValue(OPT_setrootsignature);
  227. opts.VerifyRootSignatureSource = Args.getLastArgValue(OPT_verifyrootsignature);
  228. opts.RootSignatureDefine = Args.getLastArgValue(OPT_rootsig_define);
  229. if (!opts.ForceRootSigVer.empty() && opts.ForceRootSigVer != "rootsig_1_0" &&
  230. opts.ForceRootSigVer != "rootsig_1_1") {
  231. errors << "Unsupported value '" << opts.ForceRootSigVer
  232. << "' for root signature profile.";
  233. return 1;
  234. }
  235. opts.IEEEStrict = Args.hasFlag(OPT_Gis, OPT_INVALID, false);
  236. if (Arg *A = Args.getLastArg(OPT_O0, OPT_O1, OPT_O2, OPT_O3)) {
  237. if (A->getOption().matches(OPT_O0))
  238. opts.OptLevel = 0;
  239. if (A->getOption().matches(OPT_O1))
  240. opts.OptLevel = 1;
  241. if (A->getOption().matches(OPT_O2))
  242. opts.OptLevel = 2;
  243. if (A->getOption().matches(OPT_O3))
  244. opts.OptLevel = 3;
  245. }
  246. else
  247. opts.OptLevel = 3;
  248. opts.OptDump = Args.hasFlag(OPT_Odump, OPT_INVALID, false);
  249. opts.DisableOptimizations = Args.hasFlag(OPT_Od, OPT_INVALID, false);
  250. if (opts.DisableOptimizations)
  251. opts.OptLevel = 0;
  252. opts.DisableValidation = Args.hasFlag(OPT_VD, OPT_INVALID, false);
  253. opts.AllResourcesBound = Args.hasFlag(OPT_all_resources_bound, OPT_INVALID, false);
  254. opts.ColorCodeAssembly = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
  255. opts.DefaultRowMajor = Args.hasFlag(OPT_Zpr, OPT_INVALID, false);
  256. opts.DefaultColMajor = Args.hasFlag(OPT_Zpc, OPT_INVALID, false);
  257. opts.DumpBin = Args.hasFlag(OPT_dumpbin, OPT_INVALID, false);
  258. opts.NotUseLegacyCBufLoad = Args.hasFlag(OPT_not_use_legacy_cbuf_load, OPT_INVALID, false);
  259. opts.PackPrefixStable = Args.hasFlag(OPT_pack_prefix_stable, OPT_INVALID, false);
  260. opts.PackOptimized = Args.hasFlag(OPT_pack_optimized, OPT_INVALID, false);
  261. opts.DisplayIncludeProcess = Args.hasFlag(OPT_H, OPT_INVALID, false);
  262. opts.WarningAsError = Args.hasFlag(OPT__SLASH_WX, OPT_INVALID, false);
  263. opts.AvoidFlowControl = Args.hasFlag(OPT_Gfa, OPT_INVALID, false);
  264. opts.PreferFlowControl = Args.hasFlag(OPT_Gfp, OPT_INVALID, false);
  265. opts.RecompileFromBinary = Args.hasFlag(OPT_recompile, OPT_INVALID, false);
  266. opts.StripDebug = Args.hasFlag(OPT_Qstrip_debug, OPT_INVALID, false);
  267. opts.StripRootSignature = Args.hasFlag(OPT_Qstrip_rootsignature, OPT_INVALID, false);
  268. opts.StripPrivate = Args.hasFlag(OPT_Qstrip_priv, OPT_INVALID, false);
  269. opts.StripReflection = Args.hasFlag(OPT_Qstrip_reflect, OPT_INVALID, false);
  270. opts.ExtractRootSignature = Args.hasFlag(OPT_extractrootsignature, OPT_INVALID, false);
  271. opts.DisassembleColorCoded = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
  272. opts.DisassembleInstNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID, false);
  273. opts.DisassembleByteOffset = Args.hasFlag(OPT_No, OPT_INVALID, false);
  274. opts.DisaseembleHex = Args.hasFlag(OPT_Lx, OPT_INVALID, false);
  275. if (opts.DefaultColMajor && opts.DefaultRowMajor) {
  276. errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
  277. return 1;
  278. }
  279. if (opts.AvoidFlowControl && opts.PreferFlowControl) {
  280. errors << "Cannot specify /Gfa and /Gfp together, use /? to get usage information";
  281. return 1;
  282. }
  283. if (opts.PackPrefixStable && opts.PackOptimized) {
  284. errors << "Cannot specify /pack_prefix_stable and /pack_optimized together, use /? to get usage information";
  285. return 1;
  286. }
  287. // TODO: more fxc option check.
  288. // ERR_RES_MAY_ALIAS_ONLY_IN_CS_5
  289. // ERR_NOT_ABLE_TO_FLATTEN on if that contain side effects
  290. // TODO: other front-end error.
  291. // ERR_RESOURCE_NOT_IN_TEMPLATE
  292. // ERR_COMPLEX_TEMPLATE_RESOURCE
  293. // ERR_RESOURCE_BIND_CONFLICT
  294. // ERR_TEMPLATE_VAR_CONFLICT
  295. // ERR_ATTRIBUTE_PARAM_SIDE_EFFECT
  296. if ((flagsToInclude & hlsl::options::DriverOption) && opts.InputFile.empty()) {
  297. // Input file is required in arguments only for drivers; APIs take this through an argument.
  298. errors << "Required input file argument is missing. use -help to get more information.";
  299. return 1;
  300. }
  301. if (opts.OutputHeader.empty() && !opts.VariableName.empty()) {
  302. errors << "Cannot specify a header variable name when not writing a header.";
  303. return 1;
  304. }
  305. if (!opts.Preprocess.empty() &&
  306. (!opts.OutputHeader.empty() || !opts.OutputObject.empty() ||
  307. !opts.OutputWarnings || !opts.OutputWarningsFile.empty())) {
  308. errors << "Preprocess cannot be specified with other options.";
  309. return 1;
  310. }
  311. if (opts.DumpBin) {
  312. if (opts.DisplayIncludeProcess || opts.AstDump) {
  313. errors << "Cannot perform actions related to sources from a binary file.";
  314. return 1;
  315. }
  316. if (opts.AllResourcesBound || opts.AvoidFlowControl ||
  317. opts.CodeGenHighLevel || opts.DebugInfo || opts.DefaultColMajor ||
  318. opts.DefaultRowMajor || opts.Defines.size() != 0 ||
  319. opts.DisableOptimizations ||
  320. !opts.EntryPoint.empty() || !opts.ForceRootSigVer.empty() ||
  321. opts.PreferFlowControl || !opts.TargetProfile.empty()) {
  322. errors << "Cannot specify compilation options when reading a binary file.";
  323. return 1;
  324. }
  325. }
  326. if ((flagsToInclude & hlsl::options::DriverOption) &&
  327. opts.TargetProfile.empty() && !opts.DumpBin && opts.Preprocess.empty() && !opts.RecompileFromBinary) {
  328. // Target profile is required in arguments only for drivers when compiling;
  329. // APIs take this through an argument.
  330. errors << "Target profile argument is missing";
  331. return 1;
  332. }
  333. if (!opts.DebugNameForBinary && !opts.DebugNameForSource) {
  334. opts.DebugNameForSource = true;
  335. }
  336. else if (opts.DebugNameForBinary && opts.DebugNameForSource) {
  337. errors << "Cannot specify both /Zss and /Zsb";
  338. return 1;
  339. }
  340. opts.Args = std::move(Args);
  341. return 0;
  342. }
  343. /// Sets up the specified DxcDllSupport instance as per the given options.
  344. int SetupDxcDllSupport(const DxcOpts &opts, dxc::DxcDllSupport &dxcSupport,
  345. llvm::raw_ostream &errors) {
  346. if (!opts.ExternalLib.empty()) {
  347. DXASSERT(!opts.ExternalFn.empty(), "else ReadDxcOpts should have failed");
  348. StringRefUtf16 externalLib(opts.ExternalLib);
  349. HRESULT hrLoad =
  350. dxcSupport.InitializeForDll(externalLib, opts.ExternalFn.data());
  351. if (DXC_FAILED(hrLoad)) {
  352. errors << "Unable to load support for external DLL " << opts.ExternalLib
  353. << " with function " << opts.ExternalFn << " - error 0x";
  354. errors.write_hex(hrLoad);
  355. return 1;
  356. }
  357. }
  358. return 0;
  359. }
  360. void CopyArgsToWStrings(const InputArgList &inArgs, unsigned flagsToInclude,
  361. std::vector<std::wstring> &outArgs) {
  362. ArgStringList stringList;
  363. for (const Arg *A : inArgs) {
  364. if (A->getOption().hasFlag(flagsToInclude)) {
  365. A->renderAsInput(inArgs, stringList);
  366. }
  367. }
  368. for (const char *argText : stringList) {
  369. outArgs.emplace_back(Unicode::UTF8ToUTF16StringOrThrow(argText));
  370. }
  371. }
  372. } } // hlsl::options