diff --git a/src/intel/compiler/brw_eu_validate.c b/src/intel/compiler/brw_eu_validate.c index 071025b45cc..d35b3085a11 100644 --- a/src/intel/compiler/brw_eu_validate.c +++ b/src/intel/compiler/brw_eu_validate.c @@ -1605,11 +1605,16 @@ special_requirements_for_handling_double_precision_data_types( "source and destination are not supported except for " "broadcast of a scalar."); + /* NOTE: Expanded this to include Scalar. See documentation issue + * open in https://gfxspecs.intel.com/Predator/Home/Index/56640. + */ ERROR_IF((address_mode == BRW_ADDRESS_DIRECT && file == ARF && + reg != BRW_ARF_SCALAR && reg != BRW_ARF_NULL && !(reg >= BRW_ARF_ACCUMULATOR && reg < BRW_ARF_FLAG)) || (inst->dst.file == ARF && + dst_reg != BRW_ARF_SCALAR && dst_reg != BRW_ARF_NULL && (dst_reg & 0xF0) != BRW_ARF_ACCUMULATOR), - "Explicit ARF registers except null and accumulator must not " + "Explicit ARF registers except null, accumulator, and scalar must not " "be used."); } @@ -2164,6 +2169,87 @@ send_descriptor_restrictions(const struct brw_isa_info *isa, return error_msg; } +static struct string +scalar_register_restrictions(const struct brw_isa_info *isa, + const brw_hw_decoded_inst *inst) +{ + const struct intel_device_info *devinfo = isa->devinfo; + struct string error_msg = { .str = NULL, .len = 0 }; + + /* Restrictions from BSpec 71168 (r55736). */ + + if (devinfo->ver >= 30) { + if (inst->dst.file == ARF && inst->dst.nr == BRW_ARF_SCALAR) { + switch (inst->opcode) { + case BRW_OPCODE_MOV: { + unsigned dst_size_bits = brw_type_size_bits(inst->dst.type); + ERROR_IF(inst->dst.type != inst->src[0].type, + "When destination is scalar register, " + "source and destination data-types must be the same."); + ERROR_IF(!brw_type_is_int(inst->dst.type) || (dst_size_bits != 16 && + dst_size_bits != 32 && + dst_size_bits != 64), + "When destination is scalar register, " + "it must be an integer with size 16, 32, or 64 bits."); + if (inst->src[0].file == IMM) { + ERROR_IF(inst->exec_size != 1, + "When destination is scalar register with immediate source, " + "execution size must be 1."); + ERROR_IF(inst->cond_modifier != BRW_CONDITIONAL_NONE, + "When destination is scalar register with immediate source, " + "conditional modifier must not be used."); + } + ERROR_IF((inst->dst.subnr / 32) != ((inst->dst.subnr + brw_type_size_bytes(inst->dst.type)) / 32), + "When destination is scalar register, it must not span across " + "the lower to upper 8 dword boundary of the register."); + break; + } + + default: + ERROR("When destination is scalar register, opcode must be MOV."); + break; + } + } + + if (inst->src[0].file == ARF && inst->src[0].nr == BRW_ARF_SCALAR) { + switch (inst->opcode) { + case BRW_OPCODE_MOV: { + ERROR_IF(inst->dst.file == ARF && inst->dst.nr == BRW_ARF_SCALAR, + "When source is a scalar register, destination must not be a scalar register."); + ERROR_IF(!src_has_scalar_region(inst, 0), + "When source is a scalar register and opcode is MOV, the scalar (broadcast) regioning must be used."); + break; + } + + case BRW_OPCODE_SEND: + case BRW_OPCODE_SENDC: { + ERROR_IF(!src1_is_null(inst), + "When source is a scalar and opcode is a SEND or SENDC, Src1 must be NULL."); + break; + } + + default: + ERROR("When source is a scalar register, opcode must be MOV, SEND, or SENDC."); + break; + } + } + + if ((inst->src[1].file == ARF && inst->src[1].nr == BRW_ARF_SCALAR) || + (inst->src[2].file == ARF && inst->src[2].nr == BRW_ARF_SCALAR)) { + ERROR("When source is a scalar register, it must be on Source 0."); + } + } else { + assert(devinfo->ver < 30); + if ((inst->dst.file == ARF && inst->dst.nr == BRW_ARF_SCALAR) || + (inst->src[0].file == ARF && inst->src[0].nr == BRW_ARF_SCALAR) || + (inst->src[1].file == ARF && inst->src[1].nr == BRW_ARF_SCALAR) || + (inst->src[2].file == ARF && inst->src[2].nr == BRW_ARF_SCALAR)) + ERROR("Scalar register not available before Gfx30."); + } + + return error_msg; +} + static unsigned VSTRIDE_3SRC(unsigned vstride) { @@ -2562,6 +2648,7 @@ brw_validate_instruction(const struct brw_isa_info *isa, CHECK(special_requirements_for_handling_double_precision_data_types); CHECK(instruction_restrictions); CHECK(send_descriptor_restrictions); + CHECK(scalar_register_restrictions); } #undef CHECK diff --git a/src/intel/compiler/test_eu_validate.cpp b/src/intel/compiler/test_eu_validate.cpp index 1effbd2bef5..452b910817b 100644 --- a/src/intel/compiler/test_eu_validate.cpp +++ b/src/intel/compiler/test_eu_validate.cpp @@ -3375,3 +3375,165 @@ TEST_P(validation_test, dpas_src_subreg_nr) clear_instructions(p); } } + +static brw_reg +brw_s0(enum brw_reg_type type, unsigned subnr) +{ + return brw_make_reg(ARF, + BRW_ARF_SCALAR, + subnr, + 0, + 0, + type, + BRW_VERTICAL_STRIDE_0, + BRW_WIDTH_1, + BRW_HORIZONTAL_STRIDE_0, + BRW_SWIZZLE_XYZW, + WRITEMASK_XYZW); +} + +static brw_reg +brw_s0_with_region(enum brw_reg_type type, unsigned subnr, unsigned v, unsigned w, unsigned h) +{ + return brw_make_reg(ARF, + BRW_ARF_SCALAR, + subnr, + 0, + 0, + type, + cvt(v), + cvt(w)-1, + cvt(h), + BRW_SWIZZLE_XYZW, + WRITEMASK_XYZW); +} + +static brw_reg +brw_grf(enum brw_reg_type type, unsigned nr, unsigned subnr, unsigned v, unsigned w, unsigned h) +{ + return brw_make_reg(FIXED_GRF, + nr, + subnr, + 0, + 0, + type, + cvt(v), + cvt(w)-1, + cvt(h), + BRW_SWIZZLE_XYZW, + WRITEMASK_XYZW); +} + +TEST_P(validation_test, scalar_register_restrictions) +{ + /* Restrictions from BSpec 71168 (r55736). */ + + if (devinfo.ver < 30) + return; + + const brw_reg null_ud = retype(brw_null_reg(), BRW_TYPE_UD); + + struct test { + enum opcode opcode; + unsigned exec_size; + struct { + enum brw_conditional_mod cmod; + } opts; + brw_reg dst, src0, src1; + bool expected_result; + }; + + static const struct test tests[] = { + { BRW_OPCODE_MOV, 8, {}, brw_s0(BRW_TYPE_UD, 0), brw_grf(BRW_TYPE_UD, 1, 0, 1,1,0), {}, true }, + + /* When destination, opcode must be MOV. */ + { BRW_OPCODE_NOT, 8, {}, brw_s0(BRW_TYPE_UD, 0), brw_grf(BRW_TYPE_UD, 1, 0, 1,1,0), {}, false }, + { BRW_OPCODE_ADD, 8, {}, brw_s0(BRW_TYPE_UD, 0), brw_grf(BRW_TYPE_UD, 1, 0, 1,1,0), brw_imm_ud(1), false }, + + /* Source and destination types must match. */ + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UQ, 0), brw_imm_uq(0x000036161836341E), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UQ, 0), brw_imm_ud(0x1836341E), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UQ, 0), brw_imm_uw(0x341E), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UD, 0), brw_imm_uq(0x000036161836341E), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UD, 0), brw_imm_ud(0x1836341E), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UD, 0), brw_imm_uw(0x341E), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UW, 0), brw_imm_uq(0x000036161836341E), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UW, 0), brw_imm_ud(0x1836341E), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UW, 0), brw_imm_uw(0x341E), {}, true }, + + /* When destination, must be integers of size 16, 32 or 64. */ + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_B, 0), brw_grf(BRW_TYPE_B, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UB, 0), brw_grf(BRW_TYPE_UB, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_W, 0), brw_grf(BRW_TYPE_W, 1, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UW, 0), brw_grf(BRW_TYPE_UW, 1, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_D, 0), brw_grf(BRW_TYPE_D, 1, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UD, 0), brw_grf(BRW_TYPE_UD, 1, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_Q, 0), brw_grf(BRW_TYPE_Q, 1, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UQ, 0), brw_grf(BRW_TYPE_UQ, 1, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_F, 0), brw_grf(BRW_TYPE_F, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_HF, 0), brw_grf(BRW_TYPE_HF, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_DF, 0), brw_grf(BRW_TYPE_DF, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_V, 0), brw_grf(BRW_TYPE_V, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UV, 0), brw_grf(BRW_TYPE_UV, 1, 0, 0,1,0), {}, false }, + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_VF, 0), brw_grf(BRW_TYPE_VF, 1, 0, 0,1,0), {}, false }, + + /* When destination with immediate source, execution size must be 1. */ + { BRW_OPCODE_MOV, 8, {}, brw_s0(BRW_TYPE_UW, 0), brw_imm_uw(0x1234), {}, false }, + + /* When destination with with immediate source, conditional modifier cannot be used. */ + { BRW_OPCODE_MOV, 1, {.cmod = BRW_CONDITIONAL_Z}, brw_s0(BRW_TYPE_UW, 0), brw_imm_uw(0x341E), {}, false }, + { BRW_OPCODE_MOV, 1, {.cmod = BRW_CONDITIONAL_Z}, brw_s0(BRW_TYPE_UW, 0), brw_grf(BRW_TYPE_UW, 1, 0, 0,1,0), {}, true }, + + /* When source is scalar, destination must not be scalar. */ + { BRW_OPCODE_MOV, 1, {}, brw_s0(BRW_TYPE_UW, 0), brw_s0(BRW_TYPE_UW, 4), {}, false }, + + /* When source of MOV is scalar, it must be a broadcast. */ + { BRW_OPCODE_MOV, 8, {}, brw_grf(BRW_TYPE_UW, 1, 0, 1,1,0), brw_s0_with_region(BRW_TYPE_UW, 0, 0,1,0), {}, true }, + { BRW_OPCODE_MOV, 8, {}, brw_grf(BRW_TYPE_UW, 1, 0, 1,1,0), brw_s0_with_region(BRW_TYPE_UW, 0, 1,1,0), {}, false }, + { BRW_OPCODE_MOV, 8, {}, brw_grf(BRW_TYPE_UW, 1, 0, 1,1,0), brw_s0_with_region(BRW_TYPE_UW, 0, 8,8,1), {}, false }, + + /* When source 0 of SEND/SENDC is scalar, source 1 must be null. */ + { BRW_OPCODE_SEND, 16, {}, null_ud, brw_s0(BRW_TYPE_UD, 0), null_ud, true }, + { BRW_OPCODE_SENDC, 16, {}, null_ud, brw_s0(BRW_TYPE_UD, 0), null_ud, true }, + { BRW_OPCODE_SEND, 16, {}, null_ud, brw_s0(BRW_TYPE_UD, 0), brw_grf(BRW_TYPE_UD, 1, 0, 0,1,0), false }, + { BRW_OPCODE_SENDC, 16, {}, null_ud, brw_s0(BRW_TYPE_UD, 0), brw_grf(BRW_TYPE_UD, 1, 0, 0,1,0), false }, + + /* When source is a scalar register, it must be on source 0. */ + { BRW_OPCODE_SEND, 16, {}, null_ud, brw_grf(BRW_TYPE_UD, 0, 0, 0,1,0), brw_grf(BRW_TYPE_UD, 2, 0, 0,1,0), true }, + { BRW_OPCODE_SEND, 16, {}, null_ud, brw_grf(BRW_TYPE_UD, 0, 0, 0,1,0), brw_s0(BRW_TYPE_UD, 0), false }, + }; + + for (unsigned i = 0; i < ARRAY_SIZE(tests); i++) { + const struct test &t = tests[i]; + + switch (tests[i].opcode) { + case BRW_OPCODE_ADD: + brw_ADD(p, t.dst, t.src0, t.src1); + break; + case BRW_OPCODE_NOT: + brw_NOT(p, t.dst, t.src0); + break; + case BRW_OPCODE_MOV: + brw_MOV(p, t.dst, t.src0); + break; + case BRW_OPCODE_SEND: + case BRW_OPCODE_SENDC: { + brw_inst *send = brw_next_insn(p, tests[i].opcode); + brw_set_dest(p, send, t.dst); + brw_set_src0(p, send, t.src0); + brw_set_src1(p, send, t.src1); + break; + } + default: + unreachable("unexpected opcode in tests"); + } + + brw_inst_set_exec_size(&devinfo, last_inst, cvt(t.exec_size) - 1); + brw_inst_set_cond_modifier(&devinfo, last_inst, t.opts.cmod); + + EXPECT_EQ(t.expected_result, validate(p)) << + "test vector index = " << i; + + clear_instructions(p); + } +}