return true;
}
+
+/* iterator for an instructions's sources (reg), also returns src #: */
+#define foreach_src_n(__srcreg, __n, __instr) \
+ if ((__instr)->regs_count) \
+ for (unsigned __cnt = (__instr)->regs_count - 1, __n = 0; __n < __cnt; __n++) \
+ if ((__srcreg = (__instr)->regs[__n + 1]))
+
+/* iterator for an instructions's sources (reg): */
+#define foreach_src(__srcreg, __instr) \
+ foreach_src_n(__srcreg, __i, __instr)
+
+static inline unsigned __ssa_src_cnt(struct ir3_instruction *instr)
+{
+ return instr->regs_count;
+}
+
+static inline struct ir3_instruction * __ssa_src_n(struct ir3_instruction *instr, unsigned n)
+{
+ return ssa(instr->regs[n]);
+}
+
+#define __src_cnt(__instr) ((__instr)->address ? (__instr)->regs_count : (__instr)->regs_count - 1)
+
+/* iterator for an instruction's SSA sources (instr), also returns src #: */
+#define foreach_ssa_src_n(__srcinst, __n, __instr) \
+ if ((__instr)->regs_count) \
+ for (unsigned __cnt = __ssa_src_cnt(__instr) - 1, __n = 0; __n < __cnt; __n++) \
+ if ((__srcinst = __ssa_src_n(__instr, __n + 1)))
+
+/* iterator for an instruction's SSA sources (instr): */
+#define foreach_ssa_src(__srcinst, __instr) \
+ foreach_ssa_src_n(__srcinst, __i, __instr)
+
+
/* dump: */
#include <stdio.h>
void ir3_dump(struct ir3 *shader, const char *name,
return false;
}
-static void walk_children(struct ir3_instruction *instr)
-{
- unsigned i;
-
- /* walk down the graph from each src: */
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *src = instr->regs[i];
- if (src->flags & IR3_REG_SSA)
- src->instr = instr_cp(src->instr);
- }
-}
-
static struct ir3_instruction *
instr_cp(struct ir3_instruction *instr)
* up as a src, we only need to recursively walk the children
* once.)
*/
- if (!ir3_instr_check_mark(instr))
- walk_children(instr);
+ if (!ir3_instr_check_mark(instr)) {
+ struct ir3_register *reg;
+
+ /* walk down the graph from each src: */
+ foreach_src(reg, instr)
+ if (reg->flags & IR3_REG_SSA)
+ reg->instr = instr_cp(reg->instr);
+ }
return instr;
}
static void ir3_instr_depth(struct ir3_instruction *instr)
{
- unsigned i;
+ struct ir3_instruction *src;
/* if we've already visited this instruction, bail now: */
if (ir3_instr_check_mark(instr))
instr->depth = 0;
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *src = instr->regs[i];
- if (src->flags & IR3_REG_SSA) {
- unsigned sd;
+ foreach_ssa_src_n(src, i, instr) {
+ unsigned sd;
- /* visit child to compute it's depth: */
- ir3_instr_depth(src->instr);
+ /* visit child to compute it's depth: */
+ ir3_instr_depth(src);
- sd = ir3_delayslots(src->instr, instr, i-1) +
- src->instr->depth;
+ sd = ir3_delayslots(src, instr, i) + src->depth;
- instr->depth = MAX2(instr->depth, sd);
- }
+ instr->depth = MAX2(instr->depth, sd);
}
/* meta-instructions don't add cycles, other than PHI.. which
if (is_meta(instr)) {
if ((instr->opc == OPC_META_FO) ||
(instr->opc == OPC_META_FI)) {
- unsigned i;
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- if (reg->flags & IR3_REG_SSA)
- dump_instr(ctx, reg->instr);
- }
+ struct ir3_instruction *src;
+ foreach_ssa_src(src, instr)
+ dump_instr(ctx, src);
} else if (instr->opc == OPC_META_FLOW) {
struct ir3_register *reg = instr->regs[1];
ir3_block_dump(ctx, instr->flow.if_block, "if");
printdef(ctx, defer, "[label=\".%c\"]",
"xyzw"[instr->fo.off & 0x3]);
} else if (instr->opc == OPC_META_FI) {
- unsigned i;
-
- /* recursively dump all parents and links */
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- if (reg->flags & IR3_REG_SSA) {
- dump_link2(ctx, reg->instr, target, defer);
- printdef(ctx, defer, "[label=\".%c\"]",
- "xyzw"[(i - 1) & 0x3]);
- }
+ struct ir3_instruction *src;
+
+ foreach_ssa_src_n(src, i, instr) {
+ dump_link2(ctx, src, target, defer);
+ printdef(ctx, defer, "[label=\".%c\"]",
+ "xyzw"[i & 0x3]);
}
} else if (instr->opc == OPC_META_OUTPUT) {
printdef(ctx, defer, "output%lx:<out%u>:w -> %s",
static void ir3_instr_dump(struct ir3_dump_ctx *ctx,
struct ir3_instruction *instr)
{
- unsigned i;
+ struct ir3_register *src;
fprintf(ctx->f, "instr%lx [shape=record,style=filled,fillcolor=lightgrey,label=\"{",
PTRID(instr));
fprintf(ctx->f, "|<dst0>");
/* source register(s): */
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = follow_flow(instr->regs[i]);
+ foreach_src_n(src, i, instr) {
+ struct ir3_register *reg = follow_flow(src);
fprintf(ctx->f, "|");
if (reg->flags & IR3_REG_SSA)
- fprintf(ctx->f, "<src%u> ", (i - 1));
+ fprintf(ctx->f, "<src%u> ", i);
dump_reg_name(ctx, reg, true);
}
fprintf(ctx->f, "}\"];\n");
/* and recursively dump dependent instructions: */
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
+ foreach_src_n(src, i, instr) {
+ struct ir3_register *reg = follow_flow(src);
char target[32]; /* link target */
if (!(reg->flags & IR3_REG_SSA))
continue;
snprintf(target, sizeof(target), "instr%lx:<src%u>",
- PTRID(instr), (i - 1));
+ PTRID(instr), i);
dump_instr(ctx, reg->instr);
- dump_link(ctx, follow_flow(reg)->instr, instr->block, target);
+ dump_link(ctx, reg->instr, instr->block, target);
}
}
static void ir3_instr_flatten(struct ir3_flatten_ctx *ctx,
struct ir3_instruction *instr)
{
- unsigned i;
+ struct ir3_instruction *src;
/* if we've already visited this instruction, bail now: */
if (ir3_instr_check_mark(instr))
}
/* recursively visit children: */
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *src = instr->regs[i];
- if (src->flags & IR3_REG_SSA)
- ir3_instr_flatten(ctx, src->instr);
- }
+ foreach_ssa_src(src, instr)
+ ir3_instr_flatten(ctx, src);
}
/* return >= 0 is # of phi's flattened, < 0 is error */
static void instr_find_neighbors(struct ir3_instruction *instr)
{
- unsigned i;
+ struct ir3_instruction *src;
if (check_stop(instr))
return;
if (is_meta(instr) && (instr->opc == OPC_META_FI))
group_n(&instr_ops, instr, instr->regs_count - 1);
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_instruction *src_instr = ssa(instr->regs[i]);
- if (src_instr)
- instr_find_neighbors(src_instr);
- }
+ foreach_ssa_src(src, instr)
+ instr_find_neighbors(src);
}
/* a bit of sadness.. we can't have "holes" in inputs from PoV of
* their src register(s):
*/
if (is_tex(n) || is_sfu(n)) {
- for (i = 1; i < n->regs_count; i++) {
- reg = n->regs[i];
+ foreach_src(reg, n) {
if (reg_gpr(reg))
regmask_set(&needs_ss_war, reg);
}
static void instr_assign(struct ir3_ra_ctx *ctx,
struct ir3_instruction *instr, unsigned name)
{
- struct ir3_instruction *n;
+ struct ir3_instruction *n, *src;
struct ir3_register *reg = instr->regs[0];
/* check if already assigned: */
/* and rename any subsequent use of result of this instr: */
for (n = instr->next; n && !ctx->error; n = n->next) {
- unsigned i;
+ foreach_ssa_src_n(src, i, n) {
+ unsigned r = i + 1;
- for (i = 1; i < n->regs_count; i++) {
- reg = n->regs[i];
- if ((reg->flags & IR3_REG_SSA) && (reg->instr == instr))
- instr_assign_src(ctx, n, i, name);
+ /* skip address / etc (non real sources): */
+ if (r >= n->regs_count)
+ continue;
+
+ if (src == instr)
+ instr_assign_src(ctx, n, r, name);
}
}
* to the actual instruction:
*/
if (is_meta(instr) && (instr->opc == OPC_META_FO)) {
- struct ir3_instruction *src = ssa(instr->regs[1]);
debug_assert(name >= instr->fo.off);
- if (src)
+
+ foreach_ssa_src(src, instr)
instr_assign(ctx, src, name - instr->fo.off);
}
}
unsigned delay = 0;
if (is_meta(assigner)) {
- unsigned i;
- for (i = 1; i < assigner->regs_count; i++) {
- struct ir3_register *reg = assigner->regs[i];
- if (reg->flags & IR3_REG_SSA) {
- unsigned d = delay_calc_srcn(ctx, reg->instr,
- consumer, srcn);
- delay = MAX2(delay, d);
- }
+ struct ir3_instruction *src;
+ foreach_ssa_src(src, assigner) {
+ unsigned d = delay_calc_srcn(ctx, src, consumer, srcn);
+ delay = MAX2(delay, d);
}
} else {
delay = ir3_delayslots(assigner, consumer, srcn);
static unsigned delay_calc(struct ir3_sched_ctx *ctx,
struct ir3_instruction *instr)
{
- unsigned i, delay = 0;
+ unsigned delay = 0;
+ struct ir3_instruction *src;
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- if (reg->flags & IR3_REG_SSA) {
- unsigned d = delay_calc_srcn(ctx, reg->instr,
- instr, i - 1);
- delay = MAX2(delay, d);
- }
+ foreach_ssa_src_n(src, i, instr) {
+ unsigned d = delay_calc_srcn(ctx, src, instr, i);
+ delay = MAX2(delay, d);
}
return delay;
{
struct ir3_instruction *srcs[64];
struct ir3_instruction *src;
- unsigned i, delay, nsrcs = 0;
+ unsigned delay, nsrcs = 0;
/* if already scheduled: */
if (instr->flags & IR3_INSTR_MARK)
return 0;
- debug_assert(instr->regs_count < ARRAY_SIZE(srcs));
-
- /* figure out our src's: */
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- if (reg->flags & IR3_REG_SSA)
- srcs[nsrcs++] = reg->instr;
+ /* figure out our src's, copy 'em out into an array for sorting: */
+ foreach_ssa_src(src, instr) {
+ debug_assert(nsrcs < ARRAY_SIZE(srcs));
+ srcs[nsrcs++] = src;
}
/* for each src register in sorted order:
static bool uses_current_addr(struct ir3_sched_ctx *ctx,
struct ir3_instruction *instr)
{
- unsigned i;
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- if (reg->flags & IR3_REG_SSA) {
- if (is_addr(reg->instr)) {
- struct ir3_instruction *addr;
- addr = reg->instr->regs[1]->instr; /* the mova */
- if (ctx->addr == addr)
- return true;
- }
+ struct ir3_instruction *src;
+ foreach_ssa_src(src, instr) {
+ if (is_addr(src)) {
+ struct ir3_instruction *addr =
+ src->regs[1]->instr; /* the mova */
+ if (ctx->addr == addr)
+ return true;
}
}
return false;
static bool uses_current_pred(struct ir3_sched_ctx *ctx,
struct ir3_instruction *instr)
{
- unsigned i;
- for (i = 1; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- if ((reg->flags & IR3_REG_SSA) && (ctx->pred == reg->instr))
- return true;
- }
+ struct ir3_instruction *src;
+ foreach_ssa_src(src, instr)
+ if (ctx->pred == src)
+ return true;
return false;
}