diff --git a/src/panfrost/bifrost/bi_schedule.c b/src/panfrost/bifrost/bi_schedule.c index a9fc529759d..dca53d759f6 100644 --- a/src/panfrost/bifrost/bi_schedule.c +++ b/src/panfrost/bifrost/bi_schedule.c @@ -475,6 +475,89 @@ bi_space_for_more_constants(struct bi_clause_state *clause) return (bi_nconstants(clause) < 13 - (clause->tuple_count + 1)); } +/* Updates the FAU assignment for a tuple. A valid FAU assignment must be + * possible (as a precondition); this is gauranteed per-instruction by + * bi_lower_fau and per-tuple by bi_instr_schedulable */ + +static bool +bi_update_fau(struct bi_clause_state *clause, + struct bi_tuple_state *tuple, + bi_instr *instr, bool fma, bool destructive) +{ + /* Maintain our own constants, for nondestructive mode */ + uint32_t copied_constants[2], copied_count; + unsigned *constant_count = &tuple->constant_count; + uint32_t *constants = tuple->constants; + + if (!destructive) { + memcpy(copied_constants, tuple->constants, + (*constant_count) * sizeof(constants[0])); + copied_count = tuple->constant_count; + + constant_count = &copied_count; + constants = copied_constants; + } + + bi_foreach_src(instr, s) { + bi_index src = instr->src[s]; + + if (src.type == BI_INDEX_FAU) { + bool no_constants = *constant_count == 0; + bool no_other_fau = (tuple->fau == src.value) || !tuple->fau; + bool mergable = no_constants && no_other_fau; + + if (destructive) { + assert(mergable); + tuple->fau = src.value; + } else if (!mergable) { + return false; + } + } else if (src.type == BI_INDEX_CONSTANT) { + /* No need to reserve space if we have a fast 0 */ + if (src.value == 0 && fma && bi_reads_zero(instr)) + continue; + + /* If there is a branch target, #0 by convention is the + * PC-relative offset to the target */ + bool pcrel = instr->branch_target && src.value == 0; + bool found = false; + + for (unsigned i = 0; i < *constant_count; ++i) { + found |= (constants[i] == src.value) && + (i != tuple->pcrel_idx); + } + + /* pcrel constants are unique, so don't match */ + if (found && !pcrel) + continue; + + bool no_fau = (*constant_count > 0) || !tuple->fau; + bool mergable = no_fau && ((*constant_count) < 2); + + if (destructive) { + assert(mergable); + + if (pcrel) + tuple->pcrel_idx = *constant_count; + } else if (!mergable) + return false; + + constants[(*constant_count)++] = src.value; + } + } + + /* Constants per clause may be limited by tuple count */ + bool room_for_constants = (*constant_count == 0) || + bi_space_for_more_constants(clause); + + if (destructive) + assert(room_for_constants); + else if (!room_for_constants) + return false; + + return true; +} + #ifndef NDEBUG static bi_builder *