You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
15 KiB
446 lines
15 KiB
/*
|
|
* Copyright © 2012 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
/** @file gen8_instruction.cpp
|
|
*
|
|
* A representation of a Gen8+ EU instruction, with helper methods to get
|
|
* and set various fields. This is the actual hardware format.
|
|
*/
|
|
|
|
#include "brw_defines.h"
|
|
#include "gen8_instruction.h"
|
|
|
|
void
|
|
gen8_set_dst(struct gen8_instruction *inst, struct brw_reg reg)
|
|
{
|
|
/* MRFs haven't existed since Gen7, so we better not be using them. */
|
|
if (reg.file == BRW_MESSAGE_REGISTER_FILE) {
|
|
reg.file = BRW_GENERAL_REGISTER_FILE;
|
|
reg.nr += GEN7_MRF_HACK_START;
|
|
}
|
|
|
|
assert(reg.file != BRW_MESSAGE_REGISTER_FILE);
|
|
|
|
if (reg.file == BRW_GENERAL_REGISTER_FILE)
|
|
assert(reg.nr < BRW_MAX_GRF);
|
|
|
|
gen8_set_dst_reg_file(inst, reg.file);
|
|
gen8_set_dst_reg_type(inst, reg.type);
|
|
|
|
if (reg.address_mode == BRW_ADDRESS_DIRECT) {
|
|
gen8_set_dst_da_reg_nr(inst, reg.nr);
|
|
|
|
if (gen8_access_mode(inst) == BRW_ALIGN_1) {
|
|
/* Set Dst.SubRegNum[4:0] */
|
|
gen8_set_dst_da1_subreg_nr(inst, reg.subnr);
|
|
|
|
/* Set Dst.HorzStride */
|
|
if (reg.hstride == BRW_HORIZONTAL_STRIDE_0)
|
|
reg.hstride = BRW_HORIZONTAL_STRIDE_1;
|
|
gen8_set_dst_da1_hstride(inst, reg.hstride);
|
|
} else {
|
|
/* Align16 SubRegNum only has a single bit (bit 4; bits 3:0 MBZ). */
|
|
assert(reg.subnr == 0 || reg.subnr == 16);
|
|
gen8_set_dst_da16_subreg_nr(inst, reg.subnr >> 4);
|
|
gen8_set_da16_writemask(inst, reg.dw1.bits.writemask);
|
|
}
|
|
} else {
|
|
/* Indirect mode */
|
|
assert (gen8_access_mode(inst) == BRW_ALIGN_1);
|
|
|
|
gen8_set_dst_addr_mode(inst, BRW_ADDRESS_REGISTER_INDIRECT_REGISTER);
|
|
/* Set Dst.HorzStride */
|
|
if (reg.hstride == BRW_HORIZONTAL_STRIDE_0)
|
|
reg.hstride = BRW_HORIZONTAL_STRIDE_1;
|
|
gen8_set_dst_da1_hstride(inst, reg.hstride);
|
|
gen8_set_dst_ida1_sub_nr(inst, reg.subnr);
|
|
gen8_set_dst_ida1_imm8(inst, (reg.dw1.bits.indirect_offset & IMM8_MASK));
|
|
if ((reg.dw1.bits.indirect_offset & IMM9_MASK) == IMM9_MASK)
|
|
gen8_set_dst_ida1_imm9(inst, 1);
|
|
else
|
|
gen8_set_dst_ida1_imm9(inst, 0);
|
|
}
|
|
|
|
/* Generators should set a default exec_size of either 8 (SIMD4x2 or SIMD8)
|
|
* or 16 (SIMD16), as that's normally correct. However, when dealing with
|
|
* small registers, we automatically reduce it to match the register size.
|
|
*/
|
|
if (reg.width < BRW_EXECUTE_8)
|
|
gen8_set_exec_size(inst, reg.width);
|
|
}
|
|
|
|
static void
|
|
gen8_validate_reg(struct gen8_instruction *inst, struct brw_reg reg)
|
|
{
|
|
int hstride_for_reg[] = {0, 1, 2, 4};
|
|
int vstride_for_reg[] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256};
|
|
int width_for_reg[] = {1, 2, 4, 8, 16};
|
|
int execsize_for_reg[] = {1, 2, 4, 8, 16};
|
|
int width, hstride, vstride, execsize;
|
|
|
|
if (reg.file == BRW_IMMEDIATE_VALUE) {
|
|
/* TODO: check immediate vectors */
|
|
return;
|
|
}
|
|
|
|
if (reg.file == BRW_ARCHITECTURE_REGISTER_FILE)
|
|
return;
|
|
|
|
assert(reg.hstride >= 0 && reg.hstride < Elements(hstride_for_reg));
|
|
hstride = hstride_for_reg[reg.hstride];
|
|
|
|
if (reg.vstride == 0xf) {
|
|
vstride = -1;
|
|
} else {
|
|
assert(reg.vstride >= 0 && reg.vstride < Elements(vstride_for_reg));
|
|
vstride = vstride_for_reg[reg.vstride];
|
|
}
|
|
|
|
assert(reg.width >= 0 && reg.width < Elements(width_for_reg));
|
|
width = width_for_reg[reg.width];
|
|
|
|
assert(gen8_exec_size(inst) >= 0 &&
|
|
gen8_exec_size(inst) < Elements(execsize_for_reg));
|
|
execsize = execsize_for_reg[gen8_exec_size(inst)];
|
|
|
|
/* Restrictions from 3.3.10: Register Region Restrictions. */
|
|
/* 3. */
|
|
assert(execsize >= width);
|
|
|
|
/* 4. */
|
|
if (execsize == width && hstride != 0) {
|
|
assert(vstride == -1 || vstride == width * hstride);
|
|
}
|
|
|
|
/* 5. */
|
|
if (execsize == width && hstride == 0) {
|
|
/* no restriction on vstride. */
|
|
}
|
|
|
|
/* 6. */
|
|
if (width == 1) {
|
|
assert(hstride == 0);
|
|
}
|
|
|
|
/* 7. */
|
|
if (execsize == 1 && width == 1) {
|
|
assert(hstride == 0);
|
|
assert(vstride == 0);
|
|
}
|
|
|
|
/* 8. */
|
|
if (vstride == 0 && hstride == 0) {
|
|
assert(width == 1);
|
|
}
|
|
|
|
/* 10. Check destination issues. */
|
|
}
|
|
|
|
void
|
|
gen8_set_src0(struct gen8_instruction *inst, struct brw_reg reg)
|
|
{
|
|
/* MRFs haven't existed since Gen7, so we better not be using them. */
|
|
if (reg.file == BRW_MESSAGE_REGISTER_FILE) {
|
|
reg.file = BRW_GENERAL_REGISTER_FILE;
|
|
reg.nr += GEN7_MRF_HACK_START;
|
|
}
|
|
|
|
if (reg.file == BRW_GENERAL_REGISTER_FILE)
|
|
assert(reg.nr < BRW_MAX_GRF);
|
|
|
|
gen8_validate_reg(inst, reg);
|
|
|
|
gen8_set_src0_reg_file(inst, reg.file);
|
|
gen8_set_src0_reg_type(inst, reg.type);
|
|
gen8_set_src0_abs(inst, reg.abs);
|
|
gen8_set_src0_negate(inst, reg.negate);
|
|
|
|
|
|
if (reg.file == BRW_IMMEDIATE_VALUE) {
|
|
inst->data[3] = reg.dw1.ud;
|
|
|
|
/* Required to set some fields in src1 as well: */
|
|
gen8_set_src1_reg_file(inst, 0); /* arf */
|
|
gen8_set_src1_reg_type(inst, reg.type);
|
|
} else if (reg.address_mode == BRW_ADDRESS_DIRECT) {
|
|
gen8_set_src0_da_reg_nr(inst, reg.nr);
|
|
|
|
if (gen8_access_mode(inst) == BRW_ALIGN_1) {
|
|
/* Set Src0.SubRegNum[4:0] */
|
|
gen8_set_src0_da1_subreg_nr(inst, reg.subnr);
|
|
|
|
if (reg.width == BRW_WIDTH_1 &&
|
|
gen8_exec_size(inst) == BRW_EXECUTE_1) {
|
|
gen8_set_src0_da1_hstride(inst, BRW_HORIZONTAL_STRIDE_0);
|
|
gen8_set_src0_vert_stride(inst, BRW_VERTICAL_STRIDE_0);
|
|
} else {
|
|
gen8_set_src0_da1_hstride(inst, reg.hstride);
|
|
gen8_set_src0_vert_stride(inst, reg.vstride);
|
|
}
|
|
gen8_set_src0_da1_width(inst, reg.width);
|
|
|
|
} else {
|
|
/* Align16 SubRegNum only has a single bit (bit 4; bits 3:0 MBZ). */
|
|
assert(reg.subnr == 0 || reg.subnr == 16);
|
|
gen8_set_src0_da16_subreg_nr(inst, reg.subnr >> 4);
|
|
|
|
gen8_set_src0_da16_swiz_x(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_X));
|
|
gen8_set_src0_da16_swiz_y(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_Y));
|
|
gen8_set_src0_da16_swiz_z(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_Z));
|
|
gen8_set_src0_da16_swiz_w(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_W));
|
|
|
|
/* This is an oddity of the fact that we're using the same
|
|
* descriptions for registers in both Align16 and Align1 modes.
|
|
*/
|
|
if (reg.vstride == BRW_VERTICAL_STRIDE_8)
|
|
gen8_set_src0_vert_stride(inst, BRW_VERTICAL_STRIDE_4);
|
|
else
|
|
gen8_set_src0_vert_stride(inst, reg.vstride);
|
|
}
|
|
} else if (reg.address_mode == BRW_ADDRESS_REGISTER_INDIRECT_REGISTER) {
|
|
assert (gen8_access_mode(inst) == BRW_ALIGN_1);
|
|
if (reg.width == BRW_WIDTH_1 &&
|
|
gen8_exec_size(inst) == BRW_EXECUTE_1) {
|
|
gen8_set_src0_da1_hstride(inst, BRW_HORIZONTAL_STRIDE_0);
|
|
gen8_set_src0_vert_stride(inst, BRW_VERTICAL_STRIDE_0);
|
|
} else {
|
|
gen8_set_src0_da1_hstride(inst, reg.hstride);
|
|
gen8_set_src0_vert_stride(inst, reg.vstride);
|
|
}
|
|
|
|
gen8_set_src0_da1_width(inst, reg.width);
|
|
gen8_set_src0_ida1_sub_nr(inst, reg.subnr);
|
|
gen8_set_src0_addr_mode(inst, BRW_ADDRESS_REGISTER_INDIRECT_REGISTER);
|
|
gen8_set_src0_ida1_imm8(inst, (reg.dw1.bits.indirect_offset & IMM8_MASK));
|
|
if ((reg.dw1.bits.indirect_offset & IMM9_MASK) == IMM9_MASK)
|
|
gen8_set_src0_ida1_imm9(inst, 1);
|
|
else
|
|
gen8_set_src0_ida1_imm9(inst, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
gen8_set_src1(struct gen8_instruction *inst, struct brw_reg reg)
|
|
{
|
|
/* MRFs haven't existed since Gen7, so we better not be using them. */
|
|
if (reg.file == BRW_MESSAGE_REGISTER_FILE) {
|
|
reg.file = BRW_GENERAL_REGISTER_FILE;
|
|
reg.nr += GEN7_MRF_HACK_START;
|
|
}
|
|
|
|
if (reg.file == BRW_GENERAL_REGISTER_FILE)
|
|
assert(reg.nr < BRW_MAX_GRF);
|
|
|
|
gen8_validate_reg(inst, reg);
|
|
|
|
gen8_set_src1_reg_file(inst, reg.file);
|
|
gen8_set_src1_reg_type(inst, reg.type);
|
|
gen8_set_src1_abs(inst, reg.abs);
|
|
gen8_set_src1_negate(inst, reg.negate);
|
|
|
|
/* Only src1 can be an immediate in two-argument instructions. */
|
|
assert(gen8_src0_reg_file(inst) != BRW_IMMEDIATE_VALUE);
|
|
|
|
if (reg.file == BRW_IMMEDIATE_VALUE) {
|
|
inst->data[3] = reg.dw1.ud;
|
|
} else if (reg.address_mode == BRW_ADDRESS_DIRECT) {
|
|
gen8_set_src1_da_reg_nr(inst, reg.nr);
|
|
|
|
if (gen8_access_mode(inst) == BRW_ALIGN_1) {
|
|
/* Set Src0.SubRegNum[4:0] */
|
|
gen8_set_src1_da1_subreg_nr(inst, reg.subnr);
|
|
|
|
if (reg.width == BRW_WIDTH_1 &&
|
|
gen8_exec_size(inst) == BRW_EXECUTE_1) {
|
|
gen8_set_src1_da1_hstride(inst, BRW_HORIZONTAL_STRIDE_0);
|
|
gen8_set_src1_vert_stride(inst, BRW_VERTICAL_STRIDE_0);
|
|
} else {
|
|
gen8_set_src1_da1_hstride(inst, reg.hstride);
|
|
gen8_set_src1_vert_stride(inst, reg.vstride);
|
|
}
|
|
gen8_set_src1_da1_width(inst, reg.width);
|
|
} else {
|
|
/* Align16 SubRegNum only has a single bit (bit 4; bits 3:0 MBZ). */
|
|
assert(reg.subnr == 0 || reg.subnr == 16);
|
|
gen8_set_src1_da16_subreg_nr(inst, reg.subnr >> 4);
|
|
|
|
gen8_set_src1_da16_swiz_x(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_X));
|
|
gen8_set_src1_da16_swiz_y(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_Y));
|
|
gen8_set_src1_da16_swiz_z(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_Z));
|
|
gen8_set_src1_da16_swiz_w(inst,
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle,
|
|
BRW_CHANNEL_W));
|
|
|
|
/* This is an oddity of the fact that we're using the same
|
|
* descriptions for registers in both Align16 and Align1 modes.
|
|
*/
|
|
if (reg.vstride == BRW_VERTICAL_STRIDE_8)
|
|
gen8_set_src1_vert_stride(inst, BRW_VERTICAL_STRIDE_4);
|
|
else
|
|
gen8_set_src1_vert_stride(inst, reg.vstride);
|
|
}
|
|
} else if (reg.address_mode == BRW_ADDRESS_REGISTER_INDIRECT_REGISTER) {
|
|
assert (gen8_access_mode(inst) == BRW_ALIGN_1);
|
|
if (reg.width == BRW_WIDTH_1 &&
|
|
gen8_exec_size(inst) == BRW_EXECUTE_1) {
|
|
gen8_set_src1_da1_hstride(inst, BRW_HORIZONTAL_STRIDE_0);
|
|
gen8_set_src1_vert_stride(inst, BRW_VERTICAL_STRIDE_0);
|
|
} else {
|
|
gen8_set_src1_da1_hstride(inst, reg.hstride);
|
|
gen8_set_src1_vert_stride(inst, reg.vstride);
|
|
}
|
|
|
|
gen8_set_src1_da1_width(inst, reg.width);
|
|
gen8_set_src1_ida1_sub_nr(inst, reg.subnr);
|
|
gen8_set_src1_addr_mode(inst, BRW_ADDRESS_REGISTER_INDIRECT_REGISTER);
|
|
gen8_set_src1_ida1_imm8(inst, (reg.dw1.bits.indirect_offset & IMM8_MASK));
|
|
if ((reg.dw1.bits.indirect_offset & IMM9_MASK) == IMM9_MASK)
|
|
gen8_set_src1_ida1_imm9(inst, 1);
|
|
else
|
|
gen8_set_src1_ida1_imm9(inst, 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the Message Descriptor and Extended Message Descriptor fields
|
|
* for SEND messages.
|
|
*
|
|
* \note This zeroes out the Function Control bits, so it must be called
|
|
* \b before filling out any message-specific data. Callers can
|
|
* choose not to fill in irrelevant bits; they will be zero.
|
|
*/
|
|
static void
|
|
gen8_set_message_descriptor(struct gen8_instruction *inst,
|
|
enum brw_message_target sfid,
|
|
unsigned msg_length,
|
|
unsigned response_length,
|
|
bool header_present,
|
|
bool end_of_thread)
|
|
{
|
|
gen8_set_src1(inst, brw_imm_d(0));
|
|
|
|
gen8_set_sfid(inst, sfid);
|
|
gen8_set_mlen(inst, msg_length);
|
|
gen8_set_rlen(inst, response_length);
|
|
gen8_set_header_present(inst, header_present);
|
|
gen8_set_eot(inst, end_of_thread);
|
|
}
|
|
|
|
void
|
|
gen8_set_urb_message(struct gen8_instruction *inst,
|
|
unsigned opcode,
|
|
unsigned msg_length,
|
|
unsigned response_length,
|
|
bool end_of_thread,
|
|
unsigned offset,
|
|
bool interleave)
|
|
{
|
|
gen8_set_message_descriptor(inst, BRW_SFID_URB, msg_length, response_length,
|
|
true, end_of_thread);
|
|
gen8_set_src0(inst, brw_vec8_grf(GEN7_MRF_HACK_START + 1, 0));
|
|
gen8_set_urb_opcode(inst, 0); /* URB_WRITE_HWORD */
|
|
gen8_set_urb_global_offset(inst, offset);
|
|
gen8_set_urb_interleave(inst, interleave);
|
|
/* per_slot_offset = 0 makes it ignore offsets in message header */
|
|
gen8_set_urb_per_slot_offset(inst, 0);
|
|
}
|
|
|
|
void
|
|
gen8_set_sampler_message(struct gen8_instruction *inst,
|
|
unsigned binding_table_index,
|
|
unsigned sampler,
|
|
unsigned msg_type,
|
|
unsigned response_length,
|
|
unsigned msg_length,
|
|
bool header_present,
|
|
unsigned simd_mode)
|
|
{
|
|
gen8_set_message_descriptor(inst, BRW_SFID_SAMPLER, msg_length,
|
|
response_length, header_present, false);
|
|
|
|
gen8_set_binding_table_index(inst, binding_table_index);
|
|
gen8_set_sampler(inst, sampler);
|
|
gen8_set_sampler_msg_type(inst, msg_type);
|
|
gen8_set_sampler_simd_mode(inst, simd_mode);
|
|
}
|
|
|
|
void
|
|
gen8_set_dp_message(struct gen8_instruction *inst,
|
|
enum brw_message_target sfid,
|
|
unsigned binding_table_index,
|
|
unsigned msg_type,
|
|
unsigned msg_control,
|
|
unsigned mlen,
|
|
unsigned rlen,
|
|
bool header_present,
|
|
bool end_of_thread)
|
|
{
|
|
/* Binding table index is from 0..255 */
|
|
assert((binding_table_index & 0xff) == binding_table_index);
|
|
|
|
/* Message Type is only 5 bits */
|
|
assert((msg_type & 0x1f) == msg_type);
|
|
|
|
/* Message Control is only 6 bits */
|
|
assert((msg_control & 0x3f) == msg_control);
|
|
|
|
gen8_set_message_descriptor(inst, sfid, mlen, rlen, header_present,
|
|
end_of_thread);
|
|
gen8_set_function_control(inst,
|
|
binding_table_index | msg_type << 14 | msg_control << 8);
|
|
}
|
|
|
|
|
|
void
|
|
gen9_set_send_extdesc(struct gen8_instruction *inst,
|
|
unsigned int value)
|
|
{
|
|
unsigned int extdesc;
|
|
|
|
extdesc = (value >> 16) & 0x0f;
|
|
gen8_set_bits(inst, 67, 64, extdesc);
|
|
|
|
extdesc = (value >> 20) & 0x0f;
|
|
gen8_set_bits(inst, 83, 80, extdesc);
|
|
|
|
extdesc = (value >> 24) & 0x0f;
|
|
gen8_set_bits(inst, 88, 85, extdesc);
|
|
|
|
extdesc = (value >> 28) & 0x0f;
|
|
gen8_set_bits(inst, 94, 91, extdesc);
|
|
}
|