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 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 "";
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 "";
88 
89   unsigned long long Major = 0;
90   if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
91     return "";
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 "";
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 "";
109 }
110 
111 } // namespace
112 
113 /// DirectX Toolchain
114 HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
115                              const ArgList &Args)
116     : ToolChain(D, Triple, Args) {}
117 
118 std::string
119 HLSLToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
120                                            types::ID InputType) const {
121   if (Arg *A = Args.getLastArg(options::OPT_target_profile)) {
122     StringRef Profile = A->getValue();
123     std::string Triple = tryParseProfile(Profile);
124     if (Triple == "") {
125       getDriver().Diag(diag::err_drv_invalid_directx_shader_module) << Profile;
126       Triple = ToolChain::ComputeEffectiveClangTriple(Args, InputType);
127     }
128     A->claim();
129     return Triple;
130   } else {
131     return ToolChain::ComputeEffectiveClangTriple(Args, InputType);
132   }
133 }
134