Skip to content

Commit 940c6fa

Browse files
authored
split-combined-image-sampler: synthesize names (KhronosGroup#6037)
If the original combined value has an OpName, then create names for the image and sampler parts by appending "_image" or "_sampler", respectively. Bug: crbug.com/398231475
1 parent 6c757dd commit 940c6fa

File tree

6 files changed

+142
-31
lines changed

6 files changed

+142
-31
lines changed

source/opt/split_combined_image_sampler_pass.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "source/opt/type_manager.h"
2525
#include "source/opt/types.h"
2626
#include "source/util/make_unique.h"
27+
#include "source/util/string_utils.h"
2728
#include "spirv/unified1/spirv.h"
2829

2930
namespace spvtools {
@@ -404,12 +405,16 @@ spv_result_t SplitCombinedImageSamplerPass::RemapUses(
404405
def_use_mgr_->AnalyzeInstUse(use.user);
405406
break;
406407
}
407-
case spv::Op::OpName:
408-
// TODO(dneto): Maybe we should synthesize names for the remapped vars.
408+
case spv::Op::OpName: {
409+
// Synthesize new names from the old.
410+
const auto name = use.user->GetOperand(1).AsString();
411+
AddOpName(use.image_part->result_id(), name + "_image");
412+
AddOpName(use.sampler_part->result_id(), name + "_sampler");
409413

410414
// KillInst will delete names and decorations, so don't schedule a
411415
// deletion of this instruction.
412416
break;
417+
}
413418
case spv::Op::OpFunctionCall: {
414419
// Replace each combined arg with two args: the image part, then the
415420
// sampler part.
@@ -597,6 +602,20 @@ Instruction* SplitCombinedImageSamplerPass::MakeUniformConstantPointer(
597602
return ptr;
598603
}
599604

605+
void SplitCombinedImageSamplerPass::AddOpName(uint32_t id,
606+
const std::string& name) {
607+
std::unique_ptr<Instruction> opname{new Instruction{
608+
context(),
609+
spv::Op::OpName,
610+
0u,
611+
0u,
612+
{{SPV_OPERAND_TYPE_ID, {id}},
613+
{SPV_OPERAND_TYPE_LITERAL_STRING,
614+
utils::MakeVector<spvtools::opt::Operand::OperandData>(name)}}}};
615+
616+
context()->AddDebug2Inst(std::move(opname));
617+
}
618+
600619
spv_result_t SplitCombinedImageSamplerPass::RemoveDeadTypes() {
601620
for (auto dead_type_id : combined_types_to_remove_) {
602621
if (auto* ty = def_use_mgr_->GetDef(dead_type_id)) {

source/opt/split_combined_image_sampler_pass.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ class SplitCombinedImageSamplerPass : public Pass {
8787
return ptr_ty->GetSingleWordInOperand(1);
8888
}
8989

90+
// Creates a new OpName instruction mapping the given name to the given
91+
// string, and adds it to the module at the end of the OpName and OpMemberName
92+
// section.
93+
void AddOpName(uint32_t id, const std::string& name);
94+
9095
// Cached from the IRContext. Valid while Process() is running.
9196
analysis::DefUseManager* def_use_mgr_ = nullptr;
9297
// Cached from the IRContext. Valid while Process() is running.

source/util/small_vector.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace utils {
4343
template <class T, size_t small_size>
4444
class SmallVector {
4545
public:
46+
using value_type = T;
4647
using iterator = T*;
4748
using const_iterator = const T*;
4849

source/util/string_utils.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@
1717

1818
#include <assert.h>
1919

20+
#include <cstdint>
2021
#include <cstring>
2122
#include <sstream>
2223
#include <string>
2324
#include <vector>
2425

25-
#include "source/util/string_utils.h"
26-
2726
namespace spvtools {
2827
namespace utils {
2928

@@ -48,8 +47,9 @@ std::pair<std::string, std::string> SplitFlagArgs(const std::string& flag);
4847

4948
// Encodes a string as a sequence of words, using the SPIR-V encoding, appending
5049
// to an existing vector.
51-
inline void AppendToVector(const std::string& input,
52-
std::vector<uint32_t>* result) {
50+
template <class VectorType = std::vector<uint32_t>>
51+
inline void AppendToVector(const std::string& input, VectorType* result) {
52+
static_assert(std::is_same<uint32_t, typename VectorType::value_type>::value);
5353
uint32_t word = 0;
5454
size_t num_bytes = input.size();
5555
// SPIR-V strings are null-terminated. The byte_index == num_bytes
@@ -70,8 +70,10 @@ inline void AppendToVector(const std::string& input,
7070
}
7171

7272
// Encodes a string as a sequence of words, using the SPIR-V encoding.
73-
inline std::vector<uint32_t> MakeVector(const std::string& input) {
74-
std::vector<uint32_t> result;
73+
template <class VectorType = std::vector<uint32_t>>
74+
inline VectorType MakeVector(const std::string& input) {
75+
static_assert(std::is_same<uint32_t, typename VectorType::value_type>::value);
76+
VectorType result;
7577
AppendToVector(input, &result);
7678
return result;
7779
}

test/opt/split_combined_image_sampler_pass_test.cpp

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,56 @@ TEST_F(SplitCombinedImageSamplerPassTest,
280280
EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
281281
}
282282

283+
TEST_F(SplitCombinedImageSamplerPassTest, Combined_SynthesizeVarNames) {
284+
// Also tests binding info is copied to both variables.
285+
const std::string kTest = Preamble() +
286+
R"(
287+
OpName %orig_var "orig_var"
288+
OpDecorate %orig_var DescriptorSet 0
289+
OpDecorate %orig_var Binding 0
290+
291+
; The combined image variable is replaced by an image variable and a sampler variable.
292+
293+
; CHECK: OpCapability
294+
; The original name is deleted
295+
; CHECK-NOT: OpName %orig_var "
296+
; CHECK: OpName %orig_var_image "orig_var_image"
297+
; CHECK: OpName %orig_var_sampler "orig_var_sampler"
298+
; CHECK-NOT: OpName %orig_var "
299+
300+
; CHECK: OpDecorate %orig_var_image DescriptorSet 0
301+
; CHECK: OpDecorate %orig_var_sampler DescriptorSet 0
302+
; CHECK: OpDecorate %orig_var_image Binding 0
303+
; CHECK: OpDecorate %orig_var_sampler Binding 0
304+
305+
; CHECK: %10 = OpTypeImage %
306+
; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
307+
; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
308+
; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
309+
310+
311+
; CHECK-NOT: %orig_var = OpVariable
312+
; CHECK-DAG: %orig_var_sampler = OpVariable %[[sampler_ptr_ty]] UniformConstant
313+
; CHECK-DAG: %orig_var_image = OpVariable %[[image_ptr_ty]] UniformConstant
314+
; CHECK: = OpFunction
315+
316+
)" + BasicTypes() + R"(
317+
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
318+
%11 = OpTypeSampledImage %10
319+
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
320+
321+
%orig_var = OpVariable %_ptr_UniformConstant_11 UniformConstant
322+
%main = OpFunction %void None %voidfn
323+
%main_0 = OpLabel
324+
%101 = OpLoad %11 %orig_var
325+
OpReturn
326+
OpFunctionEnd
327+
)";
328+
auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
329+
kTest, /* do_validation= */ true);
330+
EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
331+
}
332+
283333
TEST_P(SplitCombinedImageSamplerPassTypeCaseTest, Combined_RemapLoad) {
284334
// Also tests binding info is copied to both variables.
285335
const std::string kTest = Preamble() +
@@ -313,7 +363,6 @@ TEST_P(SplitCombinedImageSamplerPassTypeCaseTest, Combined_RemapLoad) {
313363
; CHECK: %[[s:\d+]] = OpLoad %[[sampler_ty]] %[[sampler_var]]
314364
; CHECK: %combined = OpSampledImage %11 %[[im]] %[[s]]
315365
316-
%bool = OpTypeBool ; location marker
317366
)" + BasicTypes() +
318367
" %10 = " + GetParam().image_type_decl + R"(
319368
%11 = OpTypeSampledImage %10
@@ -621,28 +670,18 @@ std::vector<EntryPointRemapCase> EntryPointInterfaceCases() {
621670
return std::vector<EntryPointRemapCase>{
622671
{SPV_ENV_VULKAN_1_0, " %in_var %out_var", " %in_var %out_var"},
623672
{SPV_ENV_VULKAN_1_4, " %combined_var",
624-
" %[[image_var:\\d+]] %[[sampler_var:\\d+]]"},
673+
" %combined_var_image %combined_var_sampler"},
625674
{SPV_ENV_VULKAN_1_4, " %combined_var %in_var %out_var",
626-
" %[[image_var:\\d+]] %in_var %out_var %[[sampler_var:\\d+]]"},
675+
" %combined_var_image %in_var %out_var %combined_var_sampler"},
627676
{SPV_ENV_VULKAN_1_4, " %in_var %combined_var %out_var",
628-
" %in_var %[[image_var:\\d+]] %out_var %[[sampler_var:\\d+]]"},
677+
" %in_var %combined_var_image %out_var %combined_var_sampler"},
629678
{SPV_ENV_VULKAN_1_4, " %in_var %out_var %combined_var",
630-
" %in_var %out_var %[[image_var:\\d+]] %[[sampler_var:\\d+]]"},
679+
" %in_var %out_var %combined_var_image %combined_var_sampler"},
631680
};
632681
}
633682

634683
TEST_P(SplitCombinedImageSamplerPassEntryPointRemapTest,
635684
EntryPoint_Combined_UsedInShader) {
636-
const bool combined_var_in_interface =
637-
std::string(GetParam().initial_interface).find("%combined_var") !=
638-
std::string::npos;
639-
// If the combined var is listed in the entry point, then the entry point
640-
// interface will give the pattern match definition of the sampler var ID.
641-
// Otherwise it's defined at the assignment.
642-
const std::string sampler_var_def =
643-
combined_var_in_interface ? "%[[sampler_var]]" : "%[[sampler_var:\\d+]]";
644-
const std::string image_var_def =
645-
combined_var_in_interface ? "%[[image_var]]" : "%[[image_var:\\d+]]";
646685
const std::string kTest = PreambleFragment(GetParam().initial_interface) +
647686
R"(
648687
OpName %combined "combined"
@@ -669,10 +708,8 @@ TEST_P(SplitCombinedImageSamplerPassEntryPointRemapTest,
669708
; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
670709
; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
671710
; The combined image variable is replaced by an image variable and a sampler variable.
672-
; CHECK-DAG: )" + sampler_var_def +
673-
R"( = OpVariable %[[sampler_ptr_ty]] UniformConstant
674-
; CHECK-DAG: )" + image_var_def +
675-
R"( = OpVariable %[[image_ptr_ty]] UniformConstant
711+
; CHECK-DAG: %combined_var_sampler = OpVariable %[[sampler_ptr_ty]] UniformConstant
712+
; CHECK-DAG: %combined_var_image = OpVariable %[[image_ptr_ty]] UniformConstant
676713
; CHECK: = OpFunction
677714
678715
%bool = OpTypeBool
@@ -772,8 +809,8 @@ TEST_P(SplitCombinedImageSamplerPassEntryPointRemapTest,
772809
; CHECK-NOT: %combined_var
773810
; CHECK: OpExecutionMode %main OriginUpperLeft
774811
775-
; All traces of the variable disappear
776-
; CHECK-NOT: combined_var
812+
; The variable disappears.
813+
; CHECK-NOT: %combined_var =
777814
; CHECK: OpFunctionEnd
778815
OpName %combined_var "combined_var"
779816
OpName %in_var "in_var"

test/string_utils_test.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include "source/util/string_utils.h"
16+
1517
#include <string>
18+
#include <vector>
1619

17-
#include "gtest/gtest.h"
18-
#include "source/util/string_utils.h"
20+
#include "gmock/gmock.h"
21+
#include "source/util/small_vector.h"
1922
#include "spirv-tools/libspirv.h"
2023

2124
namespace spvtools {
@@ -186,6 +189,50 @@ TEST(CardinalToOrdinal, Test) {
186189
EXPECT_EQ("1225th", CardinalToOrdinal(1225));
187190
}
188191

192+
using MakeVectorMakeStringRoundTripTest = ::testing::TestWithParam<std::string>;
193+
194+
TEST_P(MakeVectorMakeStringRoundTripTest, ViaStdVector) {
195+
const std::string str = GetParam();
196+
const auto& vec = MakeVector<std::vector<uint32_t>>(str);
197+
// Allow for the terminating null byte that must be present.
198+
const auto expected_vec_len = (str.size() + 4) / 4;
199+
EXPECT_EQ(vec.size(), expected_vec_len);
200+
const std::string back_to_string = MakeString(vec);
201+
EXPECT_EQ(str, back_to_string);
202+
}
203+
204+
TEST_P(MakeVectorMakeStringRoundTripTest, ViaSmallVector1) {
205+
const std::string str = GetParam();
206+
// Allow for the terminating null byte that must be present.
207+
const auto expected_vec_len = (str.size() + 4) / 4;
208+
const auto& vec = MakeVector<spvtools::utils::SmallVector<uint32_t, 1>>(str);
209+
EXPECT_EQ(vec.size(), expected_vec_len);
210+
const std::string back_to_string = MakeString(vec);
211+
EXPECT_EQ(str, back_to_string);
212+
}
213+
214+
TEST_P(MakeVectorMakeStringRoundTripTest, ViaSmallVector100) {
215+
const std::string str = GetParam();
216+
// Allow for the terminating null byte that must be present.
217+
const auto expected_vec_len = (str.size() + 4) / 4;
218+
const auto& vec =
219+
MakeVector<spvtools::utils::SmallVector<uint32_t, 100>>(str);
220+
EXPECT_EQ(vec.size(), expected_vec_len);
221+
const std::string back_to_string = MakeString(vec);
222+
EXPECT_EQ(str, back_to_string);
223+
}
224+
225+
INSTANTIATE_TEST_SUITE_P(Examples, MakeVectorMakeStringRoundTripTest,
226+
testing::ValuesIn(std::vector<std::string>{
227+
"",
228+
"a",
229+
"bc",
230+
"def",
231+
"ghij",
232+
"klmno",
233+
"dustclouds disappear without a trace",
234+
}));
235+
189236
} // namespace
190237
} // namespace utils
191238
} // namespace spvtools

0 commit comments

Comments
 (0)