blob: 3e1cbbc5b41563c25c28e4adeee456d2376fecd8 [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001// Copyright 2023 The Dawn & Tint Authors
James Price02b5b222023-05-04 18:50:49 +00002//
Austin Engcc2516a2023-10-17 20:57:54 +00003// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
James Price02b5b222023-05-04 18:50:49 +00005//
Austin Engcc2516a2023-10-17 20:57:54 +00006// 1. Redistributions of source code must retain the above copyright notice, this
7// list of conditions and the following disclaimer.
James Price02b5b222023-05-04 18:50:49 +00008//
Austin Engcc2516a2023-10-17 20:57:54 +00009// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12//
13// 3. Neither the name of the copyright holder nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
James Price02b5b222023-05-04 18:50:49 +000027
Ben Claytond368f2c2023-08-01 00:37:35 +000028#ifndef SRC_TINT_LANG_SPIRV_WRITER_COMMON_HELPER_TEST_H_
29#define SRC_TINT_LANG_SPIRV_WRITER_COMMON_HELPER_TEST_H_
James Price02b5b222023-05-04 18:50:49 +000030
31#include <string>
James Price3e65d902023-06-28 19:47:03 +000032#include <utility>
James Pricee9cd7192023-06-29 19:47:49 +000033#include <vector>
James Price02b5b222023-05-04 18:50:49 +000034
James Pricee9cd7192023-06-29 19:47:49 +000035#include "gmock/gmock.h"
James Price02b5b222023-05-04 18:50:49 +000036#include "gtest/gtest.h"
James Price3e65d902023-06-28 19:47:03 +000037#include "spirv-tools/libspirv.hpp"
dan sinclair97c37272023-07-24 17:11:53 +000038#include "src/tint/lang/core/ir/builder.h"
dan sinclair650bc3e2024-06-11 23:26:53 +000039#include "src/tint/lang/core/ir/disassembler.h"
dan sinclair97c37272023-07-24 17:11:53 +000040#include "src/tint/lang/core/ir/validator.h"
dan sinclair2dddb192023-07-26 20:31:48 +000041#include "src/tint/lang/core/type/array.h"
42#include "src/tint/lang/core/type/depth_texture.h"
43#include "src/tint/lang/core/type/matrix.h"
44#include "src/tint/lang/core/type/multisampled_texture.h"
45#include "src/tint/lang/core/type/sampled_texture.h"
46#include "src/tint/lang/core/type/storage_texture.h"
Ben Claytonb0ea3682023-08-15 15:35:01 +000047#include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
dan sinclair2dddb192023-07-26 20:31:48 +000048#include "src/tint/lang/spirv/writer/printer/printer.h"
James Priced974e3b2023-08-02 21:30:23 +000049#include "src/tint/lang/spirv/writer/raise/raise.h"
James Price02b5b222023-05-04 18:50:49 +000050
dan sinclair2dddb192023-07-26 20:31:48 +000051namespace tint::spirv::writer {
James Price02b5b222023-05-04 18:50:49 +000052
dan sinclairce6dffe2023-08-14 21:01:40 +000053using namespace tint::core::number_suffixes; // NOLINT
dan sinclair23314ca2023-08-03 16:02:22 +000054
James Price61307222023-06-28 23:26:34 +000055// Helper macro to check whether the SPIR-V output contains an instruction, dumping the full output
56// if the instruction was not present.
57#define EXPECT_INST(inst) ASSERT_THAT(output_, testing::HasSubstr(inst)) << output_
58
James Pricebcf41742023-05-26 15:10:30 +000059/// The element type of a test.
60enum TestElementType {
61 kBool,
62 kI32,
63 kU32,
64 kF32,
65 kF16,
66};
Ben Clayton68919602023-07-28 22:51:18 +000067template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
68auto& operator<<(STREAM& out, TestElementType type) {
James Price8558e482023-06-30 23:23:49 +000069 switch (type) {
70 case kBool:
71 out << "bool";
72 break;
73 case kI32:
74 out << "i32";
75 break;
76 case kU32:
77 out << "u32";
78 break;
79 case kF32:
80 out << "f32";
81 break;
82 case kF16:
83 out << "f16";
84 break;
85 }
86 return out;
87}
James Pricebcf41742023-05-26 15:10:30 +000088
James Price90579412023-07-21 03:51:44 +000089/// Base helper class for testing the SPIR-V writer implementation.
James Price02b5b222023-05-04 18:50:49 +000090template <typename BASE>
James Price6dbf49f2023-07-21 03:46:26 +000091class SpirvWriterTestHelperBase : public BASE {
James Price02b5b222023-05-04 18:50:49 +000092 public:
James Price41d75132023-06-02 23:34:36 +000093 /// The test module.
dan sinclair6f138fe2023-08-15 21:29:34 +000094 core::ir::Module mod;
James Price41d75132023-06-02 23:34:36 +000095 /// The test builder.
dan sinclair6f138fe2023-08-15 21:29:34 +000096 core::ir::Builder b{mod};
James Price41d75132023-06-02 23:34:36 +000097 /// The type manager.
dan sinclaircedcdf32023-08-10 02:39:48 +000098 core::type::Manager& ty{mod.Types()};
James Price02b5b222023-05-04 18:50:49 +000099
100 protected:
James Pricee9cd7192023-06-29 19:47:49 +0000101 /// Errors produced during codegen or SPIR-V validation.
dan sinclaircff18f32023-06-05 21:36:29 +0000102 std::string err_;
103
James Price3e65d902023-06-28 19:47:03 +0000104 /// SPIR-V output.
105 std::string output_;
106
Ben Clayton22581552023-10-26 14:17:18 +0000107 /// The generated SPIR-V
108 writer::Module spirv_;
109
dan sinclaircff18f32023-06-05 21:36:29 +0000110 /// @returns the error string from the validation
111 std::string Error() const { return err_; }
112
Ben Clayton22581552023-10-26 14:17:18 +0000113 /// Run the printer on the IR module and validate the result.
James Price4e6f10f2023-09-12 21:27:53 +0000114 /// @param options the optional writer options to use when raising the IR
Ben Clayton22581552023-10-26 14:17:18 +0000115 /// @param zero_init_workgroup_memory `true` to initialize all the variables in the Workgroup
116 /// storage class with OpConstantNull
James Pricee9cd7192023-06-29 19:47:49 +0000117 /// @returns true if generation and validation succeeded
Ben Clayton22581552023-10-26 14:17:18 +0000118 bool Generate(Options options = {}, bool zero_init_workgroup_memory = false) {
Ben Clayton41cdde72024-01-09 19:57:40 +0000119 auto raised = Raise(mod, options);
Ben Clayton89274f72024-01-03 10:53:42 +0000120 if (raised != Success) {
Ben Clayton1e1f4882024-02-05 17:35:59 +0000121 err_ = raised.Failure().reason.Str();
James Priced974e3b2023-08-02 21:30:23 +0000122 return false;
123 }
124
dan sinclair9cef8422024-08-22 18:01:45 +0000125 if (zero_init_workgroup_memory) {
126 options.disable_workgroup_init = false;
127 options.use_zero_initialize_workgroup_memory_extension = true;
128 }
129
130 auto spirv = PrintModule(mod, options);
Ben Clayton89274f72024-01-03 10:53:42 +0000131 if (spirv != Success) {
Ben Clayton1e1f4882024-02-05 17:35:59 +0000132 err_ = spirv.Failure().reason.Str();
dan sinclaircff18f32023-06-05 21:36:29 +0000133 return false;
134 }
James Pricee9cd7192023-06-29 19:47:49 +0000135
Ben Clayton22581552023-10-26 14:17:18 +0000136 output_ = Disassemble(spirv->Code(), SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
137 SPV_BINARY_TO_TEXT_OPTION_INDENT |
138 SPV_BINARY_TO_TEXT_OPTION_COMMENT);
James Pricee9cd7192023-06-29 19:47:49 +0000139
Ben Clayton22581552023-10-26 14:17:18 +0000140 if (!Validate(spirv->Code())) {
James Pricee9cd7192023-06-29 19:47:49 +0000141 return false;
142 }
143
Ben Clayton22581552023-10-26 14:17:18 +0000144 spirv_ = std::move(spirv.Get());
dan sinclaircff18f32023-06-05 21:36:29 +0000145 return true;
146 }
147
James Price3e65d902023-06-28 19:47:03 +0000148 /// Validate the generated SPIR-V using the SPIR-V Tools Validator.
James Pricee9cd7192023-06-29 19:47:49 +0000149 /// @param binary the SPIR-V binary module to validate
James Price3e65d902023-06-28 19:47:03 +0000150 /// @returns true if validation succeeded, false otherwise
James Pricee9cd7192023-06-29 19:47:49 +0000151 bool Validate(const std::vector<uint32_t>& binary) {
James Price3e65d902023-06-28 19:47:03 +0000152 std::string spv_errors;
153 auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
154 const spv_position_t& position, const char* message) {
155 switch (level) {
156 case SPV_MSG_FATAL:
157 case SPV_MSG_INTERNAL_ERROR:
158 case SPV_MSG_ERROR:
159 spv_errors +=
160 "error: line " + std::to_string(position.index) + ": " + message + "\n";
161 break;
162 case SPV_MSG_WARNING:
163 spv_errors +=
164 "warning: line " + std::to_string(position.index) + ": " + message + "\n";
165 break;
166 case SPV_MSG_INFO:
167 spv_errors +=
168 "info: line " + std::to_string(position.index) + ": " + message + "\n";
169 break;
170 case SPV_MSG_DEBUG:
171 break;
172 }
173 };
174
175 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_2);
176 tools.SetMessageConsumer(msg_consumer);
177
178 auto result = tools.Validate(binary);
179 err_ = std::move(spv_errors);
180 return result;
181 }
182
James Price02b5b222023-05-04 18:50:49 +0000183 /// @returns the disassembled types from the generated module.
Ben Clayton22581552023-10-26 14:17:18 +0000184 std::string DumpTypes() { return DumpInstructions(spirv_.Types()); }
James Pricebcf41742023-05-26 15:10:30 +0000185
James Price41d75132023-06-02 23:34:36 +0000186 /// Helper to make a scalar type corresponding to the element type `type`.
187 /// @param type the element type
James Pricebcf41742023-05-26 15:10:30 +0000188 /// @returns the scalar type
dan sinclaircedcdf32023-08-10 02:39:48 +0000189 const core::type::Type* MakeScalarType(TestElementType type) {
James Price41d75132023-06-02 23:34:36 +0000190 switch (type) {
James Pricebcf41742023-05-26 15:10:30 +0000191 case kBool:
James Price41d75132023-06-02 23:34:36 +0000192 return ty.bool_();
James Pricebcf41742023-05-26 15:10:30 +0000193 case kI32:
James Price41d75132023-06-02 23:34:36 +0000194 return ty.i32();
James Pricebcf41742023-05-26 15:10:30 +0000195 case kU32:
James Price41d75132023-06-02 23:34:36 +0000196 return ty.u32();
James Pricebcf41742023-05-26 15:10:30 +0000197 case kF32:
James Price41d75132023-06-02 23:34:36 +0000198 return ty.f32();
James Pricebcf41742023-05-26 15:10:30 +0000199 case kF16:
James Price41d75132023-06-02 23:34:36 +0000200 return ty.f16();
James Pricebcf41742023-05-26 15:10:30 +0000201 }
202 return nullptr;
203 }
204
James Price41d75132023-06-02 23:34:36 +0000205 /// Helper to make a vector type corresponding to the element type `type`.
206 /// @param type the element type
James Pricebcf41742023-05-26 15:10:30 +0000207 /// @returns the vector type
dan sinclaircedcdf32023-08-10 02:39:48 +0000208 const core::type::Type* MakeVectorType(TestElementType type) {
209 return ty.vec2(MakeScalarType(type));
210 }
James Pricebcf41742023-05-26 15:10:30 +0000211
James Price41d75132023-06-02 23:34:36 +0000212 /// Helper to make a scalar value with the scalar type `type`.
213 /// @param type the element type
James Price05c6fd32023-07-14 16:27:55 +0000214 /// @param value the optional value to use
James Pricebcf41742023-05-26 15:10:30 +0000215 /// @returns the scalar value
dan sinclair6f138fe2023-08-15 21:29:34 +0000216 core::ir::Constant* MakeScalarValue(TestElementType type, uint32_t value = 1) {
James Price41d75132023-06-02 23:34:36 +0000217 switch (type) {
James Pricebcf41742023-05-26 15:10:30 +0000218 case kBool:
219 return b.Constant(true);
220 case kI32:
dan sinclairce6dffe2023-08-14 21:01:40 +0000221 return b.Constant(core::i32(value));
James Pricebcf41742023-05-26 15:10:30 +0000222 case kU32:
dan sinclairce6dffe2023-08-14 21:01:40 +0000223 return b.Constant(core::u32(value));
James Pricebcf41742023-05-26 15:10:30 +0000224 case kF32:
dan sinclairce6dffe2023-08-14 21:01:40 +0000225 return b.Constant(core::f32(value));
James Pricebcf41742023-05-26 15:10:30 +0000226 case kF16:
dan sinclairce6dffe2023-08-14 21:01:40 +0000227 return b.Constant(core::f16(value));
James Pricebcf41742023-05-26 15:10:30 +0000228 }
229 return nullptr;
230 }
231
James Price41d75132023-06-02 23:34:36 +0000232 /// Helper to make a vector value with an element type of `type`.
233 /// @param type the element type
James Pricebcf41742023-05-26 15:10:30 +0000234 /// @returns the vector value
dan sinclair6f138fe2023-08-15 21:29:34 +0000235 core::ir::Constant* MakeVectorValue(TestElementType type) {
James Price41d75132023-06-02 23:34:36 +0000236 switch (type) {
James Pricebcf41742023-05-26 15:10:30 +0000237 case kBool:
dan sinclair23314ca2023-08-03 16:02:22 +0000238 return b.Composite(MakeVectorType(type), true, false);
James Pricebcf41742023-05-26 15:10:30 +0000239 case kI32:
dan sinclair23314ca2023-08-03 16:02:22 +0000240 return b.Composite(MakeVectorType(type), 42_i, -10_i);
James Pricebcf41742023-05-26 15:10:30 +0000241 case kU32:
dan sinclair23314ca2023-08-03 16:02:22 +0000242 return b.Composite(MakeVectorType(type), 42_u, 10_u);
James Pricebcf41742023-05-26 15:10:30 +0000243 case kF32:
dan sinclair23314ca2023-08-03 16:02:22 +0000244 return b.Composite(MakeVectorType(type), 42_f, -0.5_f);
James Pricebcf41742023-05-26 15:10:30 +0000245 case kF16:
dan sinclair23314ca2023-08-03 16:02:22 +0000246 return b.Composite(MakeVectorType(type), 42_h, -0.5_h);
James Pricebcf41742023-05-26 15:10:30 +0000247 }
248 return nullptr;
249 }
James Pricea7e91f52024-05-29 15:38:19 +0000250
251 /// Helper to dump the disassembly of the Tint IR module.
252 /// @returns the disassembly (with a leading newline)
dan sinclair650bc3e2024-06-11 23:26:53 +0000253 std::string IR() { return "\n" + core::ir::Disassembler(mod).Plain(); }
James Price02b5b222023-05-04 18:50:49 +0000254};
255
James Price6dbf49f2023-07-21 03:46:26 +0000256using SpirvWriterTest = SpirvWriterTestHelperBase<testing::Test>;
James Price02b5b222023-05-04 18:50:49 +0000257
258template <typename T>
James Price6dbf49f2023-07-21 03:46:26 +0000259using SpirvWriterTestWithParam = SpirvWriterTestHelperBase<testing::TestWithParam<T>>;
James Price02b5b222023-05-04 18:50:49 +0000260
dan sinclair2dddb192023-07-26 20:31:48 +0000261} // namespace tint::spirv::writer
James Price02b5b222023-05-04 18:50:49 +0000262
Ben Claytond368f2c2023-08-01 00:37:35 +0000263#endif // SRC_TINT_LANG_SPIRV_WRITER_COMMON_HELPER_TEST_H_