xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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"
11*06c3fb27SDimitry Andric #include "clang/Driver/Compilation.h"
1281ad6265SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
13*06c3fb27SDimitry Andric #include "clang/Driver/Job.h"
1481ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h"
15*06c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
1681ad6265SDimitry Andric 
1781ad6265SDimitry Andric using namespace clang::driver;
1881ad6265SDimitry Andric using namespace clang::driver::tools;
1981ad6265SDimitry Andric using namespace clang::driver::toolchains;
2081ad6265SDimitry Andric using namespace clang;
2181ad6265SDimitry Andric using namespace llvm::opt;
2281ad6265SDimitry Andric using namespace llvm;
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric namespace {
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric const unsigned OfflineLibMinor = 0xF;
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric bool isLegalShaderModel(Triple &T) {
2981ad6265SDimitry Andric   if (T.getOS() != Triple::OSType::ShaderModel)
3081ad6265SDimitry Andric     return false;
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric   auto Version = T.getOSVersion();
3381ad6265SDimitry Andric   if (Version.getBuild())
3481ad6265SDimitry Andric     return false;
3581ad6265SDimitry Andric   if (Version.getSubminor())
3681ad6265SDimitry Andric     return false;
3781ad6265SDimitry Andric 
3881ad6265SDimitry Andric   auto Kind = T.getEnvironment();
3981ad6265SDimitry Andric 
4081ad6265SDimitry Andric   switch (Kind) {
4181ad6265SDimitry Andric   default:
4281ad6265SDimitry Andric     return false;
4381ad6265SDimitry Andric   case Triple::EnvironmentType::Vertex:
4481ad6265SDimitry Andric   case Triple::EnvironmentType::Hull:
4581ad6265SDimitry Andric   case Triple::EnvironmentType::Domain:
4681ad6265SDimitry Andric   case Triple::EnvironmentType::Geometry:
4781ad6265SDimitry Andric   case Triple::EnvironmentType::Pixel:
4881ad6265SDimitry Andric   case Triple::EnvironmentType::Compute: {
4981ad6265SDimitry Andric     VersionTuple MinVer(4, 0);
5081ad6265SDimitry Andric     return MinVer <= Version;
5181ad6265SDimitry Andric   } break;
5281ad6265SDimitry Andric   case Triple::EnvironmentType::Library: {
5381ad6265SDimitry Andric     VersionTuple SM6x(6, OfflineLibMinor);
5481ad6265SDimitry Andric     if (Version == SM6x)
5581ad6265SDimitry Andric       return true;
5681ad6265SDimitry Andric 
5781ad6265SDimitry Andric     VersionTuple MinVer(6, 3);
5881ad6265SDimitry Andric     return MinVer <= Version;
5981ad6265SDimitry Andric   } break;
6081ad6265SDimitry Andric   case Triple::EnvironmentType::Amplification:
6181ad6265SDimitry Andric   case Triple::EnvironmentType::Mesh: {
6281ad6265SDimitry Andric     VersionTuple MinVer(6, 5);
6381ad6265SDimitry Andric     return MinVer <= Version;
6481ad6265SDimitry Andric   } break;
6581ad6265SDimitry Andric   }
6681ad6265SDimitry Andric   return false;
6781ad6265SDimitry Andric }
6881ad6265SDimitry Andric 
69bdd1243dSDimitry Andric std::optional<std::string> tryParseProfile(StringRef Profile) {
7081ad6265SDimitry Andric   // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
7181ad6265SDimitry Andric   SmallVector<StringRef, 3> Parts;
7281ad6265SDimitry Andric   Profile.split(Parts, "_");
7381ad6265SDimitry Andric   if (Parts.size() != 3)
74bdd1243dSDimitry Andric     return std::nullopt;
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric   Triple::EnvironmentType Kind =
7781ad6265SDimitry Andric       StringSwitch<Triple::EnvironmentType>(Parts[0])
7881ad6265SDimitry Andric           .Case("ps", Triple::EnvironmentType::Pixel)
7981ad6265SDimitry Andric           .Case("vs", Triple::EnvironmentType::Vertex)
8081ad6265SDimitry Andric           .Case("gs", Triple::EnvironmentType::Geometry)
8181ad6265SDimitry Andric           .Case("hs", Triple::EnvironmentType::Hull)
8281ad6265SDimitry Andric           .Case("ds", Triple::EnvironmentType::Domain)
8381ad6265SDimitry Andric           .Case("cs", Triple::EnvironmentType::Compute)
8481ad6265SDimitry Andric           .Case("lib", Triple::EnvironmentType::Library)
8581ad6265SDimitry Andric           .Case("ms", Triple::EnvironmentType::Mesh)
8681ad6265SDimitry Andric           .Case("as", Triple::EnvironmentType::Amplification)
8781ad6265SDimitry Andric           .Default(Triple::EnvironmentType::UnknownEnvironment);
8881ad6265SDimitry Andric   if (Kind == Triple::EnvironmentType::UnknownEnvironment)
89bdd1243dSDimitry Andric     return std::nullopt;
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric   unsigned long long Major = 0;
9281ad6265SDimitry Andric   if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
93bdd1243dSDimitry Andric     return std::nullopt;
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric   unsigned long long Minor = 0;
9681ad6265SDimitry Andric   if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library)
9781ad6265SDimitry Andric     Minor = OfflineLibMinor;
9881ad6265SDimitry Andric   else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
99bdd1243dSDimitry Andric     return std::nullopt;
10081ad6265SDimitry Andric 
10181ad6265SDimitry Andric   // dxil-unknown-shadermodel-hull
10281ad6265SDimitry Andric   llvm::Triple T;
10381ad6265SDimitry Andric   T.setArch(Triple::ArchType::dxil);
10481ad6265SDimitry Andric   T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() +
10581ad6265SDimitry Andric               VersionTuple(Major, Minor).getAsString());
10681ad6265SDimitry Andric   T.setEnvironment(Kind);
10781ad6265SDimitry Andric   if (isLegalShaderModel(T))
10881ad6265SDimitry Andric     return T.getTriple();
10981ad6265SDimitry Andric   else
110bdd1243dSDimitry Andric     return std::nullopt;
11181ad6265SDimitry Andric }
11281ad6265SDimitry Andric 
11381ad6265SDimitry Andric bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
11481ad6265SDimitry Andric   VersionTuple Version;
11581ad6265SDimitry Andric   if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
11681ad6265SDimitry Andric       Version.getSubminor() || !Version.getMinor()) {
11781ad6265SDimitry Andric     D.Diag(diag::err_drv_invalid_format_dxil_validator_version)
11881ad6265SDimitry Andric         << ValVersionStr;
11981ad6265SDimitry Andric     return false;
12081ad6265SDimitry Andric   }
12181ad6265SDimitry Andric 
12281ad6265SDimitry Andric   uint64_t Major = Version.getMajor();
12381ad6265SDimitry Andric   uint64_t Minor = *Version.getMinor();
12481ad6265SDimitry Andric   if (Major == 0 && Minor != 0) {
12581ad6265SDimitry Andric     D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr;
12681ad6265SDimitry Andric     return false;
12781ad6265SDimitry Andric   }
12881ad6265SDimitry Andric   VersionTuple MinVer(1, 0);
12981ad6265SDimitry Andric   if (Version < MinVer) {
13081ad6265SDimitry Andric     D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr;
13181ad6265SDimitry Andric     return false;
13281ad6265SDimitry Andric   }
13381ad6265SDimitry Andric   return true;
13481ad6265SDimitry Andric }
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric } // namespace
13781ad6265SDimitry Andric 
138*06c3fb27SDimitry Andric void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA,
139*06c3fb27SDimitry Andric                                           const InputInfo &Output,
140*06c3fb27SDimitry Andric                                           const InputInfoList &Inputs,
141*06c3fb27SDimitry Andric                                           const ArgList &Args,
142*06c3fb27SDimitry Andric                                           const char *LinkingOutput) const {
143*06c3fb27SDimitry Andric   std::string DxvPath = getToolChain().GetProgramPath("dxv");
144*06c3fb27SDimitry Andric   assert(DxvPath != "dxv" && "cannot find dxv");
145*06c3fb27SDimitry Andric 
146*06c3fb27SDimitry Andric   ArgStringList CmdArgs;
147*06c3fb27SDimitry Andric   assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
148*06c3fb27SDimitry Andric   const InputInfo &Input = Inputs[0];
149*06c3fb27SDimitry Andric   assert(Input.isFilename() && "Unexpected verify input");
150*06c3fb27SDimitry Andric   // Grabbing the output of the earlier cc1 run.
151*06c3fb27SDimitry Andric   CmdArgs.push_back(Input.getFilename());
152*06c3fb27SDimitry Andric   // Use the same name as output.
153*06c3fb27SDimitry Andric   CmdArgs.push_back("-o");
154*06c3fb27SDimitry Andric   CmdArgs.push_back(Input.getFilename());
155*06c3fb27SDimitry Andric 
156*06c3fb27SDimitry Andric   const char *Exec = Args.MakeArgString(DxvPath);
157*06c3fb27SDimitry Andric   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
158*06c3fb27SDimitry Andric                                          Exec, CmdArgs, Inputs, Input));
159*06c3fb27SDimitry Andric }
160*06c3fb27SDimitry Andric 
16181ad6265SDimitry Andric /// DirectX Toolchain
16281ad6265SDimitry Andric HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
16381ad6265SDimitry Andric                              const ArgList &Args)
164*06c3fb27SDimitry Andric     : ToolChain(D, Triple, Args) {
165*06c3fb27SDimitry Andric   if (Args.hasArg(options::OPT_dxc_validator_path_EQ))
166*06c3fb27SDimitry Andric     getProgramPaths().push_back(
167*06c3fb27SDimitry Andric         Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str());
168*06c3fb27SDimitry Andric }
169*06c3fb27SDimitry Andric 
170*06c3fb27SDimitry Andric Tool *clang::driver::toolchains::HLSLToolChain::getTool(
171*06c3fb27SDimitry Andric     Action::ActionClass AC) const {
172*06c3fb27SDimitry Andric   switch (AC) {
173*06c3fb27SDimitry Andric   case Action::BinaryAnalyzeJobClass:
174*06c3fb27SDimitry Andric     if (!Validator)
175*06c3fb27SDimitry Andric       Validator.reset(new tools::hlsl::Validator(*this));
176*06c3fb27SDimitry Andric     return Validator.get();
177*06c3fb27SDimitry Andric   default:
178*06c3fb27SDimitry Andric     return ToolChain::getTool(AC);
179*06c3fb27SDimitry Andric   }
180*06c3fb27SDimitry Andric }
18181ad6265SDimitry Andric 
182bdd1243dSDimitry Andric std::optional<std::string>
18381ad6265SDimitry Andric clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
18481ad6265SDimitry Andric     StringRef TargetProfile) {
18581ad6265SDimitry Andric   return tryParseProfile(TargetProfile);
18681ad6265SDimitry Andric }
18781ad6265SDimitry Andric 
18881ad6265SDimitry Andric DerivedArgList *
18981ad6265SDimitry Andric HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
19081ad6265SDimitry Andric                              Action::OffloadKind DeviceOffloadKind) const {
19181ad6265SDimitry Andric   DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
19281ad6265SDimitry Andric 
19381ad6265SDimitry Andric   const OptTable &Opts = getDriver().getOpts();
19481ad6265SDimitry Andric 
19581ad6265SDimitry Andric   for (Arg *A : Args) {
19681ad6265SDimitry Andric     if (A->getOption().getID() == options::OPT_dxil_validator_version) {
19781ad6265SDimitry Andric       StringRef ValVerStr = A->getValue();
19881ad6265SDimitry Andric       std::string ErrorMsg;
19981ad6265SDimitry Andric       if (!isLegalValidatorVersion(ValVerStr, getDriver()))
20081ad6265SDimitry Andric         continue;
20181ad6265SDimitry Andric     }
202bdd1243dSDimitry Andric     if (A->getOption().getID() == options::OPT_dxc_entrypoint) {
203bdd1243dSDimitry Andric       DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint),
204bdd1243dSDimitry Andric                           A->getValue());
205bdd1243dSDimitry Andric       A->claim();
206bdd1243dSDimitry Andric       continue;
207bdd1243dSDimitry Andric     }
208bdd1243dSDimitry Andric     if (A->getOption().getID() == options::OPT__SLASH_O) {
209bdd1243dSDimitry Andric       StringRef OStr = A->getValue();
210bdd1243dSDimitry Andric       if (OStr == "d") {
211bdd1243dSDimitry Andric         DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0));
212bdd1243dSDimitry Andric         A->claim();
213bdd1243dSDimitry Andric         continue;
214bdd1243dSDimitry Andric       } else {
215bdd1243dSDimitry Andric         DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr);
216bdd1243dSDimitry Andric         A->claim();
217bdd1243dSDimitry Andric         continue;
218bdd1243dSDimitry Andric       }
219bdd1243dSDimitry Andric     }
22081ad6265SDimitry Andric     if (A->getOption().getID() == options::OPT_emit_pristine_llvm) {
22181ad6265SDimitry Andric       // Translate fcgl into -S -emit-llvm and -disable-llvm-passes.
22281ad6265SDimitry Andric       DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
22381ad6265SDimitry Andric       DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm));
22481ad6265SDimitry Andric       DAL->AddFlagArg(nullptr,
22581ad6265SDimitry Andric                       Opts.getOption(options::OPT_disable_llvm_passes));
22681ad6265SDimitry Andric       A->claim();
22781ad6265SDimitry Andric       continue;
22881ad6265SDimitry Andric     }
22981ad6265SDimitry Andric     DAL->append(A);
23081ad6265SDimitry Andric   }
231bdd1243dSDimitry Andric 
232bdd1243dSDimitry Andric   if (DAL->hasArg(options::OPT_o)) {
233bdd1243dSDimitry Andric     // When run the whole pipeline.
234bdd1243dSDimitry Andric     if (!DAL->hasArg(options::OPT_emit_llvm))
235bdd1243dSDimitry Andric       // Emit obj if write to file.
236bdd1243dSDimitry Andric       DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj));
237bdd1243dSDimitry Andric   } else
238bdd1243dSDimitry Andric     DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-");
239bdd1243dSDimitry Andric 
24081ad6265SDimitry Andric   // Add default validator version if not set.
24181ad6265SDimitry Andric   // TODO: remove this once read validator version from validator.
24281ad6265SDimitry Andric   if (!DAL->hasArg(options::OPT_dxil_validator_version)) {
24381ad6265SDimitry Andric     const StringRef DefaultValidatorVer = "1.7";
24481ad6265SDimitry Andric     DAL->AddSeparateArg(nullptr,
24581ad6265SDimitry Andric                         Opts.getOption(options::OPT_dxil_validator_version),
24681ad6265SDimitry Andric                         DefaultValidatorVer);
24781ad6265SDimitry Andric   }
248bdd1243dSDimitry Andric   if (!DAL->hasArg(options::OPT_O_Group)) {
249bdd1243dSDimitry Andric     DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3");
250bdd1243dSDimitry Andric   }
25181ad6265SDimitry Andric   // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and
25281ad6265SDimitry Andric   // shader model 6.2.
253bdd1243dSDimitry Andric   // See: https://github.com/llvm/llvm-project/issues/57876
25481ad6265SDimitry Andric   return DAL;
25581ad6265SDimitry Andric }
256*06c3fb27SDimitry Andric 
257*06c3fb27SDimitry Andric bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const {
258*06c3fb27SDimitry Andric   if (Args.getLastArg(options::OPT_dxc_disable_validation))
259*06c3fb27SDimitry Andric     return false;
260*06c3fb27SDimitry Andric 
261*06c3fb27SDimitry Andric   std::string DxvPath = GetProgramPath("dxv");
262*06c3fb27SDimitry Andric   if (DxvPath != "dxv")
263*06c3fb27SDimitry Andric     return true;
264*06c3fb27SDimitry Andric 
265*06c3fb27SDimitry Andric   getDriver().Diag(diag::warn_drv_dxc_missing_dxv);
266*06c3fb27SDimitry Andric   return false;
267*06c3fb27SDimitry Andric }
268