mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-21 22:20:14 +01:00
brw: Add BRW_TYPE_BF validation
Reviewed-by: Rohan Garg <rohan.garg@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33664>
This commit is contained in:
parent
9916cc1050
commit
62323a934b
3 changed files with 317 additions and 16 deletions
|
|
@ -425,8 +425,9 @@ execution_type_for_type(enum brw_reg_type type)
|
||||||
case BRW_TYPE_V:
|
case BRW_TYPE_V:
|
||||||
case BRW_TYPE_UV:
|
case BRW_TYPE_UV:
|
||||||
return BRW_TYPE_W;
|
return BRW_TYPE_W;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
unreachable("invalid type");
|
return BRW_TYPE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,6 +565,43 @@ is_mixed_float(const brw_hw_decoded_inst *inst)
|
||||||
types_are_mixed_float(src1_type, dst_type);
|
types_are_mixed_float(src1_type, dst_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_pure_bfloat(const brw_hw_decoded_inst *inst)
|
||||||
|
{
|
||||||
|
if (inst_is_send(inst))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (inst->num_sources == 0 && !inst->has_dst)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < inst->num_sources; i++) {
|
||||||
|
if (!brw_type_is_bfloat(inst->src[i].type))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst->has_dst && !brw_type_is_bfloat(inst->dst.type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_mixed_bfloat(const brw_hw_decoded_inst *inst)
|
||||||
|
{
|
||||||
|
if (inst_is_send(inst))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int operands = inst->num_sources + inst->has_dst;
|
||||||
|
|
||||||
|
int bfloat = 0;
|
||||||
|
for (int i = 0; i < inst->num_sources; i++)
|
||||||
|
bfloat += brw_type_is_bfloat(inst->src[i].type);
|
||||||
|
if (inst->has_dst)
|
||||||
|
bfloat += brw_type_is_bfloat(inst->dst.type);
|
||||||
|
|
||||||
|
return bfloat > 0 && bfloat != operands;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether an instruction is an explicit or implicit conversion
|
* Returns whether an instruction is an explicit or implicit conversion
|
||||||
* to/from byte.
|
* to/from byte.
|
||||||
|
|
@ -624,6 +662,10 @@ general_restrictions_based_on_operand_types(const struct brw_isa_info *isa,
|
||||||
|
|
||||||
enum brw_reg_type dst_type = inst->dst.type;
|
enum brw_reg_type dst_type = inst->dst.type;
|
||||||
|
|
||||||
|
ERROR_IF(brw_type_is_bfloat(dst_type) &&
|
||||||
|
!devinfo->has_bfloat16,
|
||||||
|
"Bfloat destination, but platform does not support it");
|
||||||
|
|
||||||
ERROR_IF(dst_type == BRW_TYPE_DF &&
|
ERROR_IF(dst_type == BRW_TYPE_DF &&
|
||||||
!devinfo->has_64bit_float,
|
!devinfo->has_64bit_float,
|
||||||
"64-bit float destination, but platform does not support it");
|
"64-bit float destination, but platform does not support it");
|
||||||
|
|
@ -636,6 +678,10 @@ general_restrictions_based_on_operand_types(const struct brw_isa_info *isa,
|
||||||
for (unsigned s = 0; s < inst->num_sources; s++) {
|
for (unsigned s = 0; s < inst->num_sources; s++) {
|
||||||
enum brw_reg_type src_type = inst->src[s].type;
|
enum brw_reg_type src_type = inst->src[s].type;
|
||||||
|
|
||||||
|
ERROR_IF(brw_type_is_bfloat(src_type) &&
|
||||||
|
!devinfo->has_bfloat16,
|
||||||
|
"Bfloat source, but platform does not support it");
|
||||||
|
|
||||||
ERROR_IF(src_type == BRW_TYPE_DF &&
|
ERROR_IF(src_type == BRW_TYPE_DF &&
|
||||||
!devinfo->has_64bit_float,
|
!devinfo->has_64bit_float,
|
||||||
"64-bit float source, but platform does not support it");
|
"64-bit float source, but platform does not support it");
|
||||||
|
|
@ -842,7 +888,7 @@ general_restrictions_based_on_operand_types(const struct brw_isa_info *isa,
|
||||||
* override the general rule for the ratio of sizes of the destination type
|
* override the general rule for the ratio of sizes of the destination type
|
||||||
* and the execution type. We will add validation for those in a later patch.
|
* and the execution type. We will add validation for those in a later patch.
|
||||||
*/
|
*/
|
||||||
bool validate_dst_size_and_exec_size_ratio = !is_mixed_float(inst);
|
bool validate_dst_size_and_exec_size_ratio = !is_mixed_float(inst) && !is_mixed_bfloat(inst);
|
||||||
|
|
||||||
if (validate_dst_size_and_exec_size_ratio &&
|
if (validate_dst_size_and_exec_size_ratio &&
|
||||||
exec_type_size > dst_type_size) {
|
exec_type_size > dst_type_size) {
|
||||||
|
|
@ -1016,6 +1062,21 @@ general_restrictions_on_region_parameters(const struct brw_isa_info *isa,
|
||||||
return error_msg;
|
return error_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_multiplier_instruction(const brw_hw_decoded_inst *inst)
|
||||||
|
{
|
||||||
|
/* TODO: Complete this list. */
|
||||||
|
switch (inst->opcode) {
|
||||||
|
case BRW_OPCODE_MUL:
|
||||||
|
case BRW_OPCODE_MAC:
|
||||||
|
case BRW_OPCODE_MACH:
|
||||||
|
case BRW_OPCODE_MAD:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct string
|
static struct string
|
||||||
special_restrictions_for_mixed_float_mode(const struct brw_isa_info *isa,
|
special_restrictions_for_mixed_float_mode(const struct brw_isa_info *isa,
|
||||||
const brw_hw_decoded_inst *inst)
|
const brw_hw_decoded_inst *inst)
|
||||||
|
|
@ -1024,6 +1085,60 @@ special_restrictions_for_mixed_float_mode(const struct brw_isa_info *isa,
|
||||||
|
|
||||||
struct string error_msg = { .str = NULL, .len = 0 };
|
struct string error_msg = { .str = NULL, .len = 0 };
|
||||||
|
|
||||||
|
ERROR_IF(is_pure_bfloat(inst),
|
||||||
|
"Instructions with pure bfloat16 operands are not supported.");
|
||||||
|
|
||||||
|
if (is_mixed_bfloat(inst)) {
|
||||||
|
ERROR_IF(devinfo->ver < 20 && inst->exec_size > 8,
|
||||||
|
"Execution size must not be greater than 8 in Gfx12.");
|
||||||
|
ERROR_IF(devinfo->ver >= 20 && inst->exec_size > 16,
|
||||||
|
"Execution size must not be greater than 8 in Gfx20+.");
|
||||||
|
|
||||||
|
for (int i = 0; i < inst->num_sources; i++) {
|
||||||
|
ERROR_IF(brw_type_is_bfloat(inst->src[i].type) &&
|
||||||
|
src_has_scalar_region(inst, i),
|
||||||
|
"Broadcast of bfloat16 scalar is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_multiplier_instruction(inst)) {
|
||||||
|
if (inst->num_sources == 2) {
|
||||||
|
ERROR_IF(brw_type_is_bfloat(inst->src[1].type),
|
||||||
|
"Bfloat16 not allowed in Src1 of 2-source instructions involving multiplier.");
|
||||||
|
} else if (inst->num_sources == 3) {
|
||||||
|
ERROR_IF(brw_type_is_bfloat(inst->src[2].type),
|
||||||
|
"Bfloat16 not allowed in Src2 of 3-source instructions involving multiplier.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned half_offset = REG_SIZE * reg_unit(devinfo) / 2;
|
||||||
|
|
||||||
|
if (inst->has_dst && brw_type_is_bfloat(inst->dst.type)) {
|
||||||
|
unsigned dst_stride = inst->dst.hstride;
|
||||||
|
bool dst_is_packed = is_packed(inst->exec_size * dst_stride, inst->exec_size, dst_stride);
|
||||||
|
|
||||||
|
if (dst_is_packed) {
|
||||||
|
ERROR_IF(inst->dst.subnr != 0 && inst->dst.subnr != half_offset,
|
||||||
|
"Packed bfloat16 destination must have register offset 0 or half of GRF register.");
|
||||||
|
} else {
|
||||||
|
/* Offset in the restriction text is in terms of elements. */
|
||||||
|
const unsigned elem_size = brw_type_size_bytes(inst->dst.type);
|
||||||
|
ERROR_IF(dst_stride != 2 || (inst->dst.subnr != 0 &&
|
||||||
|
inst->dst.subnr != 1 * elem_size),
|
||||||
|
"Unpacked bfloat16 destination must have stride 2 and register offset 0 or 1.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < inst->num_sources; i++) {
|
||||||
|
if (brw_type_is_bfloat(inst->src[i].type)) {
|
||||||
|
bool src_is_packed = is_packed(inst->src[i].vstride, inst->src[i].width, inst->src[i].hstride);
|
||||||
|
ERROR_IF(!src_is_packed,
|
||||||
|
"Bfloat16 source must be packed");
|
||||||
|
ERROR_IF(inst->src[i].subnr != 0 && inst->src[i].subnr != half_offset,
|
||||||
|
"Bfloat16 source must have register offset 0 or half of GRF register.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned opcode = inst->opcode;
|
const unsigned opcode = inst->opcode;
|
||||||
if (inst->num_sources >= 3)
|
if (inst->num_sources >= 3)
|
||||||
return error_msg;
|
return error_msg;
|
||||||
|
|
@ -1640,13 +1755,18 @@ special_requirements_for_handling_double_precision_data_types(
|
||||||
*
|
*
|
||||||
* "Vx1 and VxH indirect addressing for Float, Half-Float, Double-Float and
|
* "Vx1 and VxH indirect addressing for Float, Half-Float, Double-Float and
|
||||||
* Quad-Word data must not be used."
|
* Quad-Word data must not be used."
|
||||||
|
*
|
||||||
|
* and
|
||||||
|
*
|
||||||
|
* "Vx1 and VxH indirect addressing for BFloat16 (...) data
|
||||||
|
* must not be used."
|
||||||
*/
|
*/
|
||||||
if (devinfo->verx10 >= 125 &&
|
if (devinfo->verx10 >= 125 &&
|
||||||
(brw_type_is_float(type) || brw_type_size_bytes(type) == 8)) {
|
(brw_type_is_float_or_bfloat(type) || brw_type_size_bytes(type) == 8)) {
|
||||||
ERROR_IF(address_mode == BRW_ADDRESS_REGISTER_INDIRECT_REGISTER &&
|
ERROR_IF(address_mode == BRW_ADDRESS_REGISTER_INDIRECT_REGISTER &&
|
||||||
vstride == BRW_VERTICAL_STRIDE_ONE_DIMENSIONAL,
|
vstride == BRW_VERTICAL_STRIDE_ONE_DIMENSIONAL,
|
||||||
"Vx1 and VxH indirect addressing for Float, Half-Float, "
|
"Vx1 and VxH indirect addressing for Float, Half-Float, "
|
||||||
"Double-Float and Quad-Word data must not be used");
|
"Double-Float, Quad-Word, and Bfloat16 data must not be used");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2442,6 +2562,18 @@ VSTRIDE_3SRC(unsigned vstride)
|
||||||
unreachable("invalid vstride");
|
unreachable("invalid vstride");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
brw_implied_width_for_3src_a1(unsigned v, unsigned h)
|
||||||
|
{
|
||||||
|
/* "Regioning Rules for Align1 Ternary Operations" */
|
||||||
|
|
||||||
|
/* TODO: Add remaining rules and de-duplicate with brw_disasm.c */
|
||||||
|
|
||||||
|
if (v == 0) return 1;
|
||||||
|
if (h == 0) return v;
|
||||||
|
return v/h;
|
||||||
|
}
|
||||||
|
|
||||||
static struct string
|
static struct string
|
||||||
brw_hw_decode_inst(const struct brw_isa_info *isa,
|
brw_hw_decode_inst(const struct brw_isa_info *isa,
|
||||||
brw_hw_decoded_inst *inst,
|
brw_hw_decoded_inst *inst,
|
||||||
|
|
@ -2629,6 +2761,7 @@ brw_hw_decode_inst(const struct brw_isa_info *isa,
|
||||||
inst->src[0].subnr = brw_eu_inst_3src_a1_src0_subreg_nr(devinfo, raw);
|
inst->src[0].subnr = brw_eu_inst_3src_a1_src0_subreg_nr(devinfo, raw);
|
||||||
inst->src[0].vstride = VSTRIDE_3SRC(brw_eu_inst_3src_a1_src0_vstride(devinfo, raw));
|
inst->src[0].vstride = VSTRIDE_3SRC(brw_eu_inst_3src_a1_src0_vstride(devinfo, raw));
|
||||||
inst->src[0].hstride = STRIDE(brw_eu_inst_3src_a1_src0_hstride(devinfo, raw));
|
inst->src[0].hstride = STRIDE(brw_eu_inst_3src_a1_src0_hstride(devinfo, raw));
|
||||||
|
inst->src[0].width = brw_implied_width_for_3src_a1(inst->src[0].vstride, inst->src[0].hstride);
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->src[1].file = brw_eu_inst_3src_a1_src1_reg_file(devinfo, raw);
|
inst->src[1].file = brw_eu_inst_3src_a1_src1_reg_file(devinfo, raw);
|
||||||
|
|
@ -2639,6 +2772,7 @@ brw_hw_decode_inst(const struct brw_isa_info *isa,
|
||||||
inst->src[1].subnr = brw_eu_inst_3src_a1_src1_subreg_nr(devinfo, raw);
|
inst->src[1].subnr = brw_eu_inst_3src_a1_src1_subreg_nr(devinfo, raw);
|
||||||
inst->src[1].vstride = VSTRIDE_3SRC(brw_eu_inst_3src_a1_src1_vstride(devinfo, raw));
|
inst->src[1].vstride = VSTRIDE_3SRC(brw_eu_inst_3src_a1_src1_vstride(devinfo, raw));
|
||||||
inst->src[1].hstride = STRIDE(brw_eu_inst_3src_a1_src1_hstride(devinfo, raw));
|
inst->src[1].hstride = STRIDE(brw_eu_inst_3src_a1_src1_hstride(devinfo, raw));
|
||||||
|
inst->src[1].width = brw_implied_width_for_3src_a1(inst->src[1].vstride, inst->src[1].hstride);
|
||||||
|
|
||||||
inst->src[2].file = brw_eu_inst_3src_a1_src2_reg_file(devinfo, raw);
|
inst->src[2].file = brw_eu_inst_3src_a1_src2_reg_file(devinfo, raw);
|
||||||
inst->src[2].type = brw_eu_inst_3src_a1_src2_type(devinfo, raw);
|
inst->src[2].type = brw_eu_inst_3src_a1_src2_type(devinfo, raw);
|
||||||
|
|
@ -2648,6 +2782,7 @@ brw_hw_decode_inst(const struct brw_isa_info *isa,
|
||||||
inst->src[2].nr = brw_eu_inst_3src_src2_reg_nr(devinfo, raw);
|
inst->src[2].nr = brw_eu_inst_3src_src2_reg_nr(devinfo, raw);
|
||||||
inst->src[2].subnr = brw_eu_inst_3src_a1_src2_subreg_nr(devinfo, raw);
|
inst->src[2].subnr = brw_eu_inst_3src_a1_src2_subreg_nr(devinfo, raw);
|
||||||
inst->src[2].hstride = STRIDE(brw_eu_inst_3src_a1_src2_hstride(devinfo, raw));
|
inst->src[2].hstride = STRIDE(brw_eu_inst_3src_a1_src2_hstride(devinfo, raw));
|
||||||
|
inst->src[2].width = brw_implied_width_for_3src_a1(inst->src[2].vstride, inst->src[2].hstride);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -345,9 +345,9 @@ brw_validate(const brw_shader &s)
|
||||||
brw_type_is_int(inst->src[1].type) +
|
brw_type_is_int(inst->src[1].type) +
|
||||||
brw_type_is_int(inst->src[2].type);
|
brw_type_is_int(inst->src[2].type);
|
||||||
const unsigned float_sources =
|
const unsigned float_sources =
|
||||||
brw_type_is_float(inst->src[0].type) +
|
brw_type_is_float_or_bfloat(inst->src[0].type) +
|
||||||
brw_type_is_float(inst->src[1].type) +
|
brw_type_is_float_or_bfloat(inst->src[1].type) +
|
||||||
brw_type_is_float(inst->src[2].type);
|
brw_type_is_float_or_bfloat(inst->src[2].type);
|
||||||
|
|
||||||
fsv_assert((integer_sources == 3 && float_sources == 0) ||
|
fsv_assert((integer_sources == 3 && float_sources == 0) ||
|
||||||
(integer_sources == 0 && float_sources == 3));
|
(integer_sources == 0 && float_sources == 3));
|
||||||
|
|
|
||||||
|
|
@ -105,15 +105,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
);
|
);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
validate(struct brw_codegen *p)
|
validate(struct brw_codegen *p, char **error = nullptr)
|
||||||
{
|
{
|
||||||
const bool print = getenv("TEST_DEBUG");
|
const bool print = getenv("TEST_DEBUG");
|
||||||
struct disasm_info *disasm = disasm_initialize(p->isa, NULL);
|
struct disasm_info *disasm = disasm_initialize(p->isa, NULL);
|
||||||
|
|
||||||
if (print) {
|
struct inst_group *group = disasm_new_inst_group(disasm, 0);
|
||||||
disasm_new_inst_group(disasm, 0);
|
disasm_new_inst_group(disasm, p->next_insn_offset);
|
||||||
disasm_new_inst_group(disasm, p->next_insn_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ret = brw_validate_instructions(p->isa, p->store, 0,
|
bool ret = brw_validate_instructions(p->isa, p->store, 0,
|
||||||
p->next_insn_offset, disasm);
|
p->next_insn_offset, disasm);
|
||||||
|
|
@ -121,7 +119,9 @@ validate(struct brw_codegen *p)
|
||||||
if (print) {
|
if (print) {
|
||||||
dump_assembly(p->store, 0, p->next_insn_offset, disasm, NULL);
|
dump_assembly(p->store, 0, p->next_insn_offset, disasm, NULL);
|
||||||
}
|
}
|
||||||
ralloc_free(disasm);
|
|
||||||
|
if (error)
|
||||||
|
*error = group->error;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -470,13 +470,17 @@ TEST_P(validation_test, invalid_type_encoding_3src_a1)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct brw_reg g = retype(g0, test_case[i].type);
|
struct brw_reg g = retype(g0, test_case[i].type);
|
||||||
if (!brw_type_is_int(test_case[i].type)) {
|
if (brw_type_is_bfloat(test_case[i].type)) {
|
||||||
|
/* BF is more restrictive, so ensure the instruction is valid. */
|
||||||
|
brw_MAD(p, retype(g, BRW_TYPE_F), g, g, retype(g, BRW_TYPE_F));
|
||||||
|
} else if (!brw_type_is_int(test_case[i].type)) {
|
||||||
brw_MAD(p, g, g, g, g);
|
brw_MAD(p, g, g, g, g);
|
||||||
} else {
|
} else {
|
||||||
brw_BFE(p, g, g, g, g);
|
brw_BFE(p, g, g, g, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_TRUE(validate(p));
|
char *error = NULL;
|
||||||
|
EXPECT_TRUE(validate(p, &error)) << "Unexpected validation failure: " << error;
|
||||||
|
|
||||||
clear_instructions(p);
|
clear_instructions(p);
|
||||||
}
|
}
|
||||||
|
|
@ -2385,7 +2389,9 @@ TEST_P(validation_test, qword_low_power_no_indirect_addressing)
|
||||||
if (intel_device_info_is_9lp(&devinfo)) {
|
if (intel_device_info_is_9lp(&devinfo)) {
|
||||||
EXPECT_EQ(inst[i].expected_result, validate(p));
|
EXPECT_EQ(inst[i].expected_result, validate(p));
|
||||||
} else {
|
} else {
|
||||||
EXPECT_TRUE(validate(p));
|
char *error = nullptr;
|
||||||
|
EXPECT_TRUE(validate(p, &error))
|
||||||
|
<< "Test index = " << i << " failed to validate: " << error;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_instructions(p);
|
clear_instructions(p);
|
||||||
|
|
@ -3718,3 +3724,163 @@ TEST_P(validation_test, scalar_register_restrictions)
|
||||||
clear_instructions(p);
|
clear_instructions(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(validation_test, bfloat_restrictions)
|
||||||
|
{
|
||||||
|
/* Restrictions from ACM PRM, vol. 9, section "Register Region
|
||||||
|
* Restrictions", sub-section 7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!devinfo.has_bfloat16)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct test {
|
||||||
|
const char *error_pattern;
|
||||||
|
enum opcode opcode;
|
||||||
|
unsigned exec_size;
|
||||||
|
brw_reg dst, src0, src1, src2;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *PASS = nullptr;
|
||||||
|
|
||||||
|
const struct test tests[] = {
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_MOV, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "pure bfloat16 operands are not supported",
|
||||||
|
BRW_OPCODE_MOV, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Execution size must not be greater than",
|
||||||
|
BRW_OPCODE_MOV, 16 * reg_unit(&devinfo),
|
||||||
|
brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "pure bfloat16 operands are not supported",
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Broadcast of bfloat16 scalar is not supported",
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 30, 0, 0,1,0) },
|
||||||
|
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_MUL, 8, brw_grf(BRW_TYPE_BF, 10, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Bfloat16 not allowed in Src1 of 2-source instructions involving multiplier",
|
||||||
|
BRW_OPCODE_MUL, 8, brw_grf(BRW_TYPE_BF, 10, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_MAD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 30, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 40, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Bfloat16 not allowed in Src2 of 3-source instructions involving multiplier",
|
||||||
|
BRW_OPCODE_MAD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 40, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 1, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Unpacked bfloat16 destination must have stride 2 and register offset 0 or 1",
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 3, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 8 * reg_unit(&devinfo), 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Packed bfloat16 destination must have register offset 0 or half of GRF register",
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 1, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Bfloat16 source must be packed",
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 0, 2,1,2),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ PASS,
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 8 * reg_unit(&devinfo), 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
|
||||||
|
{ "Bfloat16 source must have register offset 0 or half of GRF register",
|
||||||
|
BRW_OPCODE_ADD, 8, brw_grf(BRW_TYPE_BF, 10, 0, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_BF, 20, 5, 1,1,0),
|
||||||
|
brw_grf(BRW_TYPE_F, 30, 0, 1,1,0) },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||||
|
const struct test &t = tests[i];
|
||||||
|
|
||||||
|
switch (tests[i].opcode) {
|
||||||
|
case BRW_OPCODE_MOV:
|
||||||
|
brw_MOV(p, t.dst, t.src0);
|
||||||
|
break;
|
||||||
|
case BRW_OPCODE_ADD:
|
||||||
|
brw_ADD(p, t.dst, t.src0, t.src1);
|
||||||
|
break;
|
||||||
|
case BRW_OPCODE_MUL:
|
||||||
|
brw_MUL(p, t.dst, t.src0, t.src1);
|
||||||
|
break;
|
||||||
|
case BRW_OPCODE_MAD:
|
||||||
|
brw_MAD(p, t.dst, t.src0, t.src1, t.src2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unreachable("unexpected opcode in tests");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tests[i].opcode == BRW_OPCODE_MAD) {
|
||||||
|
brw_eu_inst_set_3src_exec_size(&devinfo, last_inst, cvt(t.exec_size) - 1);
|
||||||
|
} else {
|
||||||
|
brw_eu_inst_set_exec_size(&devinfo, last_inst, cvt(t.exec_size) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Expand this test logic to check validation error to other
|
||||||
|
* tests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *error = nullptr;
|
||||||
|
bool valid = validate(p, &error);
|
||||||
|
|
||||||
|
if (t.error_pattern) {
|
||||||
|
EXPECT_FALSE(valid)
|
||||||
|
<< "Test vector index = " << i << " expected to "
|
||||||
|
<< "fail validation with error containing: '" << t.error_pattern << "' "
|
||||||
|
<< "but succeeded instead.";
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
EXPECT_TRUE(strstr(error, t.error_pattern))
|
||||||
|
<< "Test vector index = " << i << " expected to "
|
||||||
|
<< "fail validation with error containing: '" << t.error_pattern << "' "
|
||||||
|
<< "but error was: '" << error << "'.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EXPECT_TRUE(valid)
|
||||||
|
<< "Test vector index = " << i << " expected to succeed "
|
||||||
|
<< "but failed validation with error: '" << error << "'.";
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_instructions(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue