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" 1106c3fb27SDimitry Andric #include "clang/Driver/Compilation.h" 1281ad6265SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 1306c3fb27SDimitry Andric #include "clang/Driver/Job.h" 1481ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h" 1506c3fb27SDimitry 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 101*0fca6ea1SDimitry Andric // Determine DXIL version using the minor version number of Shader 102*0fca6ea1SDimitry Andric // Model version specified in target profile. Prior to decoupling DXIL version 103*0fca6ea1SDimitry Andric // numbering from that of Shader Model DXIL version 1.Y corresponds to SM 6.Y. 104*0fca6ea1SDimitry Andric // E.g., dxilv1.Y-unknown-shadermodelX.Y-hull 10581ad6265SDimitry Andric llvm::Triple T; 106*0fca6ea1SDimitry Andric Triple::SubArchType SubArch = llvm::Triple::NoSubArch; 107*0fca6ea1SDimitry Andric switch (Minor) { 108*0fca6ea1SDimitry Andric case 0: 109*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_0; 110*0fca6ea1SDimitry Andric break; 111*0fca6ea1SDimitry Andric case 1: 112*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_1; 113*0fca6ea1SDimitry Andric break; 114*0fca6ea1SDimitry Andric case 2: 115*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_2; 116*0fca6ea1SDimitry Andric break; 117*0fca6ea1SDimitry Andric case 3: 118*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_3; 119*0fca6ea1SDimitry Andric break; 120*0fca6ea1SDimitry Andric case 4: 121*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_4; 122*0fca6ea1SDimitry Andric break; 123*0fca6ea1SDimitry Andric case 5: 124*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_5; 125*0fca6ea1SDimitry Andric break; 126*0fca6ea1SDimitry Andric case 6: 127*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_6; 128*0fca6ea1SDimitry Andric break; 129*0fca6ea1SDimitry Andric case 7: 130*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_7; 131*0fca6ea1SDimitry Andric break; 132*0fca6ea1SDimitry Andric case 8: 133*0fca6ea1SDimitry Andric SubArch = llvm::Triple::DXILSubArch_v1_8; 134*0fca6ea1SDimitry Andric break; 135*0fca6ea1SDimitry Andric case OfflineLibMinor: 136*0fca6ea1SDimitry Andric // Always consider minor version x as the latest supported DXIL version 137*0fca6ea1SDimitry Andric SubArch = llvm::Triple::LatestDXILSubArch; 138*0fca6ea1SDimitry Andric break; 139*0fca6ea1SDimitry Andric default: 140*0fca6ea1SDimitry Andric // No DXIL Version corresponding to specified Shader Model version found 141*0fca6ea1SDimitry Andric return std::nullopt; 142*0fca6ea1SDimitry Andric } 143*0fca6ea1SDimitry Andric T.setArch(Triple::ArchType::dxil, SubArch); 14481ad6265SDimitry Andric T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + 14581ad6265SDimitry Andric VersionTuple(Major, Minor).getAsString()); 14681ad6265SDimitry Andric T.setEnvironment(Kind); 14781ad6265SDimitry Andric if (isLegalShaderModel(T)) 14881ad6265SDimitry Andric return T.getTriple(); 14981ad6265SDimitry Andric else 150bdd1243dSDimitry Andric return std::nullopt; 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric 15381ad6265SDimitry Andric bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { 15481ad6265SDimitry Andric VersionTuple Version; 15581ad6265SDimitry Andric if (Version.tryParse(ValVersionStr) || Version.getBuild() || 15681ad6265SDimitry Andric Version.getSubminor() || !Version.getMinor()) { 15781ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_format_dxil_validator_version) 15881ad6265SDimitry Andric << ValVersionStr; 15981ad6265SDimitry Andric return false; 16081ad6265SDimitry Andric } 16181ad6265SDimitry Andric 16281ad6265SDimitry Andric uint64_t Major = Version.getMajor(); 16381ad6265SDimitry Andric uint64_t Minor = *Version.getMinor(); 16481ad6265SDimitry Andric if (Major == 0 && Minor != 0) { 16581ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; 16681ad6265SDimitry Andric return false; 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric VersionTuple MinVer(1, 0); 16981ad6265SDimitry Andric if (Version < MinVer) { 17081ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; 17181ad6265SDimitry Andric return false; 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric return true; 17481ad6265SDimitry Andric } 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric } // namespace 17781ad6265SDimitry Andric 17806c3fb27SDimitry Andric void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA, 17906c3fb27SDimitry Andric const InputInfo &Output, 18006c3fb27SDimitry Andric const InputInfoList &Inputs, 18106c3fb27SDimitry Andric const ArgList &Args, 18206c3fb27SDimitry Andric const char *LinkingOutput) const { 18306c3fb27SDimitry Andric std::string DxvPath = getToolChain().GetProgramPath("dxv"); 18406c3fb27SDimitry Andric assert(DxvPath != "dxv" && "cannot find dxv"); 18506c3fb27SDimitry Andric 18606c3fb27SDimitry Andric ArgStringList CmdArgs; 18706c3fb27SDimitry Andric assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); 18806c3fb27SDimitry Andric const InputInfo &Input = Inputs[0]; 18906c3fb27SDimitry Andric assert(Input.isFilename() && "Unexpected verify input"); 19006c3fb27SDimitry Andric // Grabbing the output of the earlier cc1 run. 19106c3fb27SDimitry Andric CmdArgs.push_back(Input.getFilename()); 19206c3fb27SDimitry Andric // Use the same name as output. 19306c3fb27SDimitry Andric CmdArgs.push_back("-o"); 19406c3fb27SDimitry Andric CmdArgs.push_back(Input.getFilename()); 19506c3fb27SDimitry Andric 19606c3fb27SDimitry Andric const char *Exec = Args.MakeArgString(DxvPath); 19706c3fb27SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 19806c3fb27SDimitry Andric Exec, CmdArgs, Inputs, Input)); 19906c3fb27SDimitry Andric } 20006c3fb27SDimitry Andric 20181ad6265SDimitry Andric /// DirectX Toolchain 20281ad6265SDimitry Andric HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, 20381ad6265SDimitry Andric const ArgList &Args) 20406c3fb27SDimitry Andric : ToolChain(D, Triple, Args) { 20506c3fb27SDimitry Andric if (Args.hasArg(options::OPT_dxc_validator_path_EQ)) 20606c3fb27SDimitry Andric getProgramPaths().push_back( 20706c3fb27SDimitry Andric Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str()); 20806c3fb27SDimitry Andric } 20906c3fb27SDimitry Andric 21006c3fb27SDimitry Andric Tool *clang::driver::toolchains::HLSLToolChain::getTool( 21106c3fb27SDimitry Andric Action::ActionClass AC) const { 21206c3fb27SDimitry Andric switch (AC) { 21306c3fb27SDimitry Andric case Action::BinaryAnalyzeJobClass: 21406c3fb27SDimitry Andric if (!Validator) 21506c3fb27SDimitry Andric Validator.reset(new tools::hlsl::Validator(*this)); 21606c3fb27SDimitry Andric return Validator.get(); 21706c3fb27SDimitry Andric default: 21806c3fb27SDimitry Andric return ToolChain::getTool(AC); 21906c3fb27SDimitry Andric } 22006c3fb27SDimitry Andric } 22181ad6265SDimitry Andric 222bdd1243dSDimitry Andric std::optional<std::string> 22381ad6265SDimitry Andric clang::driver::toolchains::HLSLToolChain::parseTargetProfile( 22481ad6265SDimitry Andric StringRef TargetProfile) { 22581ad6265SDimitry Andric return tryParseProfile(TargetProfile); 22681ad6265SDimitry Andric } 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric DerivedArgList * 22981ad6265SDimitry Andric HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, 23081ad6265SDimitry Andric Action::OffloadKind DeviceOffloadKind) const { 23181ad6265SDimitry Andric DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); 23281ad6265SDimitry Andric 23381ad6265SDimitry Andric const OptTable &Opts = getDriver().getOpts(); 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric for (Arg *A : Args) { 23681ad6265SDimitry Andric if (A->getOption().getID() == options::OPT_dxil_validator_version) { 23781ad6265SDimitry Andric StringRef ValVerStr = A->getValue(); 23881ad6265SDimitry Andric std::string ErrorMsg; 23981ad6265SDimitry Andric if (!isLegalValidatorVersion(ValVerStr, getDriver())) 24081ad6265SDimitry Andric continue; 24181ad6265SDimitry Andric } 242bdd1243dSDimitry Andric if (A->getOption().getID() == options::OPT_dxc_entrypoint) { 243bdd1243dSDimitry Andric DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint), 244bdd1243dSDimitry Andric A->getValue()); 245bdd1243dSDimitry Andric A->claim(); 246bdd1243dSDimitry Andric continue; 247bdd1243dSDimitry Andric } 248bdd1243dSDimitry Andric if (A->getOption().getID() == options::OPT__SLASH_O) { 249bdd1243dSDimitry Andric StringRef OStr = A->getValue(); 250bdd1243dSDimitry Andric if (OStr == "d") { 251bdd1243dSDimitry Andric DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0)); 252bdd1243dSDimitry Andric A->claim(); 253bdd1243dSDimitry Andric continue; 254bdd1243dSDimitry Andric } else { 255bdd1243dSDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr); 256bdd1243dSDimitry Andric A->claim(); 257bdd1243dSDimitry Andric continue; 258bdd1243dSDimitry Andric } 259bdd1243dSDimitry Andric } 26081ad6265SDimitry Andric if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { 261*0fca6ea1SDimitry Andric // Translate -fcgl into -emit-llvm and -disable-llvm-passes. 26281ad6265SDimitry Andric DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); 26381ad6265SDimitry Andric DAL->AddFlagArg(nullptr, 26481ad6265SDimitry Andric Opts.getOption(options::OPT_disable_llvm_passes)); 26581ad6265SDimitry Andric A->claim(); 26681ad6265SDimitry Andric continue; 26781ad6265SDimitry Andric } 268*0fca6ea1SDimitry Andric if (A->getOption().getID() == options::OPT_dxc_hlsl_version) { 269*0fca6ea1SDimitry Andric // Translate -HV into -std for llvm 270*0fca6ea1SDimitry Andric // depending on the value given 271*0fca6ea1SDimitry Andric LangStandard::Kind LangStd = LangStandard::getHLSLLangKind(A->getValue()); 272*0fca6ea1SDimitry Andric if (LangStd != LangStandard::lang_unspecified) { 273*0fca6ea1SDimitry Andric LangStandard l = LangStandard::getLangStandardForKind(LangStd); 274*0fca6ea1SDimitry Andric DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_std_EQ), 275*0fca6ea1SDimitry Andric l.getName()); 276*0fca6ea1SDimitry Andric } else { 277*0fca6ea1SDimitry Andric getDriver().Diag(diag::err_drv_invalid_value) << "HV" << A->getValue(); 278*0fca6ea1SDimitry Andric } 279*0fca6ea1SDimitry Andric 280*0fca6ea1SDimitry Andric A->claim(); 281*0fca6ea1SDimitry Andric continue; 282*0fca6ea1SDimitry Andric } 28381ad6265SDimitry Andric DAL->append(A); 28481ad6265SDimitry Andric } 285bdd1243dSDimitry Andric 28681ad6265SDimitry Andric // Add default validator version if not set. 28781ad6265SDimitry Andric // TODO: remove this once read validator version from validator. 28881ad6265SDimitry Andric if (!DAL->hasArg(options::OPT_dxil_validator_version)) { 28981ad6265SDimitry Andric const StringRef DefaultValidatorVer = "1.7"; 29081ad6265SDimitry Andric DAL->AddSeparateArg(nullptr, 29181ad6265SDimitry Andric Opts.getOption(options::OPT_dxil_validator_version), 29281ad6265SDimitry Andric DefaultValidatorVer); 29381ad6265SDimitry Andric } 294bdd1243dSDimitry Andric if (!DAL->hasArg(options::OPT_O_Group)) { 295bdd1243dSDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); 296bdd1243dSDimitry Andric } 297*0fca6ea1SDimitry Andric 29881ad6265SDimitry Andric return DAL; 29981ad6265SDimitry Andric } 30006c3fb27SDimitry Andric 30106c3fb27SDimitry Andric bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const { 30206c3fb27SDimitry Andric if (Args.getLastArg(options::OPT_dxc_disable_validation)) 30306c3fb27SDimitry Andric return false; 30406c3fb27SDimitry Andric 30506c3fb27SDimitry Andric std::string DxvPath = GetProgramPath("dxv"); 30606c3fb27SDimitry Andric if (DxvPath != "dxv") 30706c3fb27SDimitry Andric return true; 30806c3fb27SDimitry Andric 30906c3fb27SDimitry Andric getDriver().Diag(diag::warn_drv_dxc_missing_dxv); 31006c3fb27SDimitry Andric return false; 31106c3fb27SDimitry Andric } 312