| //===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "HLSL.h" |
| #include "CommonArgs.h" |
| #include "clang/Driver/DriverDiagnostic.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/ADT/Triple.h" |
| |
| using namespace clang::driver; |
| using namespace clang::driver::tools; |
| using namespace clang::driver::toolchains; |
| using namespace clang; |
| using namespace llvm::opt; |
| using namespace llvm; |
| |
| namespace { |
| |
| const unsigned OfflineLibMinor = 0xF; |
| |
| bool isLegalShaderModel(Triple &T) { |
| if (T.getOS() != Triple::OSType::ShaderModel) |
| return false; |
| |
| auto Version = T.getOSVersion(); |
| if (Version.getBuild()) |
| return false; |
| if (Version.getSubminor()) |
| return false; |
| |
| auto Kind = T.getEnvironment(); |
| |
| switch (Kind) { |
| default: |
| return false; |
| case Triple::EnvironmentType::Vertex: |
| case Triple::EnvironmentType::Hull: |
| case Triple::EnvironmentType::Domain: |
| case Triple::EnvironmentType::Geometry: |
| case Triple::EnvironmentType::Pixel: |
| case Triple::EnvironmentType::Compute: { |
| VersionTuple MinVer(4, 0); |
| return MinVer <= Version; |
| } break; |
| case Triple::EnvironmentType::Library: { |
| VersionTuple SM6x(6, OfflineLibMinor); |
| if (Version == SM6x) |
| return true; |
| |
| VersionTuple MinVer(6, 3); |
| return MinVer <= Version; |
| } break; |
| case Triple::EnvironmentType::Amplification: |
| case Triple::EnvironmentType::Mesh: { |
| VersionTuple MinVer(6, 5); |
| return MinVer <= Version; |
| } break; |
| } |
| return false; |
| } |
| |
| llvm::Optional<std::string> tryParseProfile(StringRef Profile) { |
| // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] |
| SmallVector<StringRef, 3> Parts; |
| Profile.split(Parts, "_"); |
| if (Parts.size() != 3) |
| return NoneType(); |
| |
| Triple::EnvironmentType Kind = |
| StringSwitch<Triple::EnvironmentType>(Parts[0]) |
| .Case("ps", Triple::EnvironmentType::Pixel) |
| .Case("vs", Triple::EnvironmentType::Vertex) |
| .Case("gs", Triple::EnvironmentType::Geometry) |
| .Case("hs", Triple::EnvironmentType::Hull) |
| .Case("ds", Triple::EnvironmentType::Domain) |
| .Case("cs", Triple::EnvironmentType::Compute) |
| .Case("lib", Triple::EnvironmentType::Library) |
| .Case("ms", Triple::EnvironmentType::Mesh) |
| .Case("as", Triple::EnvironmentType::Amplification) |
| .Default(Triple::EnvironmentType::UnknownEnvironment); |
| if (Kind == Triple::EnvironmentType::UnknownEnvironment) |
| return NoneType(); |
| |
| unsigned long long Major = 0; |
| if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) |
| return NoneType(); |
| |
| unsigned long long Minor = 0; |
| if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library) |
| Minor = OfflineLibMinor; |
| else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) |
| return NoneType(); |
| |
| // dxil-unknown-shadermodel-hull |
| llvm::Triple T; |
| T.setArch(Triple::ArchType::dxil); |
| T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + |
| VersionTuple(Major, Minor).getAsString()); |
| T.setEnvironment(Kind); |
| if (isLegalShaderModel(T)) |
| return T.getTriple(); |
| else |
| return NoneType(); |
| } |
| |
| bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { |
| VersionTuple Version; |
| if (Version.tryParse(ValVersionStr) || Version.getBuild() || |
| Version.getSubminor() || !Version.getMinor()) { |
| D.Diag(diag::err_drv_invalid_format_dxil_validator_version) |
| << ValVersionStr; |
| return false; |
| } |
| |
| uint64_t Major = Version.getMajor(); |
| uint64_t Minor = *Version.getMinor(); |
| if (Major == 0 && Minor != 0) { |
| D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; |
| return false; |
| } |
| VersionTuple MinVer(1, 0); |
| if (Version < MinVer) { |
| D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| /// DirectX Toolchain |
| HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, |
| const ArgList &Args) |
| : ToolChain(D, Triple, Args) {} |
| |
| llvm::Optional<std::string> |
| clang::driver::toolchains::HLSLToolChain::parseTargetProfile( |
| StringRef TargetProfile) { |
| return tryParseProfile(TargetProfile); |
| } |
| |
| DerivedArgList * |
| HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, |
| Action::OffloadKind DeviceOffloadKind) const { |
| DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); |
| |
| const OptTable &Opts = getDriver().getOpts(); |
| |
| for (Arg *A : Args) { |
| if (A->getOption().getID() == options::OPT_dxil_validator_version) { |
| StringRef ValVerStr = A->getValue(); |
| std::string ErrorMsg; |
| if (!isLegalValidatorVersion(ValVerStr, getDriver())) |
| continue; |
| } |
| if (A->getOption().getID() == options::OPT_dxc_entrypoint) { |
| DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint), |
| A->getValue()); |
| A->claim(); |
| continue; |
| } |
| if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { |
| // Translate fcgl into -S -emit-llvm and -disable-llvm-passes. |
| DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); |
| DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); |
| DAL->AddFlagArg(nullptr, |
| Opts.getOption(options::OPT_disable_llvm_passes)); |
| A->claim(); |
| continue; |
| } |
| DAL->append(A); |
| } |
| |
| if (DAL->hasArg(options::OPT_o)) { |
| // When run the whole pipeline. |
| if (!DAL->hasArg(options::OPT_emit_llvm)) |
| // Emit obj if write to file. |
| DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj)); |
| } else |
| DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-"); |
| |
| // Add default validator version if not set. |
| // TODO: remove this once read validator version from validator. |
| if (!DAL->hasArg(options::OPT_dxil_validator_version)) { |
| const StringRef DefaultValidatorVer = "1.7"; |
| DAL->AddSeparateArg(nullptr, |
| Opts.getOption(options::OPT_dxil_validator_version), |
| DefaultValidatorVer); |
| } |
| // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and |
| // shader model 6.2. |
| return DAL; |
| } |