* SOFTWARE.
*/
-/* #define NV50PC_DEBUG */
-
#include "nv50_pc.h"
#define DESCEND_ARBITRARY(j, f) \
return FALSE;
if (nvi->src[0]->value->join->reg.id < 0) {
- NV50_DBGMSG("nvi_isnop: orphaned value detected\n");
+ NV50_DBGMSG(PROG_IR, "nvi_isnop: orphaned value detected\n");
return TRUE;
}
int j;
uint size, n32 = 0;
+ /* find first non-empty block emitted before b */
for (j = pc->num_blocks - 1; j >= 0 && !pc->bb_list[j]->bin_size; --j);
- if (j >= 0) {
+ for (; j >= 0; --j) {
in = pc->bb_list[j];
/* check for no-op branches (BRA $PC+8) */
nv_nvi_delete(in->exit);
}
b->bin_pos = in->bin_pos + in->bin_size;
+
+ if (in->bin_size) /* no more no-op branches to b */
+ break;
}
pc->bb_list[pc->num_blocks++] = b;
}
if (!b->entry) {
- NV50_DBGMSG("block %p is now empty\n", b);
+ NV50_DBGMSG(PROG_IR, "block %p is now empty\n", b);
} else
if (!b->exit->is_long) {
assert(n32);
{
int i, ret;
- NV50_DBGMSG("preparing %u blocks for emission\n", pc->num_blocks);
+ NV50_DBGMSG(PROG_IR, "preparing %u blocks for emission\n", pc->num_blocks);
pc->num_blocks = 0; /* will reorder bb_list */
}
if (nvi->opcode == NV_OP_SET && nvi->src[0] != src0)
- nvi->set_cond = cc_swapped[nvi->set_cond];
+ nvi->set_cond = (nvi->set_cond & ~7) | cc_swapped[nvi->set_cond & 7];
}
static int
continue;
nvi->def[0] = sti->def[0];
+ nvi->def[0]->insn = nvi;
nvi->fixed = sti->fixed;
nv_nvi_delete(sti);
if (j == 0 && ld->src[4]) /* can't load shared mem */
continue;
- /* fold it ! */ /* XXX: ref->insn */
+ /* fold it ! */
nv_reference(ctx->pc, &nvi->src[j], ld->src[0]->value);
if (ld->src[4])
nv_reference(ctx->pc, &nvi->src[4], ld->src[4]->value);
return 0;
}
+/* NOTE: Assumes loads have not yet been folded. */
static int
nv_pass_lower_mods(struct nv_pass *ctx, struct nv_basic_block *b)
{
nvi->src[1]->mod ^= NV_MOD_NEG;
}
- /* should not put any modifiers on NEG and ABS */
- assert(nvi->opcode != NV_MOD_NEG || !nvi->src[0]->mod);
- assert(nvi->opcode != NV_MOD_ABS || !nvi->src[0]->mod);
-
- for (j = 0; j < 4; ++j) {
- if (!nvi->src[j])
- break;
-
+ for (j = 0; j < 4 && nvi->src[j]; ++j) {
mi = nvi->src[j]->value->insn;
if (!mi)
continue;
if (mi->opcode == NV_OP_ABS) mod = NV_MOD_ABS;
else
continue;
+ assert(!(mod & mi->src[0]->mod & NV_MOD_NEG));
- if (nvi->opcode == NV_OP_ABS)
+ mod |= mi->src[0]->mod;
+
+ if (mi->flags_def || mi->flags_src)
+ continue;
+
+ if ((nvi->opcode == NV_OP_ABS) || (nvi->src[j]->mod & NV_MOD_ABS)) {
+ /* abs neg [abs] = abs */
mod &= ~(NV_MOD_NEG | NV_MOD_ABS);
- else
- if (nvi->opcode == NV_OP_NEG && mod == NV_MOD_NEG) {
- nvi->opcode = NV_OP_MOV;
+ } else
+ if ((nvi->opcode == NV_OP_NEG) && (mod & NV_MOD_NEG)) {
+ /* neg as opcode and modifier on same insn cannot occur */
+ /* neg neg abs = abs, neg neg = identity */
+ assert(j == 0);
+ if (mod & NV_MOD_ABS)
+ nvi->opcode = NV_OP_ABS;
+ else
+ if (nvi->flags_def)
+ nvi->opcode = NV_OP_CVT;
+ else
+ nvi->opcode = NV_OP_MOV;
mod = 0;
}
- if (!(nv50_supported_src_mods(nvi->opcode, j) & mod))
+ if ((nv50_supported_src_mods(nvi->opcode, j) & mod) != mod)
continue;
nv_reference(ctx->pc, &nvi->src[j], mi->src[0]->value);
if (nvi->opcode == NV_OP_SAT) {
mi = nvi->src[0]->value->insn;
- if ((mi->opcode == NV_OP_MAD) && !mi->flags_def) {
- mi->saturate = 1;
- mi->def[0] = nvi->def[0];
- nv_nvi_delete(nvi);
- }
+ if (mi->opcode != NV_OP_ADD && mi->opcode != NV_OP_MAD)
+ continue;
+ if (mi->flags_def || mi->def[0]->refc > 1)
+ continue;
+
+ mi->saturate = 1;
+ mi->def[0] = nvi->def[0];
+ mi->def[0]->insn = mi;
+ nv_nvi_delete(nvi);
}
}
DESCEND_ARBITRARY(j, nv_pass_lower_mods);
struct load_record {
struct load_record *next;
- uint64_t data;
+ uint64_t data[2];
struct nv_value *value;
};
{
struct load_record **rec, *it;
struct nv_instruction *ld, *next;
- uint64_t data;
+ uint64_t data[2];
struct nv_value *val;
int j;
rec = NULL;
if (ld->opcode == NV_OP_LINTERP || ld->opcode == NV_OP_PINTERP) {
- data = val->reg.id;
+ data[0] = val->reg.id;
+ data[1] = 0;
rec = &ctx->mem_v;
} else
if (ld->opcode == NV_OP_LDA) {
- data = val->reg.id;
+ data[0] = val->reg.id;
+ data[1] = ld->src[4] ? ld->src[4]->value->n : ~0ULL;
if (val->reg.file >= NV_FILE_MEM_C(0) &&
val->reg.file <= NV_FILE_MEM_C(15))
rec = &ctx->mem_c[val->reg.file - NV_FILE_MEM_C(0)];
rec = &ctx->mem_l;
} else
if ((ld->opcode == NV_OP_MOV) && (val->reg.file == NV_FILE_IMM)) {
- data = val->reg.imm.u32;
+ data[0] = val->reg.imm.u32;
+ data[1] = 0;
rec = &ctx->imm;
}
continue;
for (it = *rec; it; it = it->next)
- if (it->data == data)
+ if (it->data[0] == data[0] && it->data[1] == data[1])
break;
if (it) {
continue;
it = &ctx->pool[ctx->alloc++];
it->next = *rec;
- it->data = data;
+ it->data[0] = data[0];
+ it->data[1] = data[1];
it->value = ld->def[0];
*rec = it;
}
if (bb_is_if_else_endif(b)) {
- NV50_DBGMSG("pass_flatten: IF/ELSE/ENDIF construct at BB:%i\n", b->id);
+ NV50_DBGMSG(PROG_IR,
+ "pass_flatten: IF/ELSE/ENDIF construct at BB:%i\n", b->id);
for (n0 = 0, nvi = b->out[0]->entry; nvi; nvi = nvi->next, ++n0)
if (!nv50_nvi_can_predicate(nvi))
for (n1 = 0, nvi = b->out[1]->entry; nvi; nvi = nvi->next, ++n1)
if (!nv50_nvi_can_predicate(nvi))
break;
-#ifdef NV50_PC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_PROG_IR
if (nvi) {
debug_printf("cannot predicate: "); nv_print_instruction(nvi);
}
if (ret)
return ret;
+ pc->pass_seq++;
+ ret = nv_pass_lower_mods(&pass, root);
+ if (ret)
+ return ret;
+
pc->pass_seq++;
ret = nv_pass_fold_loads(&pass, root);
if (ret)
if (ret)
return ret;
- pc->pass_seq++;
- ret = nv_pass_lower_mods(&pass, root);
- if (ret)
- return ret;
-
dce.pc = pc;
do {
dce.removed = 0;