HLSL.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. //===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "HLSL.h"
  9. #include "CommonArgs.h"
  10. #include "clang/Driver/DriverDiagnostic.h"
  11. #include "llvm/ADT/StringSwitch.h"
  12. #include "llvm/ADT/Triple.h"
  13. using namespace clang::driver;
  14. using namespace clang::driver::tools;
  15. using namespace clang::driver::toolchains;
  16. using namespace clang;
  17. using namespace llvm::opt;
  18. using namespace llvm;
  19. namespace {
  20. const unsigned OfflineLibMinor = 0xF;
  21. bool isLegalShaderModel(Triple &T) {
  22. if (T.getOS() != Triple::OSType::ShaderModel)
  23. return false;
  24. auto Version = T.getOSVersion();
  25. if (Version.getBuild())
  26. return false;
  27. if (Version.getSubminor())
  28. return false;
  29. auto Kind = T.getEnvironment();
  30. switch (Kind) {
  31. default:
  32. return false;
  33. case Triple::EnvironmentType::Vertex:
  34. case Triple::EnvironmentType::Hull:
  35. case Triple::EnvironmentType::Domain:
  36. case Triple::EnvironmentType::Geometry:
  37. case Triple::EnvironmentType::Pixel:
  38. case Triple::EnvironmentType::Compute: {
  39. VersionTuple MinVer(4, 0);
  40. return MinVer <= Version;
  41. } break;
  42. case Triple::EnvironmentType::Library: {
  43. VersionTuple SM6x(6, OfflineLibMinor);
  44. if (Version == SM6x)
  45. return true;
  46. VersionTuple MinVer(6, 3);
  47. return MinVer <= Version;
  48. } break;
  49. case Triple::EnvironmentType::Amplification:
  50. case Triple::EnvironmentType::Mesh: {
  51. VersionTuple MinVer(6, 5);
  52. return MinVer <= Version;
  53. } break;
  54. }
  55. return false;
  56. }
  57. std::optional<std::string> tryParseProfile(StringRef Profile) {
  58. // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
  59. SmallVector<StringRef, 3> Parts;
  60. Profile.split(Parts, "_");
  61. if (Parts.size() != 3)
  62. return std::nullopt;
  63. Triple::EnvironmentType Kind =
  64. StringSwitch<Triple::EnvironmentType>(Parts[0])
  65. .Case("ps", Triple::EnvironmentType::Pixel)
  66. .Case("vs", Triple::EnvironmentType::Vertex)
  67. .Case("gs", Triple::EnvironmentType::Geometry)
  68. .Case("hs", Triple::EnvironmentType::Hull)
  69. .Case("ds", Triple::EnvironmentType::Domain)
  70. .Case("cs", Triple::EnvironmentType::Compute)
  71. .Case("lib", Triple::EnvironmentType::Library)
  72. .Case("ms", Triple::EnvironmentType::Mesh)
  73. .Case("as", Triple::EnvironmentType::Amplification)
  74. .Default(Triple::EnvironmentType::UnknownEnvironment);
  75. if (Kind == Triple::EnvironmentType::UnknownEnvironment)
  76. return std::nullopt;
  77. unsigned long long Major = 0;
  78. if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
  79. return std::nullopt;
  80. unsigned long long Minor = 0;
  81. if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library)
  82. Minor = OfflineLibMinor;
  83. else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
  84. return std::nullopt;
  85. // dxil-unknown-shadermodel-hull
  86. llvm::Triple T;
  87. T.setArch(Triple::ArchType::dxil);
  88. T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() +
  89. VersionTuple(Major, Minor).getAsString());
  90. T.setEnvironment(Kind);
  91. if (isLegalShaderModel(T))
  92. return T.getTriple();
  93. else
  94. return std::nullopt;
  95. }
  96. bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
  97. VersionTuple Version;
  98. if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
  99. Version.getSubminor() || !Version.getMinor()) {
  100. D.Diag(diag::err_drv_invalid_format_dxil_validator_version)
  101. << ValVersionStr;
  102. return false;
  103. }
  104. uint64_t Major = Version.getMajor();
  105. uint64_t Minor = *Version.getMinor();
  106. if (Major == 0 && Minor != 0) {
  107. D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr;
  108. return false;
  109. }
  110. VersionTuple MinVer(1, 0);
  111. if (Version < MinVer) {
  112. D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr;
  113. return false;
  114. }
  115. return true;
  116. }
  117. } // namespace
  118. /// DirectX Toolchain
  119. HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
  120. const ArgList &Args)
  121. : ToolChain(D, Triple, Args) {}
  122. std::optional<std::string>
  123. clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
  124. StringRef TargetProfile) {
  125. return tryParseProfile(TargetProfile);
  126. }
  127. DerivedArgList *
  128. HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
  129. Action::OffloadKind DeviceOffloadKind) const {
  130. DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
  131. const OptTable &Opts = getDriver().getOpts();
  132. for (Arg *A : Args) {
  133. if (A->getOption().getID() == options::OPT_dxil_validator_version) {
  134. StringRef ValVerStr = A->getValue();
  135. std::string ErrorMsg;
  136. if (!isLegalValidatorVersion(ValVerStr, getDriver()))
  137. continue;
  138. }
  139. if (A->getOption().getID() == options::OPT_dxc_entrypoint) {
  140. DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint),
  141. A->getValue());
  142. A->claim();
  143. continue;
  144. }
  145. if (A->getOption().getID() == options::OPT__SLASH_O) {
  146. StringRef OStr = A->getValue();
  147. if (OStr == "d") {
  148. DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0));
  149. A->claim();
  150. continue;
  151. } else {
  152. DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr);
  153. A->claim();
  154. continue;
  155. }
  156. }
  157. if (A->getOption().getID() == options::OPT_emit_pristine_llvm) {
  158. // Translate fcgl into -S -emit-llvm and -disable-llvm-passes.
  159. DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
  160. DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm));
  161. DAL->AddFlagArg(nullptr,
  162. Opts.getOption(options::OPT_disable_llvm_passes));
  163. A->claim();
  164. continue;
  165. }
  166. DAL->append(A);
  167. }
  168. if (DAL->hasArg(options::OPT_o)) {
  169. // When run the whole pipeline.
  170. if (!DAL->hasArg(options::OPT_emit_llvm))
  171. // Emit obj if write to file.
  172. DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj));
  173. } else
  174. DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-");
  175. // Add default validator version if not set.
  176. // TODO: remove this once read validator version from validator.
  177. if (!DAL->hasArg(options::OPT_dxil_validator_version)) {
  178. const StringRef DefaultValidatorVer = "1.7";
  179. DAL->AddSeparateArg(nullptr,
  180. Opts.getOption(options::OPT_dxil_validator_version),
  181. DefaultValidatorVer);
  182. }
  183. if (!DAL->hasArg(options::OPT_O_Group)) {
  184. DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3");
  185. }
  186. // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and
  187. // shader model 6.2.
  188. // See: https://github.com/llvm/llvm-project/issues/57876
  189. return DAL;
  190. }