[OPT] Avoid assert in generatecopy (#5756)
We want to be able to recover when fix storage class is not able to fix
everything, and just leave the spir-v in an invalid state. The pass
should not fail because of that.
diff --git a/source/opt/copy_prop_arrays.cpp b/source/opt/copy_prop_arrays.cpp
index c2bea8a..26b5ef7 100644
--- a/source/opt/copy_prop_arrays.cpp
+++ b/source/opt/copy_prop_arrays.cpp
@@ -751,6 +751,8 @@
uint32_t pointee_type_id =
pointer_type->GetSingleWordInOperand(kTypePointerPointeeInIdx);
uint32_t copy = GenerateCopy(original_ptr_inst, pointee_type_id, use);
+ assert(copy != 0 &&
+ "Should not be updating uses unless we know it can be done.");
context()->ForgetUses(use);
use->SetInOperand(index, {copy});
diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp
index 367418d..b64026e 100644
--- a/source/opt/fix_storage_class.cpp
+++ b/source/opt/fix_storage_class.cpp
@@ -237,6 +237,9 @@
}
uint32_t copy_id = GenerateCopy(obj_inst, pointee_type_id, inst);
+ if (copy_id == 0) {
+ return false;
+ }
inst->SetInOperand(1, {copy_id});
context()->UpdateDefUse(inst);
}
diff --git a/source/opt/pass.cpp b/source/opt/pass.cpp
index 28f26c5..0f260e2 100644
--- a/source/opt/pass.cpp
+++ b/source/opt/pass.cpp
@@ -96,8 +96,10 @@
Instruction* original_type = get_def_use_mgr()->GetDef(original_type_id);
Instruction* new_type = get_def_use_mgr()->GetDef(new_type_id);
- assert(new_type->opcode() == original_type->opcode() &&
- "Can't copy an aggragate type unless the type correspond.");
+
+ if (new_type->opcode() != original_type->opcode()) {
+ return 0;
+ }
switch (original_type->opcode()) {
case spv::Op::OpTypeArray: {
@@ -114,8 +116,12 @@
for (uint32_t i = 0; i < array_length; i++) {
Instruction* extract = ir_builder.AddCompositeExtract(
original_element_type_id, object_to_copy->result_id(), {i});
- element_ids.push_back(
- GenerateCopy(extract, new_element_type_id, insertion_position));
+ uint32_t new_id =
+ GenerateCopy(extract, new_element_type_id, insertion_position);
+ if (new_id == 0) {
+ return 0;
+ }
+ element_ids.push_back(new_id);
}
return ir_builder.AddCompositeConstruct(new_type_id, element_ids)
@@ -128,8 +134,12 @@
uint32_t new_member_type_id = new_type->GetSingleWordInOperand(i);
Instruction* extract = ir_builder.AddCompositeExtract(
orig_member_type_id, object_to_copy->result_id(), {i});
- element_ids.push_back(
- GenerateCopy(extract, new_member_type_id, insertion_position));
+ uint32_t new_id =
+ GenerateCopy(extract, new_member_type_id, insertion_position);
+ if (new_id == 0) {
+ return 0;
+ }
+ element_ids.push_back(new_id);
}
return ir_builder.AddCompositeConstruct(new_type_id, element_ids)
->result_id();
@@ -137,11 +147,10 @@
default:
// If we do not have an aggregate type, then we have a problem. Either we
// found multiple instances of the same type, or we are copying to an
- // incompatible type. Either way the code is illegal.
- assert(false &&
- "Don't know how to copy this type. Code is likely illegal.");
+ // incompatible type. Either way the code is illegal. Leave the code as
+ // is and let the caller deal with it.
+ return 0;
}
- return 0;
}
} // namespace opt
diff --git a/source/opt/pass.h b/source/opt/pass.h
index b2303e2..3e6c4d0 100644
--- a/source/opt/pass.h
+++ b/source/opt/pass.h
@@ -145,7 +145,8 @@
// Returns the id whose value is the same as |object_to_copy| except its type
// is |new_type_id|. Any instructions needed to generate this value will be
- // inserted before |insertion_position|.
+ // inserted before |insertion_position|. Returns 0 if a copy could not be
+ // done.
uint32_t GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
Instruction* insertion_position);
diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp
index 410f140..01a75e0 100644
--- a/test/opt/fix_storage_class_test.cpp
+++ b/test/opt/fix_storage_class_test.cpp
@@ -987,6 +987,52 @@
SinglePassRunAndCheck<FixStorageClass>(text, text, false);
}
+// This example is generated by DXC when certain inline spiir-v is used.
+// The intention is that the function scope variable will eventually be
+// optimized away, removing the type mismatch. We want to make sure the
+// OpCopyObject is rewritten, and that the pass does not fail.
+TEST_F(FixStorageClassTest, DoNotFailWithMismatchedPointerTypes) {
+ const std::string text = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %1 "main" %38
+ OpExecutionMode %1 LocalSize 64 1 1
+ OpSource HLSL 600
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %float = OpTypeFloat 32
+ %uint = OpTypeInt 32 0
+ %uint_64 = OpConstant %uint 64
+%_arr_float_uint_64 = OpTypeArray %float %uint_64
+%_ptr_Workgroup__arr_float_uint_64 = OpTypePointer Workgroup %_arr_float_uint_64
+ %void = OpTypeVoid
+ %80 = OpTypeFunction %void
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Function__ptr_Workgroup_float = OpTypePointer Function %_ptr_Workgroup_float
+%_ptr_Workgroup_float_0 = OpTypePointer Workgroup %float
+ %38 = OpVariable %_ptr_Workgroup__arr_float_uint_64 Workgroup
+ %1 = OpFunction %void None %80
+ %98 = OpLabel
+; CHECK: [[var:%\d+]] = OpVariable %_ptr_Function__ptr_Workgroup_float Function
+ %113 = OpVariable %_ptr_Function__ptr_Workgroup_float Function
+; CHECK: [[ac:%\d+]] = OpAccessChain %_ptr_Workgroup_float_0 {{%\d+}} %int_0
+ %136 = OpAccessChain %_ptr_Workgroup_float_0 %38 %int_0
+; Verify that the type for the OpCopyObject has changed to match [[ac]].
+; CHECK: [[copy:%\d+]] = OpCopyObject %_ptr_Workgroup_float_0 [[ac]]
+ %137 = OpCopyObject %_ptr_Workgroup_float %136
+; This has a type mismatch, but this is because we do not have a way to copy
+; a pointer from one type to another, so FixStorageClass cannot do anything
+; about it. We want fix storage class to leave it as is, and the validator
+; will report an error if the store is not remove by a later optimization.
+; CHECK: OpStore [[var]] [[copy]]
+ OpStore %113 %137
+ OpReturn
+ OpFunctionEnd
+)";
+
+ SinglePassRunAndMatch<FixStorageClass>(text, false);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools