/* delay calculation: */
int ir3_delayslots(struct ir3_instruction *assigner,
struct ir3_instruction *consumer, unsigned n);
-unsigned ir3_distance(struct ir3_block *block, struct ir3_instruction *instr,
- unsigned maxd, bool pred);
unsigned ir3_delay_calc(struct ir3_block *block, struct ir3_instruction *instr,
bool soft, bool pred);
void ir3_remove_nops(struct ir3 *ir);
#define INSTR4(name) __INSTR4(0, name, OPC_##name)
/* cat0 instructions: */
-INSTR0(BR)
+INSTR1(BR)
INSTR0(JUMP)
INSTR1(KILL)
INSTR0(END)
* find the worst case (shortest) distance (only possible after
* individual blocks are all scheduled)
*/
-unsigned
-ir3_distance(struct ir3_block *block, struct ir3_instruction *instr,
+static unsigned
+distance(struct ir3_block *block, struct ir3_instruction *instr,
unsigned maxd, bool pred)
{
unsigned d = 0;
struct ir3_block *pred = (struct ir3_block *)entry->key;
unsigned n;
- n = ir3_distance(pred, instr, min, pred);
+ n = distance(pred, instr, min, pred);
min = MIN2(min, n);
}
} else {
delay = ir3_delayslots(assigner, consumer, srcn);
}
- delay -= ir3_distance(block, assigner, delay, pred);
+ delay -= distance(block, assigner, delay, pred);
}
return delay;
}
}
+/* Insert the branch/jump instructions for flow control between blocks.
+ * Initially this is done naively, without considering if the successor
+ * block immediately follows the current block (ie. so no jump required),
+ * but that is cleaned up in resolve_jumps().
+ *
+ * TODO what ensures that the last write to p0.x in a block is the
+ * branch condition? Have we been getting lucky all this time?
+ */
+static void
+block_sched(struct ir3 *ir)
+{
+ foreach_block (block, &ir->block_list) {
+ if (block->successors[1]) {
+ /* if/else, conditional branches to "then" or "else": */
+ struct ir3_instruction *br;
+
+ debug_assert(block->condition);
+
+ /* create "else" branch first (since "then" block should
+ * frequently/always end up being a fall-thru):
+ */
+ br = ir3_BR(block, block->condition, 0);
+ br->cat0.inv = true;
+ br->cat0.target = block->successors[1];
+
+ /* "then" branch: */
+ br = ir3_BR(block, block->condition, 0);
+ br->cat0.target = block->successors[0];
+
+ } else if (block->successors[0]) {
+ /* otherwise unconditional jump to next block: */
+ struct ir3_instruction *jmp;
+
+ jmp = ir3_JUMP(block);
+ jmp->cat0.target = block->successors[0];
+ }
+ }
+}
+
/* Insert nop's required to make this a legal/valid shader program: */
static void
nop_sched(struct ir3 *ir)
*max_bary = ctx->max_bary;
+ block_sched(ir);
nop_sched(ir);
do {
}
}
}
-
- /* And lastly, insert branch/jump instructions to take us to
- * the next block. Later we'll strip back out the branches
- * that simply jump to next instruction.
- */
- if (block->successors[1]) {
- /* if/else, conditional branches to "then" or "else": */
- struct ir3_instruction *br;
-
- debug_assert(ctx->pred);
- debug_assert(block->condition);
-
- /* create "else" branch first (since "then" block should
- * frequently/always end up being a fall-thru):
- */
- br = ir3_BR(block);
- br->cat0.inv = true;
- br->cat0.target = block->successors[1];
-
- /* NOTE: we have to hard code delay of 6 above, since
- * we want to insert the nop's before constructing the
- * branch. Throw in an assert so we notice if this
- * ever breaks on future generation:
- */
- debug_assert(ir3_delayslots(ctx->pred, br, 0) == 6);
-
- br = ir3_BR(block);
- br->cat0.target = block->successors[0];
-
- } else if (block->successors[0]) {
- /* otherwise unconditional jump to next block: */
- struct ir3_instruction *jmp;
-
- jmp = ir3_JUMP(block);
- jmp->cat0.target = block->successors[0];
- }
-
- /* NOTE: if we kept track of the predecessors, we could do a better
- * job w/ (jp) flags.. every node w/ > predecessor is a join point.
- * Note that as we eliminate blocks which contain only an unconditional
- * jump we probably need to propagate (jp) flag..
- */
}
int ir3_sched(struct ir3 *ir)