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" 1181ad6265SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 1281ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h" 1381ad6265SDimitry Andric #include "llvm/ADT/Triple.h" 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric using namespace clang::driver; 1681ad6265SDimitry Andric using namespace clang::driver::tools; 1781ad6265SDimitry Andric using namespace clang::driver::toolchains; 1881ad6265SDimitry Andric using namespace clang; 1981ad6265SDimitry Andric using namespace llvm::opt; 2081ad6265SDimitry Andric using namespace llvm; 2181ad6265SDimitry Andric 2281ad6265SDimitry Andric namespace { 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric const unsigned OfflineLibMinor = 0xF; 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric bool isLegalShaderModel(Triple &T) { 2781ad6265SDimitry Andric if (T.getOS() != Triple::OSType::ShaderModel) 2881ad6265SDimitry Andric return false; 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric auto Version = T.getOSVersion(); 3181ad6265SDimitry Andric if (Version.getBuild()) 3281ad6265SDimitry Andric return false; 3381ad6265SDimitry Andric if (Version.getSubminor()) 3481ad6265SDimitry Andric return false; 3581ad6265SDimitry Andric 3681ad6265SDimitry Andric auto Kind = T.getEnvironment(); 3781ad6265SDimitry Andric 3881ad6265SDimitry Andric switch (Kind) { 3981ad6265SDimitry Andric default: 4081ad6265SDimitry Andric return false; 4181ad6265SDimitry Andric case Triple::EnvironmentType::Vertex: 4281ad6265SDimitry Andric case Triple::EnvironmentType::Hull: 4381ad6265SDimitry Andric case Triple::EnvironmentType::Domain: 4481ad6265SDimitry Andric case Triple::EnvironmentType::Geometry: 4581ad6265SDimitry Andric case Triple::EnvironmentType::Pixel: 4681ad6265SDimitry Andric case Triple::EnvironmentType::Compute: { 4781ad6265SDimitry Andric VersionTuple MinVer(4, 0); 4881ad6265SDimitry Andric return MinVer <= Version; 4981ad6265SDimitry Andric } break; 5081ad6265SDimitry Andric case Triple::EnvironmentType::Library: { 5181ad6265SDimitry Andric VersionTuple SM6x(6, OfflineLibMinor); 5281ad6265SDimitry Andric if (Version == SM6x) 5381ad6265SDimitry Andric return true; 5481ad6265SDimitry Andric 5581ad6265SDimitry Andric VersionTuple MinVer(6, 3); 5681ad6265SDimitry Andric return MinVer <= Version; 5781ad6265SDimitry Andric } break; 5881ad6265SDimitry Andric case Triple::EnvironmentType::Amplification: 5981ad6265SDimitry Andric case Triple::EnvironmentType::Mesh: { 6081ad6265SDimitry Andric VersionTuple MinVer(6, 5); 6181ad6265SDimitry Andric return MinVer <= Version; 6281ad6265SDimitry Andric } break; 6381ad6265SDimitry Andric } 6481ad6265SDimitry Andric return false; 6581ad6265SDimitry Andric } 6681ad6265SDimitry Andric 67*bdd1243dSDimitry Andric std::optional<std::string> tryParseProfile(StringRef Profile) { 6881ad6265SDimitry Andric // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] 6981ad6265SDimitry Andric SmallVector<StringRef, 3> Parts; 7081ad6265SDimitry Andric Profile.split(Parts, "_"); 7181ad6265SDimitry Andric if (Parts.size() != 3) 72*bdd1243dSDimitry Andric return std::nullopt; 7381ad6265SDimitry Andric 7481ad6265SDimitry Andric Triple::EnvironmentType Kind = 7581ad6265SDimitry Andric StringSwitch<Triple::EnvironmentType>(Parts[0]) 7681ad6265SDimitry Andric .Case("ps", Triple::EnvironmentType::Pixel) 7781ad6265SDimitry Andric .Case("vs", Triple::EnvironmentType::Vertex) 7881ad6265SDimitry Andric .Case("gs", Triple::EnvironmentType::Geometry) 7981ad6265SDimitry Andric .Case("hs", Triple::EnvironmentType::Hull) 8081ad6265SDimitry Andric .Case("ds", Triple::EnvironmentType::Domain) 8181ad6265SDimitry Andric .Case("cs", Triple::EnvironmentType::Compute) 8281ad6265SDimitry Andric .Case("lib", Triple::EnvironmentType::Library) 8381ad6265SDimitry Andric .Case("ms", Triple::EnvironmentType::Mesh) 8481ad6265SDimitry Andric .Case("as", Triple::EnvironmentType::Amplification) 8581ad6265SDimitry Andric .Default(Triple::EnvironmentType::UnknownEnvironment); 8681ad6265SDimitry Andric if (Kind == Triple::EnvironmentType::UnknownEnvironment) 87*bdd1243dSDimitry Andric return std::nullopt; 8881ad6265SDimitry Andric 8981ad6265SDimitry Andric unsigned long long Major = 0; 9081ad6265SDimitry Andric if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) 91*bdd1243dSDimitry Andric return std::nullopt; 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric unsigned long long Minor = 0; 9481ad6265SDimitry Andric if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library) 9581ad6265SDimitry Andric Minor = OfflineLibMinor; 9681ad6265SDimitry Andric else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) 97*bdd1243dSDimitry Andric return std::nullopt; 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric // dxil-unknown-shadermodel-hull 10081ad6265SDimitry Andric llvm::Triple T; 10181ad6265SDimitry Andric T.setArch(Triple::ArchType::dxil); 10281ad6265SDimitry Andric T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + 10381ad6265SDimitry Andric VersionTuple(Major, Minor).getAsString()); 10481ad6265SDimitry Andric T.setEnvironment(Kind); 10581ad6265SDimitry Andric if (isLegalShaderModel(T)) 10681ad6265SDimitry Andric return T.getTriple(); 10781ad6265SDimitry Andric else 108*bdd1243dSDimitry Andric return std::nullopt; 10981ad6265SDimitry Andric } 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { 11281ad6265SDimitry Andric VersionTuple Version; 11381ad6265SDimitry Andric if (Version.tryParse(ValVersionStr) || Version.getBuild() || 11481ad6265SDimitry Andric Version.getSubminor() || !Version.getMinor()) { 11581ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_format_dxil_validator_version) 11681ad6265SDimitry Andric << ValVersionStr; 11781ad6265SDimitry Andric return false; 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric uint64_t Major = Version.getMajor(); 12181ad6265SDimitry Andric uint64_t Minor = *Version.getMinor(); 12281ad6265SDimitry Andric if (Major == 0 && Minor != 0) { 12381ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; 12481ad6265SDimitry Andric return false; 12581ad6265SDimitry Andric } 12681ad6265SDimitry Andric VersionTuple MinVer(1, 0); 12781ad6265SDimitry Andric if (Version < MinVer) { 12881ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; 12981ad6265SDimitry Andric return false; 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric return true; 13281ad6265SDimitry Andric } 13381ad6265SDimitry Andric 13481ad6265SDimitry Andric } // namespace 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric /// DirectX Toolchain 13781ad6265SDimitry Andric HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, 13881ad6265SDimitry Andric const ArgList &Args) 13981ad6265SDimitry Andric : ToolChain(D, Triple, Args) {} 14081ad6265SDimitry Andric 141*bdd1243dSDimitry Andric std::optional<std::string> 14281ad6265SDimitry Andric clang::driver::toolchains::HLSLToolChain::parseTargetProfile( 14381ad6265SDimitry Andric StringRef TargetProfile) { 14481ad6265SDimitry Andric return tryParseProfile(TargetProfile); 14581ad6265SDimitry Andric } 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric DerivedArgList * 14881ad6265SDimitry Andric HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, 14981ad6265SDimitry Andric Action::OffloadKind DeviceOffloadKind) const { 15081ad6265SDimitry Andric DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); 15181ad6265SDimitry Andric 15281ad6265SDimitry Andric const OptTable &Opts = getDriver().getOpts(); 15381ad6265SDimitry Andric 15481ad6265SDimitry Andric for (Arg *A : Args) { 15581ad6265SDimitry Andric if (A->getOption().getID() == options::OPT_dxil_validator_version) { 15681ad6265SDimitry Andric StringRef ValVerStr = A->getValue(); 15781ad6265SDimitry Andric std::string ErrorMsg; 15881ad6265SDimitry Andric if (!isLegalValidatorVersion(ValVerStr, getDriver())) 15981ad6265SDimitry Andric continue; 16081ad6265SDimitry Andric } 161*bdd1243dSDimitry Andric if (A->getOption().getID() == options::OPT_dxc_entrypoint) { 162*bdd1243dSDimitry Andric DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint), 163*bdd1243dSDimitry Andric A->getValue()); 164*bdd1243dSDimitry Andric A->claim(); 165*bdd1243dSDimitry Andric continue; 166*bdd1243dSDimitry Andric } 167*bdd1243dSDimitry Andric if (A->getOption().getID() == options::OPT__SLASH_O) { 168*bdd1243dSDimitry Andric StringRef OStr = A->getValue(); 169*bdd1243dSDimitry Andric if (OStr == "d") { 170*bdd1243dSDimitry Andric DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0)); 171*bdd1243dSDimitry Andric A->claim(); 172*bdd1243dSDimitry Andric continue; 173*bdd1243dSDimitry Andric } else { 174*bdd1243dSDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr); 175*bdd1243dSDimitry Andric A->claim(); 176*bdd1243dSDimitry Andric continue; 177*bdd1243dSDimitry Andric } 178*bdd1243dSDimitry Andric } 17981ad6265SDimitry Andric if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { 18081ad6265SDimitry Andric // Translate fcgl into -S -emit-llvm and -disable-llvm-passes. 18181ad6265SDimitry Andric DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); 18281ad6265SDimitry Andric DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); 18381ad6265SDimitry Andric DAL->AddFlagArg(nullptr, 18481ad6265SDimitry Andric Opts.getOption(options::OPT_disable_llvm_passes)); 18581ad6265SDimitry Andric A->claim(); 18681ad6265SDimitry Andric continue; 18781ad6265SDimitry Andric } 18881ad6265SDimitry Andric DAL->append(A); 18981ad6265SDimitry Andric } 190*bdd1243dSDimitry Andric 191*bdd1243dSDimitry Andric if (DAL->hasArg(options::OPT_o)) { 192*bdd1243dSDimitry Andric // When run the whole pipeline. 193*bdd1243dSDimitry Andric if (!DAL->hasArg(options::OPT_emit_llvm)) 194*bdd1243dSDimitry Andric // Emit obj if write to file. 195*bdd1243dSDimitry Andric DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj)); 196*bdd1243dSDimitry Andric } else 197*bdd1243dSDimitry Andric DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-"); 198*bdd1243dSDimitry Andric 19981ad6265SDimitry Andric // Add default validator version if not set. 20081ad6265SDimitry Andric // TODO: remove this once read validator version from validator. 20181ad6265SDimitry Andric if (!DAL->hasArg(options::OPT_dxil_validator_version)) { 20281ad6265SDimitry Andric const StringRef DefaultValidatorVer = "1.7"; 20381ad6265SDimitry Andric DAL->AddSeparateArg(nullptr, 20481ad6265SDimitry Andric Opts.getOption(options::OPT_dxil_validator_version), 20581ad6265SDimitry Andric DefaultValidatorVer); 20681ad6265SDimitry Andric } 207*bdd1243dSDimitry Andric if (!DAL->hasArg(options::OPT_O_Group)) { 208*bdd1243dSDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); 209*bdd1243dSDimitry Andric } 21081ad6265SDimitry Andric // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and 21181ad6265SDimitry Andric // shader model 6.2. 212*bdd1243dSDimitry Andric // See: https://github.com/llvm/llvm-project/issues/57876 21381ad6265SDimitry Andric return DAL; 21481ad6265SDimitry Andric } 215