[Mesa-dev] [PATCH 9/9] i965: Check accumulator restrictions.
Matt Turner
mattst88 at gmail.com
Wed Oct 21 15:58:17 PDT 2015
---
src/mesa/drivers/dri/i965/brw_eu_validate.c | 244 ++++++++++++++++++++++++++++
1 file changed, 244 insertions(+)
diff --git a/src/mesa/drivers/dri/i965/brw_eu_validate.c b/src/mesa/drivers/dri/i965/brw_eu_validate.c
index eb57962..3d16f90 100644
--- a/src/mesa/drivers/dri/i965/brw_eu_validate.c
+++ b/src/mesa/drivers/dri/i965/brw_eu_validate.c
@@ -54,6 +54,16 @@ cat(struct string *dest, const struct string src)
} \
} while(0)
+#define CHECK(func) \
+ do { \
+ struct string __msg = func; \
+ if (__msg.str) { \
+ cat(&error_msg, __msg); \
+ free(__msg.str); \
+ valid = false; \
+ } \
+ } while (0)
+
static bool
src0_is_null(const struct brw_device_info *devinfo, const brw_inst *inst)
{
@@ -68,6 +78,42 @@ src1_is_null(const struct brw_device_info *devinfo, const brw_inst *inst)
brw_inst_src1_da_reg_nr(devinfo, inst) == BRW_ARF_NULL;
}
+static bool
+dst_is_accumulator(const struct brw_device_info *devinfo, const brw_inst *inst)
+{
+ return brw_inst_dst_reg_file(devinfo, inst) == BRW_ARCHITECTURE_REGISTER_FILE &&
+ brw_inst_dst_da_reg_nr(devinfo, inst) == BRW_ARF_ACCUMULATOR;
+}
+
+static bool
+src0_is_accumulator(const struct brw_device_info *devinfo, const brw_inst *inst)
+{
+ return brw_inst_src0_reg_file(devinfo, inst) == BRW_ARCHITECTURE_REGISTER_FILE &&
+ brw_inst_src0_da_reg_nr(devinfo, inst) == BRW_ARF_ACCUMULATOR;
+}
+
+static bool
+src1_is_accumulator(const struct brw_device_info *devinfo, const brw_inst *inst)
+{
+ return brw_inst_src1_reg_file(devinfo, inst) == BRW_ARCHITECTURE_REGISTER_FILE &&
+ brw_inst_src1_da_reg_nr(devinfo, inst) == BRW_ARF_ACCUMULATOR;
+}
+
+static bool
+is_integer(enum brw_reg_type type)
+{
+ return type == BRW_REGISTER_TYPE_UD ||
+ type == BRW_REGISTER_TYPE_D ||
+ type == BRW_REGISTER_TYPE_UW ||
+ type == BRW_REGISTER_TYPE_W ||
+ type == BRW_REGISTER_TYPE_UB ||
+ type == BRW_REGISTER_TYPE_B ||
+ type == BRW_REGISTER_TYPE_V ||
+ type == BRW_REGISTER_TYPE_UV ||
+ type == BRW_REGISTER_TYPE_UQ ||
+ type == BRW_REGISTER_TYPE_Q;
+}
+
enum gen {
GEN4 = (1 << 0),
GEN45 = (1 << 1),
@@ -83,40 +129,66 @@ enum gen {
#define GEN_GE(gen) (~((gen) - 1) | gen)
#define GEN_LE(gen) (((gen) - 1) | gen)
+enum acc {
+ ACC_NO_RESTRICTIONS = 0,
+ ACC_GEN_DEPENDENT = (1 << 0),
+ ACC_NO_EXPLICIT_SOURCE = (1 << 1),
+ ACC_NO_EXPLICIT_DESTINATION = (1 << 2),
+ ACC_NO_IMPLICIT_DESTINATION = (1 << 3),
+ ACC_NO_DESTINATION = ACC_NO_EXPLICIT_DESTINATION |
+ ACC_NO_IMPLICIT_DESTINATION,
+ ACC_NO_ACCESS = ACC_NO_EXPLICIT_SOURCE |
+ ACC_NO_DESTINATION,
+ ACC_NO_SOURCE_MODIFIER = (1 << 4),
+ ACC_NO_INTEGER_SOURCE = (1 << 5),
+ ACC_IMPLICIT_WRITE_REQUIRED = (1 << 6),
+ ACC_NOT_BOTH_SOURCE_AND_DESTINATION = (1 << 7),
+};
+
struct inst_info {
enum gen gen;
+ enum acc acc;
};
static const struct inst_info inst_info[128] = {
[BRW_OPCODE_ILLEGAL] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_MOV] = {
.gen = GEN_ALL,
+ .acc = ACC_NOT_BOTH_SOURCE_AND_DESTINATION,
},
[BRW_OPCODE_SEL] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_MOVI] = {
.gen = GEN_GE(GEN45),
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_NOT] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_SOURCE_MODIFIER,
},
[BRW_OPCODE_AND] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_SOURCE_MODIFIER,
},
[BRW_OPCODE_OR] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_SOURCE_MODIFIER,
},
[BRW_OPCODE_XOR] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_SOURCE_MODIFIER,
},
[BRW_OPCODE_SHR] = {
.gen = GEN_ALL,
},
[BRW_OPCODE_SHL] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_DESTINATION,
},
/* BRW_OPCODE_DIM / BRW_OPCODE_SMOV */
/* Reserved - 11 */
@@ -126,63 +198,81 @@ static const struct inst_info inst_info[128] = {
/* Reserved - 13-15 */
[BRW_OPCODE_CMP] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_CMPN] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_CSEL] = {
.gen = GEN_GE(GEN8),
},
[BRW_OPCODE_F32TO16] = {
.gen = GEN7 | GEN75,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_F16TO32] = {
.gen = GEN7 | GEN75,
+ .acc = ACC_NO_ACCESS,
},
/* Reserved - 21-22 */
[BRW_OPCODE_BFREV] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_BFE] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_IMPLICIT_DESTINATION,
},
[BRW_OPCODE_BFI1] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_BFI2] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_IMPLICIT_DESTINATION,
},
/* Reserved - 27-31 */
[BRW_OPCODE_JMPI] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
/* BRW_OPCODE_BRD */
[BRW_OPCODE_IF] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_IFF] = { /* also BRW_OPCODE_BRC */
.gen = GEN_LE(GEN5),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_ELSE] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_ENDIF] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_DO] = { /* also BRW_OPCODE_CASE */
.gen = GEN_LE(GEN5),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_WHILE] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_BREAK] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_CONTINUE] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_HALT] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
/* BRW_OPCODE_CALLA */
/* BRW_OPCODE_MSAVE / BRW_OPCODE_CALL */
@@ -191,22 +281,28 @@ static const struct inst_info inst_info[128] = {
/* BRW_OPCODE_POP */
[BRW_OPCODE_WAIT] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_SEND] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_SENDC] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_SENDS] = {
.gen = GEN_GE(GEN9),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_SENDSC] = {
.gen = GEN_GE(GEN9),
+ .acc = ACC_NO_ACCESS,
},
/* Reserved 53-55 */
[BRW_OPCODE_MATH] = {
.gen = GEN_GE(GEN6),
+ .acc = ACC_NO_ACCESS,
},
/* Reserved 57-63 */
[BRW_OPCODE_ADD] = {
@@ -214,6 +310,7 @@ static const struct inst_info inst_info[128] = {
},
[BRW_OPCODE_MUL] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_AVG] = {
.gen = GEN_ALL,
@@ -223,65 +320,89 @@ static const struct inst_info inst_info[128] = {
},
[BRW_OPCODE_RNDU] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_RNDD] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_RNDE] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_RNDZ] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_MAC] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_MACH] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE |
+ ACC_NO_EXPLICIT_DESTINATION |
+ ACC_IMPLICIT_WRITE_REQUIRED,
},
[BRW_OPCODE_LZD] = {
.gen = GEN_ALL,
+ .acc = ACC_GEN_DEPENDENT,
},
[BRW_OPCODE_FBH] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_FBL] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_CBIT] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_ACCESS,
},
[BRW_OPCODE_ADDC] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_EXPLICIT_DESTINATION |
+ ACC_IMPLICIT_WRITE_REQUIRED,
},
[BRW_OPCODE_SUBB] = {
.gen = GEN_GE(GEN7),
+ .acc = ACC_NO_EXPLICIT_DESTINATION |
+ ACC_IMPLICIT_WRITE_REQUIRED,
},
[BRW_OPCODE_SAD2] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_SADA2] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
/* Reserved 82-83 */
[BRW_OPCODE_DP4] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_DPH] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_DP3] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_DP2] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
/* Reserved 88 */
[BRW_OPCODE_LINE] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_PLN] = {
.gen = GEN_GE(GEN45),
+ .acc = ACC_NO_EXPLICIT_SOURCE,
},
[BRW_OPCODE_MAD] = {
.gen = GEN_GE(GEN6),
@@ -293,9 +414,130 @@ static const struct inst_info inst_info[128] = {
/* BRW_OPCODE_NENOP */
[BRW_OPCODE_NOP] = {
.gen = GEN_ALL,
+ .acc = ACC_NO_ACCESS,
},
};
+static struct string
+accumulator_restrictions(const struct brw_device_info *devinfo,
+ const brw_inst *inst)
+{
+ enum opcode opcode = brw_inst_opcode(devinfo, inst);
+ enum acc acc = inst_info[opcode].acc;
+
+ /* Handle Gen-specific accumulator restrictions */
+ if ((acc & ACC_GEN_DEPENDENT) != 0) {
+ assert(acc == ACC_GEN_DEPENDENT);
+
+ switch (opcode) {
+ case BRW_OPCODE_SEL:
+ if (devinfo->gen < 7)
+ acc = ACC_NO_ACCESS;
+ else
+ acc = ACC_NO_RESTRICTIONS;
+ break;
+ case BRW_OPCODE_CMP:
+ case BRW_OPCODE_CMPN:
+ acc = ACC_NO_RESTRICTIONS;
+ if (devinfo->gen < 8)
+ acc |= ACC_NO_DESTINATION;
+ if (devinfo->gen < 7)
+ acc |= ACC_NO_SOURCE_MODIFIER |
+ ACC_NO_INTEGER_SOURCE;
+ break;
+ case BRW_OPCODE_MUL:
+ if (devinfo->gen < 8)
+ acc = ACC_NO_SOURCE_MODIFIER;
+ else
+ acc = ACC_NO_RESTRICTIONS;
+ break;
+ case BRW_OPCODE_RNDU:
+ case BRW_OPCODE_RNDD:
+ case BRW_OPCODE_RNDE:
+ case BRW_OPCODE_RNDZ:
+ if (devinfo->gen < 8)
+ acc = ACC_NO_ACCESS;
+ else
+ acc = ACC_NO_RESTRICTIONS;
+ break;
+ case BRW_OPCODE_LZD:
+ if (devinfo->gen < 8)
+ acc = ACC_NO_EXPLICIT_DESTINATION;
+ else
+ acc = ACC_NO_RESTRICTIONS;
+ break;
+ default:
+ unreachable("not reached");
+ }
+ }
+ assert((acc & ACC_GEN_DEPENDENT) == 0);
+
+ /* Gens 4 and 5 don't have an AccWrCtrl. Instead of using ACC_GEN_DEPENDENT
+ * in a ton of places, simply ignore the related restrictions.
+ */
+ if (devinfo->gen < 6)
+ acc &= ~(ACC_NO_IMPLICIT_DESTINATION | ACC_IMPLICIT_WRITE_REQUIRED);
+
+ struct string msg = {
+ .str = NULL,
+ .len = 0,
+ };
+
+ if ((acc & ACC_NO_IMPLICIT_DESTINATION) != 0 &&
+ brw_inst_acc_wr_control(devinfo, inst) == 1) {
+ CAT(msg, error("AccWrEN (\"implicit accumulator update\") not allowed"));
+ }
+
+ /* It's not possible to violate any of the other restrictions with a 3-src
+ * instruction.
+ */
+ if (is_3src(opcode))
+ return msg;
+
+ if ((acc & ACC_NO_EXPLICIT_SOURCE) != 0 &&
+ src0_is_accumulator(devinfo, inst) &&
+ src1_is_accumulator(devinfo, inst)) {
+ CAT(msg, error("Explicit accumulator source operand not allowed"));
+ }
+
+ if ((acc & ACC_NO_EXPLICIT_DESTINATION) != 0 &&
+ dst_is_accumulator(devinfo, inst)) {
+ CAT(msg, error("Explicit accumulator destination not allowed"));
+ }
+
+ if ((acc & ACC_NO_SOURCE_MODIFIER) != 0 &&
+ ((src0_is_accumulator(devinfo, inst) &&
+ (brw_inst_src0_abs(devinfo, inst) == 1 ||
+ brw_inst_src0_negate(devinfo, inst) == 1)) ||
+ (src1_is_accumulator(devinfo, inst) &&
+ (brw_inst_src1_abs(devinfo, inst) == 1 ||
+ brw_inst_src1_negate(devinfo, inst) == 1)))) {
+ CAT(msg, error("Source modifiers on accumulator source not allowed"));
+ }
+
+ if ((acc & ACC_NO_INTEGER_SOURCE) != 0 &&
+ ((src0_is_accumulator(devinfo, inst) &&
+ is_integer(brw_inst_src0_reg_type(devinfo, inst))) ||
+ (src1_is_accumulator(devinfo, inst) &&
+ is_integer(brw_inst_src1_reg_type(devinfo, inst))))) {
+ CAT(msg, "Integer accumulator source not allowed");
+ }
+
+ if ((acc & ACC_IMPLICIT_WRITE_REQUIRED) != 0 &&
+ brw_inst_acc_wr_control(devinfo, inst) == 0) {
+ CAT(msg, error("AccWrEn (\"implicit accumulator update\") required"));
+ }
+
+ if ((acc & ACC_NOT_BOTH_SOURCE_AND_DESTINATION) != 0 &&
+ (dst_is_accumulator(devinfo, inst) +
+ (src0_is_accumulator(devinfo, inst) ||
+ src1_is_accumulator(devinfo, inst)) == 2)) {
+ CAT(msg, error("Both source and destination cannot be accumulator"));
+ }
+
+ return msg;
+}
+
static unsigned
num_sources_from_inst(const struct brw_device_info *devinfo,
const brw_inst *inst)
@@ -397,6 +639,8 @@ brw_validate_instructions(const struct brw_codegen *p, int start_offset,
ERROR_IF(is_unsupported_inst(devinfo, inst),
"Instruction not supported on this Gen");
+ CHECK(accumulator_restrictions(devinfo, inst));
+
if (error_msg.str && annotation) {
annotation_insert_error(annotation, src_offset, error_msg.str);
}
--
2.4.9
More information about the mesa-dev
mailing list