In some cases, in particular when you have things that can be src
modifiers ((abs)/(neg)), once eliminating one mov, there is a
possibility to remove another. Handle this by re-visiting an
instruction after eliminating a copy on one of it's srcs.
Signed-off-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
* src (which needs to also fixup the address src reference by the
* instruction).
*/
* src (which needs to also fixup the address src reference by the
* instruction).
*/
reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
struct ir3_register *reg, unsigned n)
{
reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
struct ir3_register *reg, unsigned n)
{
unuse(src);
reg->instr->use_count++;
unuse(src);
reg->instr->use_count++;
} else if (is_same_type_mov(src) &&
/* cannot collapse const/immed/etc into meta instrs: */
!is_meta(instr)) {
} else if (is_same_type_mov(src) &&
/* cannot collapse const/immed/etc into meta instrs: */
!is_meta(instr)) {
debug_assert(new_flags & IR3_REG_IMMED);
instr->regs[n + 1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
debug_assert(new_flags & IR3_REG_IMMED);
instr->regs[n + 1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
}
/* special case for "normal" mad instructions, we can
}
/* special case for "normal" mad instructions, we can
* src[0] is !CONST and src[1] is CONST:
*/
if ((n == 1) && try_swap_mad_two_srcs(instr, new_flags)) {
* src[0] is !CONST and src[1] is CONST:
*/
if ((n == 1) && try_swap_mad_two_srcs(instr, new_flags)) {
- /* we swapped, so now we are dealing with 1st src: */
- n = 0;
*/
if ((src_reg->flags & IR3_REG_RELATIV) &&
conflicts(instr->address, reg->instr->address))
*/
if ((src_reg->flags & IR3_REG_RELATIV) &&
conflicts(instr->address, reg->instr->address))
/* This seems to be a hw bug, or something where the timings
* just somehow don't work out. This restriction may only
/* This seems to be a hw bug, or something where the timings
* just somehow don't work out. This restriction may only
if ((opc_cat(instr->opc) == 3) && (n == 2) &&
(src_reg->flags & IR3_REG_RELATIV) &&
(src_reg->array.offset == 0))
if ((opc_cat(instr->opc) == 3) && (n == 2) &&
(src_reg->flags & IR3_REG_RELATIV) &&
(src_reg->array.offset == 0))
src_reg = ir3_reg_clone(instr->block->shader, src_reg);
src_reg->flags = new_flags;
src_reg = ir3_reg_clone(instr->block->shader, src_reg);
src_reg->flags = new_flags;
if (src_reg->flags & IR3_REG_RELATIV)
ir3_instr_set_address(instr, reg->instr->address);
if (src_reg->flags & IR3_REG_RELATIV)
ir3_instr_set_address(instr, reg->instr->address);
}
if ((src_reg->flags & IR3_REG_RELATIV) &&
}
if ((src_reg->flags & IR3_REG_RELATIV) &&
instr->regs[n+1] = src_reg;
ir3_instr_set_address(instr, reg->instr->address);
instr->regs[n+1] = src_reg;
ir3_instr_set_address(instr, reg->instr->address);
}
/* NOTE: seems we can only do immed integers, so don't
}
/* NOTE: seems we can only do immed integers, so don't
src_reg->flags = new_flags;
src_reg->iim_val = iim_val;
instr->regs[n+1] = src_reg;
src_reg->flags = new_flags;
src_reg->iim_val = iim_val;
instr->regs[n+1] = src_reg;
} else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
bool f_opcode = (ir3_cat2_float(instr->opc) ||
ir3_cat3_float(instr->opc)) ? true : false;
/* See if lowering an immediate to const would help. */
instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
} else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
bool f_opcode = (ir3_cat2_float(instr->opc) ||
ir3_cat3_float(instr->opc)) ? true : false;
/* See if lowering an immediate to const would help. */
instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags, f_opcode);
}
/* Handle special case of eliminating output mov, and similar cases where
}
/* Handle special case of eliminating output mov, and similar cases where
return;
/* walk down the graph from each src: */
return;
/* walk down the graph from each src: */
- foreach_src_n(reg, n, instr) {
- struct ir3_instruction *src = ssa(reg);
+ bool progress;
+ do {
+ progress = false;
+ foreach_src_n(reg, n, instr) {
+ struct ir3_instruction *src = ssa(reg);
- /* TODO non-indirect access we could figure out which register
- * we actually want and allow cp..
- */
- if (reg->flags & IR3_REG_ARRAY)
- continue;
+ /* TODO non-indirect access we could figure out which register
+ * we actually want and allow cp..
+ */
+ if (reg->flags & IR3_REG_ARRAY)
+ continue;
- /* Don't CP absneg into meta instructions, that won't end well: */
- if (is_meta(instr) && (src->opc != OPC_MOV))
- continue;
+ /* Don't CP absneg into meta instructions, that won't end well: */
+ if (is_meta(instr) && (src->opc != OPC_MOV))
+ continue;
- reg_cp(ctx, instr, reg, n);
- }
+ progress |= reg_cp(ctx, instr, reg, n);
+ }
+ } while (progress);
if (instr->regs[0]->flags & IR3_REG_ARRAY) {
struct ir3_instruction *src = ssa(instr->regs[0]);
if (instr->regs[0]->flags & IR3_REG_ARRAY) {
struct ir3_instruction *src = ssa(instr->regs[0]);