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