Path: blob/21.2-virgl/src/gallium/drivers/lima/ir/pp/scheduler.c
4574 views
/*1* Copyright (c) 2017 Lima Project2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sub license,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the11* next paragraph) shall be included in all copies or substantial portions12* of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*22*/2324#include <limits.h>2526#include "ppir.h"272829static void ppir_schedule_calc_sched_info(ppir_instr *instr)30{31int n = 0;32float extra_reg = 1.0;3334/* update all children's sched info */35ppir_instr_foreach_pred(instr, dep) {36ppir_instr *pred = dep->pred;3738if (pred->reg_pressure < 0)39ppir_schedule_calc_sched_info(pred);4041if (instr->est < pred->est + 1)42instr->est = pred->est + 1;4344float reg_weight = 1.0 - 1.0 / list_length(&pred->succ_list);45if (extra_reg > reg_weight)46extra_reg = reg_weight;4748n++;49}5051/* leaf instr */52if (!n) {53instr->reg_pressure = 0;54return;55}5657int i = 0, reg[n];58ppir_instr_foreach_pred(instr, dep) {59ppir_instr *pred = dep->pred;60reg[i++] = pred->reg_pressure;61}6263/* sort */64for (i = 0; i < n - 1; i++) {65for (int j = 0; j < n - i - 1; j++) {66if (reg[j] > reg[j + 1]) {67int tmp = reg[j + 1];68reg[j + 1] = reg[j];69reg[j] = tmp;70}71}72}7374for (i = 0; i < n; i++) {75int pressure = reg[i] + n - (i + 1);76if (pressure > instr->reg_pressure)77instr->reg_pressure = pressure;78}7980/* If all children of this instr have multi parents, then this81* instr need an extra reg to store its result. For example,82* it's not fair for parent has the same reg pressure as child83* if n==1 and child's successor>1, because we need 2 reg for84* this.85*86* But we can't add a full reg to the reg_pressure, because the87* last parent of a multi-successor child doesn't need an extra88* reg. For example, a single child (with multi successor) instr89* should has less reg pressure than a two children (with single90* successor) instr.91*92* extra reg = min(all child)(1.0 - 1.0 / num successor)93*/94instr->reg_pressure += extra_reg;95}9697static void ppir_insert_ready_list(struct list_head *ready_list,98ppir_instr *insert_instr)99{100struct list_head *insert_pos = ready_list;101102list_for_each_entry(ppir_instr, instr, ready_list, list) {103if (insert_instr->parent_index < instr->parent_index ||104(insert_instr->parent_index == instr->parent_index &&105(insert_instr->reg_pressure < instr->reg_pressure ||106(insert_instr->reg_pressure == instr->reg_pressure &&107(insert_instr->est >= instr->est))))) {108insert_pos = &instr->list;109break;110}111}112113list_del(&insert_instr->list);114list_addtail(&insert_instr->list, insert_pos);115}116117static void ppir_schedule_ready_list(ppir_block *block,118struct list_head *ready_list)119{120if (list_is_empty(ready_list))121return;122123ppir_instr *instr = list_first_entry(ready_list, ppir_instr, list);124list_del(&instr->list);125126/* schedule the instr to the block instr list */127list_add(&instr->list, &block->instr_list);128instr->scheduled = true;129block->sched_instr_index--;130instr->seq = block->sched_instr_base + block->sched_instr_index;131132ppir_instr_foreach_pred(instr, dep) {133ppir_instr *pred = dep->pred;134pred->parent_index = block->sched_instr_index;135136bool ready = true;137ppir_instr_foreach_succ(pred, dep) {138ppir_instr *succ = dep->succ;139if (!succ->scheduled) {140ready = false;141break;142}143}144/* all successor have been scheduled */145if (ready)146ppir_insert_ready_list(ready_list, pred);147}148149ppir_schedule_ready_list(block, ready_list);150}151152/* Register sensitive schedule algorithm from paper:153* "Register-Sensitive Selection, Duplication, and Sequencing of Instructions"154* Author: Vivek Sarkar, Mauricio J. Serrano, Barbara B. Simons155*/156static void ppir_schedule_block(ppir_block *block)157{158/* move all instr to instr_list, block->instr_list will159* contain schedule result */160struct list_head instr_list;161list_replace(&block->instr_list, &instr_list);162list_inithead(&block->instr_list);163164/* step 2 & 3 */165list_for_each_entry(ppir_instr, instr, &instr_list, list) {166if (ppir_instr_is_root(instr))167ppir_schedule_calc_sched_info(instr);168block->sched_instr_index++;169}170block->sched_instr_base = block->comp->sched_instr_base;171block->comp->sched_instr_base += block->sched_instr_index;172173/* step 4 */174struct list_head ready_list;175list_inithead(&ready_list);176177/* step 5 */178list_for_each_entry_safe(ppir_instr, instr, &instr_list, list) {179if (ppir_instr_is_root(instr)) {180instr->parent_index = INT_MAX;181ppir_insert_ready_list(&ready_list, instr);182}183}184185/* step 6 */186ppir_schedule_ready_list(block, &ready_list);187}188189bool ppir_schedule_prog(ppir_compiler *comp)190{191list_for_each_entry(ppir_block, block, &comp->block_list, list) {192ppir_schedule_block(block);193}194195return true;196}197198199