/* A negative return value signals that an instruction has been newly * scheduled, return back up to the top of the stack (to block_sched()) */ static int trysched(struct ir3_sched_ctx *ctx, struct ir3_instruction *instr) { struct ir3_instruction *srcs[ARRAY_SIZE(instr->regs) - 1]; struct ir3_instruction *src; unsigned i, delay, nsrcs = 0; /* if already scheduled: */ if (instr->flags & IR3_INSTR_MARK) return 0; /* 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; } /* for each src register in sorted order: */ delay = 0; while ((src = deepest(srcs, nsrcs))) { delay = trysched(ctx, src); if (delay) return delay; } /* all our dependents are scheduled, figure out if * we have enough delay slots to schedule ourself: */ delay = delay_calc(ctx, instr); if (!delay) { schedule(ctx, instr, true); return -1; } return delay; }
int deeper ( int x ) { return deepest(x + 6); }
/* A negative return value signals that an instruction has been newly * scheduled, return back up to the top of the stack (to block_sched()) */ static int trysched(struct ir3_sched_ctx *ctx, struct ir3_instruction *instr) { struct ir3_instruction *srcs[ARRAY_SIZE(instr->regs) - 1]; struct ir3_instruction *src; unsigned i, delay, nsrcs = 0; /* if already scheduled: */ if (instr->flags & IR3_INSTR_MARK) return 0; /* 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; } /* for each src register in sorted order: */ delay = 0; while ((src = deepest(srcs, nsrcs))) { delay = trysched(ctx, src); if (delay) return delay; } /* all our dependents are scheduled, figure out if * we have enough delay slots to schedule ourself: */ delay = delay_calc(ctx, instr); if (delay) return delay; /* if the instruction is a kill, we need to ensure *every* * bary.f is scheduled. The hw seems unhappy if the thread * gets killed before the end-input (ei) flag is hit. * * We could do this by adding each bary.f instruction as * virtual ssa src for the kill instruction. But we have * fixed length instr->regs[]. * * TODO this wouldn't be quite right if we had multiple * basic blocks, if any block was conditional. We'd need * to schedule the bary.f's outside of any block which * was conditional that contained a kill.. I think.. */ if (is_kill(instr)) { struct ir3 *ir = instr->block->shader; unsigned i; for (i = 0; i < ir->baryfs_count; i++) { if (ir->baryfs[i]->depth == DEPTH_UNUSED) continue; delay = trysched(ctx, ir->baryfs[i]); if (delay) return delay; } } /* if this is a write to address/predicate register, and that * register is currently in use, we need to defer until it is * free: */ if (writes_addr(instr) && ctx->addr) { assert(ctx->addr != instr); return DELAYED; } if (writes_pred(instr) && ctx->pred) { assert(ctx->pred != instr); return DELAYED; } schedule(ctx, instr, true); return SCHEDULED; }