* test_eu_validate.cpp) will be rejected.
*/
+#include <stdlib.h>
#include "brw_eu.h"
/* We're going to do lots of string concatenation, so this should help. */
static bool
inst_is_split_send(const struct gen_device_info *devinfo, const brw_inst *inst)
{
- switch (brw_inst_opcode(devinfo, inst)) {
- case BRW_OPCODE_SENDS:
- case BRW_OPCODE_SENDSC:
- return true;
- default:
- return false;
+ if (devinfo->gen >= 12) {
+ return inst_is_send(devinfo, inst);
+ } else {
+ switch (brw_inst_opcode(devinfo, inst)) {
+ case BRW_OPCODE_SENDS:
+ case BRW_OPCODE_SENDSC:
+ return true;
+ default:
+ return false;
+ }
}
}
}
}
+static enum brw_reg_type
+inst_dst_type(const struct gen_device_info *devinfo, const brw_inst *inst)
+{
+ return (devinfo->gen < 12 || !inst_is_send(devinfo, inst)) ?
+ brw_inst_dst_type(devinfo, inst) : BRW_REGISTER_TYPE_D;
+}
+
static bool
inst_is_raw_move(const struct gen_device_info *devinfo, const brw_inst *inst)
{
- unsigned dst_type = signed_type(brw_inst_dst_type(devinfo, inst));
+ unsigned dst_type = signed_type(inst_dst_type(devinfo, inst));
unsigned src_type = signed_type(brw_inst_src0_type(devinfo, inst));
if (brw_inst_src0_reg_file(devinfo, inst) == BRW_IMMEDIATE_VALUE) {
static bool
src0_is_null(const struct gen_device_info *devinfo, const brw_inst *inst)
{
- return brw_inst_src0_reg_file(devinfo, inst) == BRW_ARCHITECTURE_REGISTER_FILE &&
+ return brw_inst_src0_address_mode(devinfo, inst) == BRW_ADDRESS_DIRECT &&
+ brw_inst_src0_reg_file(devinfo, inst) == BRW_ARCHITECTURE_REGISTER_FILE &&
brw_inst_src0_da_reg_nr(devinfo, inst) == BRW_ARF_NULL;
}
(brw_inst_src1_da_reg_nr(devinfo, inst) & 0xF0) == BRW_ARF_ACCUMULATOR;
}
-static bool
-src0_is_grf(const struct gen_device_info *devinfo, const brw_inst *inst)
-{
- return brw_inst_src0_reg_file(devinfo, inst) == BRW_GENERAL_REGISTER_FILE;
-}
-
static bool
src0_has_scalar_region(const struct gen_device_info *devinfo, const brw_inst *inst)
{
}
}
+static struct string
+invalid_values(const struct gen_device_info *devinfo, const brw_inst *inst)
+{
+ unsigned num_sources = num_sources_from_inst(devinfo, inst);
+ struct string error_msg = { .str = NULL, .len = 0 };
+
+ switch ((enum brw_execution_size) brw_inst_exec_size(devinfo, inst)) {
+ case BRW_EXECUTE_1:
+ case BRW_EXECUTE_2:
+ case BRW_EXECUTE_4:
+ case BRW_EXECUTE_8:
+ case BRW_EXECUTE_16:
+ case BRW_EXECUTE_32:
+ break;
+ default:
+ ERROR("invalid execution size");
+ break;
+ }
+
+ if (inst_is_send(devinfo, inst))
+ return error_msg;
+
+ if (num_sources == 3) {
+ /* Nothing to test:
+ * No 3-src instructions on Gen4-5
+ * No reg file bits on Gen6-10 (align16)
+ * No invalid encodings on Gen10-12 (align1)
+ */
+ } else {
+ if (devinfo->gen > 6) {
+ ERROR_IF(brw_inst_dst_reg_file(devinfo, inst) == MRF ||
+ (num_sources > 0 &&
+ brw_inst_src0_reg_file(devinfo, inst) == MRF) ||
+ (num_sources > 1 &&
+ brw_inst_src1_reg_file(devinfo, inst) == MRF),
+ "invalid register file encoding");
+ }
+ }
+
+ if (error_msg.str)
+ return error_msg;
+
+ if (num_sources == 3) {
+ if (brw_inst_access_mode(devinfo, inst) == BRW_ALIGN_1) {
+ if (devinfo->gen >= 10) {
+ ERROR_IF(brw_inst_3src_a1_dst_type (devinfo, inst) == INVALID_REG_TYPE ||
+ brw_inst_3src_a1_src0_type(devinfo, inst) == INVALID_REG_TYPE ||
+ brw_inst_3src_a1_src1_type(devinfo, inst) == INVALID_REG_TYPE ||
+ brw_inst_3src_a1_src2_type(devinfo, inst) == INVALID_REG_TYPE,
+ "invalid register type encoding");
+ } else {
+ ERROR("Align1 mode not allowed on Gen < 10");
+ }
+ } else {
+ ERROR_IF(brw_inst_3src_a16_dst_type(devinfo, inst) == INVALID_REG_TYPE ||
+ brw_inst_3src_a16_src_type(devinfo, inst) == INVALID_REG_TYPE,
+ "invalid register type encoding");
+ }
+ } else {
+ ERROR_IF(brw_inst_dst_type (devinfo, inst) == INVALID_REG_TYPE ||
+ (num_sources > 0 &&
+ brw_inst_src0_type(devinfo, inst) == INVALID_REG_TYPE) ||
+ (num_sources > 1 &&
+ brw_inst_src1_type(devinfo, inst) == INVALID_REG_TYPE),
+ "invalid register type encoding");
+ }
+
+ return error_msg;
+}
+
static struct string
sources_not_null(const struct gen_device_info *devinfo,
const brw_inst *inst)
if (inst_is_split_send(devinfo, inst))
return (struct string){};
- if (num_sources >= 1)
+ if (num_sources >= 1 && brw_inst_opcode(devinfo, inst) != BRW_OPCODE_SYNC)
ERROR_IF(src0_is_null(devinfo, inst), "src0 is null");
if (num_sources == 2)
case BRW_OPCODE_MACH:
case BRW_OPCODE_SADA2:
return true;
+ default:
+ break;
}
/* FIXME: support 3-src instructions */
"send must use direct addressing");
if (devinfo->gen >= 7) {
- ERROR_IF(!src0_is_grf(devinfo, inst), "send from non-GRF");
+ ERROR_IF(brw_inst_send_src0_reg_file(devinfo, inst) != BRW_GENERAL_REGISTER_FILE,
+ "send from non-GRF");
ERROR_IF(brw_inst_eot(devinfo, inst) &&
brw_inst_src0_da_reg_nr(devinfo, inst) < 112,
"send with EOT must use g112-g127");
is_unsupported_inst(const struct gen_device_info *devinfo,
const brw_inst *inst)
{
- return brw_opcode_desc(devinfo, brw_inst_opcode(devinfo, inst)) == NULL;
+ return brw_inst_opcode(devinfo, inst) == BRW_OPCODE_ILLEGAL;
}
/**
/* Execution data type is independent of destination data type, except in
* mixed F/HF instructions.
*/
- enum brw_reg_type dst_exec_type = brw_inst_dst_type(devinfo, inst);
+ enum brw_reg_type dst_exec_type = inst_dst_type(devinfo, inst);
src0_exec_type = execution_type_for_type(brw_inst_src0_type(devinfo, inst));
if (num_sources == 1) {
if (src0_exec_type == src1_exec_type)
return src0_exec_type;
+ if (src0_exec_type == BRW_REGISTER_TYPE_NF ||
+ src1_exec_type == BRW_REGISTER_TYPE_NF)
+ return BRW_REGISTER_TYPE_NF;
+
/* Mixed operand types where one is float is float on Gen < 6
* (and not allowed on later platforms)
*/
unsigned exec_size = 1 << brw_inst_exec_size(devinfo, inst);
struct string error_msg = { .str = NULL, .len = 0 };
+ if (inst_is_send(devinfo, inst))
+ return error_msg;
+
if (devinfo->gen >= 11) {
if (num_sources == 3) {
ERROR_IF(brw_reg_type_to_size(brw_inst_3src_a1_src1_type(devinfo, inst)) == 1 ||
if (num_sources == 3)
return error_msg;
- if (inst_is_send(devinfo, inst))
- return error_msg;
-
if (exec_size == 1)
return error_msg;
*/
unsigned dst_stride = STRIDE(brw_inst_dst_hstride(devinfo, inst));
- enum brw_reg_type dst_type = brw_inst_dst_type(devinfo, inst);
+ enum brw_reg_type dst_type = inst_dst_type(devinfo, inst);
bool dst_type_is_byte =
- brw_inst_dst_type(devinfo, inst) == BRW_REGISTER_TYPE_B ||
- brw_inst_dst_type(devinfo, inst) == BRW_REGISTER_TYPE_UB;
+ inst_dst_type(devinfo, inst) == BRW_REGISTER_TYPE_B ||
+ inst_dst_type(devinfo, inst) == BRW_REGISTER_TYPE_UB;
if (dst_type_is_byte) {
if (is_packed(exec_size * dst_stride, exec_size, dst_stride)) {
unsigned offset = rowbase;
for (int x = 0; x < width; x++) {
- access_mask |= mask << offset;
+ access_mask |= mask << (offset % 64);
offset += hstride * element_size;
}
unsigned offset = rowbase;
for (int x = 0; x < width; x++) {
- access_mask[element++] = mask << offset;
+ access_mask[element++] = mask << (offset % 64);
offset += hstride * element_size;
}
return error_msg;
unsigned stride = STRIDE(brw_inst_dst_hstride(devinfo, inst));
- enum brw_reg_type dst_type = brw_inst_dst_type(devinfo, inst);
+ enum brw_reg_type dst_type = inst_dst_type(devinfo, inst);
unsigned element_size = brw_reg_type_to_size(dst_type);
unsigned subreg = brw_inst_dst_da1_subreg_nr(devinfo, inst);
unsigned offset = ((exec_size - 1) * stride * element_size) + subreg;
* is that the size of the destination type is 4 bytes.
*/
if (devinfo->gen <= 7 && dst_regs == 2) {
- enum brw_reg_type dst_type = brw_inst_dst_type(devinfo, inst);
+ enum brw_reg_type dst_type = inst_dst_type(devinfo, inst);
bool dst_is_packed_dword =
is_packed(exec_size * stride, exec_size, stride) &&
brw_reg_type_to_size(dst_type) == 4;
if (file != BRW_IMMEDIATE_VALUE)
return (struct string){};
- enum brw_reg_type dst_type = brw_inst_dst_type(devinfo, inst);
+ enum brw_reg_type dst_type = inst_dst_type(devinfo, inst);
unsigned dst_type_size = brw_reg_type_to_size(dst_type);
unsigned dst_subreg = brw_inst_access_mode(devinfo, inst) == BRW_ALIGN_1 ?
brw_inst_dst_da1_subreg_nr(devinfo, inst) : 0;
unsigned exec_type_size = brw_reg_type_to_size(exec_type);
enum brw_reg_file dst_file = brw_inst_dst_reg_file(devinfo, inst);
- enum brw_reg_type dst_type = brw_inst_dst_type(devinfo, inst);
+ enum brw_reg_type dst_type = inst_dst_type(devinfo, inst);
unsigned dst_type_size = brw_reg_type_to_size(dst_type);
unsigned dst_hstride = STRIDE(brw_inst_dst_hstride(devinfo, inst));
unsigned dst_reg = brw_inst_dst_da_reg_nr(devinfo, inst);
return error_msg;
}
+static struct string
+instruction_restrictions(const struct gen_device_info *devinfo,
+ const brw_inst *inst)
+{
+ struct string error_msg = { .str = NULL, .len = 0 };
+
+ /* From GEN:BUG:1604601757:
+ *
+ * "When multiplying a DW and any lower precision integer, source modifier
+ * is not supported."
+ */
+ if (devinfo->gen >= 12 &&
+ brw_inst_opcode(devinfo, inst) == BRW_OPCODE_MUL) {
+ enum brw_reg_type exec_type = execution_type(devinfo, inst);
+ const bool src0_valid = type_sz(brw_inst_src0_type(devinfo, inst)) == 4 ||
+ brw_inst_src0_reg_file(devinfo, inst) == BRW_IMMEDIATE_VALUE ||
+ !(brw_inst_src0_negate(devinfo, inst) ||
+ brw_inst_src0_abs(devinfo, inst));
+ const bool src1_valid = type_sz(brw_inst_src1_type(devinfo, inst)) == 4 ||
+ brw_inst_src1_reg_file(devinfo, inst) == BRW_IMMEDIATE_VALUE ||
+ !(brw_inst_src1_negate(devinfo, inst) ||
+ brw_inst_src1_abs(devinfo, inst));
+
+ ERROR_IF(!brw_reg_type_is_floating_point(exec_type) &&
+ type_sz(exec_type) == 4 && !(src0_valid && src1_valid),
+ "When multiplying a DW and any lower precision integer, source "
+ "modifier is not supported.");
+ }
+
+ return error_msg;
+}
+
+bool
+brw_validate_instruction(const struct gen_device_info *devinfo,
+ const brw_inst *inst, int offset,
+ struct disasm_info *disasm)
+{
+ struct string error_msg = { .str = NULL, .len = 0 };
+
+ if (is_unsupported_inst(devinfo, inst)) {
+ ERROR("Instruction not supported on this Gen");
+ } else {
+ CHECK(invalid_values);
+
+ if (error_msg.str == NULL) {
+ CHECK(sources_not_null);
+ CHECK(send_restrictions);
+ CHECK(alignment_supported);
+ CHECK(general_restrictions_based_on_operand_types);
+ CHECK(general_restrictions_on_region_parameters);
+ CHECK(special_restrictions_for_mixed_float_mode);
+ CHECK(region_alignment_rules);
+ CHECK(vector_immediate_restrictions);
+ CHECK(special_requirements_for_handling_double_precision_data_types);
+ CHECK(instruction_restrictions);
+ }
+ }
+
+ if (error_msg.str && disasm) {
+ disasm_insert_error(disasm, offset, error_msg.str);
+ }
+ free(error_msg.str);
+
+ return error_msg.len == 0;
+}
+
bool
brw_validate_instructions(const struct gen_device_info *devinfo,
const void *assembly, int start_offset, int end_offset,
bool valid = true;
for (int src_offset = start_offset; src_offset < end_offset;) {
- struct string error_msg = { .str = NULL, .len = 0 };
const brw_inst *inst = assembly + src_offset;
bool is_compact = brw_inst_cmpt_control(devinfo, inst);
+ unsigned inst_size = is_compact ? sizeof(brw_compact_inst)
+ : sizeof(brw_inst);
brw_inst uncompacted;
if (is_compact) {
inst = &uncompacted;
}
- if (is_unsupported_inst(devinfo, inst)) {
- ERROR("Instruction not supported on this Gen");
- } else {
- CHECK(sources_not_null);
- CHECK(send_restrictions);
- CHECK(alignment_supported);
- CHECK(general_restrictions_based_on_operand_types);
- CHECK(general_restrictions_on_region_parameters);
- CHECK(special_restrictions_for_mixed_float_mode);
- CHECK(region_alignment_rules);
- CHECK(vector_immediate_restrictions);
- CHECK(special_requirements_for_handling_double_precision_data_types);
- }
-
- if (error_msg.str && disasm) {
- disasm_insert_error(disasm, src_offset, error_msg.str);
- }
- valid = valid && error_msg.len == 0;
- free(error_msg.str);
+ bool v = brw_validate_instruction(devinfo, inst, src_offset, disasm);
+ valid = valid && v;
- if (is_compact) {
- src_offset += sizeof(brw_compact_inst);
- } else {
- src_offset += sizeof(brw_inst);
- }
+ src_offset += inst_size;
}
return valid;