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