2006-08-09 19:14:05 +00:00
|
|
|
/*
|
|
|
|
|
Copyright (C) Intel Corp. 2006. All Rights Reserved.
|
s/Tungsten Graphics/VMware/
Tungsten Graphics Inc. was acquired by VMware Inc. in 2008. Leaving the
old copyright name is creating unnecessary confusion, hence this change.
This was the sed script I used:
$ cat tg2vmw.sed
# Run as:
#
# git reset --hard HEAD && find include scons src -type f -not -name 'sed*' -print0 | xargs -0 sed -i -f tg2vmw.sed
#
# Rename copyrights
s/Tungsten Gra\(ph\|hp\)ics,\? [iI]nc\.\?\(, Cedar Park\)\?\(, Austin\)\?\(, \(Texas\|TX\)\)\?\.\?/VMware, Inc./g
/Copyright/s/Tungsten Graphics\(,\? [iI]nc\.\)\?\(, Cedar Park\)\?\(, Austin\)\?\(, \(Texas\|TX\)\)\?\.\?/VMware, Inc./
s/TUNGSTEN GRAPHICS/VMWARE/g
# Rename emails
s/alanh@tungstengraphics.com/alanh@vmware.com/
s/jens@tungstengraphics.com/jowen@vmware.com/g
s/jrfonseca-at-tungstengraphics-dot-com/jfonseca-at-vmware-dot-com/
s/jrfonseca\?@tungstengraphics.com/jfonseca@vmware.com/g
s/keithw\?@tungstengraphics.com/keithw@vmware.com/g
s/michel@tungstengraphics.com/daenzer@vmware.com/g
s/thomas-at-tungstengraphics-dot-com/thellstom-at-vmware-dot-com/
s/zack@tungstengraphics.com/zackr@vmware.com/
# Remove dead links
s@Tungsten Graphics (http://www.tungstengraphics.com)@Tungsten Graphics@g
# C string src/gallium/state_trackers/vega/api_misc.c
s/"Tungsten Graphics, Inc"/"VMware, Inc"/
Reviewed-by: Brian Paul <brianp@vmware.com>
2014-01-17 16:27:50 +00:00
|
|
|
Intel funded Tungsten Graphics to
|
2006-08-09 19:14:05 +00:00
|
|
|
develop this 3D driver.
|
2013-11-25 15:39:03 -08:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
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:
|
2013-11-25 15:39:03 -08:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
The above copyright notice and this permission notice (including the
|
|
|
|
|
next paragraph) shall be included in all copies or substantial
|
|
|
|
|
portions of the Software.
|
2013-11-25 15:39:03 -08:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
|
2013-11-25 15:39:03 -08:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
**********************************************************************/
|
|
|
|
|
/*
|
|
|
|
|
* Authors:
|
s/Tungsten Graphics/VMware/
Tungsten Graphics Inc. was acquired by VMware Inc. in 2008. Leaving the
old copyright name is creating unnecessary confusion, hence this change.
This was the sed script I used:
$ cat tg2vmw.sed
# Run as:
#
# git reset --hard HEAD && find include scons src -type f -not -name 'sed*' -print0 | xargs -0 sed -i -f tg2vmw.sed
#
# Rename copyrights
s/Tungsten Gra\(ph\|hp\)ics,\? [iI]nc\.\?\(, Cedar Park\)\?\(, Austin\)\?\(, \(Texas\|TX\)\)\?\.\?/VMware, Inc./g
/Copyright/s/Tungsten Graphics\(,\? [iI]nc\.\)\?\(, Cedar Park\)\?\(, Austin\)\?\(, \(Texas\|TX\)\)\?\.\?/VMware, Inc./
s/TUNGSTEN GRAPHICS/VMWARE/g
# Rename emails
s/alanh@tungstengraphics.com/alanh@vmware.com/
s/jens@tungstengraphics.com/jowen@vmware.com/g
s/jrfonseca-at-tungstengraphics-dot-com/jfonseca-at-vmware-dot-com/
s/jrfonseca\?@tungstengraphics.com/jfonseca@vmware.com/g
s/keithw\?@tungstengraphics.com/keithw@vmware.com/g
s/michel@tungstengraphics.com/daenzer@vmware.com/g
s/thomas-at-tungstengraphics-dot-com/thellstom-at-vmware-dot-com/
s/zack@tungstengraphics.com/zackr@vmware.com/
# Remove dead links
s@Tungsten Graphics (http://www.tungstengraphics.com)@Tungsten Graphics@g
# C string src/gallium/state_trackers/vega/api_misc.c
s/"Tungsten Graphics, Inc"/"VMware, Inc"/
Reviewed-by: Brian Paul <brianp@vmware.com>
2014-01-17 16:27:50 +00:00
|
|
|
* Keith Whitwell <keithw@vmware.com>
|
2006-08-09 19:14:05 +00:00
|
|
|
*/
|
2013-11-25 15:39:03 -08:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
#include "brw_context.h"
|
|
|
|
|
#include "brw_defines.h"
|
|
|
|
|
#include "brw_eu.h"
|
|
|
|
|
|
2014-02-24 23:39:14 -08:00
|
|
|
#include "util/ralloc.h"
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* Internal helper for constructing instructions
|
|
|
|
|
*/
|
|
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
static void guess_execution_size(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
2010-12-03 11:49:29 -08:00
|
|
|
struct brw_reg reg)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
|
|
|
|
|
if (reg.width == BRW_WIDTH_8 && p->compressed) {
|
|
|
|
|
brw_inst_set_exec_size(brw, insn, BRW_EXECUTE_16);
|
|
|
|
|
} else {
|
|
|
|
|
/* Register width definitions are compatible with BRW_EXECUTE_* enums. */
|
|
|
|
|
brw_inst_set_exec_size(brw, insn, reg.width);
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-03-16 14:09:17 -07:00
|
|
|
/**
|
|
|
|
|
* Prior to Sandybridge, the SEND instruction accepted non-MRF source
|
|
|
|
|
* registers, implicitly moving the operand to a message register.
|
|
|
|
|
*
|
|
|
|
|
* On Sandybridge, this is no longer the case. This function performs the
|
|
|
|
|
* explicit move; it should be called before emitting a SEND instruction.
|
|
|
|
|
*/
|
2011-08-22 10:35:24 -07:00
|
|
|
void
|
2011-03-16 14:09:17 -07:00
|
|
|
gen6_resolve_implied_move(struct brw_compile *p,
|
|
|
|
|
struct brw_reg *src,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_reg_nr)
|
2011-03-16 14:09:17 -07:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
|
|
|
|
if (brw->gen < 6)
|
2011-03-16 14:09:17 -07:00
|
|
|
return;
|
|
|
|
|
|
2011-11-14 19:49:54 -08:00
|
|
|
if (src->file == BRW_MESSAGE_REGISTER_FILE)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-04-03 00:57:30 -07:00
|
|
|
if (src->file != BRW_ARCHITECTURE_REGISTER_FILE || src->nr != BRW_ARF_NULL) {
|
|
|
|
|
brw_push_insn_state(p);
|
2014-05-31 16:57:02 -07:00
|
|
|
brw_set_default_mask_control(p, BRW_MASK_DISABLE);
|
|
|
|
|
brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
|
2011-04-03 00:57:30 -07:00
|
|
|
brw_MOV(p, retype(brw_message_reg(msg_reg_nr), BRW_REGISTER_TYPE_UD),
|
|
|
|
|
retype(*src, BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_pop_insn_state(p);
|
|
|
|
|
}
|
2011-03-16 14:09:17 -07:00
|
|
|
*src = brw_message_reg(msg_reg_nr);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-09 00:32:46 -07:00
|
|
|
static void
|
|
|
|
|
gen7_convert_mrf_to_grf(struct brw_compile *p, struct brw_reg *reg)
|
|
|
|
|
{
|
2013-07-10 13:16:13 -07:00
|
|
|
/* From the Ivybridge PRM, Volume 4 Part 3, page 218 ("send"):
|
2012-01-17 08:08:25 -08:00
|
|
|
* "The send with EOT should use register space R112-R127 for <src>. This is
|
|
|
|
|
* to enable loading of a new thread into the same slot while the message
|
|
|
|
|
* with EOT for current thread is pending dispatch."
|
|
|
|
|
*
|
|
|
|
|
* Since we're pretending to have 16 MRFs anyway, we may as well use the
|
|
|
|
|
* registers required for messages with EOT.
|
|
|
|
|
*/
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-30 07:26:30 -07:00
|
|
|
if (brw->gen >= 7 && reg->file == BRW_MESSAGE_REGISTER_FILE) {
|
2011-04-09 00:32:46 -07:00
|
|
|
reg->file = BRW_GENERAL_REGISTER_FILE;
|
2012-01-27 12:54:11 -08:00
|
|
|
reg->nr += GEN7_MRF_HACK_START;
|
2011-04-09 00:32:46 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
i965: Abstract BRW_REGISTER_TYPE_* into an enum with unique values.
On released hardware, values 4-6 are overloaded. For normal registers,
they mean UB/B/DF. But for immediates, they mean UV/VF/V.
Previously, we just created #defines for each name, reusing the same
value. This meant we could directly splat the brw_reg::type field into
the assembly encoding, which was fairly nice, and worked well.
Unfortunately, Broadwell makes this infeasible: the HF and DF types are
represented as different numeric values depending on whether the
source register is an immediate or not.
To preserve sanity, I decided to simply convert BRW_REGISTER_TYPE_* to
an abstract enum that has a unique value for each register type, and
write translation functions. One nice benefit is that we can add
assertions about register files and generations.
I've chosen not to convert brw_reg::type to the enum, since converting
it caused a lot of trouble due to C++ enum rules (even though it's
defined in an extern "C" block...).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-12-10 00:33:56 -08:00
|
|
|
/**
|
|
|
|
|
* Convert a brw_reg_type enumeration value into the hardware representation.
|
|
|
|
|
*
|
|
|
|
|
* The hardware encoding may depend on whether the value is an immediate.
|
|
|
|
|
*/
|
|
|
|
|
unsigned
|
|
|
|
|
brw_reg_type_to_hw_type(const struct brw_context *brw,
|
|
|
|
|
enum brw_reg_type type, unsigned file)
|
|
|
|
|
{
|
|
|
|
|
if (file == BRW_IMMEDIATE_VALUE) {
|
|
|
|
|
const static int imm_hw_types[] = {
|
|
|
|
|
[BRW_REGISTER_TYPE_UD] = BRW_HW_REG_TYPE_UD,
|
|
|
|
|
[BRW_REGISTER_TYPE_D] = BRW_HW_REG_TYPE_D,
|
|
|
|
|
[BRW_REGISTER_TYPE_UW] = BRW_HW_REG_TYPE_UW,
|
|
|
|
|
[BRW_REGISTER_TYPE_W] = BRW_HW_REG_TYPE_W,
|
|
|
|
|
[BRW_REGISTER_TYPE_F] = BRW_HW_REG_TYPE_F,
|
|
|
|
|
[BRW_REGISTER_TYPE_UB] = -1,
|
|
|
|
|
[BRW_REGISTER_TYPE_B] = -1,
|
|
|
|
|
[BRW_REGISTER_TYPE_UV] = BRW_HW_REG_IMM_TYPE_UV,
|
|
|
|
|
[BRW_REGISTER_TYPE_VF] = BRW_HW_REG_IMM_TYPE_VF,
|
|
|
|
|
[BRW_REGISTER_TYPE_V] = BRW_HW_REG_IMM_TYPE_V,
|
2013-12-10 01:53:26 -08:00
|
|
|
[BRW_REGISTER_TYPE_DF] = GEN8_HW_REG_IMM_TYPE_DF,
|
|
|
|
|
[BRW_REGISTER_TYPE_HF] = GEN8_HW_REG_IMM_TYPE_HF,
|
|
|
|
|
[BRW_REGISTER_TYPE_UQ] = GEN8_HW_REG_TYPE_UQ,
|
|
|
|
|
[BRW_REGISTER_TYPE_Q] = GEN8_HW_REG_TYPE_Q,
|
i965: Abstract BRW_REGISTER_TYPE_* into an enum with unique values.
On released hardware, values 4-6 are overloaded. For normal registers,
they mean UB/B/DF. But for immediates, they mean UV/VF/V.
Previously, we just created #defines for each name, reusing the same
value. This meant we could directly splat the brw_reg::type field into
the assembly encoding, which was fairly nice, and worked well.
Unfortunately, Broadwell makes this infeasible: the HF and DF types are
represented as different numeric values depending on whether the
source register is an immediate or not.
To preserve sanity, I decided to simply convert BRW_REGISTER_TYPE_* to
an abstract enum that has a unique value for each register type, and
write translation functions. One nice benefit is that we can add
assertions about register files and generations.
I've chosen not to convert brw_reg::type to the enum, since converting
it caused a lot of trouble due to C++ enum rules (even though it's
defined in an extern "C" block...).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-12-10 00:33:56 -08:00
|
|
|
};
|
|
|
|
|
assert(type < ARRAY_SIZE(imm_hw_types));
|
|
|
|
|
assert(imm_hw_types[type] != -1);
|
2013-12-10 01:53:26 -08:00
|
|
|
assert(brw->gen >= 8 || type < BRW_REGISTER_TYPE_DF);
|
i965: Abstract BRW_REGISTER_TYPE_* into an enum with unique values.
On released hardware, values 4-6 are overloaded. For normal registers,
they mean UB/B/DF. But for immediates, they mean UV/VF/V.
Previously, we just created #defines for each name, reusing the same
value. This meant we could directly splat the brw_reg::type field into
the assembly encoding, which was fairly nice, and worked well.
Unfortunately, Broadwell makes this infeasible: the HF and DF types are
represented as different numeric values depending on whether the
source register is an immediate or not.
To preserve sanity, I decided to simply convert BRW_REGISTER_TYPE_* to
an abstract enum that has a unique value for each register type, and
write translation functions. One nice benefit is that we can add
assertions about register files and generations.
I've chosen not to convert brw_reg::type to the enum, since converting
it caused a lot of trouble due to C++ enum rules (even though it's
defined in an extern "C" block...).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-12-10 00:33:56 -08:00
|
|
|
return imm_hw_types[type];
|
|
|
|
|
} else {
|
|
|
|
|
/* Non-immediate registers */
|
|
|
|
|
const static int hw_types[] = {
|
|
|
|
|
[BRW_REGISTER_TYPE_UD] = BRW_HW_REG_TYPE_UD,
|
|
|
|
|
[BRW_REGISTER_TYPE_D] = BRW_HW_REG_TYPE_D,
|
|
|
|
|
[BRW_REGISTER_TYPE_UW] = BRW_HW_REG_TYPE_UW,
|
|
|
|
|
[BRW_REGISTER_TYPE_W] = BRW_HW_REG_TYPE_W,
|
|
|
|
|
[BRW_REGISTER_TYPE_UB] = BRW_HW_REG_NON_IMM_TYPE_UB,
|
|
|
|
|
[BRW_REGISTER_TYPE_B] = BRW_HW_REG_NON_IMM_TYPE_B,
|
|
|
|
|
[BRW_REGISTER_TYPE_F] = BRW_HW_REG_TYPE_F,
|
|
|
|
|
[BRW_REGISTER_TYPE_UV] = -1,
|
|
|
|
|
[BRW_REGISTER_TYPE_VF] = -1,
|
|
|
|
|
[BRW_REGISTER_TYPE_V] = -1,
|
2013-12-10 01:49:18 -08:00
|
|
|
[BRW_REGISTER_TYPE_DF] = GEN7_HW_REG_NON_IMM_TYPE_DF,
|
2013-12-10 01:53:26 -08:00
|
|
|
[BRW_REGISTER_TYPE_HF] = GEN8_HW_REG_NON_IMM_TYPE_HF,
|
|
|
|
|
[BRW_REGISTER_TYPE_UQ] = GEN8_HW_REG_TYPE_UQ,
|
|
|
|
|
[BRW_REGISTER_TYPE_Q] = GEN8_HW_REG_TYPE_Q,
|
i965: Abstract BRW_REGISTER_TYPE_* into an enum with unique values.
On released hardware, values 4-6 are overloaded. For normal registers,
they mean UB/B/DF. But for immediates, they mean UV/VF/V.
Previously, we just created #defines for each name, reusing the same
value. This meant we could directly splat the brw_reg::type field into
the assembly encoding, which was fairly nice, and worked well.
Unfortunately, Broadwell makes this infeasible: the HF and DF types are
represented as different numeric values depending on whether the
source register is an immediate or not.
To preserve sanity, I decided to simply convert BRW_REGISTER_TYPE_* to
an abstract enum that has a unique value for each register type, and
write translation functions. One nice benefit is that we can add
assertions about register files and generations.
I've chosen not to convert brw_reg::type to the enum, since converting
it caused a lot of trouble due to C++ enum rules (even though it's
defined in an extern "C" block...).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-12-10 00:33:56 -08:00
|
|
|
};
|
|
|
|
|
assert(type < ARRAY_SIZE(hw_types));
|
|
|
|
|
assert(hw_types[type] != -1);
|
2013-12-10 01:49:18 -08:00
|
|
|
assert(brw->gen >= 7 || type < BRW_REGISTER_TYPE_DF);
|
2013-12-10 01:53:26 -08:00
|
|
|
assert(brw->gen >= 8 || type < BRW_REGISTER_TYPE_HF);
|
i965: Abstract BRW_REGISTER_TYPE_* into an enum with unique values.
On released hardware, values 4-6 are overloaded. For normal registers,
they mean UB/B/DF. But for immediates, they mean UV/VF/V.
Previously, we just created #defines for each name, reusing the same
value. This meant we could directly splat the brw_reg::type field into
the assembly encoding, which was fairly nice, and worked well.
Unfortunately, Broadwell makes this infeasible: the HF and DF types are
represented as different numeric values depending on whether the
source register is an immediate or not.
To preserve sanity, I decided to simply convert BRW_REGISTER_TYPE_* to
an abstract enum that has a unique value for each register type, and
write translation functions. One nice benefit is that we can add
assertions about register files and generations.
I've chosen not to convert brw_reg::type to the enum, since converting
it caused a lot of trouble due to C++ enum rules (even though it's
defined in an extern "C" block...).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-12-10 00:33:56 -08:00
|
|
|
return hw_types[type];
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-16 14:09:17 -07:00
|
|
|
|
2011-08-07 13:16:06 -07:00
|
|
|
void
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_set_dest(struct brw_compile *p, brw_inst *inst, struct brw_reg dest)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
|
2009-11-06 17:45:13 -08:00
|
|
|
if (dest.file != BRW_ARCHITECTURE_REGISTER_FILE &&
|
|
|
|
|
dest.file != BRW_MESSAGE_REGISTER_FILE)
|
2009-03-13 09:17:08 -06:00
|
|
|
assert(dest.nr < 128);
|
|
|
|
|
|
2011-04-09 00:32:46 -07:00
|
|
|
gen7_convert_mrf_to_grf(p, &dest);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_reg_file(brw, inst, dest.file);
|
|
|
|
|
brw_inst_set_dst_reg_type(brw, inst, brw_reg_type_to_hw_type(brw, dest.type,
|
|
|
|
|
dest.file));
|
|
|
|
|
brw_inst_set_dst_address_mode(brw, inst, dest.address_mode);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-11-25 15:39:03 -08:00
|
|
|
if (dest.address_mode == BRW_ADDRESS_DIRECT) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_da_reg_nr(brw, inst, dest.nr);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
|
|
|
|
brw_inst_set_dst_da1_subreg_nr(brw, inst, dest.subnr);
|
2008-11-01 14:38:19 -07:00
|
|
|
if (dest.hstride == BRW_HORIZONTAL_STRIDE_0)
|
|
|
|
|
dest.hstride = BRW_HORIZONTAL_STRIDE_1;
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_hstride(brw, inst, dest.hstride);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_da16_subreg_nr(brw, inst, dest.subnr / 16);
|
|
|
|
|
brw_inst_set_da16_writemask(brw, inst, dest.dw1.bits.writemask);
|
2013-09-17 11:54:05 -07:00
|
|
|
if (dest.file == BRW_GENERAL_REGISTER_FILE ||
|
|
|
|
|
dest.file == BRW_MESSAGE_REGISTER_FILE) {
|
|
|
|
|
assert(dest.dw1.bits.writemask != 0);
|
|
|
|
|
}
|
2013-01-09 11:40:29 -08:00
|
|
|
/* From the Ivybridge PRM, Vol 4, Part 3, Section 5.2.4.1:
|
|
|
|
|
* Although Dst.HorzStride is a don't care for Align16, HW needs
|
|
|
|
|
* this to be programmed as "01".
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_hstride(brw, inst, 1);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_ia_subreg_nr(brw, inst, dest.subnr);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/* These are different sizes in align1 vs align16:
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
|
|
|
|
brw_inst_set_dst_ia1_addr_imm(brw, inst,
|
|
|
|
|
dest.dw1.bits.indirect_offset);
|
2008-11-01 14:38:19 -07:00
|
|
|
if (dest.hstride == BRW_HORIZONTAL_STRIDE_0)
|
|
|
|
|
dest.hstride = BRW_HORIZONTAL_STRIDE_1;
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_hstride(brw, inst, dest.hstride);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_ia16_addr_imm(brw, inst,
|
|
|
|
|
dest.dw1.bits.indirect_offset);
|
2010-08-20 15:01:11 -07:00
|
|
|
/* even ignored in da16, still need to set as '01' */
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dst_hstride(brw, inst, 1);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* NEW: Set the execution size based on dest.width and
|
2014-06-04 17:08:57 -07:00
|
|
|
* inst->compression_control:
|
2006-08-09 19:14:05 +00:00
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
guess_execution_size(p, inst, dest);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2010-09-04 21:04:58 -07:00
|
|
|
extern int reg_type_size[];
|
|
|
|
|
|
2010-09-03 21:37:00 -07:00
|
|
|
static void
|
2014-06-13 14:29:25 -07:00
|
|
|
validate_reg(const struct brw_context *brw, brw_inst *inst, struct brw_reg reg)
|
2010-09-03 21:37:00 -07:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2010-09-04 21:04:58 -07:00
|
|
|
if (reg.file == BRW_IMMEDIATE_VALUE) {
|
|
|
|
|
/* 3.3.6: Region Parameters. Restriction: Immediate vectors
|
|
|
|
|
* mean the destination has to be 128-bit aligned and the
|
|
|
|
|
* destination horiz stride has to be a word.
|
|
|
|
|
*/
|
|
|
|
|
if (reg.type == BRW_REGISTER_TYPE_V) {
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(hstride_for_reg[brw_inst_dst_hstride(brw, inst)] *
|
|
|
|
|
reg_type_size[brw_inst_dst_reg_type(brw, inst)] == 2);
|
2010-09-04 21:04:58 -07:00
|
|
|
}
|
|
|
|
|
|
2010-09-03 21:37:00 -07:00
|
|
|
return;
|
2010-09-04 21:04:58 -07:00
|
|
|
}
|
2010-09-03 21:37:00 -07:00
|
|
|
|
|
|
|
|
if (reg.file == BRW_ARCHITECTURE_REGISTER_FILE &&
|
2013-04-18 21:51:49 -07:00
|
|
|
reg.file == BRW_ARF_NULL)
|
2010-09-03 21:37:00 -07:00
|
|
|
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];
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_exec_size(brw, inst) >= 0 &&
|
|
|
|
|
brw_inst_exec_size(brw, inst) < Elements(execsize_for_reg));
|
|
|
|
|
execsize = execsize_for_reg[brw_inst_exec_size(brw, inst)];
|
2010-09-03 21:37:00 -07:00
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-17 15:54:05 -07:00
|
|
|
static bool
|
|
|
|
|
is_compactable_immediate(unsigned imm)
|
|
|
|
|
{
|
|
|
|
|
/* We get the low 12 bits as-is. */
|
|
|
|
|
imm &= ~0xfff;
|
|
|
|
|
|
|
|
|
|
/* We get one bit replicated through the top 20 bits. */
|
|
|
|
|
return imm == 0 || imm == 0xfffff000;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-07 13:16:06 -07:00
|
|
|
void
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_set_src0(struct brw_compile *p, brw_inst *inst, struct brw_reg reg)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2012-11-09 11:38:14 -08:00
|
|
|
struct brw_context *brw = p->brw;
|
|
|
|
|
|
2014-07-06 20:11:05 +12:00
|
|
|
if (reg.file != BRW_ARCHITECTURE_REGISTER_FILE)
|
2009-03-13 09:17:08 -06:00
|
|
|
assert(reg.nr < 128);
|
|
|
|
|
|
2011-04-09 00:32:46 -07:00
|
|
|
gen7_convert_mrf_to_grf(p, ®);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw->gen >= 6 && (brw_inst_opcode(brw, inst) == BRW_OPCODE_SEND ||
|
|
|
|
|
brw_inst_opcode(brw, inst) == BRW_OPCODE_SENDC)) {
|
2012-11-09 11:38:14 -08:00
|
|
|
/* Any source modifiers or regions will be ignored, since this just
|
|
|
|
|
* identifies the MRF/GRF to start reading the message contents from.
|
|
|
|
|
* Check for some likely failures.
|
|
|
|
|
*/
|
|
|
|
|
assert(!reg.negate);
|
|
|
|
|
assert(!reg.abs);
|
|
|
|
|
assert(reg.address_mode == BRW_ADDRESS_DIRECT);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
validate_reg(brw, inst, reg);
|
2010-09-03 21:37:00 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_reg_file(brw, inst, reg.file);
|
|
|
|
|
brw_inst_set_src0_reg_type(brw, inst,
|
|
|
|
|
brw_reg_type_to_hw_type(brw, reg.type, reg.file));
|
|
|
|
|
brw_inst_set_src0_abs(brw, inst, reg.abs);
|
|
|
|
|
brw_inst_set_src0_negate(brw, inst, reg.negate);
|
|
|
|
|
brw_inst_set_src0_address_mode(brw, inst, reg.address_mode);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
if (reg.file == BRW_IMMEDIATE_VALUE) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_imm_ud(brw, inst, reg.dw1.ud);
|
2013-11-25 15:39:03 -08:00
|
|
|
|
2014-05-02 14:14:11 -07:00
|
|
|
/* The Bspec's section titled "Non-present Operands" claims that if src0
|
|
|
|
|
* is an immediate that src1's type must be the same as that of src0.
|
|
|
|
|
*
|
|
|
|
|
* The SNB+ DataTypeIndex instruction compaction tables contain mappings
|
|
|
|
|
* that do not follow this rule. E.g., from the IVB/HSW table:
|
|
|
|
|
*
|
|
|
|
|
* DataTypeIndex 18-Bit Mapping Mapped Meaning
|
|
|
|
|
* 3 001000001011111101 r:f | i:vf | a:ud | <1> | dir |
|
|
|
|
|
*
|
|
|
|
|
* And from the SNB table:
|
|
|
|
|
*
|
|
|
|
|
* DataTypeIndex 18-Bit Mapping Mapped Meaning
|
|
|
|
|
* 8 001000000111101100 a:w | i:w | a:ud | <1> | dir |
|
|
|
|
|
*
|
|
|
|
|
* Neither of these cause warnings from the simulator when used,
|
|
|
|
|
* compacted or otherwise. In fact, all compaction mappings that have an
|
|
|
|
|
* immediate in src0 use a:ud for src1.
|
|
|
|
|
*
|
|
|
|
|
* The GM45 instruction compaction tables do not contain mapped meanings
|
|
|
|
|
* so it's not clear whether it has the restriction. We'll assume it was
|
|
|
|
|
* lifted on SNB. (FINISHME: decode the GM45 tables and check.)
|
2006-08-09 19:14:05 +00:00
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_reg_file(brw, inst, BRW_ARCHITECTURE_REGISTER_FILE);
|
2014-05-02 14:14:11 -07:00
|
|
|
if (brw->gen < 6) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_reg_type(brw, inst,
|
|
|
|
|
brw_inst_src0_reg_type(brw, inst));
|
2014-05-02 14:14:11 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_reg_type(brw, inst, BRW_HW_REG_TYPE_UD);
|
2014-05-02 14:14:11 -07:00
|
|
|
}
|
2014-05-02 14:47:55 -07:00
|
|
|
|
|
|
|
|
/* Compacted instructions only have 12-bits (plus 1 for the other 20)
|
|
|
|
|
* for immediate values. Presumably the hardware engineers realized
|
|
|
|
|
* that the only useful floating-point value that could be represented
|
|
|
|
|
* in this format is 0.0, which can also be represented as a VF-typed
|
|
|
|
|
* immediate, so they gave us the previously mentioned mapping on IVB+.
|
|
|
|
|
*
|
|
|
|
|
* Strangely, we do have a mapping for imm:f in src1, so we don't need
|
|
|
|
|
* to do this there.
|
|
|
|
|
*
|
|
|
|
|
* If we see a 0.0:F, change the type to VF so that it can be compacted.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_imm_ud(brw, inst) == 0x0 &&
|
|
|
|
|
brw_inst_src0_reg_type(brw, inst) == BRW_HW_REG_TYPE_F) {
|
|
|
|
|
brw_inst_set_src0_reg_type(brw, inst, BRW_HW_REG_IMM_TYPE_VF);
|
2014-05-02 14:47:55 -07:00
|
|
|
}
|
2014-05-17 15:54:05 -07:00
|
|
|
|
|
|
|
|
/* There are no mappings for dst:d | i:d, so if the immediate is suitable
|
|
|
|
|
* set the types to :UD so the instruction can be compacted.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
if (is_compactable_immediate(brw_inst_imm_ud(brw, inst)) &&
|
|
|
|
|
brw_inst_cond_modifier(brw, inst) == BRW_CONDITIONAL_NONE &&
|
|
|
|
|
brw_inst_src0_reg_type(brw, inst) == BRW_HW_REG_TYPE_D &&
|
|
|
|
|
brw_inst_dst_reg_type(brw, inst) == BRW_HW_REG_TYPE_D) {
|
|
|
|
|
brw_inst_set_src0_reg_type(brw, inst, BRW_HW_REG_TYPE_UD);
|
|
|
|
|
brw_inst_set_dst_reg_type(brw, inst, BRW_HW_REG_TYPE_UD);
|
2014-05-17 15:54:05 -07:00
|
|
|
}
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2006-08-09 19:14:05 +00:00
|
|
|
if (reg.address_mode == BRW_ADDRESS_DIRECT) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_da_reg_nr(brw, inst, reg.nr);
|
|
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
|
|
|
|
brw_inst_set_src0_da1_subreg_nr(brw, inst, reg.subnr);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_da16_subreg_nr(brw, inst, reg.subnr / 16);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_ia_subreg_nr(brw, inst, reg.subnr);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
|
|
|
|
brw_inst_set_src0_ia1_addr_imm(brw, inst, reg.dw1.bits.indirect_offset);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_ia_subreg_nr(brw, inst, reg.dw1.bits.indirect_offset);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
2013-11-25 15:39:03 -08:00
|
|
|
if (reg.width == BRW_WIDTH_1 &&
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_exec_size(brw, inst) == BRW_EXECUTE_1) {
|
|
|
|
|
brw_inst_set_src0_hstride(brw, inst, BRW_HORIZONTAL_STRIDE_0);
|
|
|
|
|
brw_inst_set_src0_width(brw, inst, BRW_WIDTH_1);
|
|
|
|
|
brw_inst_set_src0_vstride(brw, inst, BRW_VERTICAL_STRIDE_0);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_hstride(brw, inst, reg.hstride);
|
|
|
|
|
brw_inst_set_src0_width(brw, inst, reg.width);
|
|
|
|
|
brw_inst_set_src0_vstride(brw, inst, reg.vstride);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_da16_swiz_x(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_X));
|
|
|
|
|
brw_inst_set_src0_da16_swiz_y(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Y));
|
|
|
|
|
brw_inst_set_src0_da16_swiz_z(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Z));
|
|
|
|
|
brw_inst_set_src0_da16_swiz_w(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_W));
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/* This is an oddity of the fact we're using the same
|
|
|
|
|
* descriptions for registers in align_16 as align_1:
|
|
|
|
|
*/
|
|
|
|
|
if (reg.vstride == BRW_VERTICAL_STRIDE_8)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_vstride(brw, inst, BRW_VERTICAL_STRIDE_4);
|
2006-08-09 19:14:05 +00:00
|
|
|
else
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src0_vstride(brw, inst, reg.vstride);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-05-02 14:49:24 -07:00
|
|
|
void
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_set_src1(struct brw_compile *p, brw_inst *inst, struct brw_reg reg)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2006-09-01 14:18:06 +00:00
|
|
|
assert(reg.file != BRW_MESSAGE_REGISTER_FILE);
|
|
|
|
|
|
2014-07-06 20:11:05 +12:00
|
|
|
if (reg.file != BRW_ARCHITECTURE_REGISTER_FILE)
|
2012-11-27 14:10:52 -08:00
|
|
|
assert(reg.nr < 128);
|
2009-03-13 09:17:08 -06:00
|
|
|
|
2011-04-09 00:32:46 -07:00
|
|
|
gen7_convert_mrf_to_grf(p, ®);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
validate_reg(brw, inst, reg);
|
2010-09-03 21:37:00 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_reg_file(brw, inst, reg.file);
|
|
|
|
|
brw_inst_set_src1_reg_type(brw, inst,
|
|
|
|
|
brw_reg_type_to_hw_type(brw, reg.type, reg.file));
|
|
|
|
|
brw_inst_set_src1_abs(brw, inst, reg.abs);
|
|
|
|
|
brw_inst_set_src1_negate(brw, inst, reg.negate);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/* Only src1 can be immediate in two-argument instructions.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_src0_reg_file(brw, inst) != BRW_IMMEDIATE_VALUE);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
if (reg.file == BRW_IMMEDIATE_VALUE) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_imm_ud(brw, inst, reg.dw1.ud);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2006-08-09 19:14:05 +00:00
|
|
|
/* This is a hardware restriction, which may or may not be lifted
|
|
|
|
|
* in the future:
|
|
|
|
|
*/
|
|
|
|
|
assert (reg.address_mode == BRW_ADDRESS_DIRECT);
|
2009-12-28 18:46:15 -08:00
|
|
|
/* assert (reg.file == BRW_GENERAL_REGISTER_FILE); */
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_da_reg_nr(brw, inst, reg.nr);
|
|
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
|
|
|
|
brw_inst_set_src1_da1_subreg_nr(brw, inst, reg.subnr);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_da16_subreg_nr(brw, inst, reg.subnr / 16);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_access_mode(brw, inst) == BRW_ALIGN_1) {
|
2013-11-25 15:39:03 -08:00
|
|
|
if (reg.width == BRW_WIDTH_1 &&
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_exec_size(brw, inst) == BRW_EXECUTE_1) {
|
|
|
|
|
brw_inst_set_src1_hstride(brw, inst, BRW_HORIZONTAL_STRIDE_0);
|
|
|
|
|
brw_inst_set_src1_width(brw, inst, BRW_WIDTH_1);
|
|
|
|
|
brw_inst_set_src1_vstride(brw, inst, BRW_VERTICAL_STRIDE_0);
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_hstride(brw, inst, reg.hstride);
|
|
|
|
|
brw_inst_set_src1_width(brw, inst, reg.width);
|
|
|
|
|
brw_inst_set_src1_vstride(brw, inst, reg.vstride);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
2014-06-04 16:55:59 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_da16_swiz_x(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_X));
|
|
|
|
|
brw_inst_set_src1_da16_swiz_y(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Y));
|
|
|
|
|
brw_inst_set_src1_da16_swiz_z(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Z));
|
|
|
|
|
brw_inst_set_src1_da16_swiz_w(brw, inst,
|
|
|
|
|
BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_W));
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/* This is an oddity of the fact we're using the same
|
|
|
|
|
* descriptions for registers in align_16 as align_1:
|
|
|
|
|
*/
|
|
|
|
|
if (reg.vstride == BRW_VERTICAL_STRIDE_8)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_vstride(brw, inst, BRW_VERTICAL_STRIDE_4);
|
2006-08-09 19:14:05 +00:00
|
|
|
else
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_src1_vstride(brw, inst, reg.vstride);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
brw_set_message_descriptor(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *inst,
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
enum brw_message_target sfid,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length,
|
|
|
|
|
bool header_present,
|
|
|
|
|
bool end_of_thread)
|
|
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2006-08-09 19:14:05 +00:00
|
|
|
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
brw_set_src1(p, inst, brw_imm_d(0));
|
2014-08-03 12:02:25 +12:00
|
|
|
|
|
|
|
|
/* For indirect sends, `inst` will not be the SEND/SENDC instruction
|
|
|
|
|
* itself; instead, it will be a MOV/OR into the address register.
|
|
|
|
|
*
|
|
|
|
|
* In this case, we avoid setting the extended message descriptor bits,
|
|
|
|
|
* since they go on the later SEND/SENDC instead and if set here would
|
|
|
|
|
* instead clobber the conditionalmod bits.
|
|
|
|
|
*/
|
|
|
|
|
unsigned opcode = brw_inst_opcode(brw, inst);
|
|
|
|
|
if (opcode == BRW_OPCODE_SEND || opcode == BRW_OPCODE_SENDC) {
|
|
|
|
|
brw_inst_set_sfid(brw, inst, sfid);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_mlen(brw, inst, msg_length);
|
|
|
|
|
brw_inst_set_rlen(brw, inst, response_length);
|
|
|
|
|
brw_inst_set_eot(brw, inst, end_of_thread);
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 5) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_header_present(brw, inst, header_present);
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
static void brw_set_math_message( struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *inst,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned function,
|
|
|
|
|
unsigned integer_type,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool low_precision,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned dataType )
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2011-05-10 16:51:12 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2011-09-28 17:37:52 -07:00
|
|
|
unsigned msg_length;
|
|
|
|
|
unsigned response_length;
|
|
|
|
|
|
|
|
|
|
/* Infer message length from the function */
|
|
|
|
|
switch (function) {
|
|
|
|
|
case BRW_MATH_FUNCTION_POW:
|
|
|
|
|
case BRW_MATH_FUNCTION_INT_DIV_QUOTIENT:
|
|
|
|
|
case BRW_MATH_FUNCTION_INT_DIV_REMAINDER:
|
|
|
|
|
case BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER:
|
|
|
|
|
msg_length = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
msg_length = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Infer response length from the function */
|
|
|
|
|
switch (function) {
|
|
|
|
|
case BRW_MATH_FUNCTION_SINCOS:
|
|
|
|
|
case BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER:
|
|
|
|
|
response_length = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
response_length = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2012-08-06 14:59:39 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_set_message_descriptor(p, inst, BRW_SFID_MATH,
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
msg_length, response_length, false, false);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_math_msg_function(brw, inst, function);
|
|
|
|
|
brw_inst_set_math_msg_signed_int(brw, inst, integer_type);
|
|
|
|
|
brw_inst_set_math_msg_precision(brw, inst, low_precision);
|
|
|
|
|
brw_inst_set_math_msg_saturate(brw, inst, brw_inst_saturate(brw, inst));
|
|
|
|
|
brw_inst_set_math_msg_data_type(brw, inst, dataType);
|
|
|
|
|
brw_inst_set_saturate(brw, inst, 0);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-13 10:48:43 +08:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
static void brw_set_ff_sync_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool allocate,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned response_length,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool end_of_thread)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
brw_set_message_descriptor(p, insn, BRW_SFID_URB,
|
|
|
|
|
1, response_length, true, end_of_thread);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_urb_opcode(brw, insn, 1); /* FF_SYNC */
|
|
|
|
|
brw_inst_set_urb_allocate(brw, insn, allocate);
|
|
|
|
|
/* The following fields are not used by FF_SYNC: */
|
|
|
|
|
brw_inst_set_urb_global_offset(brw, insn, 0);
|
|
|
|
|
brw_inst_set_urb_swizzle_control(brw, insn, 0);
|
|
|
|
|
brw_inst_set_urb_used(brw, insn, 0);
|
|
|
|
|
brw_inst_set_urb_complete(brw, insn, 0);
|
2009-07-13 10:48:43 +08:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
static void brw_set_urb_message( struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
i965: Allow C++ type safety in the use of enum brw_urb_write_flags.
(From a suggestion by Francisco Jerez)
If an enum represents a bitfield of flags, e.g.:
enum E {
A = 1,
B = 2,
C = 4,
D = 8,
};
then C++ normally prohibits statements like this:
enum E x = A | B;
because A and B are implicitly converted to ints before OR-ing them,
and an int can't be stored in an enum without a type cast. C, on the
other hand, allows an int to be implicitly converted to an enum
without casting.
In the past we've dealt with this situation by storing flag bitfields
as ints. This avoids ugly casting at the expense of some type safety
that C++ would normally have offered (e.g. we get no warning if we
accidentally use the wrong enum type).
However, we can get the best of both worlds if we override the |
operator. The ugly casting is confined to the operator overload, and
we still get the benefit of C++ making sure we don't use the wrong
enum type.
v2: Remove unnecessary comment and unnecessary use of "enum" keyword.
Use static_cast.
Reviewed-by: Chad Versace <chad.versace@linux.intel.com>
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
2013-08-23 13:19:19 -07:00
|
|
|
enum brw_urb_write_flags flags,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length,
|
|
|
|
|
unsigned offset,
|
|
|
|
|
unsigned swizzle_control )
|
2009-07-13 10:48:43 +08:00
|
|
|
{
|
2011-10-07 11:59:06 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw->gen < 7 || swizzle_control != BRW_URB_SWIZZLE_TRANSPOSE);
|
|
|
|
|
assert(brw->gen < 7 || !(flags & BRW_URB_WRITE_ALLOCATE));
|
|
|
|
|
assert(brw->gen >= 7 || !(flags & BRW_URB_WRITE_PER_SLOT_OFFSET));
|
|
|
|
|
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
brw_set_message_descriptor(p, insn, BRW_SFID_URB,
|
2013-08-10 21:13:33 -07:00
|
|
|
msg_length, response_length, true,
|
|
|
|
|
flags & BRW_URB_WRITE_EOT);
|
2014-06-04 17:08:57 -07:00
|
|
|
|
|
|
|
|
if (flags & BRW_URB_WRITE_OWORD) {
|
|
|
|
|
assert(msg_length == 2); /* header + one OWORD of data */
|
|
|
|
|
brw_inst_set_urb_opcode(brw, insn, BRW_URB_OPCODE_WRITE_OWORD);
|
|
|
|
|
} else {
|
|
|
|
|
brw_inst_set_urb_opcode(brw, insn, BRW_URB_OPCODE_WRITE_HWORD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
brw_inst_set_urb_global_offset(brw, insn, offset);
|
|
|
|
|
brw_inst_set_urb_swizzle_control(brw, insn, swizzle_control);
|
|
|
|
|
|
|
|
|
|
if (brw->gen < 8) {
|
|
|
|
|
brw_inst_set_urb_complete(brw, insn, !!(flags & BRW_URB_WRITE_COMPLETE));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (brw->gen < 7) {
|
|
|
|
|
brw_inst_set_urb_allocate(brw, insn, !!(flags & BRW_URB_WRITE_ALLOCATE));
|
|
|
|
|
brw_inst_set_urb_used(brw, insn, !(flags & BRW_URB_WRITE_UNUSED));
|
2011-10-07 11:59:06 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_urb_per_slot_offset(brw, insn,
|
|
|
|
|
!!(flags & BRW_URB_WRITE_PER_SLOT_OFFSET));
|
2011-10-07 11:59:06 -07:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2011-08-07 13:16:06 -07:00
|
|
|
void
|
|
|
|
|
brw_set_dp_write_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned binding_table_index,
|
|
|
|
|
unsigned msg_control,
|
|
|
|
|
unsigned msg_type,
|
|
|
|
|
unsigned msg_length,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool header_present,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned last_render_target,
|
|
|
|
|
unsigned response_length,
|
|
|
|
|
unsigned end_of_thread,
|
|
|
|
|
unsigned send_commit_msg)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2011-05-10 16:51:12 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
unsigned sfid;
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 7) {
|
2011-10-07 21:09:53 -07:00
|
|
|
/* Use the Render Cache for RT writes; otherwise use the Data Cache */
|
|
|
|
|
if (msg_type == GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE)
|
2011-10-07 20:55:35 -07:00
|
|
|
sfid = GEN6_SFID_DATAPORT_RENDER_CACHE;
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
else
|
|
|
|
|
sfid = GEN7_SFID_DATAPORT_DATA_CACHE;
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
/* Use the render cache for all write messages. */
|
|
|
|
|
sfid = GEN6_SFID_DATAPORT_RENDER_CACHE;
|
|
|
|
|
} else {
|
|
|
|
|
sfid = BRW_SFID_DATAPORT_WRITE;
|
|
|
|
|
}
|
2011-10-07 21:09:53 -07:00
|
|
|
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
brw_set_message_descriptor(p, insn, sfid, msg_length, response_length,
|
|
|
|
|
header_present, end_of_thread);
|
2011-10-07 21:09:53 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_binding_table_index(brw, insn, binding_table_index);
|
|
|
|
|
brw_inst_set_dp_write_msg_type(brw, insn, msg_type);
|
|
|
|
|
brw_inst_set_dp_write_msg_control(brw, insn, msg_control);
|
|
|
|
|
brw_inst_set_rt_last(brw, insn, last_render_target);
|
|
|
|
|
if (brw->gen < 7) {
|
|
|
|
|
brw_inst_set_dp_write_commit(brw, insn, send_commit_msg);
|
2009-07-13 10:48:43 +08:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2011-08-07 13:16:06 -07:00
|
|
|
void
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_dp_read_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned binding_table_index,
|
|
|
|
|
unsigned msg_control,
|
|
|
|
|
unsigned msg_type,
|
|
|
|
|
unsigned target_cache,
|
|
|
|
|
unsigned msg_length,
|
2012-11-09 11:17:48 -08:00
|
|
|
bool header_present,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned response_length)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2011-05-10 16:51:12 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
unsigned sfid;
|
|
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 7) {
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
sfid = GEN7_SFID_DATAPORT_DATA_CACHE;
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
if (target_cache == BRW_DATAPORT_READ_TARGET_RENDER_CACHE)
|
|
|
|
|
sfid = GEN6_SFID_DATAPORT_RENDER_CACHE;
|
|
|
|
|
else
|
|
|
|
|
sfid = GEN6_SFID_DATAPORT_SAMPLER_CACHE;
|
|
|
|
|
} else {
|
|
|
|
|
sfid = BRW_SFID_DATAPORT_READ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
brw_set_message_descriptor(p, insn, sfid, msg_length, response_length,
|
2012-11-09 11:17:48 -08:00
|
|
|
header_present, false);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_binding_table_index(brw, insn, binding_table_index);
|
|
|
|
|
brw_inst_set_dp_read_msg_type(brw, insn, msg_type);
|
|
|
|
|
brw_inst_set_dp_read_msg_control(brw, insn, msg_control);
|
|
|
|
|
if (brw->gen < 6)
|
|
|
|
|
brw_inst_set_dp_read_target_cache(brw, insn, target_cache);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2012-01-26 05:33:19 -08:00
|
|
|
void
|
|
|
|
|
brw_set_sampler_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *inst,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned binding_table_index,
|
|
|
|
|
unsigned sampler,
|
|
|
|
|
unsigned msg_type,
|
|
|
|
|
unsigned response_length,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned header_present,
|
|
|
|
|
unsigned simd_mode,
|
|
|
|
|
unsigned return_format)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2011-05-10 16:51:12 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_set_message_descriptor(p, inst, BRW_SFID_SAMPLER, msg_length,
|
i965: Factor out code for setting Message Descriptors.
Every brw_set_???_message function had duplicated code, per-generation,
to set the Message Descriptor and Extended Message Descriptor bits
(SFID, message length, response length, header present, end of thread).
However, these fields are actually specified as part of the SEND
instruction itself; individual types of messages don't even specify
them (except for header present, but that's in the same bit location).
Since these are exactly the same regardless of the message type, just
create a function to set them, using the generic message structs. This
not only shortens the code, but hides a lot of the per-generation
complexity (like the SFID being in destreg__conditionalmod) in one spot.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-10-07 21:09:08 -07:00
|
|
|
response_length, header_present, false);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_binding_table_index(brw, inst, binding_table_index);
|
|
|
|
|
brw_inst_set_sampler(brw, inst, sampler);
|
|
|
|
|
brw_inst_set_sampler_msg_type(brw, inst, msg_type);
|
|
|
|
|
if (brw->gen >= 5) {
|
|
|
|
|
brw_inst_set_sampler_simd_mode(brw, inst, simd_mode);
|
|
|
|
|
} else if (brw->gen == 4 && !brw->is_g4x) {
|
|
|
|
|
brw_inst_set_sampler_return_format(brw, inst, return_format);
|
2008-01-29 11:13:53 +08:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2014-08-03 11:44:25 +12:00
|
|
|
void brw_set_indirect_send_descriptor(struct brw_compile *p,
|
|
|
|
|
brw_inst *insn,
|
|
|
|
|
unsigned sfid,
|
|
|
|
|
struct brw_reg descriptor)
|
|
|
|
|
{
|
|
|
|
|
/* Only a0.0 may be used as SEND's descriptor operand. */
|
|
|
|
|
assert(descriptor.file == BRW_ARCHITECTURE_REGISTER_FILE);
|
|
|
|
|
assert(descriptor.type == BRW_REGISTER_TYPE_UD);
|
|
|
|
|
assert(descriptor.nr == BRW_ARF_ADDRESS);
|
|
|
|
|
assert(descriptor.subnr == 0);
|
|
|
|
|
|
|
|
|
|
brw_set_message_descriptor(p, insn, sfid, 0, 0, false, false);
|
|
|
|
|
brw_set_src1(p, insn, descriptor);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
static void
|
|
|
|
|
gen7_set_dp_scratch_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *inst,
|
2014-06-04 17:08:57 -07:00
|
|
|
bool write,
|
|
|
|
|
bool dword,
|
|
|
|
|
bool invalidate_after_read,
|
|
|
|
|
unsigned num_regs,
|
|
|
|
|
unsigned addr_offset,
|
|
|
|
|
unsigned mlen,
|
|
|
|
|
unsigned rlen,
|
|
|
|
|
bool header_present)
|
|
|
|
|
{
|
|
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
assert(num_regs == 1 || num_regs == 2 || num_regs == 4 ||
|
|
|
|
|
(brw->gen >= 8 && num_regs == 8));
|
|
|
|
|
brw_set_message_descriptor(p, inst, GEN7_SFID_DATAPORT_DATA_CACHE,
|
|
|
|
|
mlen, rlen, header_present, false);
|
|
|
|
|
brw_inst_set_dp_category(brw, inst, 1); /* Scratch Block Read/Write msgs */
|
|
|
|
|
brw_inst_set_scratch_read_write(brw, inst, write);
|
|
|
|
|
brw_inst_set_scratch_type(brw, inst, dword);
|
|
|
|
|
brw_inst_set_scratch_invalidate_after_read(brw, inst, invalidate_after_read);
|
|
|
|
|
brw_inst_set_scratch_block_size(brw, inst, ffs(num_regs) - 1);
|
|
|
|
|
brw_inst_set_scratch_addr_offset(brw, inst, addr_offset);
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-08-07 13:16:06 -07:00
|
|
|
#define next_insn brw_next_insn
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
2013-11-25 15:51:24 -08:00
|
|
|
brw_next_insn(struct brw_compile *p, unsigned opcode)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-12-21 15:38:44 +08:00
|
|
|
if (p->nr_insn + 1 > p->store_size) {
|
|
|
|
|
p->store_size <<= 1;
|
2014-06-13 14:29:25 -07:00
|
|
|
p->store = reralloc(p->mem_ctx, p->store, brw_inst, p->store_size);
|
2011-12-21 15:38:44 +08:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2012-02-03 11:50:42 +01:00
|
|
|
p->next_insn_offset += 16;
|
2006-08-09 19:14:05 +00:00
|
|
|
insn = &p->store[p->nr_insn++];
|
|
|
|
|
memcpy(insn, p->current, sizeof(*insn));
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_opcode(brw, insn, opcode);
|
2006-08-09 19:14:05 +00:00
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
static brw_inst *
|
|
|
|
|
brw_alu1(struct brw_compile *p, unsigned opcode,
|
|
|
|
|
struct brw_reg dest, struct brw_reg src)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, opcode);
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src);
|
2006-08-09 19:14:05 +00:00
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
static brw_inst *
|
|
|
|
|
brw_alu2(struct brw_compile *p, unsigned opcode,
|
|
|
|
|
struct brw_reg dest, struct brw_reg src0, struct brw_reg src1)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, opcode);
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, src1);
|
2006-08-09 19:14:05 +00:00
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-22 10:05:42 -07:00
|
|
|
static int
|
|
|
|
|
get_3src_subreg_nr(struct brw_reg reg)
|
|
|
|
|
{
|
|
|
|
|
if (reg.vstride == BRW_VERTICAL_STRIDE_0) {
|
|
|
|
|
assert(brw_is_single_value_swizzle(reg.dw1.bits.swizzle));
|
|
|
|
|
return reg.subnr / 4 + BRW_GET_SWZ(reg.dw1.bits.swizzle, 0);
|
|
|
|
|
} else {
|
|
|
|
|
return reg.subnr / 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
static brw_inst *
|
|
|
|
|
brw_alu3(struct brw_compile *p, unsigned opcode, struct brw_reg dest,
|
|
|
|
|
struct brw_reg src0, struct brw_reg src1, struct brw_reg src2)
|
2010-03-22 10:05:42 -07:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *inst = next_insn(p, opcode);
|
2010-03-22 10:05:42 -07:00
|
|
|
|
|
|
|
|
gen7_convert_mrf_to_grf(p, &dest);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_access_mode(brw, inst) == BRW_ALIGN_16);
|
2010-03-22 10:05:42 -07:00
|
|
|
|
|
|
|
|
assert(dest.file == BRW_GENERAL_REGISTER_FILE ||
|
|
|
|
|
dest.file == BRW_MESSAGE_REGISTER_FILE);
|
|
|
|
|
assert(dest.nr < 128);
|
|
|
|
|
assert(dest.address_mode == BRW_ADDRESS_DIRECT);
|
2013-04-17 12:23:54 -07:00
|
|
|
assert(dest.type == BRW_REGISTER_TYPE_F ||
|
|
|
|
|
dest.type == BRW_REGISTER_TYPE_D ||
|
|
|
|
|
dest.type == BRW_REGISTER_TYPE_UD);
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw->gen == 6) {
|
|
|
|
|
brw_inst_set_3src_dst_reg_file(brw, inst,
|
|
|
|
|
dest.file == BRW_MESSAGE_REGISTER_FILE);
|
|
|
|
|
}
|
|
|
|
|
brw_inst_set_3src_dst_reg_nr(brw, inst, dest.nr);
|
|
|
|
|
brw_inst_set_3src_dst_subreg_nr(brw, inst, dest.subnr / 16);
|
|
|
|
|
brw_inst_set_3src_dst_writemask(brw, inst, dest.dw1.bits.writemask);
|
|
|
|
|
guess_execution_size(p, inst, dest);
|
2010-03-22 10:05:42 -07:00
|
|
|
|
|
|
|
|
assert(src0.file == BRW_GENERAL_REGISTER_FILE);
|
|
|
|
|
assert(src0.address_mode == BRW_ADDRESS_DIRECT);
|
|
|
|
|
assert(src0.nr < 128);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_3src_src0_swizzle(brw, inst, src0.dw1.bits.swizzle);
|
|
|
|
|
brw_inst_set_3src_src0_subreg_nr(brw, inst, get_3src_subreg_nr(src0));
|
|
|
|
|
brw_inst_set_3src_src0_reg_nr(brw, inst, src0.nr);
|
|
|
|
|
brw_inst_set_3src_src0_abs(brw, inst, src0.abs);
|
|
|
|
|
brw_inst_set_3src_src0_negate(brw, inst, src0.negate);
|
|
|
|
|
brw_inst_set_3src_src0_rep_ctrl(brw, inst,
|
|
|
|
|
src0.vstride == BRW_VERTICAL_STRIDE_0);
|
2010-03-22 10:05:42 -07:00
|
|
|
|
|
|
|
|
assert(src1.file == BRW_GENERAL_REGISTER_FILE);
|
|
|
|
|
assert(src1.address_mode == BRW_ADDRESS_DIRECT);
|
|
|
|
|
assert(src1.nr < 128);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_3src_src1_swizzle(brw, inst, src1.dw1.bits.swizzle);
|
|
|
|
|
brw_inst_set_3src_src1_subreg_nr(brw, inst, get_3src_subreg_nr(src1));
|
|
|
|
|
brw_inst_set_3src_src1_reg_nr(brw, inst, src1.nr);
|
|
|
|
|
brw_inst_set_3src_src1_abs(brw, inst, src1.abs);
|
|
|
|
|
brw_inst_set_3src_src1_negate(brw, inst, src1.negate);
|
|
|
|
|
brw_inst_set_3src_src1_rep_ctrl(brw, inst,
|
|
|
|
|
src1.vstride == BRW_VERTICAL_STRIDE_0);
|
2010-03-22 10:05:42 -07:00
|
|
|
|
|
|
|
|
assert(src2.file == BRW_GENERAL_REGISTER_FILE);
|
|
|
|
|
assert(src2.address_mode == BRW_ADDRESS_DIRECT);
|
|
|
|
|
assert(src2.nr < 128);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_3src_src2_swizzle(brw, inst, src2.dw1.bits.swizzle);
|
|
|
|
|
brw_inst_set_3src_src2_subreg_nr(brw, inst, get_3src_subreg_nr(src2));
|
|
|
|
|
brw_inst_set_3src_src2_reg_nr(brw, inst, src2.nr);
|
|
|
|
|
brw_inst_set_3src_src2_abs(brw, inst, src2.abs);
|
|
|
|
|
brw_inst_set_3src_src2_negate(brw, inst, src2.negate);
|
|
|
|
|
brw_inst_set_3src_src2_rep_ctrl(brw, inst,
|
|
|
|
|
src2.vstride == BRW_VERTICAL_STRIDE_0);
|
2010-03-22 10:05:42 -07:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 7) {
|
2013-06-13 14:55:19 -07:00
|
|
|
/* Set both the source and destination types based on dest.type,
|
|
|
|
|
* ignoring the source register types. The MAD and LRP emitters ensure
|
|
|
|
|
* that all four types are float. The BFE and BFI2 emitters, however,
|
|
|
|
|
* may send us mixed D and UD types and want us to ignore that and use
|
|
|
|
|
* the destination type.
|
2013-04-17 12:23:54 -07:00
|
|
|
*/
|
|
|
|
|
switch (dest.type) {
|
|
|
|
|
case BRW_REGISTER_TYPE_F:
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_3src_src_type(brw, inst, BRW_3SRC_TYPE_F);
|
|
|
|
|
brw_inst_set_3src_dst_type(brw, inst, BRW_3SRC_TYPE_F);
|
2013-04-17 12:23:54 -07:00
|
|
|
break;
|
|
|
|
|
case BRW_REGISTER_TYPE_D:
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_3src_src_type(brw, inst, BRW_3SRC_TYPE_D);
|
|
|
|
|
brw_inst_set_3src_dst_type(brw, inst, BRW_3SRC_TYPE_D);
|
2013-04-17 12:23:54 -07:00
|
|
|
break;
|
|
|
|
|
case BRW_REGISTER_TYPE_UD:
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_3src_src_type(brw, inst, BRW_3SRC_TYPE_UD);
|
|
|
|
|
brw_inst_set_3src_dst_type(brw, inst, BRW_3SRC_TYPE_UD);
|
2013-04-17 12:23:54 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
return inst;
|
2010-03-22 10:05:42 -07:00
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* Convenience routines.
|
|
|
|
|
*/
|
|
|
|
|
#define ALU1(OP) \
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *brw_##OP(struct brw_compile *p, \
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg dest, \
|
|
|
|
|
struct brw_reg src0) \
|
|
|
|
|
{ \
|
|
|
|
|
return brw_alu1(p, BRW_OPCODE_##OP, dest, src0); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define ALU2(OP) \
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *brw_##OP(struct brw_compile *p, \
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg dest, \
|
|
|
|
|
struct brw_reg src0, \
|
|
|
|
|
struct brw_reg src1) \
|
|
|
|
|
{ \
|
|
|
|
|
return brw_alu2(p, BRW_OPCODE_##OP, dest, src0, src1); \
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-22 10:05:42 -07:00
|
|
|
#define ALU3(OP) \
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *brw_##OP(struct brw_compile *p, \
|
2010-03-22 10:05:42 -07:00
|
|
|
struct brw_reg dest, \
|
|
|
|
|
struct brw_reg src0, \
|
|
|
|
|
struct brw_reg src1, \
|
|
|
|
|
struct brw_reg src2) \
|
|
|
|
|
{ \
|
|
|
|
|
return brw_alu3(p, BRW_OPCODE_##OP, dest, src0, src1, src2); \
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-13 14:55:18 -07:00
|
|
|
#define ALU3F(OP) \
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *brw_##OP(struct brw_compile *p, \
|
2013-06-13 14:55:18 -07:00
|
|
|
struct brw_reg dest, \
|
|
|
|
|
struct brw_reg src0, \
|
|
|
|
|
struct brw_reg src1, \
|
|
|
|
|
struct brw_reg src2) \
|
|
|
|
|
{ \
|
|
|
|
|
assert(dest.type == BRW_REGISTER_TYPE_F); \
|
|
|
|
|
assert(src0.type == BRW_REGISTER_TYPE_F); \
|
|
|
|
|
assert(src1.type == BRW_REGISTER_TYPE_F); \
|
|
|
|
|
assert(src2.type == BRW_REGISTER_TYPE_F); \
|
|
|
|
|
return brw_alu3(p, BRW_OPCODE_##OP, dest, src0, src1, src2); \
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-14 11:40:19 -07:00
|
|
|
/* Rounding operations (other than RNDD) require two instructions - the first
|
|
|
|
|
* stores a rounded value (possibly the wrong way) in the dest register, but
|
|
|
|
|
* also sets a per-channel "increment bit" in the flag register. A predicated
|
|
|
|
|
* add of 1.0 fixes dest to contain the desired result.
|
2011-05-11 02:18:24 -07:00
|
|
|
*
|
|
|
|
|
* Sandybridge and later appear to round correctly without an ADD.
|
2010-10-14 11:40:19 -07:00
|
|
|
*/
|
|
|
|
|
#define ROUND(OP) \
|
|
|
|
|
void brw_##OP(struct brw_compile *p, \
|
|
|
|
|
struct brw_reg dest, \
|
|
|
|
|
struct brw_reg src) \
|
|
|
|
|
{ \
|
2014-06-10 17:44:56 -07:00
|
|
|
struct brw_context *brw = p->brw; \
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *rnd, *add; \
|
2010-10-14 11:40:19 -07:00
|
|
|
rnd = next_insn(p, BRW_OPCODE_##OP); \
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, rnd, dest); \
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, rnd, src); \
|
2010-10-14 11:40:19 -07:00
|
|
|
\
|
2014-06-10 17:44:56 -07:00
|
|
|
if (brw->gen < 6) { \
|
2011-05-11 02:18:24 -07:00
|
|
|
/* turn on round-increments */ \
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_cond_modifier(brw, rnd, BRW_CONDITIONAL_R); \
|
2011-05-11 02:18:24 -07:00
|
|
|
add = brw_ADD(p, dest, dest, brw_imm_f(1.0f)); \
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_pred_control(brw, add, BRW_PREDICATE_NORMAL); \
|
2011-05-11 02:18:24 -07:00
|
|
|
} \
|
2010-10-14 11:40:19 -07:00
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
ALU1(MOV)
|
|
|
|
|
ALU2(SEL)
|
|
|
|
|
ALU1(NOT)
|
|
|
|
|
ALU2(AND)
|
|
|
|
|
ALU2(OR)
|
|
|
|
|
ALU2(XOR)
|
|
|
|
|
ALU2(SHR)
|
|
|
|
|
ALU2(SHL)
|
|
|
|
|
ALU2(ASR)
|
|
|
|
|
ALU1(FRC)
|
|
|
|
|
ALU1(RNDD)
|
|
|
|
|
ALU2(MAC)
|
|
|
|
|
ALU2(MACH)
|
|
|
|
|
ALU1(LZD)
|
|
|
|
|
ALU2(DP4)
|
|
|
|
|
ALU2(DPH)
|
|
|
|
|
ALU2(DP3)
|
|
|
|
|
ALU2(DP2)
|
|
|
|
|
ALU2(LINE)
|
2010-03-10 14:46:27 -08:00
|
|
|
ALU2(PLN)
|
2013-06-13 14:55:18 -07:00
|
|
|
ALU3F(MAD)
|
|
|
|
|
ALU3F(LRP)
|
2013-04-09 17:56:19 -07:00
|
|
|
ALU1(BFREV)
|
|
|
|
|
ALU3(BFE)
|
|
|
|
|
ALU2(BFI1)
|
|
|
|
|
ALU3(BFI2)
|
|
|
|
|
ALU1(FBH)
|
|
|
|
|
ALU1(FBL)
|
|
|
|
|
ALU1(CBIT)
|
2013-09-19 13:01:08 -07:00
|
|
|
ALU2(ADDC)
|
|
|
|
|
ALU2(SUBB)
|
2010-10-14 11:40:19 -07:00
|
|
|
|
|
|
|
|
ROUND(RNDZ)
|
2010-10-14 14:31:54 -07:00
|
|
|
ROUND(RNDE)
|
2010-10-14 11:40:19 -07:00
|
|
|
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_ADD(struct brw_compile *p, struct brw_reg dest,
|
|
|
|
|
struct brw_reg src0, struct brw_reg src1)
|
2010-09-04 21:28:04 -07:00
|
|
|
{
|
|
|
|
|
/* 6.2.2: add */
|
|
|
|
|
if (src0.type == BRW_REGISTER_TYPE_F ||
|
|
|
|
|
(src0.file == BRW_IMMEDIATE_VALUE &&
|
|
|
|
|
src0.type == BRW_REGISTER_TYPE_VF)) {
|
|
|
|
|
assert(src1.type != BRW_REGISTER_TYPE_UD);
|
|
|
|
|
assert(src1.type != BRW_REGISTER_TYPE_D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (src1.type == BRW_REGISTER_TYPE_F ||
|
|
|
|
|
(src1.file == BRW_IMMEDIATE_VALUE &&
|
|
|
|
|
src1.type == BRW_REGISTER_TYPE_VF)) {
|
|
|
|
|
assert(src0.type != BRW_REGISTER_TYPE_UD);
|
|
|
|
|
assert(src0.type != BRW_REGISTER_TYPE_D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return brw_alu2(p, BRW_OPCODE_ADD, dest, src0, src1);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_AVG(struct brw_compile *p, struct brw_reg dest,
|
|
|
|
|
struct brw_reg src0, struct brw_reg src1)
|
2012-07-07 08:28:46 -07:00
|
|
|
{
|
|
|
|
|
assert(dest.type == src0.type);
|
|
|
|
|
assert(src0.type == src1.type);
|
|
|
|
|
switch (src0.type) {
|
|
|
|
|
case BRW_REGISTER_TYPE_B:
|
|
|
|
|
case BRW_REGISTER_TYPE_UB:
|
|
|
|
|
case BRW_REGISTER_TYPE_W:
|
|
|
|
|
case BRW_REGISTER_TYPE_UW:
|
|
|
|
|
case BRW_REGISTER_TYPE_D:
|
|
|
|
|
case BRW_REGISTER_TYPE_UD:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2014-06-29 14:54:01 -07:00
|
|
|
unreachable("Bad type for brw_AVG");
|
2012-07-07 08:28:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return brw_alu2(p, BRW_OPCODE_AVG, dest, src0, src1);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_MUL(struct brw_compile *p, struct brw_reg dest,
|
|
|
|
|
struct brw_reg src0, struct brw_reg src1)
|
2010-09-04 21:28:04 -07:00
|
|
|
{
|
|
|
|
|
/* 6.32.38: mul */
|
|
|
|
|
if (src0.type == BRW_REGISTER_TYPE_D ||
|
|
|
|
|
src0.type == BRW_REGISTER_TYPE_UD ||
|
|
|
|
|
src1.type == BRW_REGISTER_TYPE_D ||
|
|
|
|
|
src1.type == BRW_REGISTER_TYPE_UD) {
|
|
|
|
|
assert(dest.type != BRW_REGISTER_TYPE_F);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (src0.type == BRW_REGISTER_TYPE_F ||
|
|
|
|
|
(src0.file == BRW_IMMEDIATE_VALUE &&
|
|
|
|
|
src0.type == BRW_REGISTER_TYPE_VF)) {
|
|
|
|
|
assert(src1.type != BRW_REGISTER_TYPE_UD);
|
|
|
|
|
assert(src1.type != BRW_REGISTER_TYPE_D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (src1.type == BRW_REGISTER_TYPE_F ||
|
|
|
|
|
(src1.file == BRW_IMMEDIATE_VALUE &&
|
|
|
|
|
src1.type == BRW_REGISTER_TYPE_VF)) {
|
|
|
|
|
assert(src0.type != BRW_REGISTER_TYPE_UD);
|
|
|
|
|
assert(src0.type != BRW_REGISTER_TYPE_D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(src0.file != BRW_ARCHITECTURE_REGISTER_FILE ||
|
|
|
|
|
src0.nr != BRW_ARF_ACCUMULATOR);
|
|
|
|
|
assert(src1.file != BRW_ARCHITECTURE_REGISTER_FILE ||
|
|
|
|
|
src1.nr != BRW_ARF_ACCUMULATOR);
|
|
|
|
|
|
|
|
|
|
return brw_alu2(p, BRW_OPCODE_MUL, dest, src0, src1);
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-28 16:08:39 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_F32TO16(struct brw_compile *p, struct brw_reg dst, struct brw_reg src)
|
|
|
|
|
{
|
|
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
bool align16 = brw_inst_access_mode(brw, p->current) == BRW_ALIGN_16;
|
|
|
|
|
|
|
|
|
|
if (align16) {
|
|
|
|
|
assert(dst.type == BRW_REGISTER_TYPE_UD);
|
|
|
|
|
} else {
|
|
|
|
|
assert(dst.type == BRW_REGISTER_TYPE_W ||
|
|
|
|
|
dst.type == BRW_REGISTER_TYPE_UW ||
|
|
|
|
|
dst.type == BRW_REGISTER_TYPE_HF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
if (align16) {
|
|
|
|
|
/* Emulate the Gen7 zeroing bug (see comments in vec4_visitor's
|
|
|
|
|
* emit_pack_half_2x16 method.)
|
|
|
|
|
*/
|
|
|
|
|
brw_MOV(p, retype(dst, BRW_REGISTER_TYPE_UD), brw_imm_ud(0u));
|
|
|
|
|
}
|
|
|
|
|
return brw_MOV(p, retype(dst, BRW_REGISTER_TYPE_HF), src);
|
|
|
|
|
} else {
|
|
|
|
|
assert(brw->gen == 7);
|
|
|
|
|
return brw_alu1(p, BRW_OPCODE_F32TO16, dst, src);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
brw_inst *
|
|
|
|
|
brw_F16TO32(struct brw_compile *p, struct brw_reg dst, struct brw_reg src)
|
|
|
|
|
{
|
|
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
bool align16 = brw_inst_access_mode(brw, p->current) == BRW_ALIGN_16;
|
|
|
|
|
|
|
|
|
|
if (align16) {
|
|
|
|
|
assert(src.type == BRW_REGISTER_TYPE_UD);
|
|
|
|
|
} else {
|
|
|
|
|
assert(src.type == BRW_REGISTER_TYPE_W ||
|
|
|
|
|
src.type == BRW_REGISTER_TYPE_UW ||
|
|
|
|
|
src.type == BRW_REGISTER_TYPE_HF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
return brw_MOV(p, dst, retype(src, BRW_REGISTER_TYPE_HF));
|
|
|
|
|
} else {
|
|
|
|
|
assert(brw->gen == 7);
|
|
|
|
|
return brw_alu1(p, BRW_OPCODE_F16TO32, dst, src);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
void brw_NOP(struct brw_compile *p)
|
|
|
|
|
{
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_NOP);
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_ud(0x0));
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* Comparisons, if/else/endif
|
|
|
|
|
*/
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_JMPI(struct brw_compile *p, struct brw_reg index,
|
|
|
|
|
unsigned predicate_control)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-05-27 22:45:16 -07:00
|
|
|
struct brw_reg ip = brw_ip_reg();
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *inst = brw_alu2(p, BRW_OPCODE_JMPI, ip, ip, index);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, inst, BRW_EXECUTE_2);
|
|
|
|
|
brw_inst_set_qtr_control(brw, inst, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_inst_set_mask_control(brw, inst, BRW_MASK_DISABLE);
|
|
|
|
|
brw_inst_set_pred_control(brw, inst, predicate_control);
|
2009-07-02 16:32:19 +08:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
return inst;
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2011-05-16 12:25:18 -07:00
|
|
|
static void
|
2014-06-13 14:29:25 -07:00
|
|
|
push_if_stack(struct brw_compile *p, brw_inst *inst)
|
2011-05-16 12:25:18 -07:00
|
|
|
{
|
2011-12-21 14:51:59 +08:00
|
|
|
p->if_stack[p->if_stack_depth] = inst - p->store;
|
2011-05-16 12:25:18 -07:00
|
|
|
|
|
|
|
|
p->if_stack_depth++;
|
|
|
|
|
if (p->if_stack_array_size <= p->if_stack_depth) {
|
|
|
|
|
p->if_stack_array_size *= 2;
|
2011-12-21 14:51:59 +08:00
|
|
|
p->if_stack = reralloc(p->mem_ctx, p->if_stack, int,
|
2011-05-16 12:25:18 -07:00
|
|
|
p->if_stack_array_size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
static brw_inst *
|
2011-12-21 14:51:59 +08:00
|
|
|
pop_if_stack(struct brw_compile *p)
|
|
|
|
|
{
|
|
|
|
|
p->if_stack_depth--;
|
|
|
|
|
return &p->store[p->if_stack[p->if_stack_depth]];
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-06 12:13:32 -08:00
|
|
|
static void
|
2014-06-13 14:29:25 -07:00
|
|
|
push_loop_stack(struct brw_compile *p, brw_inst *inst)
|
2011-12-06 12:13:32 -08:00
|
|
|
{
|
|
|
|
|
if (p->loop_stack_array_size < p->loop_stack_depth) {
|
|
|
|
|
p->loop_stack_array_size *= 2;
|
|
|
|
|
p->loop_stack = reralloc(p->mem_ctx, p->loop_stack, int,
|
|
|
|
|
p->loop_stack_array_size);
|
2011-12-06 12:44:41 -08:00
|
|
|
p->if_depth_in_loop = reralloc(p->mem_ctx, p->if_depth_in_loop, int,
|
|
|
|
|
p->loop_stack_array_size);
|
2011-12-06 12:13:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p->loop_stack[p->loop_stack_depth] = inst - p->store;
|
|
|
|
|
p->loop_stack_depth++;
|
2011-12-06 12:44:41 -08:00
|
|
|
p->if_depth_in_loop[p->loop_stack_depth] = 0;
|
2011-12-06 12:13:32 -08:00
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
static brw_inst *
|
2011-12-06 12:13:32 -08:00
|
|
|
get_inner_do_insn(struct brw_compile *p)
|
|
|
|
|
{
|
|
|
|
|
return &p->store[p->loop_stack[p->loop_stack_depth - 1]];
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
/* EU takes the value from the flag register and pushes it onto some
|
|
|
|
|
* sort of a stack (presumably merging with any flag value already on
|
|
|
|
|
* the stack). Within an if block, the flags at the top of the stack
|
|
|
|
|
* control execution on each channel of the unit, eg. on each of the
|
|
|
|
|
* 16 pixel values in our wm programs.
|
|
|
|
|
*
|
|
|
|
|
* When the matching 'else' instruction is reached (presumably by
|
|
|
|
|
* countdown of the instruction count patched in by our ELSE/ENDIF
|
|
|
|
|
* functions), the relevent flags are inverted.
|
|
|
|
|
*
|
|
|
|
|
* When the matching 'endif' instruction is reached, the flags are
|
|
|
|
|
* popped off. If the stack is now empty, normal execution resumes.
|
|
|
|
|
*/
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
2013-11-25 15:51:24 -08:00
|
|
|
brw_IF(struct brw_compile *p, unsigned execute_size)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2006-10-18 00:24:01 -07:00
|
|
|
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
insn = next_insn(p, BRW_OPCODE_IF);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
|
|
|
|
/* Override the defaults for this instruction:
|
|
|
|
|
*/
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_ip_reg());
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_ip_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0));
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_imm_w(0));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen6_jump_count(brw, insn, 0);
|
2011-12-05 13:52:16 -08:00
|
|
|
brw_set_src0(p, insn, vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_D)));
|
|
|
|
|
brw_set_src1(p, insn, vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_D)));
|
2014-08-10 07:10:55 -07:00
|
|
|
} else if (brw->gen == 7) {
|
2011-12-05 13:52:16 -08:00
|
|
|
brw_set_dest(p, insn, vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_D)));
|
|
|
|
|
brw_set_src0(p, insn, vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_D)));
|
2011-03-15 23:53:40 -07:00
|
|
|
brw_set_src1(p, insn, brw_imm_ud(0));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, 0);
|
|
|
|
|
brw_inst_set_uip(brw, insn, 0);
|
2014-08-10 07:10:55 -07:00
|
|
|
} else {
|
|
|
|
|
brw_set_dest(p, insn, vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_D)));
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0));
|
|
|
|
|
brw_inst_set_jip(brw, insn, 0);
|
|
|
|
|
brw_inst_set_uip(brw, insn, 0);
|
2010-10-04 15:08:03 -07:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, execute_size);
|
|
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_inst_set_pred_control(brw, insn, BRW_PREDICATE_NORMAL);
|
|
|
|
|
brw_inst_set_mask_control(brw, insn, BRW_MASK_ENABLE);
|
2012-12-12 18:01:00 -08:00
|
|
|
if (!p->single_program_flow && brw->gen < 6)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_thread_control(brw, insn, BRW_THREAD_SWITCH);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-05-16 12:25:18 -07:00
|
|
|
push_if_stack(p, insn);
|
2011-12-06 12:44:41 -08:00
|
|
|
p->if_depth_in_loop[p->loop_stack_depth]++;
|
2006-08-09 19:14:05 +00:00
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-15 23:53:40 -07:00
|
|
|
/* This function is only used for gen6-style IF instructions with an
|
|
|
|
|
* embedded comparison (conditional modifier). It is not used on gen7.
|
|
|
|
|
*/
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
2014-06-29 17:50:20 -07:00
|
|
|
gen6_IF(struct brw_compile *p, enum brw_conditional_mod conditional,
|
2011-03-16 00:00:09 -07:00
|
|
|
struct brw_reg src0, struct brw_reg src1)
|
2010-10-19 12:55:04 -07:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2010-10-19 12:55:04 -07:00
|
|
|
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_IF);
|
|
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_imm_w(0));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, p->compressed ? BRW_EXECUTE_16
|
|
|
|
|
: BRW_EXECUTE_8);
|
|
|
|
|
brw_inst_set_gen6_jump_count(brw, insn, 0);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, src1);
|
2010-10-19 12:55:04 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_qtr_control(brw, insn) == BRW_COMPRESSION_NONE);
|
|
|
|
|
assert(brw_inst_pred_control(brw, insn) == BRW_PREDICATE_NONE);
|
|
|
|
|
brw_inst_set_cond_modifier(brw, insn, conditional);
|
2010-10-19 12:55:04 -07:00
|
|
|
|
2011-05-16 12:25:18 -07:00
|
|
|
push_if_stack(p, insn);
|
2010-10-19 12:55:04 -07:00
|
|
|
return insn;
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/**
|
|
|
|
|
* In single-program-flow (SPF) mode, convert IF and ELSE into ADDs.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
convert_IF_ELSE_to_ADD(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *if_inst, brw_inst *else_inst)
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* The next instruction (where the ENDIF would be, if it existed) */
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *next_inst = &p->store[p->nr_insn];
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
|
|
|
|
assert(p->single_program_flow);
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(if_inst != NULL && brw_inst_opcode(brw, if_inst) == BRW_OPCODE_IF);
|
|
|
|
|
assert(else_inst == NULL || brw_inst_opcode(brw, else_inst) == BRW_OPCODE_ELSE);
|
|
|
|
|
assert(brw_inst_exec_size(brw, if_inst) == BRW_EXECUTE_1);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
|
|
|
|
/* Convert IF to an ADD instruction that moves the instruction pointer
|
|
|
|
|
* to the first instruction of the ELSE block. If there is no ELSE
|
|
|
|
|
* block, point to where ENDIF would be. Reverse the predicate.
|
|
|
|
|
*
|
|
|
|
|
* There's no need to execute an ENDIF since we don't need to do any
|
|
|
|
|
* stack operations, and if we're currently executing, we just want to
|
|
|
|
|
* continue normally.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_opcode(brw, if_inst, BRW_OPCODE_ADD);
|
|
|
|
|
brw_inst_set_pred_inv(brw, if_inst, true);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
|
|
|
|
if (else_inst != NULL) {
|
|
|
|
|
/* Convert ELSE to an ADD instruction that points where the ENDIF
|
|
|
|
|
* would be.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_opcode(brw, else_inst, BRW_OPCODE_ADD);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_imm_ud(brw, if_inst, (else_inst - if_inst + 1) * 16);
|
|
|
|
|
brw_inst_set_imm_ud(brw, else_inst, (next_inst - else_inst) * 16);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_imm_ud(brw, if_inst, (next_inst - if_inst) * 16);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Patch IF and ELSE instructions with appropriate jump targets.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
patch_IF_ELSE(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *if_inst, brw_inst *else_inst, brw_inst *endif_inst)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2009-07-15 10:40:16 +08:00
|
|
|
|
i965: Only convert if/else to conditional adds prior to Gen6.
Normally when outputting instructions in SPF (single program flow)
mode, we convert IF and ELSE instructions to conditional ADD
instructions applied to the IP register. On platforms prior to Gen6,
flow control instructions cause an implied thread switch, so this is a
significant savings.
However, according to the SandyBridge PRM (Volume 4 part 2, p79):
[Errata DevSNB{WA}] - When SPF is ON, IP may not be updated by
non-flow control instructions.
So we have to disable this optimization on Gen6.
On later platforms, there is no significant benefit to converting flow
control instructions to ADDs, so for the sake of consistency, this
patch disables the optimization on later platforms too.
The reason we never noticed this problem before is that so far we
haven't needed to use SPF mode on Gen6. However, later patches in
this series will introduce a Gen6 GS program which uses SPF mode.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-24 21:41:07 -08:00
|
|
|
/* We shouldn't be patching IF and ELSE instructions in single program flow
|
|
|
|
|
* mode when gen < 6, because in single program flow mode on those
|
|
|
|
|
* platforms, we convert flow control instructions to conditional ADDs that
|
|
|
|
|
* operate on IP (see brw_ENDIF).
|
|
|
|
|
*
|
|
|
|
|
* However, on Gen6, writing to IP doesn't work in single program flow mode
|
|
|
|
|
* (see the SandyBridge PRM, Volume 4 part 2, p79: "When SPF is ON, IP may
|
|
|
|
|
* not be updated by non-flow control instructions."). And on later
|
|
|
|
|
* platforms, there is no significant benefit to converting control flow
|
|
|
|
|
* instructions to conditional ADDs. So we do patch IF and ELSE
|
|
|
|
|
* instructions in single program flow mode on those platforms.
|
|
|
|
|
*/
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6)
|
i965: Only convert if/else to conditional adds prior to Gen6.
Normally when outputting instructions in SPF (single program flow)
mode, we convert IF and ELSE instructions to conditional ADD
instructions applied to the IP register. On platforms prior to Gen6,
flow control instructions cause an implied thread switch, so this is a
significant savings.
However, according to the SandyBridge PRM (Volume 4 part 2, p79):
[Errata DevSNB{WA}] - When SPF is ON, IP may not be updated by
non-flow control instructions.
So we have to disable this optimization on Gen6.
On later platforms, there is no significant benefit to converting flow
control instructions to ADDs, so for the sake of consistency, this
patch disables the optimization on later platforms too.
The reason we never noticed this problem before is that so far we
haven't needed to use SPF mode on Gen6. However, later patches in
this series will introduce a Gen6 GS program which uses SPF mode.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-24 21:41:07 -08:00
|
|
|
assert(!p->single_program_flow);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(if_inst != NULL && brw_inst_opcode(brw, if_inst) == BRW_OPCODE_IF);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
assert(endif_inst != NULL);
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(else_inst == NULL || brw_inst_opcode(brw, else_inst) == BRW_OPCODE_ELSE);
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
2014-06-30 08:00:25 -07:00
|
|
|
unsigned br = brw_jump_scale(brw);
|
2006-10-18 00:24:01 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_opcode(brw, endif_inst) == BRW_OPCODE_ENDIF);
|
|
|
|
|
brw_inst_set_exec_size(brw, endif_inst, brw_inst_exec_size(brw, if_inst));
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
|
|
|
|
if (else_inst == NULL) {
|
|
|
|
|
/* Patch IF -> ENDIF */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* Turn it into an IFF, which means no mask stack operations for
|
|
|
|
|
* all-false and jumping past the ENDIF.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_opcode(brw, if_inst, BRW_OPCODE_IFF);
|
|
|
|
|
brw_inst_set_gen4_jump_count(brw, if_inst,
|
|
|
|
|
br * (endif_inst - if_inst + 1));
|
|
|
|
|
brw_inst_set_gen4_pop_count(brw, if_inst, 0);
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* As of gen6, there is no IFF and IF must point to the ENDIF. */
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen6_jump_count(brw, if_inst, br*(endif_inst - if_inst));
|
2011-03-15 23:53:40 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_uip(brw, if_inst, br * (endif_inst - if_inst));
|
|
|
|
|
brw_inst_set_jip(brw, if_inst, br * (endif_inst - if_inst));
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
}
|
2006-10-18 00:24:01 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, else_inst, brw_inst_exec_size(brw, if_inst));
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
|
|
|
|
/* Patch IF -> ELSE */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen4_jump_count(brw, if_inst,
|
|
|
|
|
br * (else_inst - if_inst));
|
|
|
|
|
brw_inst_set_gen4_pop_count(brw, if_inst, 0);
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen6_jump_count(brw, if_inst,
|
|
|
|
|
br * (else_inst - if_inst + 1));
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Patch ELSE -> ENDIF */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* BRW_OPCODE_ELSE pre-gen6 should point just past the
|
|
|
|
|
* matching ENDIF.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen4_jump_count(brw, else_inst,
|
|
|
|
|
br * (endif_inst - else_inst + 1));
|
|
|
|
|
brw_inst_set_gen4_pop_count(brw, else_inst, 1);
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* BRW_OPCODE_ELSE on gen6 should point to the matching ENDIF. */
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen6_jump_count(brw, else_inst,
|
|
|
|
|
br * (endif_inst - else_inst));
|
2011-03-15 23:53:40 -07:00
|
|
|
} else {
|
|
|
|
|
/* The IF instruction's JIP should point just past the ELSE */
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, if_inst, br * (else_inst - if_inst + 1));
|
2011-03-15 23:53:40 -07:00
|
|
|
/* The IF instruction's UIP and ELSE's JIP should point to ENDIF */
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_uip(brw, if_inst, br * (endif_inst - if_inst));
|
|
|
|
|
brw_inst_set_jip(brw, else_inst, br * (endif_inst - else_inst));
|
2014-06-30 08:05:42 -07:00
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
/* Since we don't set branch_ctrl, the ELSE's JIP and UIP both
|
|
|
|
|
* should point to ENDIF.
|
|
|
|
|
*/
|
|
|
|
|
brw_inst_set_uip(brw, else_inst, br * (endif_inst - else_inst));
|
|
|
|
|
}
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
}
|
2006-10-18 00:24:01 -07:00
|
|
|
}
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
brw_ELSE(struct brw_compile *p)
|
|
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_ELSE);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_ip_reg());
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_ip_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0));
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_imm_w(0));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen6_jump_count(brw, insn, 0);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
2014-08-10 07:10:55 -07:00
|
|
|
} else if (brw->gen == 7) {
|
2011-03-15 23:53:40 -07:00
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_ud(0));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, 0);
|
|
|
|
|
brw_inst_set_uip(brw, insn, 0);
|
2014-08-10 07:10:55 -07:00
|
|
|
} else {
|
|
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0));
|
|
|
|
|
brw_inst_set_jip(brw, insn, 0);
|
|
|
|
|
brw_inst_set_uip(brw, insn, 0);
|
2010-10-04 15:08:03 -07:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_inst_set_mask_control(brw, insn, BRW_MASK_ENABLE);
|
2012-12-12 18:01:00 -08:00
|
|
|
if (!p->single_program_flow && brw->gen < 6)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_thread_control(brw, insn, BRW_THREAD_SWITCH);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
push_if_stack(p, insn);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2011-05-16 12:25:18 -07:00
|
|
|
void
|
|
|
|
|
brw_ENDIF(struct brw_compile *p)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = NULL;
|
|
|
|
|
brw_inst *else_inst = NULL;
|
|
|
|
|
brw_inst *if_inst = NULL;
|
|
|
|
|
brw_inst *tmp;
|
2011-12-21 15:32:02 +08:00
|
|
|
bool emit_endif = true;
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
|
i965: Only convert if/else to conditional adds prior to Gen6.
Normally when outputting instructions in SPF (single program flow)
mode, we convert IF and ELSE instructions to conditional ADD
instructions applied to the IP register. On platforms prior to Gen6,
flow control instructions cause an implied thread switch, so this is a
significant savings.
However, according to the SandyBridge PRM (Volume 4 part 2, p79):
[Errata DevSNB{WA}] - When SPF is ON, IP may not be updated by
non-flow control instructions.
So we have to disable this optimization on Gen6.
On later platforms, there is no significant benefit to converting flow
control instructions to ADDs, so for the sake of consistency, this
patch disables the optimization on later platforms too.
The reason we never noticed this problem before is that so far we
haven't needed to use SPF mode on Gen6. However, later patches in
this series will introduce a Gen6 GS program which uses SPF mode.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2011-11-24 21:41:07 -08:00
|
|
|
/* In single program flow mode, we can express IF and ELSE instructions
|
|
|
|
|
* equivalently as ADD instructions that operate on IP. On platforms prior
|
|
|
|
|
* to Gen6, flow control instructions cause an implied thread switch, so
|
|
|
|
|
* this is a significant savings.
|
|
|
|
|
*
|
|
|
|
|
* However, on Gen6, writing to IP doesn't work in single program flow mode
|
|
|
|
|
* (see the SandyBridge PRM, Volume 4 part 2, p79: "When SPF is ON, IP may
|
|
|
|
|
* not be updated by non-flow control instructions."). And on later
|
|
|
|
|
* platforms, there is no significant benefit to converting control flow
|
|
|
|
|
* instructions to conditional ADDs. So we only do this trick on Gen4 and
|
|
|
|
|
* Gen5.
|
|
|
|
|
*/
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6 && p->single_program_flow)
|
2011-12-21 15:32:02 +08:00
|
|
|
emit_endif = false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A single next_insn() may change the base adress of instruction store
|
|
|
|
|
* memory(p->store), so call it first before referencing the instruction
|
|
|
|
|
* store pointer from an index
|
|
|
|
|
*/
|
|
|
|
|
if (emit_endif)
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_ENDIF);
|
|
|
|
|
|
|
|
|
|
/* Pop the IF and (optional) ELSE instructions from the stack */
|
|
|
|
|
p->if_depth_in_loop[p->loop_stack_depth]--;
|
|
|
|
|
tmp = pop_if_stack(p);
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_opcode(brw, tmp) == BRW_OPCODE_ELSE) {
|
2011-12-21 15:32:02 +08:00
|
|
|
else_inst = tmp;
|
|
|
|
|
tmp = pop_if_stack(p);
|
|
|
|
|
}
|
|
|
|
|
if_inst = tmp;
|
|
|
|
|
|
|
|
|
|
if (!emit_endif) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* ENDIF is useless; don't bother emitting it. */
|
|
|
|
|
convert_IF_ELSE_to_ADD(p, if_inst, else_inst);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
brw_set_dest(p, insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0));
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
brw_set_dest(p, insn, brw_imm_w(0));
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
2014-08-10 07:10:55 -07:00
|
|
|
} else if (brw->gen == 7) {
|
2011-03-15 23:53:40 -07:00
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_ud(0));
|
2014-08-10 07:10:55 -07:00
|
|
|
} else {
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0));
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
}
|
2006-10-18 00:24:01 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_inst_set_mask_control(brw, insn, BRW_MASK_ENABLE);
|
2012-12-12 18:01:00 -08:00
|
|
|
if (brw->gen < 6)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_thread_control(brw, insn, BRW_THREAD_SWITCH);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
/* Also pop item off the stack in the endif instruction: */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen4_jump_count(brw, insn, 0);
|
|
|
|
|
brw_inst_set_gen4_pop_count(brw, insn, 1);
|
2013-07-06 00:36:46 -07:00
|
|
|
} else if (brw->gen == 6) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen6_jump_count(brw, insn, 2);
|
2011-03-15 23:53:40 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, 2);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
i965: Rework IF/ELSE jump target back-patching.
The primary motivation for this is to better support Ivybridge control
flow. Ivybridge IF instructions need to point to the first instruction
of the ELSE block -and- the ENDIF instruction; the existing code only
supported back-patching one instruction ago.
A second goal is to simplify and centralize the back-patching, hopefully
clarifying the code somewhat.
Previously, brw_ELSE back-patched the IF instruction, and brw_ENDIF
back-patched the previous instruction (IF or ELSE). With this patch,
brw_ENDIF is responsible for patching both the IF and (optional) ELSE.
To support this, the control flow stack (if_stack) maintains pointers to
both the IF and ELSE instructions. Unfortunately, in single program
flow (SPF) mode, both were emitted as ADD instructions, and thus
indistinguishable.
To remedy this, this patch simply emits IF and ELSE, rather than ADDs;
brw_ENDIF will convert them to ADDs (the SPF version of back-patching).
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-05-16 13:40:00 -07:00
|
|
|
patch_IF_ELSE(p, if_inst, else_inst, insn);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_BREAK(struct brw_compile *p)
|
2007-06-21 10:22:28 +08:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2007-06-21 10:22:28 +08:00
|
|
|
insn = next_insn(p, BRW_OPCODE_BREAK);
|
2014-08-10 07:10:55 -07:00
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0x0));
|
|
|
|
|
} else if (brw->gen >= 6) {
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0));
|
2010-12-01 11:46:46 -08:00
|
|
|
} else {
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_ip_reg());
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_ip_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen4_pop_count(brw, insn,
|
|
|
|
|
p->if_depth_in_loop[p->loop_stack_depth]);
|
2010-12-01 11:46:46 -08:00
|
|
|
}
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2014-08-04 00:06:05 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, p->compressed ? BRW_EXECUTE_16
|
|
|
|
|
: BRW_EXECUTE_8);
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2007-09-29 15:00:52 +08:00
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
2014-08-04 14:26:26 -07:00
|
|
|
brw_CONT(struct brw_compile *p)
|
2010-12-01 14:02:14 -08:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2010-12-01 14:02:14 -08:00
|
|
|
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_CONTINUE);
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_ip_reg());
|
2014-08-10 07:10:55 -07:00
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0x0));
|
|
|
|
|
} else {
|
|
|
|
|
brw_set_src0(p, insn, brw_ip_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0));
|
|
|
|
|
}
|
2010-12-01 14:02:14 -08:00
|
|
|
|
2014-08-04 14:26:26 -07:00
|
|
|
if (brw->gen < 6) {
|
|
|
|
|
brw_inst_set_gen4_pop_count(brw, insn,
|
|
|
|
|
p->if_depth_in_loop[p->loop_stack_depth]);
|
|
|
|
|
}
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2014-08-04 00:06:05 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, p->compressed ? BRW_EXECUTE_16
|
|
|
|
|
: BRW_EXECUTE_8);
|
2007-06-21 10:22:28 +08:00
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
gen6_HALT(struct brw_compile *p)
|
2012-12-06 10:15:08 -08:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2012-12-06 10:15:08 -08:00
|
|
|
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_HALT);
|
|
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
2014-08-10 07:10:55 -07:00
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0x0));
|
|
|
|
|
} else {
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0x0)); /* UIP and JIP, updated later. */
|
|
|
|
|
}
|
2012-12-06 10:15:08 -08:00
|
|
|
|
|
|
|
|
if (p->compressed) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, BRW_EXECUTE_16);
|
2012-12-06 10:15:08 -08:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_inst_set_exec_size(brw, insn, BRW_EXECUTE_8);
|
2012-12-06 10:15:08 -08:00
|
|
|
}
|
|
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
/* DO/WHILE loop:
|
2010-12-01 10:45:52 -08:00
|
|
|
*
|
|
|
|
|
* The DO/WHILE is just an unterminated loop -- break or continue are
|
|
|
|
|
* used for control within the loop. We have a few ways they can be
|
|
|
|
|
* done.
|
|
|
|
|
*
|
|
|
|
|
* For uniform control flow, the WHILE is just a jump, so ADD ip, ip,
|
|
|
|
|
* jip and no DO instruction.
|
|
|
|
|
*
|
|
|
|
|
* For non-uniform control flow pre-gen6, there's a DO instruction to
|
|
|
|
|
* push the mask, and a WHILE to jump back, and BREAK to get out and
|
|
|
|
|
* pop the mask.
|
|
|
|
|
*
|
|
|
|
|
* For gen6, there's no more mask stack, so no need for DO. WHILE
|
|
|
|
|
* just points back to the first instruction of the loop.
|
2006-08-09 19:14:05 +00:00
|
|
|
*/
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_DO(struct brw_compile *p, unsigned execute_size)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2010-12-01 10:45:52 -08:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6 || p->single_program_flow) {
|
2011-12-06 12:13:32 -08:00
|
|
|
push_loop_stack(p, &p->store[p->nr_insn]);
|
2006-10-18 00:24:01 -07:00
|
|
|
return &p->store[p->nr_insn];
|
|
|
|
|
} else {
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_DO);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-12-06 12:13:32 -08:00
|
|
|
push_loop_stack(p, insn);
|
|
|
|
|
|
2006-10-18 00:24:01 -07:00
|
|
|
/* Override the defaults for this instruction:
|
|
|
|
|
*/
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_null_reg());
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_null_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_null_reg());
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_inst_set_exec_size(brw, insn, execute_size);
|
|
|
|
|
brw_inst_set_pred_control(brw, insn, BRW_PREDICATE_NONE);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2006-10-18 00:24:01 -07:00
|
|
|
return insn;
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-06 12:30:03 -08:00
|
|
|
/**
|
|
|
|
|
* For pre-gen6, we patch BREAK/CONT instructions to point at the WHILE
|
|
|
|
|
* instruction here.
|
|
|
|
|
*
|
|
|
|
|
* For gen6+, see brw_set_uip_jip(), which doesn't care so much about the loop
|
|
|
|
|
* nesting, since it can always just point to the end of the block/current loop.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_patch_break_cont(struct brw_compile *p, brw_inst *while_inst)
|
2011-12-06 12:30:03 -08:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *do_inst = get_inner_do_insn(p);
|
|
|
|
|
brw_inst *inst;
|
2014-06-30 08:00:25 -07:00
|
|
|
unsigned br = brw_jump_scale(brw);
|
2011-12-06 12:30:03 -08:00
|
|
|
|
2014-06-30 09:22:27 -07:00
|
|
|
assert(brw->gen < 6);
|
|
|
|
|
|
2011-12-06 12:30:03 -08:00
|
|
|
for (inst = while_inst - 1; inst != do_inst; inst--) {
|
|
|
|
|
/* If the jump count is != 0, that means that this instruction has already
|
|
|
|
|
* been patched because it's part of a loop inside of the one we're
|
|
|
|
|
* patching.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_opcode(brw, inst) == BRW_OPCODE_BREAK &&
|
|
|
|
|
brw_inst_gen4_jump_count(brw, inst) == 0) {
|
|
|
|
|
brw_inst_set_gen4_jump_count(brw, inst, br*((while_inst - inst) + 1));
|
|
|
|
|
} else if (brw_inst_opcode(brw, inst) == BRW_OPCODE_CONTINUE &&
|
|
|
|
|
brw_inst_gen4_jump_count(brw, inst) == 0) {
|
|
|
|
|
brw_inst_set_gen4_jump_count(brw, inst, br * (while_inst - inst));
|
2011-12-06 12:30:03 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *
|
|
|
|
|
brw_WHILE(struct brw_compile *p)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn, *do_insn;
|
2014-06-30 08:00:25 -07:00
|
|
|
unsigned br = brw_jump_scale(brw);
|
2006-10-18 00:24:01 -07:00
|
|
|
|
2014-08-10 07:06:36 -07:00
|
|
|
if (brw->gen >= 6) {
|
2006-10-18 00:24:01 -07:00
|
|
|
insn = next_insn(p, BRW_OPCODE_WHILE);
|
2011-12-21 15:32:02 +08:00
|
|
|
do_insn = get_inner_do_insn(p);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-08-10 07:10:55 -07:00
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src0(p, insn, brw_imm_d(0));
|
|
|
|
|
brw_inst_set_jip(brw, insn, br * (do_insn - insn));
|
|
|
|
|
} else if (brw->gen == 7) {
|
2014-08-10 07:06:36 -07:00
|
|
|
brw_set_dest(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_ud(0));
|
|
|
|
|
brw_inst_set_jip(brw, insn, br * (do_insn - insn));
|
|
|
|
|
} else {
|
|
|
|
|
brw_set_dest(p, insn, brw_imm_w(0));
|
|
|
|
|
brw_inst_set_gen6_jump_count(brw, insn, br * (do_insn - insn));
|
|
|
|
|
brw_set_src0(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
brw_set_src1(p, insn, retype(brw_null_reg(), BRW_REGISTER_TYPE_D));
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-08-04 00:06:05 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, p->compressed ? BRW_EXECUTE_16
|
|
|
|
|
: BRW_EXECUTE_8);
|
2010-12-01 10:45:52 -08:00
|
|
|
} else {
|
|
|
|
|
if (p->single_program_flow) {
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_ADD);
|
2011-12-21 15:32:02 +08:00
|
|
|
do_insn = get_inner_do_insn(p);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_ip_reg());
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_ip_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d((do_insn - insn) * 16));
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, BRW_EXECUTE_1);
|
2010-12-01 10:45:52 -08:00
|
|
|
} else {
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_WHILE);
|
2011-12-21 15:32:02 +08:00
|
|
|
do_insn = get_inner_do_insn(p);
|
2006-10-18 00:24:01 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_opcode(brw, do_insn) == BRW_OPCODE_DO);
|
2006-10-18 00:24:01 -07:00
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, brw_ip_reg());
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_ip_reg());
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0));
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_exec_size(brw, insn, brw_inst_exec_size(brw, do_insn));
|
|
|
|
|
brw_inst_set_gen4_jump_count(brw, insn, br * (do_insn - insn + 1));
|
|
|
|
|
brw_inst_set_gen4_pop_count(brw, insn, 0);
|
2011-12-06 12:30:03 -08:00
|
|
|
|
|
|
|
|
brw_patch_break_cont(p, insn);
|
2010-12-01 10:45:52 -08:00
|
|
|
}
|
|
|
|
|
}
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-12-06 12:30:03 -08:00
|
|
|
p->loop_stack_depth--;
|
|
|
|
|
|
2007-06-21 10:22:28 +08:00
|
|
|
return insn;
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-05 15:03:07 +02:00
|
|
|
/* FORWARD JUMPS:
|
|
|
|
|
*/
|
|
|
|
|
void brw_land_fwd_jump(struct brw_compile *p, int jmp_insn_idx)
|
|
|
|
|
{
|
|
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *jmp_insn = &p->store[jmp_insn_idx];
|
2014-06-05 15:03:07 +02:00
|
|
|
unsigned jmpi = 1;
|
|
|
|
|
|
|
|
|
|
if (brw->gen >= 5)
|
|
|
|
|
jmpi = 2;
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_opcode(brw, jmp_insn) == BRW_OPCODE_JMPI);
|
|
|
|
|
assert(brw_inst_src1_reg_file(brw, jmp_insn) == BRW_IMMEDIATE_VALUE);
|
2014-06-05 15:03:07 +02:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_gen4_jump_count(brw, jmp_insn,
|
|
|
|
|
jmpi * (p->nr_insn - jmp_insn_idx - 1));
|
2014-06-05 15:03:07 +02:00
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
/* To integrate with the above, it makes sense that the comparison
|
|
|
|
|
* instruction should populate the flag register. It might be simpler
|
|
|
|
|
* just to use the flag reg for most WM tasks?
|
|
|
|
|
*/
|
|
|
|
|
void brw_CMP(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned conditional,
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg src0,
|
|
|
|
|
struct brw_reg src1)
|
|
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_CMP);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-30 07:51:51 -07:00
|
|
|
if (brw->gen >= 8) {
|
|
|
|
|
/* The CMP instruction appears to behave erratically for floating point
|
|
|
|
|
* sources unless the destination type is also float. Overriding it to
|
|
|
|
|
* match src0 makes it work in all cases.
|
|
|
|
|
*/
|
|
|
|
|
dest.type = src0.type;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_cond_modifier(brw, insn, conditional);
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, src1);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-04-15 14:59:09 -07:00
|
|
|
/* Item WaCMPInstNullDstForcesThreadSwitch in the Haswell Bspec workarounds
|
|
|
|
|
* page says:
|
|
|
|
|
* "Any CMP instruction with a null destination must use a {switch}."
|
2013-04-21 00:18:11 -07:00
|
|
|
*
|
|
|
|
|
* It also applies to other Gen7 platforms (IVB, BYT) even though it isn't
|
|
|
|
|
* mentioned on their work-arounds pages.
|
2013-04-15 14:59:09 -07:00
|
|
|
*/
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen == 7) {
|
2013-04-15 14:59:09 -07:00
|
|
|
if (dest.file == BRW_ARCHITECTURE_REGISTER_FILE &&
|
|
|
|
|
dest.nr == BRW_ARF_NULL) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_thread_control(brw, insn, BRW_THREAD_SWITCH);
|
2013-04-15 14:59:09 -07:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* Helpers for the various SEND message types:
|
|
|
|
|
*/
|
|
|
|
|
|
2009-03-31 10:49:41 -06:00
|
|
|
/** Extended math function, float[8].
|
2006-08-09 19:14:05 +00:00
|
|
|
*/
|
2014-06-07 02:12:46 -07:00
|
|
|
void gen4_math(struct brw_compile *p,
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned function,
|
|
|
|
|
unsigned msg_reg_nr,
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg src,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned data_type,
|
|
|
|
|
unsigned precision )
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2014-06-07 01:56:12 -07:00
|
|
|
assert(brw->gen < 6);
|
2010-02-24 09:16:19 -08:00
|
|
|
|
2014-06-07 01:56:12 -07:00
|
|
|
/* Example code doesn't set predicate_control for send
|
|
|
|
|
* instructions.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_pred_control(brw, insn, 0);
|
|
|
|
|
brw_inst_set_base_mrf(brw, insn, msg_reg_nr);
|
2011-09-28 17:37:52 -07:00
|
|
|
|
2014-06-07 01:56:12 -07:00
|
|
|
brw_set_dest(p, insn, dest);
|
|
|
|
|
brw_set_src0(p, insn, src);
|
|
|
|
|
brw_set_math_message(p,
|
|
|
|
|
insn,
|
|
|
|
|
function,
|
|
|
|
|
src.type == BRW_REGISTER_TYPE_D,
|
|
|
|
|
precision,
|
|
|
|
|
data_type);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-07 01:56:12 -07:00
|
|
|
void gen6_math(struct brw_compile *p,
|
2010-08-22 01:33:57 -07:00
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned function,
|
2010-08-22 01:33:57 -07:00
|
|
|
struct brw_reg src0,
|
|
|
|
|
struct brw_reg src1)
|
|
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_MATH);
|
2010-08-22 01:33:57 -07:00
|
|
|
|
2014-06-07 01:56:12 -07:00
|
|
|
assert(brw->gen >= 6);
|
|
|
|
|
|
2013-02-11 11:06:13 -08:00
|
|
|
assert(dest.file == BRW_GENERAL_REGISTER_FILE ||
|
2013-07-06 00:36:46 -07:00
|
|
|
(brw->gen >= 7 && dest.file == BRW_MESSAGE_REGISTER_FILE));
|
2014-07-11 15:54:11 -07:00
|
|
|
assert(src0.file == BRW_GENERAL_REGISTER_FILE ||
|
|
|
|
|
(brw->gen >= 8 && src0.file == BRW_IMMEDIATE_VALUE));
|
2010-10-11 13:30:12 -07:00
|
|
|
|
|
|
|
|
assert(dest.hstride == BRW_HORIZONTAL_STRIDE_1);
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen == 6) {
|
2011-10-18 12:24:47 -07:00
|
|
|
assert(src0.hstride == BRW_HORIZONTAL_STRIDE_1);
|
|
|
|
|
assert(src1.hstride == BRW_HORIZONTAL_STRIDE_1);
|
|
|
|
|
}
|
2010-10-11 13:30:12 -07:00
|
|
|
|
2011-09-28 17:37:51 -07:00
|
|
|
if (function == BRW_MATH_FUNCTION_INT_DIV_QUOTIENT ||
|
|
|
|
|
function == BRW_MATH_FUNCTION_INT_DIV_REMAINDER ||
|
|
|
|
|
function == BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER) {
|
|
|
|
|
assert(src0.type != BRW_REGISTER_TYPE_F);
|
|
|
|
|
assert(src1.type != BRW_REGISTER_TYPE_F);
|
2014-07-11 15:54:11 -07:00
|
|
|
assert(src1.file == BRW_GENERAL_REGISTER_FILE ||
|
|
|
|
|
(brw->gen >= 8 && src1.file == BRW_IMMEDIATE_VALUE));
|
2011-09-28 17:37:51 -07:00
|
|
|
} else {
|
2010-10-11 13:30:12 -07:00
|
|
|
assert(src0.type == BRW_REGISTER_TYPE_F);
|
|
|
|
|
assert(src1.type == BRW_REGISTER_TYPE_F);
|
2014-06-07 01:56:12 -07:00
|
|
|
if (function == BRW_MATH_FUNCTION_POW) {
|
2014-07-11 15:54:11 -07:00
|
|
|
assert(src1.file == BRW_GENERAL_REGISTER_FILE ||
|
|
|
|
|
(brw->gen >= 8 && src1.file == BRW_IMMEDIATE_VALUE));
|
2014-06-07 01:56:12 -07:00
|
|
|
} else {
|
|
|
|
|
assert(src1.file == BRW_ARCHITECTURE_REGISTER_FILE &&
|
|
|
|
|
src1.nr == BRW_ARF_NULL);
|
|
|
|
|
}
|
2010-10-11 13:30:12 -07:00
|
|
|
}
|
|
|
|
|
|
2011-10-18 12:24:47 -07:00
|
|
|
/* Source modifiers are ignored for extended math instructions on Gen6. */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen == 6) {
|
2011-10-18 12:24:47 -07:00
|
|
|
assert(!src0.negate);
|
|
|
|
|
assert(!src0.abs);
|
|
|
|
|
assert(!src1.negate);
|
|
|
|
|
assert(!src1.abs);
|
|
|
|
|
}
|
2010-12-07 14:50:50 -08:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_math_function(brw, insn, function);
|
2010-08-22 01:33:57 -07:00
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, src1);
|
2010-08-22 01:33:57 -07:00
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2009-03-31 10:49:41 -06:00
|
|
|
/**
|
2010-10-19 09:25:51 -07:00
|
|
|
* Write a block of OWORDs (half a GRF each) from the scratch buffer,
|
|
|
|
|
* using a constant offset per channel.
|
|
|
|
|
*
|
|
|
|
|
* The offset must be aligned to oword size (16 bytes). Used for
|
|
|
|
|
* register spilling.
|
2009-03-31 10:49:41 -06:00
|
|
|
*/
|
2010-10-22 12:57:00 -07:00
|
|
|
void brw_oword_block_write_scratch(struct brw_compile *p,
|
|
|
|
|
struct brw_reg mrf,
|
|
|
|
|
int num_regs,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned offset)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2011-04-14 19:36:28 -07:00
|
|
|
uint32_t msg_control, msg_type;
|
2010-10-19 09:25:51 -07:00
|
|
|
int mlen;
|
|
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6)
|
2011-04-14 19:36:28 -07:00
|
|
|
offset /= 16;
|
|
|
|
|
|
2010-10-21 14:40:49 -07:00
|
|
|
mrf = retype(mrf, BRW_REGISTER_TYPE_UD);
|
|
|
|
|
|
2010-10-19 09:25:51 -07:00
|
|
|
if (num_regs == 1) {
|
|
|
|
|
msg_control = BRW_DATAPORT_OWORD_BLOCK_2_OWORDS;
|
|
|
|
|
mlen = 2;
|
|
|
|
|
} else {
|
|
|
|
|
msg_control = BRW_DATAPORT_OWORD_BLOCK_4_OWORDS;
|
|
|
|
|
mlen = 3;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-21 14:40:49 -07:00
|
|
|
/* Set up the message header. This is g0, with g0.2 filled with
|
|
|
|
|
* the offset. We don't want to leave our offset around in g0 or
|
|
|
|
|
* it'll screw up texture samples, so set it up inside the message
|
|
|
|
|
* reg.
|
|
|
|
|
*/
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
|
|
|
|
brw_push_insn_state(p);
|
2014-05-31 16:57:02 -07:00
|
|
|
brw_set_default_mask_control(p, BRW_MASK_DISABLE);
|
|
|
|
|
brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2010-10-21 14:40:49 -07:00
|
|
|
brw_MOV(p, mrf, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD));
|
|
|
|
|
|
2009-03-31 10:49:41 -06:00
|
|
|
/* set message header global offset field (reg 0, element 2) */
|
2006-08-09 19:14:05 +00:00
|
|
|
brw_MOV(p,
|
2010-10-21 14:40:49 -07:00
|
|
|
retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE,
|
|
|
|
|
mrf.nr,
|
|
|
|
|
2), BRW_REGISTER_TYPE_UD),
|
|
|
|
|
brw_imm_ud(offset));
|
2009-06-26 20:38:07 +02:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
brw_pop_insn_state(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2010-07-21 13:07:12 -07:00
|
|
|
struct brw_reg dest;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
2010-07-21 13:07:12 -07:00
|
|
|
int send_commit_msg;
|
2010-10-19 09:25:51 -07:00
|
|
|
struct brw_reg src_header = retype(brw_vec8_grf(0, 0),
|
|
|
|
|
BRW_REGISTER_TYPE_UW);
|
2010-07-21 13:07:12 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_qtr_control(brw, insn) != BRW_COMPRESSION_NONE) {
|
|
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2010-10-19 09:25:51 -07:00
|
|
|
src_header = vec16(src_header);
|
|
|
|
|
}
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_pred_control(brw, insn) == BRW_PREDICATE_NONE);
|
|
|
|
|
if (brw->gen < 6)
|
|
|
|
|
brw_inst_set_base_mrf(brw, insn, mrf.nr);
|
2010-07-21 13:07:12 -07:00
|
|
|
|
|
|
|
|
/* Until gen6, writes followed by reads from the same location
|
|
|
|
|
* are not guaranteed to be ordered unless write_commit is set.
|
|
|
|
|
* If set, then a no-op write is issued to the destination
|
|
|
|
|
* register to set a dependency, and a read from the destination
|
|
|
|
|
* can be used to ensure the ordering.
|
|
|
|
|
*
|
|
|
|
|
* For gen6, only writes between different threads need ordering
|
|
|
|
|
* protection. Our use of DP writes is all about register
|
|
|
|
|
* spilling within a thread.
|
|
|
|
|
*/
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6) {
|
2010-07-21 15:54:53 -07:00
|
|
|
dest = retype(vec16(brw_null_reg()), BRW_REGISTER_TYPE_UW);
|
2010-07-21 13:07:12 -07:00
|
|
|
send_commit_msg = 0;
|
|
|
|
|
} else {
|
2010-10-19 09:25:51 -07:00
|
|
|
dest = src_header;
|
2010-07-21 13:07:12 -07:00
|
|
|
send_commit_msg = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6) {
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, mrf);
|
2011-04-14 19:36:28 -07:00
|
|
|
} else {
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_null_reg());
|
2011-04-14 19:36:28 -07:00
|
|
|
}
|
|
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6)
|
2011-04-14 19:36:28 -07:00
|
|
|
msg_type = GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE;
|
|
|
|
|
else
|
|
|
|
|
msg_type = BRW_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE;
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_dp_write_message(p,
|
2009-07-13 10:48:43 +08:00
|
|
|
insn,
|
2009-03-31 10:49:41 -06:00
|
|
|
255, /* binding table index (255=stateless) */
|
2010-10-19 09:25:51 -07:00
|
|
|
msg_control,
|
2011-04-14 19:36:28 -07:00
|
|
|
msg_type,
|
2010-10-19 09:25:51 -07:00
|
|
|
mlen,
|
2011-10-07 12:26:50 -07:00
|
|
|
true, /* header_present */
|
2011-10-07 22:26:40 -07:00
|
|
|
0, /* not a render target */
|
2010-07-21 13:07:12 -07:00
|
|
|
send_commit_msg, /* response_length */
|
|
|
|
|
0, /* eot */
|
|
|
|
|
send_commit_msg);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-03-31 10:49:41 -06:00
|
|
|
/**
|
2010-10-19 09:25:51 -07:00
|
|
|
* Read a block of owords (half a GRF each) from the scratch buffer
|
|
|
|
|
* using a constant index per channel.
|
|
|
|
|
*
|
|
|
|
|
* Offset must be aligned to oword size (16 bytes). Used for register
|
|
|
|
|
* spilling.
|
2009-03-31 10:49:41 -06:00
|
|
|
*/
|
2010-10-19 09:25:51 -07:00
|
|
|
void
|
2010-10-22 12:57:00 -07:00
|
|
|
brw_oword_block_read_scratch(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
|
|
|
|
struct brw_reg mrf,
|
|
|
|
|
int num_regs,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned offset)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2010-10-19 09:25:51 -07:00
|
|
|
uint32_t msg_control;
|
|
|
|
|
int rlen;
|
|
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6)
|
2011-04-14 19:36:28 -07:00
|
|
|
offset /= 16;
|
|
|
|
|
|
2010-10-21 14:40:49 -07:00
|
|
|
mrf = retype(mrf, BRW_REGISTER_TYPE_UD);
|
2010-10-19 09:25:51 -07:00
|
|
|
dest = retype(dest, BRW_REGISTER_TYPE_UW);
|
|
|
|
|
|
|
|
|
|
if (num_regs == 1) {
|
|
|
|
|
msg_control = BRW_DATAPORT_OWORD_BLOCK_2_OWORDS;
|
|
|
|
|
rlen = 1;
|
|
|
|
|
} else {
|
|
|
|
|
msg_control = BRW_DATAPORT_OWORD_BLOCK_4_OWORDS;
|
|
|
|
|
rlen = 2;
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
|
|
|
|
brw_push_insn_state(p);
|
2014-05-31 16:57:02 -07:00
|
|
|
brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_set_default_mask_control(p, BRW_MASK_DISABLE);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2010-10-21 14:40:49 -07:00
|
|
|
brw_MOV(p, mrf, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD));
|
|
|
|
|
|
2009-03-31 10:49:41 -06:00
|
|
|
/* set message header global offset field (reg 0, element 2) */
|
2006-08-09 19:14:05 +00:00
|
|
|
brw_MOV(p,
|
2010-10-21 14:40:49 -07:00
|
|
|
retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE,
|
|
|
|
|
mrf.nr,
|
|
|
|
|
2), BRW_REGISTER_TYPE_UD),
|
|
|
|
|
brw_imm_ud(offset));
|
2009-06-26 20:38:07 +02:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
brw_pop_insn_state(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
2010-10-19 09:25:51 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_pred_control(brw, insn) == 0);
|
|
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2010-10-19 09:25:51 -07:00
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest); /* UW? */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6) {
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, mrf);
|
2011-04-14 19:36:28 -07:00
|
|
|
} else {
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_null_reg());
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_base_mrf(brw, insn, mrf.nr);
|
2011-04-14 19:36:28 -07:00
|
|
|
}
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_dp_read_message(p,
|
2009-07-13 10:48:43 +08:00
|
|
|
insn,
|
2009-03-31 10:49:41 -06:00
|
|
|
255, /* binding table index (255=stateless) */
|
2010-10-19 09:25:51 -07:00
|
|
|
msg_control,
|
2006-08-09 19:14:05 +00:00
|
|
|
BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ, /* msg_type */
|
2011-04-14 19:36:28 -07:00
|
|
|
BRW_DATAPORT_READ_TARGET_RENDER_CACHE,
|
2006-08-09 19:14:05 +00:00
|
|
|
1, /* msg_length */
|
2012-11-09 11:17:48 -08:00
|
|
|
true, /* header_present */
|
2010-10-26 13:46:09 -07:00
|
|
|
rlen);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-16 11:51:22 -07:00
|
|
|
void
|
|
|
|
|
gen7_block_read_scratch(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
|
|
|
|
int num_regs,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned offset)
|
2013-10-16 11:51:22 -07:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_pred_control(brw, insn) == BRW_PREDICATE_NONE);
|
2013-10-16 11:51:22 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_set_dest(p, insn, retype(dest, BRW_REGISTER_TYPE_UW));
|
2013-10-16 11:51:22 -07:00
|
|
|
|
|
|
|
|
/* The HW requires that the header is present; this is to get the g0.5
|
|
|
|
|
* scratch offset.
|
|
|
|
|
*/
|
|
|
|
|
brw_set_src0(p, insn, brw_vec8_grf(0, 0));
|
|
|
|
|
|
|
|
|
|
/* According to the docs, offset is "A 12-bit HWord offset into the memory
|
|
|
|
|
* Immediate Memory buffer as specified by binding table 0xFF." An HWORD
|
|
|
|
|
* is 32 bytes, which happens to be the size of a register.
|
|
|
|
|
*/
|
|
|
|
|
offset /= REG_SIZE;
|
|
|
|
|
assert(offset < (1 << 12));
|
2014-06-04 17:08:57 -07:00
|
|
|
|
|
|
|
|
gen7_set_dp_scratch_message(p, insn,
|
|
|
|
|
false, /* scratch read */
|
|
|
|
|
false, /* OWords */
|
|
|
|
|
false, /* invalidate after read */
|
|
|
|
|
num_regs,
|
|
|
|
|
offset,
|
|
|
|
|
1, /* mlen: just g0 */
|
|
|
|
|
num_regs, /* rlen */
|
|
|
|
|
true); /* header present */
|
2013-10-16 11:51:22 -07:00
|
|
|
}
|
|
|
|
|
|
2009-03-31 10:50:55 -06:00
|
|
|
/**
|
|
|
|
|
* Read a float[4] vector from the data port Data Cache (const buffer).
|
2009-04-14 11:08:42 -06:00
|
|
|
* Location (in buffer) should be a multiple of 16.
|
2009-03-31 10:50:55 -06:00
|
|
|
* Used for fetching shader constants.
|
|
|
|
|
*/
|
2010-10-22 12:57:00 -07:00
|
|
|
void brw_oword_block_read(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
|
|
|
|
struct brw_reg mrf,
|
|
|
|
|
uint32_t offset,
|
|
|
|
|
uint32_t bind_table_index)
|
2009-03-31 10:50:55 -06:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2010-10-26 13:17:54 -07:00
|
|
|
|
|
|
|
|
/* On newer hardware, offset is in units of owords. */
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6)
|
2010-10-26 13:17:54 -07:00
|
|
|
offset /= 16;
|
|
|
|
|
|
2010-10-22 12:57:00 -07:00
|
|
|
mrf = retype(mrf, BRW_REGISTER_TYPE_UD);
|
2009-03-31 10:50:55 -06:00
|
|
|
|
2010-10-22 12:57:00 -07:00
|
|
|
brw_push_insn_state(p);
|
2014-05-31 16:57:02 -07:00
|
|
|
brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
|
|
|
|
|
brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
|
|
|
|
|
brw_set_default_mask_control(p, BRW_MASK_DISABLE);
|
2009-03-31 10:50:55 -06:00
|
|
|
|
2010-10-22 12:57:00 -07:00
|
|
|
brw_MOV(p, mrf, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD));
|
2009-03-31 10:50:55 -06:00
|
|
|
|
2010-10-22 12:57:00 -07:00
|
|
|
/* set message header global offset field (reg 0, element 2) */
|
|
|
|
|
brw_MOV(p,
|
|
|
|
|
retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE,
|
|
|
|
|
mrf.nr,
|
|
|
|
|
2), BRW_REGISTER_TYPE_UD),
|
|
|
|
|
brw_imm_ud(offset));
|
2009-03-31 10:50:55 -06:00
|
|
|
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
2010-10-22 12:57:00 -07:00
|
|
|
|
|
|
|
|
/* cast dest to a uword[8] vector */
|
|
|
|
|
dest = retype(vec8(dest), BRW_REGISTER_TYPE_UW);
|
|
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6) {
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, mrf);
|
2010-10-26 13:17:54 -07:00
|
|
|
} else {
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, brw_null_reg());
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_base_mrf(brw, insn, mrf.nr);
|
2010-10-26 13:17:54 -07:00
|
|
|
}
|
2010-10-22 12:57:00 -07:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_dp_read_message(p,
|
2010-10-22 12:57:00 -07:00
|
|
|
insn,
|
|
|
|
|
bind_table_index,
|
|
|
|
|
BRW_DATAPORT_OWORD_BLOCK_1_OWORDLOW,
|
|
|
|
|
BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ,
|
2011-05-13 09:04:09 -07:00
|
|
|
BRW_DATAPORT_READ_TARGET_DATA_CACHE,
|
2010-10-22 12:57:00 -07:00
|
|
|
1, /* msg_length */
|
2012-11-09 11:17:48 -08:00
|
|
|
true, /* header_present */
|
2010-10-26 13:46:09 -07:00
|
|
|
1); /* response_length (1 reg, 2 owords!) */
|
2010-10-22 12:57:00 -07:00
|
|
|
|
|
|
|
|
brw_pop_insn_state(p);
|
2009-03-31 10:50:55 -06:00
|
|
|
}
|
|
|
|
|
|
2010-10-22 12:57:00 -07:00
|
|
|
|
2006-08-09 19:14:05 +00:00
|
|
|
void brw_fb_WRITE(struct brw_compile *p,
|
2010-08-20 15:32:17 -07:00
|
|
|
int dispatch_width,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_reg_nr,
|
2009-02-12 15:40:04 -07:00
|
|
|
struct brw_reg src0,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_control,
|
|
|
|
|
unsigned binding_table_index,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool eot,
|
|
|
|
|
bool header_present)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_type;
|
2011-03-14 10:51:19 -07:00
|
|
|
struct brw_reg dest;
|
|
|
|
|
|
|
|
|
|
if (dispatch_width == 16)
|
|
|
|
|
dest = retype(vec16(brw_null_reg()), BRW_REGISTER_TYPE_UW);
|
|
|
|
|
else
|
|
|
|
|
dest = retype(vec8(brw_null_reg()), BRW_REGISTER_TYPE_UW);
|
2010-08-20 15:02:19 -07:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6) {
|
2010-10-26 09:35:34 -07:00
|
|
|
insn = next_insn(p, BRW_OPCODE_SENDC);
|
|
|
|
|
} else {
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_SEND);
|
|
|
|
|
}
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2010-08-20 15:02:19 -07:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen >= 6) {
|
2011-10-07 11:59:06 -07:00
|
|
|
/* headerless version, just submit color payload */
|
|
|
|
|
src0 = brw_message_reg(msg_reg_nr);
|
2010-08-20 15:02:19 -07:00
|
|
|
|
2011-10-07 11:59:06 -07:00
|
|
|
msg_type = GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE;
|
2010-08-20 15:02:19 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_base_mrf(brw, insn, msg_reg_nr);
|
2010-08-20 15:02:19 -07:00
|
|
|
|
2010-08-20 15:32:17 -07:00
|
|
|
msg_type = BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE;
|
2010-08-20 15:02:19 -07:00
|
|
|
}
|
|
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_dp_write_message(p,
|
2009-07-13 10:48:43 +08:00
|
|
|
insn,
|
2006-08-09 19:14:05 +00:00
|
|
|
binding_table_index,
|
2010-08-20 15:02:19 -07:00
|
|
|
msg_control,
|
|
|
|
|
msg_type,
|
2006-08-09 19:14:05 +00:00
|
|
|
msg_length,
|
2010-10-04 15:07:17 -07:00
|
|
|
header_present,
|
2012-02-18 21:29:29 -08:00
|
|
|
eot, /* last render target write */
|
2010-08-20 15:02:19 -07:00
|
|
|
response_length,
|
2010-07-21 13:07:12 -07:00
|
|
|
eot,
|
|
|
|
|
0 /* send_commit_msg */);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-03-24 18:05:53 -06:00
|
|
|
/**
|
|
|
|
|
* Texture sample instruction.
|
|
|
|
|
* Note: the msg_type plus msg_length values determine exactly what kind
|
|
|
|
|
* of sampling operation is performed. See volume 4, page 161 of docs.
|
|
|
|
|
*/
|
2006-08-09 19:14:05 +00:00
|
|
|
void brw_SAMPLE(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_reg_nr,
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg src0,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned binding_table_index,
|
|
|
|
|
unsigned sampler,
|
|
|
|
|
unsigned msg_type,
|
|
|
|
|
unsigned response_length,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned header_present,
|
|
|
|
|
unsigned simd_mode,
|
|
|
|
|
unsigned return_format)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2010-09-17 14:17:06 +08:00
|
|
|
|
i965/fs: Convert gen7 to using GRFs for texture messages.
Looking at Lightsmark's shaders, the way we used MRFs (or in gen7's
case, GRFs) was bad in a couple of ways. One was that it prevented
compute-to-MRF for the common case of a texcoord that gets used
exactly once, but where the texcoord setup all gets emitted before the
texture calls (such as when it's a bare fragment shader input, which
gets interpolated before processing main()). Another was that it
introduced a bunch of dependencies that constrained scheduling, and
forced waits for texture operations to be done before they are
required. For example, we can now move the compute-to-MRF
interpolation for the second texture send down after the first send.
The downside is that this generally prevents
remove_duplicate_mrf_writes() from doing anything, whereas previously
it avoided work for the case of sampling from the same texcoord twice.
However, I suspect that most of the win that originally justified that
code was in avoiding the WAR stall on the first send, which this patch
also avoids, rather than the small cost of the extra instruction. We
see instruction count regressions in shaders in unigine, yofrankie,
savage2, hon, and gstreamer.
Improves GLB2.7 performance by 0.633628% +/- 0.491809% (n=121/125, avg of
~66fps, outliers below 61 dropped).
Improves openarena performance by 1.01092% +/- 0.66897% (n=425).
No significant difference on Lightsmark (n=44).
v2: Squash in the fix for register unspilling for send-from-GRF, fixing a
segfault in lightsmark.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Acked-by: Matt Turner <mattst88@gmail.com>
2013-10-09 17:17:59 -07:00
|
|
|
if (msg_reg_nr != -1)
|
|
|
|
|
gen6_resolve_implied_move(p, &src0, msg_reg_nr);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-02-05 16:21:07 -08:00
|
|
|
insn = next_insn(p, BRW_OPCODE_SEND);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_pred_control(brw, insn, BRW_PREDICATE_NONE); /* XXX */
|
2013-09-27 15:23:56 +08:00
|
|
|
|
|
|
|
|
/* From the 965 PRM (volume 4, part 1, section 14.2.41):
|
|
|
|
|
*
|
|
|
|
|
* "Instruction compression is not allowed for this instruction (that
|
|
|
|
|
* is, send). The hardware behavior is undefined if this instruction is
|
|
|
|
|
* set as compressed. However, compress control can be set to "SecHalf"
|
|
|
|
|
* to affect the EMask generation."
|
|
|
|
|
*
|
|
|
|
|
* No similar wording is found in later PRMs, but there are examples
|
|
|
|
|
* utilizing send with SecHalf. More importantly, SIMD8 sampler messages
|
|
|
|
|
* are allowed in SIMD16 mode and they could not work without SecHalf. For
|
|
|
|
|
* these reasons, we allow BRW_COMPRESSION_2NDHALF here.
|
|
|
|
|
*/
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_qtr_control(brw, insn) != BRW_COMPRESSION_2NDHALF)
|
|
|
|
|
brw_inst_set_qtr_control(brw, insn, BRW_COMPRESSION_NONE);
|
2013-09-27 15:23:56 +08:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_base_mrf(brw, insn, msg_reg_nr);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-02-05 16:21:07 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
|
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_sampler_message(p, insn,
|
|
|
|
|
binding_table_index,
|
|
|
|
|
sampler,
|
|
|
|
|
msg_type,
|
|
|
|
|
response_length,
|
|
|
|
|
msg_length,
|
|
|
|
|
header_present,
|
|
|
|
|
simd_mode,
|
|
|
|
|
return_format);
|
2006-08-09 19:14:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* All these variables are pretty confusing - we might be better off
|
|
|
|
|
* using bitmasks and macros for this, in the old style. Or perhaps
|
|
|
|
|
* just having the caller instantiate the fields in dword3 itself.
|
|
|
|
|
*/
|
|
|
|
|
void brw_urb_WRITE(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_reg_nr,
|
2006-08-09 19:14:05 +00:00
|
|
|
struct brw_reg src0,
|
i965: Allow C++ type safety in the use of enum brw_urb_write_flags.
(From a suggestion by Francisco Jerez)
If an enum represents a bitfield of flags, e.g.:
enum E {
A = 1,
B = 2,
C = 4,
D = 8,
};
then C++ normally prohibits statements like this:
enum E x = A | B;
because A and B are implicitly converted to ints before OR-ing them,
and an int can't be stored in an enum without a type cast. C, on the
other hand, allows an int to be implicitly converted to an enum
without casting.
In the past we've dealt with this situation by storing flag bitfields
as ints. This avoids ugly casting at the expense of some type safety
that C++ would normally have offered (e.g. we get no warning if we
accidentally use the wrong enum type).
However, we can get the best of both worlds if we override the |
operator. The ugly casting is confined to the operator overload, and
we still get the benefit of C++ making sure we don't use the wrong
enum type.
v2: Remove unnecessary comment and unnecessary use of "enum" keyword.
Use static_cast.
Reviewed-by: Chad Versace <chad.versace@linux.intel.com>
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
2013-08-23 13:19:19 -07:00
|
|
|
enum brw_urb_write_flags flags,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length,
|
|
|
|
|
unsigned offset,
|
|
|
|
|
unsigned swizzle)
|
2006-08-09 19:14:05 +00:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2010-02-25 18:35:08 -08:00
|
|
|
|
2011-03-16 14:09:17 -07:00
|
|
|
gen6_resolve_implied_move(p, &src0, msg_reg_nr);
|
2010-02-25 18:35:08 -08:00
|
|
|
|
2014-06-30 07:26:30 -07:00
|
|
|
if (brw->gen >= 7 && !(flags & BRW_URB_WRITE_USE_CHANNEL_MASKS)) {
|
2011-04-26 17:24:38 -07:00
|
|
|
/* Enable Channel Masks in the URB_WRITE_HWORD message header */
|
2011-08-18 02:15:56 -07:00
|
|
|
brw_push_insn_state(p);
|
2014-05-31 16:57:02 -07:00
|
|
|
brw_set_default_access_mode(p, BRW_ALIGN_1);
|
|
|
|
|
brw_set_default_mask_control(p, BRW_MASK_DISABLE);
|
2014-08-14 12:22:16 -07:00
|
|
|
brw_OR(p, retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE, msg_reg_nr, 5),
|
|
|
|
|
BRW_REGISTER_TYPE_UD),
|
|
|
|
|
retype(brw_vec1_grf(0, 5), BRW_REGISTER_TYPE_UD),
|
|
|
|
|
brw_imm_ud(0xff00));
|
2011-08-18 02:15:56 -07:00
|
|
|
brw_pop_insn_state(p);
|
2011-04-26 17:24:38 -07:00
|
|
|
}
|
|
|
|
|
|
2010-02-25 18:35:08 -08:00
|
|
|
insn = next_insn(p, BRW_OPCODE_SEND);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2009-06-30 17:08:40 -06:00
|
|
|
assert(msg_length < BRW_MAX_MRF);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0));
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_base_mrf(brw, insn, msg_reg_nr);
|
2006-08-09 19:14:05 +00:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_urb_message(p,
|
2009-07-13 10:48:43 +08:00
|
|
|
insn,
|
2013-08-10 21:13:33 -07:00
|
|
|
flags,
|
2006-08-09 19:14:05 +00:00
|
|
|
msg_length,
|
2013-11-25 15:39:03 -08:00
|
|
|
response_length,
|
2006-08-09 19:14:05 +00:00
|
|
|
offset,
|
|
|
|
|
swizzle);
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-01 11:46:46 -08:00
|
|
|
static int
|
2014-05-17 12:53:56 -07:00
|
|
|
brw_find_next_block_end(struct brw_compile *p, int start_offset)
|
2010-12-01 11:46:46 -08:00
|
|
|
{
|
2014-05-17 12:53:56 -07:00
|
|
|
int offset;
|
2012-02-03 12:05:05 +01:00
|
|
|
void *store = p->store;
|
2014-06-07 21:15:59 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2014-06-07 21:15:59 -07:00
|
|
|
for (offset = next_offset(brw, store, start_offset);
|
|
|
|
|
offset < p->next_insn_offset;
|
|
|
|
|
offset = next_offset(brw, store, offset)) {
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = store + offset;
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
switch (brw_inst_opcode(brw, insn)) {
|
2010-12-01 11:46:46 -08:00
|
|
|
case BRW_OPCODE_ENDIF:
|
|
|
|
|
case BRW_OPCODE_ELSE:
|
|
|
|
|
case BRW_OPCODE_WHILE:
|
2012-12-12 12:47:50 -08:00
|
|
|
case BRW_OPCODE_HALT:
|
2014-05-17 12:53:56 -07:00
|
|
|
return offset;
|
2010-12-01 11:46:46 -08:00
|
|
|
}
|
|
|
|
|
}
|
2012-12-06 10:15:08 -08:00
|
|
|
|
|
|
|
|
return 0;
|
2010-12-01 11:46:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* There is no DO instruction on gen6, so to find the end of the loop
|
|
|
|
|
* we have to see if the loop is jumping back before our start
|
|
|
|
|
* instruction.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2014-05-17 12:53:56 -07:00
|
|
|
brw_find_loop_end(struct brw_compile *p, int start_offset)
|
2010-12-01 11:46:46 -08:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-05-17 12:53:56 -07:00
|
|
|
int offset;
|
2014-06-30 08:00:25 -07:00
|
|
|
int scale = 16 / brw_jump_scale(brw);
|
2012-02-03 12:05:05 +01:00
|
|
|
void *store = p->store;
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2014-06-30 08:06:43 -07:00
|
|
|
assert(brw->gen >= 6);
|
|
|
|
|
|
2012-02-03 12:05:05 +01:00
|
|
|
/* Always start after the instruction (such as a WHILE) we're trying to fix
|
|
|
|
|
* up.
|
|
|
|
|
*/
|
2014-06-07 21:15:59 -07:00
|
|
|
for (offset = next_offset(brw, store, start_offset);
|
|
|
|
|
offset < p->next_insn_offset;
|
|
|
|
|
offset = next_offset(brw, store, offset)) {
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = store + offset;
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_opcode(brw, insn) == BRW_OPCODE_WHILE) {
|
|
|
|
|
int jip = brw->gen == 6 ? brw_inst_gen6_jump_count(brw, insn)
|
|
|
|
|
: brw_inst_jip(brw, insn);
|
2014-05-17 12:53:56 -07:00
|
|
|
if (offset + jip * scale <= start_offset)
|
|
|
|
|
return offset;
|
2010-12-01 11:46:46 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(!"not reached");
|
2014-05-17 12:53:56 -07:00
|
|
|
return start_offset;
|
2010-12-01 11:46:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* After program generation, go back and update the UIP and JIP of
|
2012-12-06 10:15:08 -08:00
|
|
|
* BREAK, CONT, and HALT instructions to their correct locations.
|
2010-12-01 11:46:46 -08:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
brw_set_uip_jip(struct brw_compile *p)
|
|
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-05-17 12:53:56 -07:00
|
|
|
int offset;
|
2014-06-30 08:00:25 -07:00
|
|
|
int br = brw_jump_scale(brw);
|
|
|
|
|
int scale = 16 / br;
|
2012-02-03 12:05:05 +01:00
|
|
|
void *store = p->store;
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6)
|
2010-12-01 11:46:46 -08:00
|
|
|
return;
|
|
|
|
|
|
2014-05-17 12:53:56 -07:00
|
|
|
for (offset = 0; offset < p->next_insn_offset;
|
2014-06-07 21:15:59 -07:00
|
|
|
offset = next_offset(brw, store, offset)) {
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = store + offset;
|
2012-02-03 12:05:05 +01:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_cmpt_control(brw, insn)) {
|
2012-02-03 12:05:05 +01:00
|
|
|
/* Fixups for compacted BREAK/CONTINUE not supported yet. */
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_opcode(brw, insn) != BRW_OPCODE_BREAK &&
|
|
|
|
|
brw_inst_opcode(brw, insn) != BRW_OPCODE_CONTINUE &&
|
|
|
|
|
brw_inst_opcode(brw, insn) != BRW_OPCODE_HALT);
|
2012-02-03 12:05:05 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2010-12-01 11:46:46 -08:00
|
|
|
|
2014-05-17 12:53:56 -07:00
|
|
|
int block_end_offset = brw_find_next_block_end(p, offset);
|
2014-06-04 17:08:57 -07:00
|
|
|
switch (brw_inst_opcode(brw, insn)) {
|
2010-12-01 11:46:46 -08:00
|
|
|
case BRW_OPCODE_BREAK:
|
2014-05-17 12:53:56 -07:00
|
|
|
assert(block_end_offset != 0);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, (block_end_offset - offset) / scale);
|
2011-04-30 01:17:52 -07:00
|
|
|
/* Gen7 UIP points to WHILE; Gen6 points just after it */
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_uip(brw, insn,
|
2014-05-17 12:53:56 -07:00
|
|
|
(brw_find_loop_end(p, offset) - offset +
|
2014-06-04 17:08:57 -07:00
|
|
|
(brw->gen == 6 ? 16 : 0)) / scale);
|
2010-12-01 11:46:46 -08:00
|
|
|
break;
|
|
|
|
|
case BRW_OPCODE_CONTINUE:
|
2014-05-17 12:53:56 -07:00
|
|
|
assert(block_end_offset != 0);
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, (block_end_offset - offset) / scale);
|
|
|
|
|
brw_inst_set_uip(brw, insn,
|
|
|
|
|
(brw_find_loop_end(p, offset) - offset) / scale);
|
2011-04-30 01:30:55 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_uip(brw, insn) != 0);
|
|
|
|
|
assert(brw_inst_jip(brw, insn) != 0);
|
2013-01-01 17:02:38 -08:00
|
|
|
break;
|
i965: Jump to the end of the next outer conditional block on ENDIFs.
From the Ivybridge PRM, Volume 4, Part 3, section 6.24 (page 172):
"The endif instruction is also used to hop out of nested conditionals by
jumping to the end of the next outer conditional block when all
channels are disabled."
Also:
"Pseudocode:
Evaluate(WrEn);
if ( WrEn == 0 ) { // all channels false
Jump(IP + JIP);
}"
First, ENDIF re-enables any channels that were disabled because they
didn't match the conditional. If any channels are active, it proceeds
to the next instruction (IP + 16). However, if they're all disabled,
there's no point in walking through all of the instructions that have no
effect---it can jump to the next instruction that might re-enable some
channels (an ELSE, ENDIF, or WHILE).
Previously, we always set JIP on ENDIF instructions to 2 (which is
measured in 8-byte units). This made it do Jump(IP + 16), which just
meant it would go to the next instruction even if all channels were off.
It turns out that walking over instructions while all the channels are
disabled like this is worse than just instruction dispatch overhead: if
there are texturing messages, it still costs a couple hundred cycles to
not-actually-read from the texture results.
This patch finds the next instruction that could re-enable channels and
sets JIP accordingly.
Reviewed-by: Eric Anholt <eric@anholt.net>
2012-12-12 02:20:05 -08:00
|
|
|
|
|
|
|
|
case BRW_OPCODE_ENDIF:
|
2014-05-17 12:53:56 -07:00
|
|
|
if (block_end_offset == 0)
|
2014-06-30 08:00:25 -07:00
|
|
|
brw_inst_set_jip(brw, insn, 1 * br);
|
i965: Jump to the end of the next outer conditional block on ENDIFs.
From the Ivybridge PRM, Volume 4, Part 3, section 6.24 (page 172):
"The endif instruction is also used to hop out of nested conditionals by
jumping to the end of the next outer conditional block when all
channels are disabled."
Also:
"Pseudocode:
Evaluate(WrEn);
if ( WrEn == 0 ) { // all channels false
Jump(IP + JIP);
}"
First, ENDIF re-enables any channels that were disabled because they
didn't match the conditional. If any channels are active, it proceeds
to the next instruction (IP + 16). However, if they're all disabled,
there's no point in walking through all of the instructions that have no
effect---it can jump to the next instruction that might re-enable some
channels (an ELSE, ENDIF, or WHILE).
Previously, we always set JIP on ENDIF instructions to 2 (which is
measured in 8-byte units). This made it do Jump(IP + 16), which just
meant it would go to the next instruction even if all channels were off.
It turns out that walking over instructions while all the channels are
disabled like this is worse than just instruction dispatch overhead: if
there are texturing messages, it still costs a couple hundred cycles to
not-actually-read from the texture results.
This patch finds the next instruction that could re-enable channels and
sets JIP accordingly.
Reviewed-by: Eric Anholt <eric@anholt.net>
2012-12-12 02:20:05 -08:00
|
|
|
else
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, (block_end_offset - offset) / scale);
|
2010-12-01 11:46:46 -08:00
|
|
|
break;
|
i965: Jump to the end of the next outer conditional block on ENDIFs.
From the Ivybridge PRM, Volume 4, Part 3, section 6.24 (page 172):
"The endif instruction is also used to hop out of nested conditionals by
jumping to the end of the next outer conditional block when all
channels are disabled."
Also:
"Pseudocode:
Evaluate(WrEn);
if ( WrEn == 0 ) { // all channels false
Jump(IP + JIP);
}"
First, ENDIF re-enables any channels that were disabled because they
didn't match the conditional. If any channels are active, it proceeds
to the next instruction (IP + 16). However, if they're all disabled,
there's no point in walking through all of the instructions that have no
effect---it can jump to the next instruction that might re-enable some
channels (an ELSE, ENDIF, or WHILE).
Previously, we always set JIP on ENDIF instructions to 2 (which is
measured in 8-byte units). This made it do Jump(IP + 16), which just
meant it would go to the next instruction even if all channels were off.
It turns out that walking over instructions while all the channels are
disabled like this is worse than just instruction dispatch overhead: if
there are texturing messages, it still costs a couple hundred cycles to
not-actually-read from the texture results.
This patch finds the next instruction that could re-enable channels and
sets JIP accordingly.
Reviewed-by: Eric Anholt <eric@anholt.net>
2012-12-12 02:20:05 -08:00
|
|
|
|
2012-12-06 10:15:08 -08:00
|
|
|
case BRW_OPCODE_HALT:
|
|
|
|
|
/* From the Sandy Bridge PRM (volume 4, part 2, section 8.3.19):
|
|
|
|
|
*
|
|
|
|
|
* "In case of the halt instruction not inside any conditional
|
|
|
|
|
* code block, the value of <JIP> and <UIP> should be the
|
|
|
|
|
* same. In case of the halt instruction inside conditional code
|
|
|
|
|
* block, the <UIP> should be the end of the program, and the
|
|
|
|
|
* <JIP> should be end of the most inner conditional code block."
|
|
|
|
|
*
|
|
|
|
|
* The uip will have already been set by whoever set up the
|
|
|
|
|
* instruction.
|
|
|
|
|
*/
|
2014-05-17 12:53:56 -07:00
|
|
|
if (block_end_offset == 0) {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, brw_inst_uip(brw, insn));
|
2012-12-06 10:15:08 -08:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_jip(brw, insn, (block_end_offset - offset) / scale);
|
2012-12-06 10:15:08 -08:00
|
|
|
}
|
2014-06-04 17:08:57 -07:00
|
|
|
assert(brw_inst_uip(brw, insn) != 0);
|
|
|
|
|
assert(brw_inst_jip(brw, insn) != 0);
|
2012-12-06 10:15:08 -08:00
|
|
|
break;
|
2010-12-01 11:46:46 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-13 10:48:43 +08:00
|
|
|
void brw_ff_sync(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_reg_nr,
|
2009-07-13 10:48:43 +08:00
|
|
|
struct brw_reg src0,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool allocate,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned response_length,
|
2011-10-07 12:26:50 -07:00
|
|
|
bool eot)
|
2009-07-13 10:48:43 +08:00
|
|
|
{
|
2013-07-06 00:36:46 -07:00
|
|
|
struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
2009-07-13 10:48:43 +08:00
|
|
|
|
2011-03-16 14:09:17 -07:00
|
|
|
gen6_resolve_implied_move(p, &src0, msg_reg_nr);
|
2010-09-17 14:23:48 +08:00
|
|
|
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_SEND);
|
2010-12-03 11:49:29 -08:00
|
|
|
brw_set_dest(p, insn, dest);
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0));
|
2009-07-13 10:48:43 +08:00
|
|
|
|
2013-07-06 00:36:46 -07:00
|
|
|
if (brw->gen < 6)
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_base_mrf(brw, insn, msg_reg_nr);
|
2009-07-13 10:48:43 +08:00
|
|
|
|
2011-05-10 16:51:12 -07:00
|
|
|
brw_set_ff_sync_message(p,
|
2010-05-13 22:15:34 -07:00
|
|
|
insn,
|
|
|
|
|
allocate,
|
|
|
|
|
response_length,
|
|
|
|
|
eot);
|
2009-07-13 10:48:43 +08:00
|
|
|
}
|
i965 gen6: Initial implementation of transform feedback.
This patch adds basic transform feedback capability for Gen6 hardware.
This consists of several related pieces of functionality:
(1) In gen6_sol.c, we set up binding table entries for use by
transform feedback. We use one binding table entry per transform
feedback varying (this allows us to avoid doing pointer arithmetic in
the shader, since we can set up the binding table entries with the
appropriate offsets and surface pitches to place each varying at the
correct address).
(2) In brw_context.c, we advertise the hardware capabilities, which
are as follows:
MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 64
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 4
MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 16
OpenGL 3.0 requires these values to be at least 64, 4, and 4,
respectively. The reason we advertise a larger value than required
for MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is that we have already
set aside 64 binding table entries, so we might as well make them all
available in both separate attribs and interleaved modes.
(3) We set aside a single SVBI ("streamed vertex buffer index") for
use by transform feedback. The hardware supports four independent
SVBI's, but we only need one, since vertices are added to all
transform feedback buffers at the same rate. Note: at the moment this
index is reset to 0 only when the driver is initialized. It needs to
be reset to 0 whenever BeginTransformFeedback() is called, and
otherwise preserved.
(4) In brw_gs_emit.c and brw_gs.c, we modify the geometry shader
program to output transform feedback data as a side effect.
(5) In gen6_gs_state.c, we configure the geometry shader stage to
handle the SVBI pointer correctly.
Note: ordering of vertices is not yet correct for triangle strips
(alternate triangles are improperly oriented). This will be addressed
in a future patch.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-11-28 06:55:01 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Emit the SEND instruction necessary to generate stream output data on Gen6
|
|
|
|
|
* (for transform feedback).
|
|
|
|
|
*
|
|
|
|
|
* If send_commit_msg is true, this is the last piece of stream output data
|
|
|
|
|
* from this thread, so send the data as a committed write. According to the
|
|
|
|
|
* Sandy Bridge PRM (volume 2 part 1, section 4.5.1):
|
|
|
|
|
*
|
|
|
|
|
* "Prior to End of Thread with a URB_WRITE, the kernel must ensure all
|
|
|
|
|
* writes are complete by sending the final write as a committed write."
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
brw_svb_write(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned msg_reg_nr,
|
i965 gen6: Initial implementation of transform feedback.
This patch adds basic transform feedback capability for Gen6 hardware.
This consists of several related pieces of functionality:
(1) In gen6_sol.c, we set up binding table entries for use by
transform feedback. We use one binding table entry per transform
feedback varying (this allows us to avoid doing pointer arithmetic in
the shader, since we can set up the binding table entries with the
appropriate offsets and surface pitches to place each varying at the
correct address).
(2) In brw_context.c, we advertise the hardware capabilities, which
are as follows:
MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 64
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 4
MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 16
OpenGL 3.0 requires these values to be at least 64, 4, and 4,
respectively. The reason we advertise a larger value than required
for MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is that we have already
set aside 64 binding table entries, so we might as well make them all
available in both separate attribs and interleaved modes.
(3) We set aside a single SVBI ("streamed vertex buffer index") for
use by transform feedback. The hardware supports four independent
SVBI's, but we only need one, since vertices are added to all
transform feedback buffers at the same rate. Note: at the moment this
index is reset to 0 only when the driver is initialized. It needs to
be reset to 0 whenever BeginTransformFeedback() is called, and
otherwise preserved.
(4) In brw_gs_emit.c and brw_gs.c, we modify the geometry shader
program to output transform feedback data as a side effect.
(5) In gen6_gs_state.c, we configure the geometry shader stage to
handle the SVBI pointer correctly.
Note: ordering of vertices is not yet correct for triangle strips
(alternate triangles are improperly oriented). This will be addressed
in a future patch.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-11-28 06:55:01 -08:00
|
|
|
struct brw_reg src0,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned binding_table_index,
|
i965 gen6: Initial implementation of transform feedback.
This patch adds basic transform feedback capability for Gen6 hardware.
This consists of several related pieces of functionality:
(1) In gen6_sol.c, we set up binding table entries for use by
transform feedback. We use one binding table entry per transform
feedback varying (this allows us to avoid doing pointer arithmetic in
the shader, since we can set up the binding table entries with the
appropriate offsets and surface pitches to place each varying at the
correct address).
(2) In brw_context.c, we advertise the hardware capabilities, which
are as follows:
MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 64
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 4
MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 16
OpenGL 3.0 requires these values to be at least 64, 4, and 4,
respectively. The reason we advertise a larger value than required
for MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is that we have already
set aside 64 binding table entries, so we might as well make them all
available in both separate attribs and interleaved modes.
(3) We set aside a single SVBI ("streamed vertex buffer index") for
use by transform feedback. The hardware supports four independent
SVBI's, but we only need one, since vertices are added to all
transform feedback buffers at the same rate. Note: at the moment this
index is reset to 0 only when the driver is initialized. It needs to
be reset to 0 whenever BeginTransformFeedback() is called, and
otherwise preserved.
(4) In brw_gs_emit.c and brw_gs.c, we modify the geometry shader
program to output transform feedback data as a side effect.
(5) In gen6_gs_state.c, we configure the geometry shader stage to
handle the SVBI pointer correctly.
Note: ordering of vertices is not yet correct for triangle strips
(alternate triangles are improperly oriented). This will be addressed
in a future patch.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-11-28 06:55:01 -08:00
|
|
|
bool send_commit_msg)
|
|
|
|
|
{
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn;
|
i965 gen6: Initial implementation of transform feedback.
This patch adds basic transform feedback capability for Gen6 hardware.
This consists of several related pieces of functionality:
(1) In gen6_sol.c, we set up binding table entries for use by
transform feedback. We use one binding table entry per transform
feedback varying (this allows us to avoid doing pointer arithmetic in
the shader, since we can set up the binding table entries with the
appropriate offsets and surface pitches to place each varying at the
correct address).
(2) In brw_context.c, we advertise the hardware capabilities, which
are as follows:
MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 64
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 4
MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 16
OpenGL 3.0 requires these values to be at least 64, 4, and 4,
respectively. The reason we advertise a larger value than required
for MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is that we have already
set aside 64 binding table entries, so we might as well make them all
available in both separate attribs and interleaved modes.
(3) We set aside a single SVBI ("streamed vertex buffer index") for
use by transform feedback. The hardware supports four independent
SVBI's, but we only need one, since vertices are added to all
transform feedback buffers at the same rate. Note: at the moment this
index is reset to 0 only when the driver is initialized. It needs to
be reset to 0 whenever BeginTransformFeedback() is called, and
otherwise preserved.
(4) In brw_gs_emit.c and brw_gs.c, we modify the geometry shader
program to output transform feedback data as a side effect.
(5) In gen6_gs_state.c, we configure the geometry shader stage to
handle the SVBI pointer correctly.
Note: ordering of vertices is not yet correct for triangle strips
(alternate triangles are improperly oriented). This will be addressed
in a future patch.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
2011-11-28 06:55:01 -08:00
|
|
|
|
|
|
|
|
gen6_resolve_implied_move(p, &src0, msg_reg_nr);
|
|
|
|
|
|
|
|
|
|
insn = next_insn(p, BRW_OPCODE_SEND);
|
|
|
|
|
brw_set_dest(p, insn, dest);
|
|
|
|
|
brw_set_src0(p, insn, src0);
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0));
|
|
|
|
|
brw_set_dp_write_message(p, insn,
|
|
|
|
|
binding_table_index,
|
|
|
|
|
0, /* msg_control: ignored */
|
|
|
|
|
GEN6_DATAPORT_WRITE_MESSAGE_STREAMED_VB_WRITE,
|
|
|
|
|
1, /* msg_length */
|
|
|
|
|
true, /* header_present */
|
|
|
|
|
0, /* last_render_target: ignored */
|
|
|
|
|
send_commit_msg, /* response_length */
|
|
|
|
|
0, /* end_of_thread */
|
|
|
|
|
send_commit_msg); /* send_commit_msg */
|
|
|
|
|
}
|
2012-11-27 14:10:52 -08:00
|
|
|
|
2013-09-11 14:01:50 -07:00
|
|
|
static void
|
|
|
|
|
brw_set_dp_untyped_atomic_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned atomic_op,
|
|
|
|
|
unsigned bind_table_index,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length,
|
2013-09-11 14:01:50 -07:00
|
|
|
bool header_present)
|
|
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
|
|
|
|
|
unsigned msg_control =
|
|
|
|
|
atomic_op | /* Atomic Operation Type: BRW_AOP_* */
|
|
|
|
|
(response_length ? 1 << 5 : 0); /* Return data expected */
|
|
|
|
|
|
2014-07-11 15:48:14 -07:00
|
|
|
if (brw->gen >= 8 || brw->is_haswell) {
|
2013-09-11 14:01:50 -07:00
|
|
|
brw_set_message_descriptor(p, insn, HSW_SFID_DATAPORT_DATA_CACHE_1,
|
|
|
|
|
msg_length, response_length,
|
|
|
|
|
header_present, false);
|
|
|
|
|
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_access_mode(brw, insn) == BRW_ALIGN_1) {
|
|
|
|
|
if (brw_inst_exec_size(brw, insn) != BRW_EXECUTE_16)
|
|
|
|
|
msg_control |= 1 << 4; /* SIMD8 mode */
|
2013-09-11 14:01:50 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dp_msg_type(brw, insn,
|
|
|
|
|
HSW_DATAPORT_DC_PORT1_UNTYPED_ATOMIC_OP);
|
2013-09-11 14:01:50 -07:00
|
|
|
} else {
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dp_msg_type(brw, insn,
|
|
|
|
|
HSW_DATAPORT_DC_PORT1_UNTYPED_ATOMIC_OP_SIMD4X2);
|
2013-09-11 14:01:50 -07:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
brw_set_message_descriptor(p, insn, GEN7_SFID_DATAPORT_DATA_CACHE,
|
|
|
|
|
msg_length, response_length,
|
|
|
|
|
header_present, false);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dp_msg_type(brw, insn, GEN7_DATAPORT_DC_UNTYPED_ATOMIC_OP);
|
2013-09-11 14:01:50 -07:00
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
if (brw_inst_exec_size(brw, insn) != BRW_EXECUTE_16)
|
|
|
|
|
msg_control |= 1 << 4; /* SIMD8 mode */
|
2013-09-11 14:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_binding_table_index(brw, insn, bind_table_index);
|
|
|
|
|
brw_inst_set_dp_msg_control(brw, insn, msg_control);
|
2013-09-11 14:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
brw_untyped_atomic(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
|
|
|
|
struct brw_reg mrf,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned atomic_op,
|
|
|
|
|
unsigned bind_table_index,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length) {
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = brw_next_insn(p, BRW_OPCODE_SEND);
|
2013-09-11 14:01:50 -07:00
|
|
|
|
|
|
|
|
brw_set_dest(p, insn, retype(dest, BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_src0(p, insn, retype(mrf, BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_src1(p, insn, brw_imm_d(0));
|
|
|
|
|
brw_set_dp_untyped_atomic_message(
|
|
|
|
|
p, insn, atomic_op, bind_table_index, msg_length, response_length,
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_access_mode(brw, insn) == BRW_ALIGN_1);
|
2013-09-11 14:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
2013-09-11 14:03:13 -07:00
|
|
|
static void
|
|
|
|
|
brw_set_dp_untyped_surface_read_message(struct brw_compile *p,
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned bind_table_index,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length,
|
2013-09-11 14:03:13 -07:00
|
|
|
bool header_present)
|
|
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2013-09-11 14:03:13 -07:00
|
|
|
const unsigned dispatch_width =
|
2014-06-04 17:08:57 -07:00
|
|
|
(brw_inst_exec_size(brw, insn) == BRW_EXECUTE_16 ? 16 : 8);
|
2013-09-11 14:03:13 -07:00
|
|
|
const unsigned num_channels = response_length / (dispatch_width / 8);
|
|
|
|
|
|
2014-07-11 15:48:14 -07:00
|
|
|
if (brw->gen >= 8 || brw->is_haswell) {
|
2013-09-11 14:03:13 -07:00
|
|
|
brw_set_message_descriptor(p, insn, HSW_SFID_DATAPORT_DATA_CACHE_1,
|
|
|
|
|
msg_length, response_length,
|
|
|
|
|
header_present, false);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dp_msg_type(brw, insn,
|
|
|
|
|
HSW_DATAPORT_DC_PORT1_UNTYPED_SURFACE_READ);
|
2013-09-11 14:03:13 -07:00
|
|
|
} else {
|
|
|
|
|
brw_set_message_descriptor(p, insn, GEN7_SFID_DATAPORT_DATA_CACHE,
|
|
|
|
|
msg_length, response_length,
|
|
|
|
|
header_present, false);
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_dp_msg_type(brw, insn,
|
|
|
|
|
GEN7_DATAPORT_DC_UNTYPED_SURFACE_READ);
|
2013-09-11 14:03:13 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
/* Set mask of 32-bit channels to drop. */
|
|
|
|
|
unsigned msg_control = (0xf & (0xf << num_channels));
|
|
|
|
|
|
|
|
|
|
if (brw_inst_access_mode(brw, insn) == BRW_ALIGN_1) {
|
2013-09-11 14:03:13 -07:00
|
|
|
if (dispatch_width == 16)
|
2014-06-04 17:08:57 -07:00
|
|
|
msg_control |= 1 << 4; /* SIMD16 mode */
|
2013-09-11 14:03:13 -07:00
|
|
|
else
|
2014-06-04 17:08:57 -07:00
|
|
|
msg_control |= 2 << 4; /* SIMD8 mode */
|
2013-09-11 14:03:13 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_set_binding_table_index(brw, insn, bind_table_index);
|
|
|
|
|
brw_inst_set_dp_msg_control(brw, insn, msg_control);
|
2013-09-11 14:03:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
brw_untyped_surface_read(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
|
|
|
|
struct brw_reg mrf,
|
2013-11-25 15:51:24 -08:00
|
|
|
unsigned bind_table_index,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length)
|
2013-09-11 14:03:13 -07:00
|
|
|
{
|
2014-06-04 17:08:57 -07:00
|
|
|
const struct brw_context *brw = p->brw;
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
2013-09-11 14:03:13 -07:00
|
|
|
|
|
|
|
|
brw_set_dest(p, insn, retype(dest, BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_src0(p, insn, retype(mrf, BRW_REGISTER_TYPE_UD));
|
|
|
|
|
brw_set_dp_untyped_surface_read_message(
|
|
|
|
|
p, insn, bind_table_index, msg_length, response_length,
|
2014-06-04 17:08:57 -07:00
|
|
|
brw_inst_access_mode(brw, insn) == BRW_ALIGN_1);
|
2013-09-11 14:03:13 -07:00
|
|
|
}
|
|
|
|
|
|
2013-11-17 21:47:22 +13:00
|
|
|
void
|
|
|
|
|
brw_pixel_interpolator_query(struct brw_compile *p,
|
|
|
|
|
struct brw_reg dest,
|
|
|
|
|
struct brw_reg mrf,
|
|
|
|
|
bool noperspective,
|
|
|
|
|
unsigned mode,
|
|
|
|
|
unsigned data,
|
|
|
|
|
unsigned msg_length,
|
|
|
|
|
unsigned response_length)
|
|
|
|
|
{
|
|
|
|
|
const struct brw_context *brw = p->brw;
|
|
|
|
|
struct brw_inst *insn = next_insn(p, BRW_OPCODE_SEND);
|
|
|
|
|
|
|
|
|
|
brw_set_dest(p, insn, dest);
|
|
|
|
|
brw_set_src0(p, insn, mrf);
|
|
|
|
|
brw_set_message_descriptor(p, insn, GEN7_SFID_PIXEL_INTERPOLATOR,
|
|
|
|
|
msg_length, response_length,
|
|
|
|
|
false /* header is never present for PI */,
|
|
|
|
|
false);
|
|
|
|
|
|
|
|
|
|
brw_inst_set_pi_simd_mode(
|
|
|
|
|
brw, insn, brw_inst_exec_size(brw, insn) == BRW_EXECUTE_16);
|
|
|
|
|
brw_inst_set_pi_slot_group(brw, insn, 0); /* zero unless 32/64px dispatch */
|
|
|
|
|
brw_inst_set_pi_nopersp(brw, insn, noperspective);
|
|
|
|
|
brw_inst_set_pi_message_type(brw, insn, mode);
|
|
|
|
|
brw_inst_set_pi_message_data(brw, insn, data);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-27 14:10:52 -08:00
|
|
|
/**
|
|
|
|
|
* This instruction is generated as a single-channel align1 instruction by
|
|
|
|
|
* both the VS and FS stages when using INTEL_DEBUG=shader_time.
|
|
|
|
|
*
|
|
|
|
|
* We can't use the typed atomic op in the FS because that has the execution
|
|
|
|
|
* mask ANDed with the pixel mask, but we just want to write the one dword for
|
|
|
|
|
* all the pixels.
|
|
|
|
|
*
|
|
|
|
|
* We don't use the SIMD4x2 atomic ops in the VS because want to just write
|
|
|
|
|
* one u32. So we use the same untyped atomic write message as the pixel
|
|
|
|
|
* shader.
|
|
|
|
|
*
|
|
|
|
|
* The untyped atomic operation requires a BUFFER surface type with RAW
|
|
|
|
|
* format, and is only accessible through the legacy DATA_CACHE dataport
|
|
|
|
|
* messages.
|
|
|
|
|
*/
|
|
|
|
|
void brw_shader_time_add(struct brw_compile *p,
|
2013-03-19 15:28:11 -07:00
|
|
|
struct brw_reg payload,
|
2012-11-27 14:10:52 -08:00
|
|
|
uint32_t surf_index)
|
|
|
|
|
{
|
2014-06-14 22:52:35 -07:00
|
|
|
assert(p->brw->gen >= 7);
|
2012-11-27 14:10:52 -08:00
|
|
|
|
|
|
|
|
brw_push_insn_state(p);
|
2014-05-31 16:57:02 -07:00
|
|
|
brw_set_default_access_mode(p, BRW_ALIGN_1);
|
|
|
|
|
brw_set_default_mask_control(p, BRW_MASK_DISABLE);
|
2014-06-13 14:29:25 -07:00
|
|
|
brw_inst *send = brw_next_insn(p, BRW_OPCODE_SEND);
|
2012-11-27 14:10:52 -08:00
|
|
|
brw_pop_insn_state(p);
|
|
|
|
|
|
|
|
|
|
/* We use brw_vec1_reg and unmasked because we want to increment the given
|
|
|
|
|
* offset only once.
|
|
|
|
|
*/
|
|
|
|
|
brw_set_dest(p, send, brw_vec1_reg(BRW_ARCHITECTURE_REGISTER_FILE,
|
|
|
|
|
BRW_ARF_NULL, 0));
|
2013-03-19 15:28:11 -07:00
|
|
|
brw_set_src0(p, send, brw_vec1_reg(payload.file,
|
|
|
|
|
payload.nr, 0));
|
2013-10-20 14:05:24 -07:00
|
|
|
brw_set_dp_untyped_atomic_message(p, send, BRW_AOP_ADD, surf_index,
|
|
|
|
|
2 /* message length */,
|
|
|
|
|
0 /* response length */,
|
|
|
|
|
false /* header present */);
|
2012-11-27 14:10:52 -08:00
|
|
|
}
|