1 | //===- unittests/Driver/DXCModeTest.cpp --- DXC Mode tests ----------------===// |
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 | // Unit tests for driver DXCMode. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/Basic/DiagnosticIDs.h" |
14 | #include "clang/Basic/DiagnosticOptions.h" |
15 | #include "clang/Basic/LLVM.h" |
16 | #include "clang/Basic/TargetOptions.h" |
17 | #include "clang/Driver/Compilation.h" |
18 | #include "clang/Driver/Driver.h" |
19 | #include "clang/Driver/ToolChain.h" |
20 | #include "clang/Frontend/CompilerInstance.h" |
21 | #include "llvm/Support/VirtualFileSystem.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | #include "gtest/gtest.h" |
24 | #include <memory> |
25 | |
26 | #include "SimpleDiagnosticConsumer.h" |
27 | |
28 | using namespace clang; |
29 | using namespace clang::driver; |
30 | |
31 | static void validateTargetProfile( |
32 | StringRef TargetProfile, StringRef ExpectTriple, |
33 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> &InMemoryFileSystem, |
34 | DiagnosticsEngine &Diags) { |
35 | Driver TheDriver("/bin/clang" , "" , Diags, "" , InMemoryFileSystem); |
36 | std::unique_ptr<Compilation> C{TheDriver.BuildCompilation( |
37 | Args: {"clang" , "--driver-mode=dxc" , TargetProfile.data(), "foo.hlsl" , "-Vd" })}; |
38 | EXPECT_TRUE(C); |
39 | EXPECT_STREQ(TheDriver.getTargetTriple().c_str(), ExpectTriple.data()); |
40 | EXPECT_EQ(Diags.getNumErrors(), 0u); |
41 | } |
42 | |
43 | static void validateTargetProfile( |
44 | StringRef TargetProfile, StringRef ExpectError, |
45 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> &InMemoryFileSystem, |
46 | DiagnosticsEngine &Diags, SimpleDiagnosticConsumer *DiagConsumer, |
47 | unsigned NumOfErrors) { |
48 | Driver TheDriver("/bin/clang" , "" , Diags, "" , InMemoryFileSystem); |
49 | std::unique_ptr<Compilation> C{TheDriver.BuildCompilation( |
50 | Args: {"clang" , "--driver-mode=dxc" , TargetProfile.data(), "foo.hlsl" , "-Vd" })}; |
51 | EXPECT_TRUE(C); |
52 | EXPECT_EQ(Diags.getNumErrors(), NumOfErrors); |
53 | EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), ExpectError.data()); |
54 | Diags.Clear(); |
55 | DiagConsumer->clear(); |
56 | } |
57 | |
58 | TEST(DxcModeTest, TargetProfileValidation) { |
59 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
60 | |
61 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
62 | new llvm::vfs::InMemoryFileSystem); |
63 | |
64 | InMemoryFileSystem->addFile(Path: "foo.hlsl" , ModificationTime: 0, |
65 | Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n" )); |
66 | |
67 | auto *DiagConsumer = new SimpleDiagnosticConsumer; |
68 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
69 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer); |
70 | |
71 | validateTargetProfile(TargetProfile: "-Tvs_6_0" , ExpectTriple: "dxil--shadermodel6.0-vertex" , |
72 | InMemoryFileSystem, Diags); |
73 | validateTargetProfile(TargetProfile: "-Ths_6_1" , ExpectTriple: "dxil--shadermodel6.1-hull" , |
74 | InMemoryFileSystem, Diags); |
75 | validateTargetProfile(TargetProfile: "-Tds_6_2" , ExpectTriple: "dxil--shadermodel6.2-domain" , |
76 | InMemoryFileSystem, Diags); |
77 | validateTargetProfile(TargetProfile: "-Tds_6_2" , ExpectTriple: "dxil--shadermodel6.2-domain" , |
78 | InMemoryFileSystem, Diags); |
79 | validateTargetProfile(TargetProfile: "-Tgs_6_3" , ExpectTriple: "dxil--shadermodel6.3-geometry" , |
80 | InMemoryFileSystem, Diags); |
81 | validateTargetProfile(TargetProfile: "-Tps_6_4" , ExpectTriple: "dxil--shadermodel6.4-pixel" , |
82 | InMemoryFileSystem, Diags); |
83 | validateTargetProfile(TargetProfile: "-Tcs_6_5" , ExpectTriple: "dxil--shadermodel6.5-compute" , |
84 | InMemoryFileSystem, Diags); |
85 | validateTargetProfile(TargetProfile: "-Tms_6_6" , ExpectTriple: "dxil--shadermodel6.6-mesh" , |
86 | InMemoryFileSystem, Diags); |
87 | validateTargetProfile(TargetProfile: "-Tas_6_7" , ExpectTriple: "dxil--shadermodel6.7-amplification" , |
88 | InMemoryFileSystem, Diags); |
89 | validateTargetProfile(TargetProfile: "-Tlib_6_x" , ExpectTriple: "dxil--shadermodel6.15-library" , |
90 | InMemoryFileSystem, Diags); |
91 | |
92 | // Invalid tests. |
93 | validateTargetProfile(TargetProfile: "-Tpss_6_1" , ExpectError: "invalid profile : pss_6_1" , |
94 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 1); |
95 | |
96 | validateTargetProfile(TargetProfile: "-Tps_6_x" , ExpectError: "invalid profile : ps_6_x" , |
97 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 2); |
98 | validateTargetProfile(TargetProfile: "-Tlib_6_1" , ExpectError: "invalid profile : lib_6_1" , |
99 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 3); |
100 | validateTargetProfile(TargetProfile: "-Tfoo" , ExpectError: "invalid profile : foo" , InMemoryFileSystem, |
101 | Diags, DiagConsumer, NumOfErrors: 4); |
102 | validateTargetProfile(TargetProfile: "" , ExpectError: "target profile option (-T) is missing" , |
103 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 5); |
104 | } |
105 | |
106 | TEST(DxcModeTest, ValidatorVersionValidation) { |
107 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
108 | |
109 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
110 | new llvm::vfs::InMemoryFileSystem); |
111 | |
112 | InMemoryFileSystem->addFile(Path: "foo.hlsl" , ModificationTime: 0, |
113 | Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n" )); |
114 | |
115 | auto *DiagConsumer = new SimpleDiagnosticConsumer; |
116 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
117 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer); |
118 | Driver TheDriver("/bin/clang" , "" , Diags, "" , InMemoryFileSystem); |
119 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( |
120 | Args: {"clang" , "--driver-mode=dxc" , "-Tlib_6_7" , "foo.hlsl" })); |
121 | EXPECT_TRUE(C); |
122 | EXPECT_TRUE(!C->containsError()); |
123 | |
124 | auto &TC = C->getDefaultToolChain(); |
125 | bool ContainsError = false; |
126 | auto Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "1.1" }, UseDriverMode: false, |
127 | ContainsError); |
128 | EXPECT_FALSE(ContainsError); |
129 | auto DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
130 | for (auto *A : Args) |
131 | DAL->append(A); |
132 | |
133 | std::unique_ptr<llvm::opt::DerivedArgList> TranslatedArgs{ |
134 | TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)}; |
135 | EXPECT_NE(TranslatedArgs, nullptr); |
136 | if (TranslatedArgs) { |
137 | auto *A = TranslatedArgs->getLastArg( |
138 | clang::driver::options::OPT_dxil_validator_version); |
139 | EXPECT_NE(A, nullptr); |
140 | if (A) { |
141 | EXPECT_STREQ(A->getValue(), "1.1" ); |
142 | } |
143 | } |
144 | EXPECT_EQ(Diags.getNumErrors(), 0u); |
145 | |
146 | // Invalid tests. |
147 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "0.1" }, UseDriverMode: false, |
148 | ContainsError); |
149 | EXPECT_FALSE(ContainsError); |
150 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
151 | for (auto *A : Args) |
152 | DAL->append(A); |
153 | |
154 | TranslatedArgs.reset( |
155 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
156 | EXPECT_EQ(Diags.getNumErrors(), 1u); |
157 | EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), |
158 | "invalid validator version : 0.1\nIf validator major version is " |
159 | "0, minor version must also be 0." ); |
160 | Diags.Clear(); |
161 | DiagConsumer->clear(); |
162 | |
163 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "1" }, UseDriverMode: false, |
164 | ContainsError); |
165 | EXPECT_FALSE(ContainsError); |
166 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
167 | for (auto *A : Args) |
168 | DAL->append(A); |
169 | |
170 | TranslatedArgs.reset( |
171 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
172 | EXPECT_EQ(Diags.getNumErrors(), 2u); |
173 | EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), |
174 | "invalid validator version : 1\nFormat of validator version is " |
175 | "\"<major>.<minor>\" (ex:\"1.4\")." ); |
176 | Diags.Clear(); |
177 | DiagConsumer->clear(); |
178 | |
179 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "-Tlib_6_7" }, UseDriverMode: false, |
180 | ContainsError); |
181 | EXPECT_FALSE(ContainsError); |
182 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
183 | for (auto *A : Args) |
184 | DAL->append(A); |
185 | |
186 | TranslatedArgs.reset( |
187 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
188 | EXPECT_EQ(Diags.getNumErrors(), 3u); |
189 | EXPECT_STREQ( |
190 | DiagConsumer->Errors.back().c_str(), |
191 | "invalid validator version : -Tlib_6_7\nFormat of validator version is " |
192 | "\"<major>.<minor>\" (ex:\"1.4\")." ); |
193 | Diags.Clear(); |
194 | DiagConsumer->clear(); |
195 | |
196 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "foo" }, UseDriverMode: false, |
197 | ContainsError); |
198 | EXPECT_FALSE(ContainsError); |
199 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
200 | for (auto *A : Args) |
201 | DAL->append(A); |
202 | |
203 | TranslatedArgs.reset( |
204 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
205 | EXPECT_EQ(Diags.getNumErrors(), 4u); |
206 | EXPECT_STREQ( |
207 | DiagConsumer->Errors.back().c_str(), |
208 | "invalid validator version : foo\nFormat of validator version is " |
209 | "\"<major>.<minor>\" (ex:\"1.4\")." ); |
210 | Diags.Clear(); |
211 | DiagConsumer->clear(); |
212 | } |
213 | |
214 | TEST(DxcModeTest, DefaultEntry) { |
215 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
216 | new llvm::vfs::InMemoryFileSystem); |
217 | |
218 | InMemoryFileSystem->addFile(Path: "foo.hlsl" , ModificationTime: 0, |
219 | Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n" )); |
220 | |
221 | const char *Args[] = {"clang" , "--driver-mode=dxc" , "-Tcs_6_7" , "foo.hlsl" }; |
222 | |
223 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags = |
224 | CompilerInstance::createDiagnostics(Opts: new DiagnosticOptions()); |
225 | |
226 | CreateInvocationOptions CIOpts; |
227 | CIOpts.Diags = Diags; |
228 | std::unique_ptr<CompilerInvocation> CInvok = |
229 | createInvocation(Args, Opts: std::move(CIOpts)); |
230 | EXPECT_TRUE(CInvok); |
231 | // Make sure default entry is "main". |
232 | EXPECT_STREQ(CInvok->getTargetOpts().HLSLEntry.c_str(), "main" ); |
233 | |
234 | const char *EntryArgs[] = {"clang" , "--driver-mode=dxc" , "-Ebar" , "-Tcs_6_7" , |
235 | "foo.hlsl" }; |
236 | CInvok = createInvocation(Args: EntryArgs, Opts: std::move(CIOpts)); |
237 | EXPECT_TRUE(CInvok); |
238 | // Make sure "-E" will set entry. |
239 | EXPECT_STREQ(CInvok->getTargetOpts().HLSLEntry.c_str(), "bar" ); |
240 | } |
241 | |