/*
- * Copyright © 2015 Intel Corporation
+ * Copyright © 2015-2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
/** @file brw_eu_validate.c
*
* This file implements a pass that validates shader assembly.
+ *
+ * The restrictions implemented herein are intended to verify that instructions
+ * in shader assembly do not violate restrictions documented in the graphics
+ * programming reference manuals.
+ *
+ * The restrictions are difficult for humans to quickly verify due to their
+ * complexity and abundance.
+ *
+ * It is critical that this code is thoroughly unit tested because false
+ * results will lead developers astray, which is worse than having no validator
+ * at all. Functional changes to this file without corresponding unit tests (in
+ * test_eu_validate.cpp) will be rejected.
*/
#include "brw_eu.h"
}
}
+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;
+ }
+}
+
static unsigned
signed_type(unsigned type)
{
if (num_sources == 3)
return (struct string){};
+ /* Nothing to test. Split sends can only encode a file in sources that are
+ * allowed to be NULL.
+ */
+ if (inst_is_split_send(devinfo, inst))
+ return (struct string){};
+
if (num_sources >= 1)
ERROR_IF(src0_is_null(devinfo, inst), "src0 is null");
{
struct string error_msg = { .str = NULL, .len = 0 };
- if (brw_inst_opcode(devinfo, inst) == BRW_OPCODE_SEND) {
+ if (inst_is_split_send(devinfo, inst)) {
+ ERROR_IF(brw_inst_send_src1_reg_file(devinfo, inst) == BRW_ARCHITECTURE_REGISTER_FILE &&
+ brw_inst_send_src1_reg_nr(devinfo, inst) != BRW_ARF_NULL,
+ "src1 of split send must be a GRF or NULL");
+
+ ERROR_IF(brw_inst_eot(devinfo, inst) &&
+ brw_inst_src0_da_reg_nr(devinfo, inst) < 112,
+ "send with EOT must use g112-g127");
+ ERROR_IF(brw_inst_eot(devinfo, inst) &&
+ brw_inst_send_src1_reg_file(devinfo, inst) == BRW_GENERAL_REGISTER_FILE &&
+ brw_inst_send_src1_reg_nr(devinfo, inst) < 112,
+ "send with EOT must use g112-g127");
+
+ if (brw_inst_send_src1_reg_file(devinfo, inst) == BRW_GENERAL_REGISTER_FILE) {
+ /* Assume minimums if we don't know */
+ unsigned mlen = 1;
+ if (!brw_inst_send_sel_reg32_desc(devinfo, inst)) {
+ const uint32_t desc = brw_inst_send_desc(devinfo, inst);
+ mlen = brw_message_desc_mlen(devinfo, desc);
+ }
+
+ unsigned ex_mlen = 1;
+ if (!brw_inst_send_sel_reg32_ex_desc(devinfo, inst)) {
+ const uint32_t ex_desc = brw_inst_send_ex_desc(devinfo, inst);
+ ex_mlen = brw_message_ex_desc_ex_mlen(devinfo, ex_desc);
+ }
+ const unsigned src0_reg_nr = brw_inst_src0_da_reg_nr(devinfo, inst);
+ const unsigned src1_reg_nr = brw_inst_send_src1_reg_nr(devinfo, inst);
+ ERROR_IF((src0_reg_nr <= src1_reg_nr &&
+ src1_reg_nr < src0_reg_nr + mlen) ||
+ (src1_reg_nr <= src0_reg_nr &&
+ src0_reg_nr < src1_reg_nr + ex_mlen),
+ "split send payloads must not overlap");
+ }
+ } else if (inst_is_send(devinfo, inst)) {
ERROR_IF(brw_inst_src0_address_mode(devinfo, inst) != BRW_ADDRESS_DIRECT,
"send must use direct addressing");
brw_inst_src0_da_reg_nr(devinfo, inst) < 112,
"send with EOT must use g112-g127");
}
+
+ if (devinfo->gen >= 8) {
+ ERROR_IF(!dst_is_null(devinfo, inst) &&
+ (brw_inst_dst_da_reg_nr(devinfo, inst) +
+ brw_inst_rlen(devinfo, inst) > 127) &&
+ (brw_inst_src0_da_reg_nr(devinfo, inst) +
+ brw_inst_mlen(devinfo, inst) >
+ brw_inst_dst_da_reg_nr(devinfo, inst)),
+ "r127 must not be used for return address when there is "
+ "a src and dest overlap");
+ }
}
return error_msg;
execution_type_for_type(enum brw_reg_type type)
{
switch (type) {
+ case BRW_REGISTER_TYPE_NF:
case BRW_REGISTER_TYPE_DF:
case BRW_REGISTER_TYPE_F:
case BRW_REGISTER_TYPE_HF:
dst_type_size = 8;
if (exec_type_size > dst_type_size) {
- ERROR_IF(dst_stride * dst_type_size != exec_type_size,
- "Destination stride must be equal to the ratio of the sizes of "
- "the execution data type to the destination type");
+ if (!(dst_type_is_byte && inst_is_raw_move(devinfo, inst))) {
+ ERROR_IF(dst_stride * dst_type_size != exec_type_size,
+ "Destination stride must be equal to the ratio of the sizes "
+ "of the execution data type to the destination type");
+ }
unsigned subreg = brw_inst_dst_da1_subreg_nr(devinfo, inst);
if (num_sources == 3)
return (struct string){};
+ /* Split sends don't have the bits in the instruction to encode regions so
+ * there's nothing to check.
+ */
+ if (inst_is_split_send(devinfo, inst))
+ return (struct string){};
+
if (brw_inst_access_mode(devinfo, inst) == BRW_ALIGN_16) {
if (desc->ndst != 0 && !dst_is_null(devinfo, inst))
ERROR_IF(brw_inst_dst_hstride(devinfo, inst) != BRW_HORIZONTAL_STRIDE_1,
if (num_sources == 3 || num_sources == 0)
return (struct string){};
+ /* Split sends don't have types so there's no doubles there. */
+ if (inst_is_split_send(devinfo, inst))
+ return (struct string){};
+
enum brw_reg_type exec_type = execution_type(devinfo, inst);
unsigned exec_type_size = brw_reg_type_to_size(exec_type);