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