Skip to content

Commit e08c012

Browse files
authored
[OPT] Identify arrays with unknown length in copy prop arrays (KhronosGroup#5570)
* [OPT] Identify arrays with unknown length in copy prop arrays The code in copy propagate arrays assumes that the length of an OpTypeArray is known at compile time, but that is not true when the size is an OpSpecConstant. We try to fix that assumption. Fixes https://crbug.com/oss-fuzz/66634
1 parent 56a51dd commit e08c012

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

source/opt/copy_prop_arrays.cpp

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,32 @@ bool IsDebugDeclareOrValue(Instruction* di) {
3535
dbg_opcode == CommonDebugInfoDebugValue;
3636
}
3737

38+
// Returns the number of members in |type|. If |type| is not a composite type
39+
// or the number of components is not known at compile time, the return value
40+
// will be 0.
41+
uint32_t GetNumberOfMembers(const analysis::Type* type, IRContext* context) {
42+
if (const analysis::Struct* struct_type = type->AsStruct()) {
43+
return static_cast<uint32_t>(struct_type->element_types().size());
44+
} else if (const analysis::Array* array_type = type->AsArray()) {
45+
const analysis::Constant* length_const =
46+
context->get_constant_mgr()->FindDeclaredConstant(
47+
array_type->LengthId());
48+
49+
if (length_const == nullptr) {
50+
// This can happen if the length is an OpSpecConstant.
51+
return 0;
52+
}
53+
assert(length_const->type()->AsInteger());
54+
return length_const->GetU32();
55+
} else if (const analysis::Vector* vector_type = type->AsVector()) {
56+
return vector_type->element_count();
57+
} else if (const analysis::Matrix* matrix_type = type->AsMatrix()) {
58+
return matrix_type->element_count();
59+
} else {
60+
return 0;
61+
}
62+
}
63+
3864
} // namespace
3965

4066
Pass::Status CopyPropagateArrays::Process() {
@@ -357,22 +383,9 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) {
357383

358384
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
359385
analysis::TypeManager* type_mgr = context()->get_type_mgr();
360-
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
361386
const analysis::Type* result_type = type_mgr->GetType(insert_inst->type_id());
362387

363-
uint32_t number_of_elements = 0;
364-
if (const analysis::Struct* struct_type = result_type->AsStruct()) {
365-
number_of_elements =
366-
static_cast<uint32_t>(struct_type->element_types().size());
367-
} else if (const analysis::Array* array_type = result_type->AsArray()) {
368-
const analysis::Constant* length_const =
369-
const_mgr->FindDeclaredConstant(array_type->LengthId());
370-
number_of_elements = length_const->GetU32();
371-
} else if (const analysis::Vector* vector_type = result_type->AsVector()) {
372-
number_of_elements = vector_type->element_count();
373-
} else if (const analysis::Matrix* matrix_type = result_type->AsMatrix()) {
374-
number_of_elements = matrix_type->element_count();
375-
}
388+
uint32_t number_of_elements = GetNumberOfMembers(result_type, context());
376389

377390
if (number_of_elements == 0) {
378391
return nullptr;
@@ -800,23 +813,8 @@ uint32_t CopyPropagateArrays::MemoryObject::GetNumberOfMembers() {
800813
std::vector<uint32_t> access_indices = GetAccessIds();
801814
type = type_mgr->GetMemberType(type, access_indices);
802815

803-
if (const analysis::Struct* struct_type = type->AsStruct()) {
804-
return static_cast<uint32_t>(struct_type->element_types().size());
805-
} else if (const analysis::Array* array_type = type->AsArray()) {
806-
const analysis::Constant* length_const =
807-
context->get_constant_mgr()->FindDeclaredConstant(
808-
array_type->LengthId());
809-
assert(length_const->type()->AsInteger());
810-
return length_const->GetU32();
811-
} else if (const analysis::Vector* vector_type = type->AsVector()) {
812-
return vector_type->element_count();
813-
} else if (const analysis::Matrix* matrix_type = type->AsMatrix()) {
814-
return matrix_type->element_count();
815-
} else {
816-
return 0;
817-
}
816+
return opt::GetNumberOfMembers(type, context);
818817
}
819-
820818
template <class iterator>
821819
CopyPropagateArrays::MemoryObject::MemoryObject(Instruction* var_inst,
822820
iterator begin, iterator end)

source/opt/copy_prop_arrays.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ class CopyPropagateArrays : public MemPass {
101101
bool IsMember() const { return !access_chain_.empty(); }
102102

103103
// Returns the number of members in the object represented by |this|. If
104-
// |this| does not represent a composite type, the return value will be 0.
104+
// |this| does not represent a composite type or the number of components is
105+
// not known at compile time, the return value will be 0.
105106
uint32_t GetNumberOfMembers();
106107

107108
// Returns the owning variable that the memory object is contained in.
@@ -207,7 +208,7 @@ class CopyPropagateArrays : public MemPass {
207208

208209
// Returns the memory object that at some point was equivalent to the result
209210
// of |insert_inst|. If a memory object cannot be identified, the return
210-
// value is |nullptr\. The opcode of |insert_inst| must be
211+
// value is |nullptr|. The opcode of |insert_inst| must be
211212
// |OpCompositeInsert|. This function looks for a series of
212213
// |OpCompositeInsert| instructions that insert the elements one at a time in
213214
// order from beginning to end.

test/opt/copy_prop_array_test.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1942,6 +1942,41 @@ OpFunctionEnd
19421942

19431943
SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
19441944
}
1945+
1946+
// If the size of an array used in an OpCompositeInsert is not known at compile
1947+
// time, then we should not propagate the array, because we do not have a single
1948+
// array that represents the final value.
1949+
TEST_F(CopyPropArrayPassTest, SpecConstSizedArray) {
1950+
const std::string text = R"(OpCapability Shader
1951+
%1 = OpExtInstImport "GLSL.std.450"
1952+
OpMemoryModel Logical GLSL450
1953+
OpEntryPoint Fragment %2 "main"
1954+
OpExecutionMode %2 OriginUpperLeft
1955+
%void = OpTypeVoid
1956+
%4 = OpTypeFunction %void
1957+
%int = OpTypeInt 32 1
1958+
%uint = OpTypeInt 32 0
1959+
%7 = OpSpecConstant %uint 32
1960+
%_arr_int_7 = OpTypeArray %int %7
1961+
%int_63 = OpConstant %int 63
1962+
%uint_0 = OpConstant %uint 0
1963+
%bool = OpTypeBool
1964+
%int_0 = OpConstant %int 0
1965+
%int_587202566 = OpConstant %int 587202566
1966+
%false = OpConstantFalse %bool
1967+
%_ptr_Function__arr_int_7 = OpTypePointer Function %_arr_int_7
1968+
%16 = OpUndef %_arr_int_7
1969+
%2 = OpFunction %void None %4
1970+
%17 = OpLabel
1971+
%18 = OpVariable %_ptr_Function__arr_int_7 Function
1972+
%19 = OpCompositeInsert %_arr_int_7 %int_0 %16 0
1973+
OpStore %18 %19
1974+
OpReturn
1975+
OpFunctionEnd
1976+
)";
1977+
1978+
SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
1979+
}
19451980
} // namespace
19461981
} // namespace opt
19471982
} // namespace spvtools

0 commit comments

Comments
 (0)