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 | DiagConsumer->clear(); |
55 | } |
56 | |
57 | TEST(DxcModeTest, TargetProfileValidation) { |
58 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
59 | |
60 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
61 | new llvm::vfs::InMemoryFileSystem); |
62 | |
63 | InMemoryFileSystem->addFile(Path: "foo.hlsl" , ModificationTime: 0, |
64 | Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n" )); |
65 | |
66 | auto *DiagConsumer = new SimpleDiagnosticConsumer; |
67 | DiagnosticOptions DiagOpts; |
68 | DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer); |
69 | |
70 | validateTargetProfile(TargetProfile: "-Tvs_6_0" , ExpectTriple: "dxilv1.0--shadermodel6.0-vertex" , |
71 | InMemoryFileSystem, Diags); |
72 | validateTargetProfile(TargetProfile: "-Ths_6_1" , ExpectTriple: "dxilv1.1--shadermodel6.1-hull" , |
73 | InMemoryFileSystem, Diags); |
74 | validateTargetProfile(TargetProfile: "-Tds_6_2" , ExpectTriple: "dxilv1.2--shadermodel6.2-domain" , |
75 | InMemoryFileSystem, Diags); |
76 | validateTargetProfile(TargetProfile: "-Tds_6_2" , ExpectTriple: "dxilv1.2--shadermodel6.2-domain" , |
77 | InMemoryFileSystem, Diags); |
78 | validateTargetProfile(TargetProfile: "-Tgs_6_3" , ExpectTriple: "dxilv1.3--shadermodel6.3-geometry" , |
79 | InMemoryFileSystem, Diags); |
80 | validateTargetProfile(TargetProfile: "-Tps_6_4" , ExpectTriple: "dxilv1.4--shadermodel6.4-pixel" , |
81 | InMemoryFileSystem, Diags); |
82 | validateTargetProfile(TargetProfile: "-Tcs_6_5" , ExpectTriple: "dxilv1.5--shadermodel6.5-compute" , |
83 | InMemoryFileSystem, Diags); |
84 | validateTargetProfile(TargetProfile: "-Tms_6_6" , ExpectTriple: "dxilv1.6--shadermodel6.6-mesh" , |
85 | InMemoryFileSystem, Diags); |
86 | validateTargetProfile(TargetProfile: "-Tas_6_7" , ExpectTriple: "dxilv1.7--shadermodel6.7-amplification" , |
87 | InMemoryFileSystem, Diags); |
88 | validateTargetProfile(TargetProfile: "-Tcs_6_8" , ExpectTriple: "dxilv1.8--shadermodel6.8-compute" , |
89 | InMemoryFileSystem, Diags); |
90 | validateTargetProfile(TargetProfile: "-Tlib_6_x" , ExpectTriple: "dxilv1.8--shadermodel6.15-library" , |
91 | InMemoryFileSystem, Diags); |
92 | |
93 | // Invalid tests. |
94 | validateTargetProfile(TargetProfile: "-Tpss_6_1" , ExpectError: "invalid profile : pss_6_1" , |
95 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 1); |
96 | |
97 | validateTargetProfile(TargetProfile: "-Tps_6_x" , ExpectError: "invalid profile : ps_6_x" , |
98 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 2); |
99 | validateTargetProfile(TargetProfile: "-Tlib_6_1" , ExpectError: "invalid profile : lib_6_1" , |
100 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 3); |
101 | validateTargetProfile(TargetProfile: "-Tfoo" , ExpectError: "invalid profile : foo" , InMemoryFileSystem, |
102 | Diags, DiagConsumer, NumOfErrors: 4); |
103 | validateTargetProfile(TargetProfile: "" , ExpectError: "target profile option (-T) is missing" , |
104 | InMemoryFileSystem, Diags, DiagConsumer, NumOfErrors: 5); |
105 | } |
106 | |
107 | TEST(DxcModeTest, ValidatorVersionValidation) { |
108 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
109 | |
110 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
111 | new llvm::vfs::InMemoryFileSystem); |
112 | |
113 | InMemoryFileSystem->addFile(Path: "foo.hlsl" , ModificationTime: 0, |
114 | Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n" )); |
115 | |
116 | auto *DiagConsumer = new SimpleDiagnosticConsumer; |
117 | DiagnosticOptions DiagOpts; |
118 | DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer); |
119 | Driver TheDriver("/bin/clang" , "" , Diags, "" , InMemoryFileSystem); |
120 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( |
121 | Args: {"clang" , "--driver-mode=dxc" , "-Tlib_6_7" , "foo.hlsl" })); |
122 | EXPECT_TRUE(C); |
123 | EXPECT_TRUE(!C->containsError()); |
124 | |
125 | auto &TC = C->getDefaultToolChain(); |
126 | bool ContainsError = false; |
127 | auto Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "1.1" }, UseDriverMode: false, |
128 | ContainsError); |
129 | EXPECT_FALSE(ContainsError); |
130 | auto DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
131 | for (auto *A : Args) |
132 | DAL->append(A); |
133 | |
134 | std::unique_ptr<llvm::opt::DerivedArgList> TranslatedArgs{ |
135 | TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)}; |
136 | EXPECT_NE(TranslatedArgs, nullptr); |
137 | if (TranslatedArgs) { |
138 | auto *A = TranslatedArgs->getLastArg( |
139 | clang::driver::options::OPT_dxil_validator_version); |
140 | EXPECT_NE(A, nullptr); |
141 | if (A) { |
142 | EXPECT_STREQ(A->getValue(), "1.1" ); |
143 | } |
144 | } |
145 | EXPECT_EQ(Diags.getNumErrors(), 0u); |
146 | |
147 | // Invalid tests. |
148 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "0.1" }, UseDriverMode: false, |
149 | ContainsError); |
150 | EXPECT_FALSE(ContainsError); |
151 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
152 | for (auto *A : Args) |
153 | DAL->append(A); |
154 | |
155 | TranslatedArgs.reset( |
156 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
157 | EXPECT_EQ(Diags.getNumErrors(), 1u); |
158 | EXPECT_STREQ( |
159 | DiagConsumer->Errors.back().c_str(), |
160 | "invalid validator version : 0.1; if validator major version is 0, " |
161 | "minor version must also be 0" ); |
162 | DiagConsumer->clear(); |
163 | |
164 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "1" }, UseDriverMode: false, |
165 | ContainsError); |
166 | EXPECT_FALSE(ContainsError); |
167 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
168 | for (auto *A : Args) |
169 | DAL->append(A); |
170 | |
171 | TranslatedArgs.reset( |
172 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
173 | EXPECT_EQ(Diags.getNumErrors(), 2u); |
174 | EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), |
175 | "invalid validator version : 1; format of validator version is " |
176 | "\"<major>.<minor>\" (ex:\"1.4\")" ); |
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; format of validator version is " |
192 | "\"<major>.<minor>\" (ex:\"1.4\")" ); |
193 | DiagConsumer->clear(); |
194 | |
195 | Args = TheDriver.ParseArgStrings(Args: {"-validator-version" , "foo" }, UseDriverMode: false, |
196 | ContainsError); |
197 | EXPECT_FALSE(ContainsError); |
198 | DAL = std::make_unique<llvm::opt::DerivedArgList>(args&: Args); |
199 | for (auto *A : Args) |
200 | DAL->append(A); |
201 | |
202 | TranslatedArgs.reset( |
203 | p: TC.TranslateArgs(Args: *DAL, BoundArch: "0" , DeviceOffloadKind: Action::OffloadKind::OFK_None)); |
204 | EXPECT_EQ(Diags.getNumErrors(), 4u); |
205 | EXPECT_STREQ( |
206 | DiagConsumer->Errors.back().c_str(), |
207 | "invalid validator version : foo; format of validator version is " |
208 | "\"<major>.<minor>\" (ex:\"1.4\")" ); |
209 | DiagConsumer->clear(); |
210 | } |
211 | |
212 | TEST(DxcModeTest, DefaultEntry) { |
213 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
214 | new llvm::vfs::InMemoryFileSystem); |
215 | |
216 | InMemoryFileSystem->addFile(Path: "foo.hlsl" , ModificationTime: 0, |
217 | Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n" )); |
218 | |
219 | const char *Args[] = {"clang" , "--driver-mode=dxc" , "-Tcs_6_7" , "foo.hlsl" }; |
220 | |
221 | DiagnosticOptions DiagOpts; |
222 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags = |
223 | CompilerInstance::createDiagnostics(VFS&: *InMemoryFileSystem, Opts&: DiagOpts); |
224 | |
225 | CreateInvocationOptions CIOpts; |
226 | CIOpts.Diags = Diags; |
227 | std::unique_ptr<CompilerInvocation> CInvok = |
228 | createInvocation(Args, Opts: std::move(CIOpts)); |
229 | EXPECT_TRUE(CInvok); |
230 | // Make sure default entry is "main". |
231 | EXPECT_STREQ(CInvok->getTargetOpts().HLSLEntry.c_str(), "main" ); |
232 | |
233 | const char *EntryArgs[] = {"clang" , "--driver-mode=dxc" , "-Ebar" , "-Tcs_6_7" , |
234 | "foo.hlsl" }; |
235 | CInvok = createInvocation(Args: EntryArgs, Opts: std::move(CIOpts)); |
236 | EXPECT_TRUE(CInvok); |
237 | // Make sure "-E" will set entry. |
238 | EXPECT_STREQ(CInvok->getTargetOpts().HLSLEntry.c_str(), "bar" ); |
239 | } |
240 | |