//===--- 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 tryParseProfile(StringRef Profile) { // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] SmallVector Parts; Profile.split(Parts, "_"); if (Parts.size() != 3) return NoneType(); Triple::EnvironmentType Kind = StringSwitch(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 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_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); } // 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; }