Fix operand access (#3427)
Fixes #3426.
diff --git a/source/fuzz/transformation_set_memory_operands_mask.cpp b/source/fuzz/transformation_set_memory_operands_mask.cpp
index 131a499..f52f170 100644
--- a/source/fuzz/transformation_set_memory_operands_mask.cpp
+++ b/source/fuzz/transformation_set_memory_operands_mask.cpp
@@ -101,6 +101,14 @@
// Either add a new operand, if no mask operand was already present, or
// replace an existing mask operand.
if (original_mask_in_operand_index >= instruction->NumInOperands()) {
+ // Add first memory operand if it's missing.
+ if (message_.memory_operands_mask_index() == 1 &&
+ GetInOperandIndexForMask(*instruction, 0) >=
+ instruction->NumInOperands()) {
+ instruction->AddOperand(
+ {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessMaskNone}});
+ }
+
instruction->AddOperand(
{SPV_OPERAND_TYPE_MEMORY_ACCESS, {message_.memory_operands_mask()}});
@@ -154,11 +162,26 @@
break;
}
// If we are looking for the input operand index of the first mask, return it.
+ // This will also return a correct value if the operand is missing.
if (mask_index == 0) {
return first_mask_in_operand_index;
}
assert(mask_index == 1 && "Memory operands mask index must be 0 or 1.");
+ // Memory mask operands are optional. Thus, if the second operand exists,
+ // its index will be >= |first_mask_in_operand_index + 1|. We can reason as
+ // follows to separate the cases where the index of the second operand is
+ // equal to |first_mask_in_operand_index + 1|:
+ // - If the first memory operand doesn't exist, its value is equal to None.
+ // This means that it doesn't have additional operands following it and the
+ // condition in the if statement below will be satisfied.
+ // - If the first memory operand exists and has no additional memory operands
+ // following it, the condition in the if statement below will be satisfied
+ // and we will return the correct value from the function.
+ if (first_mask_in_operand_index + 1 >= instruction.NumInOperands()) {
+ return first_mask_in_operand_index + 1;
+ }
+
// We are looking for the input operand index of the second mask. This is a
// little complicated because, depending on the contents of the first mask,
// there may be some input operands separating the two masks.
diff --git a/test/fuzz/transformation_set_memory_operands_mask_test.cpp b/test/fuzz/transformation_set_memory_operands_mask_test.cpp
index c02d8d4..518ce9d 100644
--- a/test/fuzz/transformation_set_memory_operands_mask_test.cpp
+++ b/test/fuzz/transformation_set_memory_operands_mask_test.cpp
@@ -75,6 +75,7 @@
%21 = OpAccessChain %20 %17 %19
OpCopyMemory %12 %21 Aligned 16
OpCopyMemory %133 %12 Volatile
+ OpCopyMemory %133 %12
%136 = OpAccessChain %135 %17 %30
%138 = OpAccessChain %24 %12 %19
OpCopyMemory %138 %136 None
@@ -109,12 +110,14 @@
0)
.IsApplicable(context.get(), transformation_context));
- TransformationSetMemoryOperandsMask transformation1(
- MakeInstructionDescriptor(147, SpvOpLoad, 0),
- SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0);
- ASSERT_TRUE(
- transformation1.IsApplicable(context.get(), transformation_context));
- transformation1.Apply(context.get(), &transformation_context);
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(147, SpvOpLoad, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
// Not OK to remove Aligned
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
@@ -128,15 +131,17 @@
SpvMemoryAccessAlignedMask, 0)
.IsApplicable(context.get(), transformation_context));
- // OK: adds Nontemporal and Volatile
- TransformationSetMemoryOperandsMask transformation2(
- MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
- SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask |
- SpvMemoryAccessVolatileMask,
- 0);
- ASSERT_TRUE(
- transformation2.IsApplicable(context.get(), transformation_context));
- transformation2.Apply(context.get(), &transformation_context);
+ {
+ // OK: adds Nontemporal and Volatile
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask |
+ SpvMemoryAccessVolatileMask,
+ 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
// Not OK to remove Volatile
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
@@ -150,29 +155,45 @@
SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0)
.IsApplicable(context.get(), transformation_context));
- // OK: adds Nontemporal
- TransformationSetMemoryOperandsMask transformation3(
- MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
- SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
- ASSERT_TRUE(
- transformation3.IsApplicable(context.get(), transformation_context));
- transformation3.Apply(context.get(), &transformation_context);
+ {
+ // OK: adds Nontemporal
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- // OK: adds Nontemporal and Volatile
- TransformationSetMemoryOperandsMask transformation4(
- MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
- SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
- ASSERT_TRUE(
- transformation4.IsApplicable(context.get(), transformation_context));
- transformation4.Apply(context.get(), &transformation_context);
+ {
+ // OK: adds Nontemporal (creates new operand)
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 2),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- // OK: removes Nontemporal, adds Volatile
- TransformationSetMemoryOperandsMask transformation5(
- MakeInstructionDescriptor(148, SpvOpStore, 0),
- SpvMemoryAccessVolatileMask, 0);
- ASSERT_TRUE(
- transformation5.IsApplicable(context.get(), transformation_context));
- transformation5.Apply(context.get(), &transformation_context);
+ {
+ // OK: adds Nontemporal and Volatile
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
+
+ {
+ // OK: removes Nontemporal, adds Volatile
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(148, SpvOpStore, 0),
+ SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
std::string after_transformation = R"(
OpCapability Shader
@@ -228,6 +249,7 @@
%21 = OpAccessChain %20 %17 %19
OpCopyMemory %12 %21 Aligned|Nontemporal|Volatile 16
OpCopyMemory %133 %12 Nontemporal|Volatile
+ OpCopyMemory %133 %12 Nontemporal|Volatile
%136 = OpAccessChain %135 %17 %30
%138 = OpAccessChain %24 %12 %19
OpCopyMemory %138 %136 Nontemporal|Volatile
@@ -296,6 +318,8 @@
%21 = OpAccessChain %20 %17 %19
OpCopyMemory %12 %21 Aligned 16 Nontemporal|Aligned 16
OpCopyMemory %133 %12 Volatile
+ OpCopyMemory %133 %12
+ OpCopyMemory %133 %12
%136 = OpAccessChain %135 %17 %30
%138 = OpAccessChain %24 %12 %19
OpCopyMemory %138 %136 None Aligned 16
@@ -318,63 +342,95 @@
TransformationContext transformation_context(&fact_manager,
validator_options);
- TransformationSetMemoryOperandsMask transformation1(
- MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
- SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1);
- // Bad: cannot remove aligned
- ASSERT_FALSE(TransformationSetMemoryOperandsMask(
- MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
- SpvMemoryAccessVolatileMask, 1)
- .IsApplicable(context.get(), transformation_context));
- ASSERT_TRUE(
- transformation1.IsApplicable(context.get(), transformation_context));
- transformation1.Apply(context.get(), &transformation_context);
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1);
+ // Bad: cannot remove aligned
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
+ SpvMemoryAccessVolatileMask, 1)
+ .IsApplicable(context.get(), transformation_context));
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- TransformationSetMemoryOperandsMask transformation2(
- MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
- SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
- // Bad: cannot remove volatile
- ASSERT_FALSE(TransformationSetMemoryOperandsMask(
- MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
- SpvMemoryAccessNontemporalMask, 0)
- .IsApplicable(context.get(), transformation_context));
- ASSERT_TRUE(
- transformation2.IsApplicable(context.get(), transformation_context));
- transformation2.Apply(context.get(), &transformation_context);
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
+ // Bad: cannot remove volatile
+ ASSERT_FALSE(TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
+ SpvMemoryAccessNontemporalMask, 0)
+ .IsApplicable(context.get(), transformation_context));
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- TransformationSetMemoryOperandsMask transformation3(
- MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
- SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1);
- // Bad: the first mask is None, so Aligned cannot be added to it.
- ASSERT_FALSE(TransformationSetMemoryOperandsMask(
- MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
- SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask,
- 0)
- .IsApplicable(context.get(), transformation_context));
- ASSERT_TRUE(
- transformation3.IsApplicable(context.get(), transformation_context));
- transformation3.Apply(context.get(), &transformation_context);
+ {
+ // Creates the first operand.
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 2),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- TransformationSetMemoryOperandsMask transformation4(
- MakeInstructionDescriptor(138, SpvOpCopyMemory, 1),
- SpvMemoryAccessVolatileMask, 1);
- ASSERT_TRUE(
- transformation4.IsApplicable(context.get(), transformation_context));
- transformation4.Apply(context.get(), &transformation_context);
+ {
+ // Creates both operands.
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(21, SpvOpCopyMemory, 3),
+ SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- TransformationSetMemoryOperandsMask transformation5(
- MakeInstructionDescriptor(147, SpvOpLoad, 0),
- SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0);
- ASSERT_TRUE(
- transformation5.IsApplicable(context.get(), transformation_context));
- transformation5.Apply(context.get(), &transformation_context);
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1);
+ // Bad: the first mask is None, so Aligned cannot be added to it.
+ ASSERT_FALSE(
+ TransformationSetMemoryOperandsMask(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
+ SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 0)
+ .IsApplicable(context.get(), transformation_context));
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
- TransformationSetMemoryOperandsMask transformation6(
- MakeInstructionDescriptor(148, SpvOpStore, 0), SpvMemoryAccessMaskNone,
- 0);
- ASSERT_TRUE(
- transformation6.IsApplicable(context.get(), transformation_context));
- transformation6.Apply(context.get(), &transformation_context);
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(138, SpvOpCopyMemory, 1),
+ SpvMemoryAccessVolatileMask, 1);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
+
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(147, SpvOpLoad, 0),
+ SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
+
+ {
+ TransformationSetMemoryOperandsMask transformation(
+ MakeInstructionDescriptor(148, SpvOpStore, 0), SpvMemoryAccessMaskNone,
+ 0);
+ ASSERT_TRUE(
+ transformation.IsApplicable(context.get(), transformation_context));
+ transformation.Apply(context.get(), &transformation_context);
+ }
std::string after_transformation = R"(
OpCapability Shader
@@ -430,6 +486,8 @@
%21 = OpAccessChain %20 %17 %19
OpCopyMemory %12 %21 Aligned 16 Aligned|Volatile 16
OpCopyMemory %133 %12 Volatile Nontemporal|Volatile
+ OpCopyMemory %133 %12 Nontemporal|Volatile
+ OpCopyMemory %133 %12 None Nontemporal|Volatile
%136 = OpAccessChain %135 %17 %30
%138 = OpAccessChain %24 %12 %19
OpCopyMemory %138 %136 None Aligned|Nontemporal 16