spirv-fuzz: Support bitwise or and xor in TransformationAddBitInstructionSynonym (#4310)

Fixes #4172.
This commit is contained in:
EGJ1996 2021-06-09 17:23:26 +02:00 committed by GitHub
parent d07505c761
commit c1a75bfabf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 47 deletions

View File

@ -79,6 +79,8 @@ void FuzzerPassAddSynonyms::Apply() {
case protobufs::TransformationAddSynonym::ADD_ZERO: case protobufs::TransformationAddSynonym::ADD_ZERO:
case protobufs::TransformationAddSynonym::SUB_ZERO: case protobufs::TransformationAddSynonym::SUB_ZERO:
case protobufs::TransformationAddSynonym::LOGICAL_OR: case protobufs::TransformationAddSynonym::LOGICAL_OR:
case protobufs::TransformationAddSynonym::BITWISE_OR:
case protobufs::TransformationAddSynonym::BITWISE_XOR:
// Create a zero constant to be used as an operand of the synonymous // Create a zero constant to be used as an operand of the synonymous
// instruction. // instruction.
FindOrCreateZeroConstant(existing_synonym->type_id(), false); FindOrCreateZeroConstant(existing_synonym->type_id(), false);

View File

@ -1136,6 +1136,14 @@ message TransformationAddSynonym {
// New synonym is derived by applying OpLogicalAnd to |result_id| with the second // New synonym is derived by applying OpLogicalAnd to |result_id| with the second
// operand being 'true'. // operand being 'true'.
LOGICAL_AND = 5; LOGICAL_AND = 5;
// New synonym is derived by applying OpBitwiseOr to |result_id| with the second
// operand being 0 taken with the same bit length as |result_id|
BITWISE_OR = 6;
// New synonym is derived by applying OpBitwiseXor to |result_id| with the second
// operand being 0 taken with the same bit length as |result_id|
BITWISE_XOR = 7;
} }
// Type of the synonym to create. See SynonymType for more details. // Type of the synonym to create. See SynonymType for more details.

View File

@ -170,6 +170,18 @@ bool TransformationAddSynonym::IsInstructionValid(
return type->AsInteger() || type->AsFloat(); return type->AsInteger() || type->AsFloat();
} }
case protobufs::TransformationAddSynonym::BITWISE_OR:
case protobufs::TransformationAddSynonym::BITWISE_XOR: {
// The instruction must be either an integer or a vector of integers.
const auto* type = ir_context->get_type_mgr()->GetType(inst->type_id());
assert(type && "Instruction's result id is invalid");
if (const auto* vector = type->AsVector()) {
return vector->element_type()->AsInteger();
}
return type->AsInteger();
}
case protobufs::TransformationAddSynonym::COPY_OBJECT: case protobufs::TransformationAddSynonym::COPY_OBJECT:
// All checks for OpCopyObject are handled by // All checks for OpCopyObject are handled by
// fuzzerutil::CanMakeSynonymOf. // fuzzerutil::CanMakeSynonymOf.
@ -195,68 +207,56 @@ TransformationAddSynonym::MakeSynonymousInstruction(
auto synonym_type_id = auto synonym_type_id =
fuzzerutil::GetTypeId(ir_context, message_.result_id()); fuzzerutil::GetTypeId(ir_context, message_.result_id());
assert(synonym_type_id && "Synonym has invalid type id"); assert(synonym_type_id && "Synonym has invalid type id");
auto opcode = SpvOpNop;
const auto* synonym_type =
ir_context->get_type_mgr()->GetType(synonym_type_id);
assert(synonym_type && "Synonym has invalid type");
auto is_integral = (synonym_type->AsVector() &&
synonym_type->AsVector()->element_type()->AsInteger()) ||
synonym_type->AsInteger();
switch (message_.synonym_type()) { switch (message_.synonym_type()) {
case protobufs::TransformationAddSynonym::SUB_ZERO: case protobufs::TransformationAddSynonym::SUB_ZERO:
opcode = is_integral ? SpvOpISub : SpvOpFSub;
break;
case protobufs::TransformationAddSynonym::MUL_ONE: case protobufs::TransformationAddSynonym::MUL_ONE:
case protobufs::TransformationAddSynonym::ADD_ZERO: { opcode = is_integral ? SpvOpIMul : SpvOpFMul;
const auto* synonym_type = break;
ir_context->get_type_mgr()->GetType(synonym_type_id); case protobufs::TransformationAddSynonym::ADD_ZERO:
assert(synonym_type && "Synonym has invalid type"); opcode = is_integral ? SpvOpIAdd : SpvOpFAdd;
break;
case protobufs::TransformationAddSynonym::LOGICAL_OR:
opcode = SpvOpLogicalOr;
break;
case protobufs::TransformationAddSynonym::LOGICAL_AND:
opcode = SpvOpLogicalAnd;
break;
case protobufs::TransformationAddSynonym::BITWISE_OR:
opcode = SpvOpBitwiseOr;
break;
case protobufs::TransformationAddSynonym::BITWISE_XOR:
opcode = SpvOpBitwiseXor;
break;
// Compute instruction's opcode based on the type of the operand.
// We have already checked that the operand is either a scalar or a vector
// of either integers or floats.
auto is_integral =
(synonym_type->AsVector() &&
synonym_type->AsVector()->element_type()->AsInteger()) ||
synonym_type->AsInteger();
auto opcode = SpvOpNop;
switch (message_.synonym_type()) {
case protobufs::TransformationAddSynonym::SUB_ZERO:
opcode = is_integral ? SpvOpISub : SpvOpFSub;
break;
case protobufs::TransformationAddSynonym::MUL_ONE:
opcode = is_integral ? SpvOpIMul : SpvOpFMul;
break;
case protobufs::TransformationAddSynonym::ADD_ZERO:
opcode = is_integral ? SpvOpIAdd : SpvOpFAdd;
break;
default:
assert(false && "Unreachable");
break;
}
return MakeUnique<opt::Instruction>(
ir_context, opcode, synonym_type_id, message_.synonym_fresh_id(),
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_ID, {message_.result_id()}},
{SPV_OPERAND_TYPE_ID,
{MaybeGetConstantId(ir_context, transformation_context)}}});
}
case protobufs::TransformationAddSynonym::COPY_OBJECT: case protobufs::TransformationAddSynonym::COPY_OBJECT:
return MakeUnique<opt::Instruction>( return MakeUnique<opt::Instruction>(
ir_context, SpvOpCopyObject, synonym_type_id, ir_context, SpvOpCopyObject, synonym_type_id,
message_.synonym_fresh_id(), message_.synonym_fresh_id(),
opt::Instruction::OperandList{ opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_ID, {message_.result_id()}}}); {SPV_OPERAND_TYPE_ID, {message_.result_id()}}});
case protobufs::TransformationAddSynonym::LOGICAL_OR:
case protobufs::TransformationAddSynonym::LOGICAL_AND: {
auto opcode = message_.synonym_type() ==
protobufs::TransformationAddSynonym::LOGICAL_OR
? SpvOpLogicalOr
: SpvOpLogicalAnd;
return MakeUnique<opt::Instruction>(
ir_context, opcode, synonym_type_id, message_.synonym_fresh_id(),
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_ID, {message_.result_id()}},
{SPV_OPERAND_TYPE_ID,
{MaybeGetConstantId(ir_context, transformation_context)}}});
}
default: default:
assert(false && "Unhandled synonym type"); assert(false && "Unhandled synonym type");
return nullptr; return nullptr;
} }
return MakeUnique<opt::Instruction>(
ir_context, opcode, synonym_type_id, message_.synonym_fresh_id(),
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_ID, {message_.result_id()}},
{SPV_OPERAND_TYPE_ID,
{MaybeGetConstantId(ir_context, transformation_context)}}});
} }
uint32_t TransformationAddSynonym::MaybeGetConstantId( uint32_t TransformationAddSynonym::MaybeGetConstantId(
@ -273,6 +273,8 @@ uint32_t TransformationAddSynonym::MaybeGetConstantId(
case protobufs::TransformationAddSynonym::ADD_ZERO: case protobufs::TransformationAddSynonym::ADD_ZERO:
case protobufs::TransformationAddSynonym::SUB_ZERO: case protobufs::TransformationAddSynonym::SUB_ZERO:
case protobufs::TransformationAddSynonym::LOGICAL_OR: case protobufs::TransformationAddSynonym::LOGICAL_OR:
case protobufs::TransformationAddSynonym::BITWISE_OR:
case protobufs::TransformationAddSynonym::BITWISE_XOR:
return fuzzerutil::MaybeGetZeroConstant( return fuzzerutil::MaybeGetZeroConstant(
ir_context, transformation_context, synonym_type_id, false); ir_context, transformation_context, synonym_type_id, false);
case protobufs::TransformationAddSynonym::MUL_ONE: case protobufs::TransformationAddSynonym::MUL_ONE:
@ -319,6 +321,8 @@ bool TransformationAddSynonym::IsAdditionalConstantRequired(
case protobufs::TransformationAddSynonym::LOGICAL_OR: case protobufs::TransformationAddSynonym::LOGICAL_OR:
case protobufs::TransformationAddSynonym::MUL_ONE: case protobufs::TransformationAddSynonym::MUL_ONE:
case protobufs::TransformationAddSynonym::LOGICAL_AND: case protobufs::TransformationAddSynonym::LOGICAL_AND:
case protobufs::TransformationAddSynonym::BITWISE_OR:
case protobufs::TransformationAddSynonym::BITWISE_XOR:
return true; return true;
default: default:
return false; return false;

View File

@ -197,6 +197,7 @@ TEST(TransformationAddSynonymTest, AddZeroSubZeroMulOne) {
%37 = OpTypeVector %36 2 %37 = OpTypeVector %36 2
%38 = OpConstantTrue %36 %38 = OpConstantTrue %36
%39 = OpConstantComposite %37 %38 %38 %39 = OpConstantComposite %37 %38 %38
%40 = OpConstant %6 37
%4 = OpFunction %2 None %3 %4 = OpFunction %2 None %3
%5 = OpLabel %5 = OpLabel
OpReturn OpReturn
@ -249,6 +250,29 @@ TEST(TransformationAddSynonymTest, AddZeroSubZeroMulOne) {
++fresh_id; ++fresh_id;
} }
} }
{
TransformationAddSynonym transformation(
40, protobufs::TransformationAddSynonym::BITWISE_OR, fresh_id,
insert_before);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
MakeDataDescriptor(40, {}), MakeDataDescriptor(fresh_id, {})));
++fresh_id;
}
{
TransformationAddSynonym transformation(
40, protobufs::TransformationAddSynonym::BITWISE_XOR, fresh_id,
insert_before);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
MakeDataDescriptor(40, {}), MakeDataDescriptor(fresh_id, {})));
}
std::string expected_shader = R"( std::string expected_shader = R"(
OpCapability Shader OpCapability Shader
@ -289,6 +313,7 @@ TEST(TransformationAddSynonymTest, AddZeroSubZeroMulOne) {
%37 = OpTypeVector %36 2 %37 = OpTypeVector %36 2
%38 = OpConstantTrue %36 %38 = OpConstantTrue %36
%39 = OpConstantComposite %37 %38 %38 %39 = OpConstantComposite %37 %38 %38
%40 = OpConstant %6 37
%4 = OpFunction %2 None %3 %4 = OpFunction %2 None %3
%5 = OpLabel %5 = OpLabel
%50 = OpIAdd %6 %9 %7 %50 = OpIAdd %6 %9 %7
@ -303,6 +328,8 @@ TEST(TransformationAddSynonymTest, AddZeroSubZeroMulOne) {
%59 = OpFMul %14 %17 %16 %59 = OpFMul %14 %17 %16
%60 = OpFMul %18 %23 %20 %60 = OpFMul %18 %23 %20
%61 = OpIMul %24 %29 %26 %61 = OpIMul %24 %29 %26
%62 = OpBitwiseOr %6 %40 %7
%63 = OpBitwiseXor %6 %40 %7
OpReturn OpReturn
OpFunctionEnd OpFunctionEnd
)"; )";