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