mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
parent
4c239bd81b
commit
3131686d2e
@ -281,14 +281,9 @@ void DataSynonymAndIdEquationFacts::ComputeConversionDataSynonymFacts(
|
||||
assert(synonymous_.Exists(dd) &&
|
||||
"|dd| should've been registered in the equivalence relation");
|
||||
|
||||
const auto* representative = synonymous_.Find(&dd);
|
||||
assert(representative &&
|
||||
"Representative can't be null for a registered descriptor");
|
||||
|
||||
const auto* type =
|
||||
context->get_type_mgr()->GetType(fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, fuzzerutil::GetTypeId(context, representative->object()),
|
||||
representative->index()));
|
||||
context, fuzzerutil::GetTypeId(context, dd.object()), dd.index()));
|
||||
assert(type && "Data descriptor has invalid type");
|
||||
|
||||
if ((type->AsVector() && type->AsVector()->element_type()->AsInteger()) ||
|
||||
@ -300,24 +295,36 @@ void DataSynonymAndIdEquationFacts::ComputeConversionDataSynonymFacts(
|
||||
std::vector<const protobufs::DataDescriptor*> convert_u_to_f_lhs;
|
||||
|
||||
for (const auto& fact : id_equations_) {
|
||||
auto equivalence_class = synonymous_.GetEquivalenceClass(*fact.first);
|
||||
auto dd_it = std::find_if(
|
||||
equivalence_class.begin(), equivalence_class.end(),
|
||||
[context](const protobufs::DataDescriptor* a) {
|
||||
return context->get_def_use_mgr()->GetDef(a->object()) != nullptr;
|
||||
});
|
||||
if (dd_it == equivalence_class.end()) {
|
||||
// Skip |equivalence_class| if it has no valid ids.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& equation : fact.second) {
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *representative)) {
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], dd)) {
|
||||
if (equation.opcode == SpvOpConvertSToF) {
|
||||
convert_s_to_f_lhs.push_back(fact.first);
|
||||
convert_s_to_f_lhs.push_back(*dd_it);
|
||||
} else if (equation.opcode == SpvOpConvertUToF) {
|
||||
convert_u_to_f_lhs.push_back(fact.first);
|
||||
convert_u_to_f_lhs.push_back(*dd_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& synonyms :
|
||||
{std::move(convert_s_to_f_lhs), std::move(convert_u_to_f_lhs)}) {
|
||||
for (const auto* synonym_a : synonyms) {
|
||||
for (const auto* synonym_b : synonyms) {
|
||||
if (!synonymous_.IsEquivalent(*synonym_a, *synonym_b) &&
|
||||
DataDescriptorsAreWellFormedAndComparable(context, *synonym_a,
|
||||
*synonym_b)) {
|
||||
// We use pointers in the initializer list here since otherwise we would
|
||||
// copy memory from these vectors.
|
||||
for (const auto* synonyms : {&convert_s_to_f_lhs, &convert_u_to_f_lhs}) {
|
||||
for (const auto* synonym_a : *synonyms) {
|
||||
for (const auto* synonym_b : *synonyms) {
|
||||
// DataDescriptorsAreWellFormedAndComparable will be called in the
|
||||
// AddDataSynonymFactRecursive method.
|
||||
if (!synonymous_.IsEquivalent(*synonym_a, *synonym_b)) {
|
||||
// |synonym_a| and |synonym_b| have compatible types - they are
|
||||
// synonymous.
|
||||
AddDataSynonymFactRecursive(*synonym_a, *synonym_b, context);
|
||||
@ -765,12 +772,14 @@ DataSynonymAndIdEquationFacts::RegisterDataDescriptor(
|
||||
bool DataSynonymAndIdEquationFacts::DataDescriptorsAreWellFormedAndComparable(
|
||||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2) {
|
||||
assert(context->get_def_use_mgr()->GetDef(dd1.object()) &&
|
||||
context->get_def_use_mgr()->GetDef(dd2.object()) &&
|
||||
"Both descriptors must exist in the module");
|
||||
|
||||
auto end_type_id_1 = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(),
|
||||
dd1.index());
|
||||
context, fuzzerutil::GetTypeId(context, dd1.object()), dd1.index());
|
||||
auto end_type_id_2 = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, context->get_def_use_mgr()->GetDef(dd2.object())->type_id(),
|
||||
dd2.index());
|
||||
context, fuzzerutil::GetTypeId(context, dd2.object()), dd2.index());
|
||||
// The end types of the data descriptors must exist.
|
||||
if (end_type_id_1 == 0 || end_type_id_2 == 0) {
|
||||
return false;
|
||||
|
@ -572,7 +572,9 @@ bool InstructionIsFunctionParameter(opt::Instruction* instruction,
|
||||
}
|
||||
|
||||
uint32_t GetTypeId(opt::IRContext* context, uint32_t result_id) {
|
||||
return context->get_def_use_mgr()->GetDef(result_id)->type_id();
|
||||
const auto* inst = context->get_def_use_mgr()->GetDef(result_id);
|
||||
assert(inst && "|result_id| is invalid");
|
||||
return inst->type_id();
|
||||
}
|
||||
|
||||
uint32_t GetPointeeTypeIdFromPointerType(opt::Instruction* pointer_type_inst) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "source/fuzz/transformation_merge_blocks.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
@ -871,6 +872,78 @@ TEST(FactManagerTest, CorollaryConversionFacts) {
|
||||
MakeDataDescriptor(29, {})));
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, HandlesCorollariesWithInvalidIds) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %12 "main"
|
||||
OpExecutionMode %12 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%8 = OpTypeInt 32 1
|
||||
%9 = OpConstant %8 3
|
||||
%12 = OpFunction %2 None %3
|
||||
%13 = OpLabel
|
||||
%14 = OpConvertSToF %6 %9
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%17 = OpPhi %6 %14 %13
|
||||
%15 = OpConvertSToF %6 %9
|
||||
%18 = OpConvertSToF %6 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Add required facts.
|
||||
fact_manager.AddFactIdEquation(14, SpvOpConvertSToF, {9}, context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(14, {}),
|
||||
MakeDataDescriptor(17, {}), context.get());
|
||||
|
||||
// Apply TransformationMergeBlocks which will remove %17 from the module.
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
TransformationContext transformation_context(&fact_manager,
|
||||
validator_options);
|
||||
TransformationMergeBlocks transformation(16);
|
||||
ASSERT_TRUE(
|
||||
transformation.IsApplicable(context.get(), transformation_context));
|
||||
transformation.Apply(context.get(), &transformation_context);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_EQ(context->get_def_use_mgr()->GetDef(17), nullptr);
|
||||
|
||||
// Add another equation.
|
||||
fact_manager.AddFactIdEquation(15, SpvOpConvertSToF, {9}, context.get());
|
||||
|
||||
// Check that two ids are synonymous even though one of them doesn't exist in
|
||||
// the module (%17).
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}),
|
||||
MakeDataDescriptor(17, {})));
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}),
|
||||
MakeDataDescriptor(14, {})));
|
||||
|
||||
// Remove some instructions from the module. At this point, the equivalence
|
||||
// class of %14 has no valid members.
|
||||
ASSERT_TRUE(context->KillDef(14));
|
||||
ASSERT_TRUE(context->KillDef(15));
|
||||
|
||||
fact_manager.AddFactIdEquation(18, SpvOpConvertSToF, {9}, context.get());
|
||||
|
||||
// We don't create synonyms if at least one of the equivalence classes has no
|
||||
// valid members.
|
||||
ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(14, {}),
|
||||
MakeDataDescriptor(18, {})));
|
||||
}
|
||||
|
||||
TEST(FactManagerTest, LogicalNotEquationFacts) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
|
Loading…
Reference in New Issue
Block a user