xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "HLSL.h"
1081ad6265SDimitry Andric #include "CommonArgs.h"
1181ad6265SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
1281ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h"
1381ad6265SDimitry Andric #include "llvm/ADT/Triple.h"
1481ad6265SDimitry Andric 
1581ad6265SDimitry Andric using namespace clang::driver;
1681ad6265SDimitry Andric using namespace clang::driver::tools;
1781ad6265SDimitry Andric using namespace clang::driver::toolchains;
1881ad6265SDimitry Andric using namespace clang;
1981ad6265SDimitry Andric using namespace llvm::opt;
2081ad6265SDimitry Andric using namespace llvm;
2181ad6265SDimitry Andric 
2281ad6265SDimitry Andric namespace {
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric const unsigned OfflineLibMinor = 0xF;
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric bool isLegalShaderModel(Triple &T) {
2781ad6265SDimitry Andric   if (T.getOS() != Triple::OSType::ShaderModel)
2881ad6265SDimitry Andric     return false;
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric   auto Version = T.getOSVersion();
3181ad6265SDimitry Andric   if (Version.getBuild())
3281ad6265SDimitry Andric     return false;
3381ad6265SDimitry Andric   if (Version.getSubminor())
3481ad6265SDimitry Andric     return false;
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric   auto Kind = T.getEnvironment();
3781ad6265SDimitry Andric 
3881ad6265SDimitry Andric   switch (Kind) {
3981ad6265SDimitry Andric   default:
4081ad6265SDimitry Andric     return false;
4181ad6265SDimitry Andric   case Triple::EnvironmentType::Vertex:
4281ad6265SDimitry Andric   case Triple::EnvironmentType::Hull:
4381ad6265SDimitry Andric   case Triple::EnvironmentType::Domain:
4481ad6265SDimitry Andric   case Triple::EnvironmentType::Geometry:
4581ad6265SDimitry Andric   case Triple::EnvironmentType::Pixel:
4681ad6265SDimitry Andric   case Triple::EnvironmentType::Compute: {
4781ad6265SDimitry Andric     VersionTuple MinVer(4, 0);
4881ad6265SDimitry Andric     return MinVer <= Version;
4981ad6265SDimitry Andric   } break;
5081ad6265SDimitry Andric   case Triple::EnvironmentType::Library: {
5181ad6265SDimitry Andric     VersionTuple SM6x(6, OfflineLibMinor);
5281ad6265SDimitry Andric     if (Version == SM6x)
5381ad6265SDimitry Andric       return true;
5481ad6265SDimitry Andric 
5581ad6265SDimitry Andric     VersionTuple MinVer(6, 3);
5681ad6265SDimitry Andric     return MinVer <= Version;
5781ad6265SDimitry Andric   } break;
5881ad6265SDimitry Andric   case Triple::EnvironmentType::Amplification:
5981ad6265SDimitry Andric   case Triple::EnvironmentType::Mesh: {
6081ad6265SDimitry Andric     VersionTuple MinVer(6, 5);
6181ad6265SDimitry Andric     return MinVer <= Version;
6281ad6265SDimitry Andric   } break;
6381ad6265SDimitry Andric   }
6481ad6265SDimitry Andric   return false;
6581ad6265SDimitry Andric }
6681ad6265SDimitry Andric 
67*bdd1243dSDimitry Andric std::optional<std::string> tryParseProfile(StringRef Profile) {
6881ad6265SDimitry Andric   // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
6981ad6265SDimitry Andric   SmallVector<StringRef, 3> Parts;
7081ad6265SDimitry Andric   Profile.split(Parts, "_");
7181ad6265SDimitry Andric   if (Parts.size() != 3)
72*bdd1243dSDimitry Andric     return std::nullopt;
7381ad6265SDimitry Andric 
7481ad6265SDimitry Andric   Triple::EnvironmentType Kind =
7581ad6265SDimitry Andric       StringSwitch<Triple::EnvironmentType>(Parts[0])
7681ad6265SDimitry Andric           .Case("ps", Triple::EnvironmentType::Pixel)
7781ad6265SDimitry Andric           .Case("vs", Triple::EnvironmentType::Vertex)
7881ad6265SDimitry Andric           .Case("gs", Triple::EnvironmentType::Geometry)
7981ad6265SDimitry Andric           .Case("hs", Triple::EnvironmentType::Hull)
8081ad6265SDimitry Andric           .Case("ds", Triple::EnvironmentType::Domain)
8181ad6265SDimitry Andric           .Case("cs", Triple::EnvironmentType::Compute)
8281ad6265SDimitry Andric           .Case("lib", Triple::EnvironmentType::Library)
8381ad6265SDimitry Andric           .Case("ms", Triple::EnvironmentType::Mesh)
8481ad6265SDimitry Andric           .Case("as", Triple::EnvironmentType::Amplification)
8581ad6265SDimitry Andric           .Default(Triple::EnvironmentType::UnknownEnvironment);
8681ad6265SDimitry Andric   if (Kind == Triple::EnvironmentType::UnknownEnvironment)
87*bdd1243dSDimitry Andric     return std::nullopt;
8881ad6265SDimitry Andric 
8981ad6265SDimitry Andric   unsigned long long Major = 0;
9081ad6265SDimitry Andric   if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
91*bdd1243dSDimitry Andric     return std::nullopt;
9281ad6265SDimitry Andric 
9381ad6265SDimitry Andric   unsigned long long Minor = 0;
9481ad6265SDimitry Andric   if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library)
9581ad6265SDimitry Andric     Minor = OfflineLibMinor;
9681ad6265SDimitry Andric   else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
97*bdd1243dSDimitry Andric     return std::nullopt;
9881ad6265SDimitry Andric 
9981ad6265SDimitry Andric   // dxil-unknown-shadermodel-hull
10081ad6265SDimitry Andric   llvm::Triple T;
10181ad6265SDimitry Andric   T.setArch(Triple::ArchType::dxil);
10281ad6265SDimitry Andric   T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() +
10381ad6265SDimitry Andric               VersionTuple(Major, Minor).getAsString());
10481ad6265SDimitry Andric   T.setEnvironment(Kind);
10581ad6265SDimitry Andric   if (isLegalShaderModel(T))
10681ad6265SDimitry Andric     return T.getTriple();
10781ad6265SDimitry Andric   else
108*bdd1243dSDimitry Andric     return std::nullopt;
10981ad6265SDimitry Andric }
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
11281ad6265SDimitry Andric   VersionTuple Version;
11381ad6265SDimitry Andric   if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
11481ad6265SDimitry Andric       Version.getSubminor() || !Version.getMinor()) {
11581ad6265SDimitry Andric     D.Diag(diag::err_drv_invalid_format_dxil_validator_version)
11681ad6265SDimitry Andric         << ValVersionStr;
11781ad6265SDimitry Andric     return false;
11881ad6265SDimitry Andric   }
11981ad6265SDimitry Andric 
12081ad6265SDimitry Andric   uint64_t Major = Version.getMajor();
12181ad6265SDimitry Andric   uint64_t Minor = *Version.getMinor();
12281ad6265SDimitry Andric   if (Major == 0 && Minor != 0) {
12381ad6265SDimitry Andric     D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr;
12481ad6265SDimitry Andric     return false;
12581ad6265SDimitry Andric   }
12681ad6265SDimitry Andric   VersionTuple MinVer(1, 0);
12781ad6265SDimitry Andric   if (Version < MinVer) {
12881ad6265SDimitry Andric     D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr;
12981ad6265SDimitry Andric     return false;
13081ad6265SDimitry Andric   }
13181ad6265SDimitry Andric   return true;
13281ad6265SDimitry Andric }
13381ad6265SDimitry Andric 
13481ad6265SDimitry Andric } // namespace
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric /// DirectX Toolchain
13781ad6265SDimitry Andric HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
13881ad6265SDimitry Andric                              const ArgList &Args)
13981ad6265SDimitry Andric     : ToolChain(D, Triple, Args) {}
14081ad6265SDimitry Andric 
141*bdd1243dSDimitry Andric std::optional<std::string>
14281ad6265SDimitry Andric clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
14381ad6265SDimitry Andric     StringRef TargetProfile) {
14481ad6265SDimitry Andric   return tryParseProfile(TargetProfile);
14581ad6265SDimitry Andric }
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric DerivedArgList *
14881ad6265SDimitry Andric HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
14981ad6265SDimitry Andric                              Action::OffloadKind DeviceOffloadKind) const {
15081ad6265SDimitry Andric   DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
15181ad6265SDimitry Andric 
15281ad6265SDimitry Andric   const OptTable &Opts = getDriver().getOpts();
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric   for (Arg *A : Args) {
15581ad6265SDimitry Andric     if (A->getOption().getID() == options::OPT_dxil_validator_version) {
15681ad6265SDimitry Andric       StringRef ValVerStr = A->getValue();
15781ad6265SDimitry Andric       std::string ErrorMsg;
15881ad6265SDimitry Andric       if (!isLegalValidatorVersion(ValVerStr, getDriver()))
15981ad6265SDimitry Andric         continue;
16081ad6265SDimitry Andric     }
161*bdd1243dSDimitry Andric     if (A->getOption().getID() == options::OPT_dxc_entrypoint) {
162*bdd1243dSDimitry Andric       DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint),
163*bdd1243dSDimitry Andric                           A->getValue());
164*bdd1243dSDimitry Andric       A->claim();
165*bdd1243dSDimitry Andric       continue;
166*bdd1243dSDimitry Andric     }
167*bdd1243dSDimitry Andric     if (A->getOption().getID() == options::OPT__SLASH_O) {
168*bdd1243dSDimitry Andric       StringRef OStr = A->getValue();
169*bdd1243dSDimitry Andric       if (OStr == "d") {
170*bdd1243dSDimitry Andric         DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0));
171*bdd1243dSDimitry Andric         A->claim();
172*bdd1243dSDimitry Andric         continue;
173*bdd1243dSDimitry Andric       } else {
174*bdd1243dSDimitry Andric         DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr);
175*bdd1243dSDimitry Andric         A->claim();
176*bdd1243dSDimitry Andric         continue;
177*bdd1243dSDimitry Andric       }
178*bdd1243dSDimitry Andric     }
17981ad6265SDimitry Andric     if (A->getOption().getID() == options::OPT_emit_pristine_llvm) {
18081ad6265SDimitry Andric       // Translate fcgl into -S -emit-llvm and -disable-llvm-passes.
18181ad6265SDimitry Andric       DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
18281ad6265SDimitry Andric       DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm));
18381ad6265SDimitry Andric       DAL->AddFlagArg(nullptr,
18481ad6265SDimitry Andric                       Opts.getOption(options::OPT_disable_llvm_passes));
18581ad6265SDimitry Andric       A->claim();
18681ad6265SDimitry Andric       continue;
18781ad6265SDimitry Andric     }
18881ad6265SDimitry Andric     DAL->append(A);
18981ad6265SDimitry Andric   }
190*bdd1243dSDimitry Andric 
191*bdd1243dSDimitry Andric   if (DAL->hasArg(options::OPT_o)) {
192*bdd1243dSDimitry Andric     // When run the whole pipeline.
193*bdd1243dSDimitry Andric     if (!DAL->hasArg(options::OPT_emit_llvm))
194*bdd1243dSDimitry Andric       // Emit obj if write to file.
195*bdd1243dSDimitry Andric       DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj));
196*bdd1243dSDimitry Andric   } else
197*bdd1243dSDimitry Andric     DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-");
198*bdd1243dSDimitry Andric 
19981ad6265SDimitry Andric   // Add default validator version if not set.
20081ad6265SDimitry Andric   // TODO: remove this once read validator version from validator.
20181ad6265SDimitry Andric   if (!DAL->hasArg(options::OPT_dxil_validator_version)) {
20281ad6265SDimitry Andric     const StringRef DefaultValidatorVer = "1.7";
20381ad6265SDimitry Andric     DAL->AddSeparateArg(nullptr,
20481ad6265SDimitry Andric                         Opts.getOption(options::OPT_dxil_validator_version),
20581ad6265SDimitry Andric                         DefaultValidatorVer);
20681ad6265SDimitry Andric   }
207*bdd1243dSDimitry Andric   if (!DAL->hasArg(options::OPT_O_Group)) {
208*bdd1243dSDimitry Andric     DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3");
209*bdd1243dSDimitry Andric   }
21081ad6265SDimitry Andric   // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and
21181ad6265SDimitry Andric   // shader model 6.2.
212*bdd1243dSDimitry Andric   // See: https://github.com/llvm/llvm-project/issues/57876
21381ad6265SDimitry Andric   return DAL;
21481ad6265SDimitry Andric }
215