/* * 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); }