1 //===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "HLSL.h" 10 #include "CommonArgs.h" 11 #include "clang/Driver/DriverDiagnostic.h" 12 #include "llvm/ADT/StringSwitch.h" 13 #include "llvm/ADT/Triple.h" 14 15 using namespace clang::driver; 16 using namespace clang::driver::tools; 17 using namespace clang::driver::toolchains; 18 using namespace clang; 19 using namespace llvm::opt; 20 using namespace llvm; 21 22 namespace { 23 24 const unsigned OfflineLibMinor = 0xF; 25 26 bool isLegalShaderModel(Triple &T) { 27 if (T.getOS() != Triple::OSType::ShaderModel) 28 return false; 29 30 auto Version = T.getOSVersion(); 31 if (Version.getBuild()) 32 return false; 33 if (Version.getSubminor()) 34 return false; 35 36 auto Kind = T.getEnvironment(); 37 38 switch (Kind) { 39 default: 40 return false; 41 case Triple::EnvironmentType::Vertex: 42 case Triple::EnvironmentType::Hull: 43 case Triple::EnvironmentType::Domain: 44 case Triple::EnvironmentType::Geometry: 45 case Triple::EnvironmentType::Pixel: 46 case Triple::EnvironmentType::Compute: { 47 VersionTuple MinVer(4, 0); 48 return MinVer <= Version; 49 } break; 50 case Triple::EnvironmentType::Library: { 51 VersionTuple SM6x(6, OfflineLibMinor); 52 if (Version == SM6x) 53 return true; 54 55 VersionTuple MinVer(6, 3); 56 return MinVer <= Version; 57 } break; 58 case Triple::EnvironmentType::Amplification: 59 case Triple::EnvironmentType::Mesh: { 60 VersionTuple MinVer(6, 5); 61 return MinVer <= Version; 62 } break; 63 } 64 return false; 65 } 66 67 llvm::Optional<std::string> tryParseProfile(StringRef Profile) { 68 // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] 69 SmallVector<StringRef, 3> Parts; 70 Profile.split(Parts, "_"); 71 if (Parts.size() != 3) 72 return NoneType(); 73 74 Triple::EnvironmentType Kind = 75 StringSwitch<Triple::EnvironmentType>(Parts[0]) 76 .Case("ps", Triple::EnvironmentType::Pixel) 77 .Case("vs", Triple::EnvironmentType::Vertex) 78 .Case("gs", Triple::EnvironmentType::Geometry) 79 .Case("hs", Triple::EnvironmentType::Hull) 80 .Case("ds", Triple::EnvironmentType::Domain) 81 .Case("cs", Triple::EnvironmentType::Compute) 82 .Case("lib", Triple::EnvironmentType::Library) 83 .Case("ms", Triple::EnvironmentType::Mesh) 84 .Case("as", Triple::EnvironmentType::Amplification) 85 .Default(Triple::EnvironmentType::UnknownEnvironment); 86 if (Kind == Triple::EnvironmentType::UnknownEnvironment) 87 return NoneType(); 88 89 unsigned long long Major = 0; 90 if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) 91 return NoneType(); 92 93 unsigned long long Minor = 0; 94 if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library) 95 Minor = OfflineLibMinor; 96 else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) 97 return NoneType(); 98 99 // dxil-unknown-shadermodel-hull 100 llvm::Triple T; 101 T.setArch(Triple::ArchType::dxil); 102 T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + 103 VersionTuple(Major, Minor).getAsString()); 104 T.setEnvironment(Kind); 105 if (isLegalShaderModel(T)) 106 return T.getTriple(); 107 else 108 return NoneType(); 109 } 110 111 bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { 112 VersionTuple Version; 113 if (Version.tryParse(ValVersionStr) || Version.getBuild() || 114 Version.getSubminor() || !Version.getMinor()) { 115 D.Diag(diag::err_drv_invalid_format_dxil_validator_version) 116 << ValVersionStr; 117 return false; 118 } 119 120 uint64_t Major = Version.getMajor(); 121 uint64_t Minor = *Version.getMinor(); 122 if (Major == 0 && Minor != 0) { 123 D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; 124 return false; 125 } 126 VersionTuple MinVer(1, 0); 127 if (Version < MinVer) { 128 D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; 129 return false; 130 } 131 return true; 132 } 133 134 } // namespace 135 136 /// DirectX Toolchain 137 HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, 138 const ArgList &Args) 139 : ToolChain(D, Triple, Args) {} 140 141 llvm::Optional<std::string> 142 clang::driver::toolchains::HLSLToolChain::parseTargetProfile( 143 StringRef TargetProfile) { 144 return tryParseProfile(TargetProfile); 145 } 146 147 DerivedArgList * 148 HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, 149 Action::OffloadKind DeviceOffloadKind) const { 150 DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); 151 152 const OptTable &Opts = getDriver().getOpts(); 153 154 for (Arg *A : Args) { 155 if (A->getOption().getID() == options::OPT_dxil_validator_version) { 156 StringRef ValVerStr = A->getValue(); 157 std::string ErrorMsg; 158 if (!isLegalValidatorVersion(ValVerStr, getDriver())) 159 continue; 160 } 161 if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { 162 // Translate fcgl into -S -emit-llvm and -disable-llvm-passes. 163 DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); 164 DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); 165 DAL->AddFlagArg(nullptr, 166 Opts.getOption(options::OPT_disable_llvm_passes)); 167 A->claim(); 168 continue; 169 } 170 DAL->append(A); 171 } 172 // Add default validator version if not set. 173 // TODO: remove this once read validator version from validator. 174 if (!DAL->hasArg(options::OPT_dxil_validator_version)) { 175 const StringRef DefaultValidatorVer = "1.7"; 176 DAL->AddSeparateArg(nullptr, 177 Opts.getOption(options::OPT_dxil_validator_version), 178 DefaultValidatorVer); 179 } 180 // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and 181 // shader model 6.2. 182 return DAL; 183 } 184