r600/sb: Check whether optimizations would result in reladdr conflict

v2: * Check whether the node src and dst registers are NULL before using
      them.
    * fix a type in the commit message.

Two cases are handled with this patch:

1. If copy propagation tries to eliminated a move from a relative
   array access then it could optimize

     MOV R1, ARRAY[RELADDR_1]
     MOV R2, ARRAY[RELADDR_2]
     OP2 R3, R1 R2

   into

     OP2 R3, ARRAY[RELADDR_1], ARRAY[RELADDR_2]

   which is forbidden, because there is only one address register available.

2. When MULADD(x,a,MUL(x,c)) is handled

      MUL TMP, R1, ARRAY[RELADDR_1]
      MULLADD R3, R1, ARRAY[RELADDR_2], TMP

   by folding this into

      ADD TMP, ARRAY[RELADDR_2], ARRAY[RELADDR_1]
      MUL R3, R1, TMP

   which is also forbidden.

Test for these cases and reject the optimization if a forbidden combination
of relative access would be created.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103142
Signed-off-by: Gert Wollny <gw.fossdev@gmail.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Gert Wollny 2018-02-08 15:11:58 +01:00 committed by Dave Airlie
parent 1d871aa626
commit c36172e387
3 changed files with 55 additions and 4 deletions

View File

@ -412,7 +412,8 @@ bool expr_handler::fold_alu_op1(alu_node& n) {
n.bc.op == ALU_OP1_MOVA_GPR_INT)
&& n.bc.clamp == 0 && n.bc.omod == 0
&& n.bc.src[0].abs == 0 && n.bc.src[0].neg == 0 &&
n.src.size() == 1 /* RIM/SIM can be appended as additional values */) {
n.src.size() == 1 /* RIM/SIM can be appended as additional values */
&& n.dst[0]->no_reladdr_conflict_with(v0)) {
assign_source(n.dst[0], v0);
return true;
}
@ -1027,9 +1028,17 @@ bool expr_handler::fold_alu_op3(alu_node& n) {
es1 = 1;
}
if (es0 != -1) {
value *va0 = es0 == 0 ? v1 : v0;
value *va1 = es1 == 0 ? mv1 : mv0;
value *va0 = es0 == 0 ? v1 : v0;
value *va1 = es1 == 0 ? mv1 : mv0;
/* Don't fold if no equal multipliers were found.
* Also don#t fold if the operands of the to be created ADD are both
* relatively accessed with different AR values because that would
* create impossible code.
*/
if (es0 != -1 &&
(!va0->is_rel() || !va1->is_rel() ||
(va0->rel == va1->rel))) {
alu_node *add = sh.create_alu();
add->bc.set_op(ALU_OP2_ADD);

View File

@ -616,6 +616,12 @@ public:
}
}
/* Check whether copy-propagation of src into this would create an access
* conflict with relative addressing, i.e. an operation that tries to access
* array elements with different address register values.
*/
bool no_reladdr_conflict_with(value *src);
val_set interferences;
unsigned uid;
};

View File

@ -296,6 +296,42 @@ void value::delete_uses() {
uses.erase(uses.begin(), uses.end());
}
bool value::no_reladdr_conflict_with(value *src)
{
/* if the register is not relative, it can't create an relative access conflict */
if (!src->is_rel())
return true;
/* If the destination is AR then we accept the copy propagation, because the
* scheduler actually re-creates the address loading operation and will
* signal interference if there is an address register load and it will fail
* because of this.
*/
if (gvalue()->is_AR())
return true;
/* For all nodes that use this value test whether the operation uses another
* relative access with a different address value. If found, signal conflict.
*/
for (uselist::const_iterator N = uses.begin(); N != uses.end(); ++N) {
for (vvec::const_iterator V = (*N)->src.begin(); V != (*N)->src.end(); ++V) {
if (*V) {
value *v = (*V)->gvalue();
if (v != src && v->is_rel() && v->rel != src->rel)
return false;
}
}
for (vvec::const_iterator V = (*N)->dst.begin(); V != (*N)->dst.end(); ++V) {
if (*V) {
value *v = (*V)->gvalue();
if (v && v != src && v->is_rel() && (v->rel != src->rel))
return false;
}
}
}
return true;
}
void ra_constraint::update_values() {
for (vvec::iterator I = values.begin(), E = values.end(); I != E; ++I) {
assert(!(*I)->constraint);