Skip to content

Commit 246daf2

Browse files
authored
[OPT] Avoid assert in generatecopy (KhronosGroup#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.
1 parent 3634864 commit 246daf2

File tree

5 files changed

+72
-11
lines changed

5 files changed

+72
-11
lines changed

source/opt/copy_prop_arrays.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,8 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
751751
uint32_t pointee_type_id =
752752
pointer_type->GetSingleWordInOperand(kTypePointerPointeeInIdx);
753753
uint32_t copy = GenerateCopy(original_ptr_inst, pointee_type_id, use);
754+
assert(copy != 0 &&
755+
"Should not be updating uses unless we know it can be done.");
754756

755757
context()->ForgetUses(use);
756758
use->SetInOperand(index, {copy});

source/opt/fix_storage_class.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id,
237237
}
238238

239239
uint32_t copy_id = GenerateCopy(obj_inst, pointee_type_id, inst);
240+
if (copy_id == 0) {
241+
return false;
242+
}
240243
inst->SetInOperand(1, {copy_id});
241244
context()->UpdateDefUse(inst);
242245
}

source/opt/pass.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,10 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
9696

9797
Instruction* original_type = get_def_use_mgr()->GetDef(original_type_id);
9898
Instruction* new_type = get_def_use_mgr()->GetDef(new_type_id);
99-
assert(new_type->opcode() == original_type->opcode() &&
100-
"Can't copy an aggragate type unless the type correspond.");
99+
100+
if (new_type->opcode() != original_type->opcode()) {
101+
return 0;
102+
}
101103

102104
switch (original_type->opcode()) {
103105
case spv::Op::OpTypeArray: {
@@ -114,8 +116,12 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
114116
for (uint32_t i = 0; i < array_length; i++) {
115117
Instruction* extract = ir_builder.AddCompositeExtract(
116118
original_element_type_id, object_to_copy->result_id(), {i});
117-
element_ids.push_back(
118-
GenerateCopy(extract, new_element_type_id, insertion_position));
119+
uint32_t new_id =
120+
GenerateCopy(extract, new_element_type_id, insertion_position);
121+
if (new_id == 0) {
122+
return 0;
123+
}
124+
element_ids.push_back(new_id);
119125
}
120126

121127
return ir_builder.AddCompositeConstruct(new_type_id, element_ids)
@@ -128,20 +134,23 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
128134
uint32_t new_member_type_id = new_type->GetSingleWordInOperand(i);
129135
Instruction* extract = ir_builder.AddCompositeExtract(
130136
orig_member_type_id, object_to_copy->result_id(), {i});
131-
element_ids.push_back(
132-
GenerateCopy(extract, new_member_type_id, insertion_position));
137+
uint32_t new_id =
138+
GenerateCopy(extract, new_member_type_id, insertion_position);
139+
if (new_id == 0) {
140+
return 0;
141+
}
142+
element_ids.push_back(new_id);
133143
}
134144
return ir_builder.AddCompositeConstruct(new_type_id, element_ids)
135145
->result_id();
136146
}
137147
default:
138148
// If we do not have an aggregate type, then we have a problem. Either we
139149
// found multiple instances of the same type, or we are copying to an
140-
// incompatible type. Either way the code is illegal.
141-
assert(false &&
142-
"Don't know how to copy this type. Code is likely illegal.");
150+
// incompatible type. Either way the code is illegal. Leave the code as
151+
// is and let the caller deal with it.
152+
return 0;
143153
}
144-
return 0;
145154
}
146155

147156
} // namespace opt

source/opt/pass.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ class Pass {
145145

146146
// Returns the id whose value is the same as |object_to_copy| except its type
147147
// is |new_type_id|. Any instructions needed to generate this value will be
148-
// inserted before |insertion_position|.
148+
// inserted before |insertion_position|. Returns 0 if a copy could not be
149+
// done.
149150
uint32_t GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
150151
Instruction* insertion_position);
151152

test/opt/fix_storage_class_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,52 @@ OpFunctionEnd
987987
SinglePassRunAndCheck<FixStorageClass>(text, text, false);
988988
}
989989

990+
// This example is generated by DXC when certain inline spiir-v is used.
991+
// The intention is that the function scope variable will eventually be
992+
// optimized away, removing the type mismatch. We want to make sure the
993+
// OpCopyObject is rewritten, and that the pass does not fail.
994+
TEST_F(FixStorageClassTest, DoNotFailWithMismatchedPointerTypes) {
995+
const std::string text = R"(
996+
OpCapability Shader
997+
OpMemoryModel Logical GLSL450
998+
OpEntryPoint GLCompute %1 "main" %38
999+
OpExecutionMode %1 LocalSize 64 1 1
1000+
OpSource HLSL 600
1001+
%int = OpTypeInt 32 1
1002+
%int_0 = OpConstant %int 0
1003+
%float = OpTypeFloat 32
1004+
%uint = OpTypeInt 32 0
1005+
%uint_64 = OpConstant %uint 64
1006+
%_arr_float_uint_64 = OpTypeArray %float %uint_64
1007+
%_ptr_Workgroup__arr_float_uint_64 = OpTypePointer Workgroup %_arr_float_uint_64
1008+
%void = OpTypeVoid
1009+
%80 = OpTypeFunction %void
1010+
%_ptr_Workgroup_float = OpTypePointer Workgroup %float
1011+
%_ptr_Function__ptr_Workgroup_float = OpTypePointer Function %_ptr_Workgroup_float
1012+
%_ptr_Workgroup_float_0 = OpTypePointer Workgroup %float
1013+
%38 = OpVariable %_ptr_Workgroup__arr_float_uint_64 Workgroup
1014+
%1 = OpFunction %void None %80
1015+
%98 = OpLabel
1016+
; CHECK: [[var:%\d+]] = OpVariable %_ptr_Function__ptr_Workgroup_float Function
1017+
%113 = OpVariable %_ptr_Function__ptr_Workgroup_float Function
1018+
; CHECK: [[ac:%\d+]] = OpAccessChain %_ptr_Workgroup_float_0 {{%\d+}} %int_0
1019+
%136 = OpAccessChain %_ptr_Workgroup_float_0 %38 %int_0
1020+
; Verify that the type for the OpCopyObject has changed to match [[ac]].
1021+
; CHECK: [[copy:%\d+]] = OpCopyObject %_ptr_Workgroup_float_0 [[ac]]
1022+
%137 = OpCopyObject %_ptr_Workgroup_float %136
1023+
; This has a type mismatch, but this is because we do not have a way to copy
1024+
; a pointer from one type to another, so FixStorageClass cannot do anything
1025+
; about it. We want fix storage class to leave it as is, and the validator
1026+
; will report an error if the store is not remove by a later optimization.
1027+
; CHECK: OpStore [[var]] [[copy]]
1028+
OpStore %113 %137
1029+
OpReturn
1030+
OpFunctionEnd
1031+
)";
1032+
1033+
SinglePassRunAndMatch<FixStorageClass>(text, false);
1034+
}
1035+
9901036
} // namespace
9911037
} // namespace opt
9921038
} // namespace spvtools

0 commit comments

Comments
 (0)