Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2010 Intel Corporation
  3.  * Copyright © 2014 Broadcom
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining a
  6.  * copy of this software and associated documentation files (the "Software"),
  7.  * to deal in the Software without restriction, including without limitation
  8.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9.  * and/or sell copies of the Software, and to permit persons to whom the
  10.  * Software is furnished to do so, subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice (including the next
  13.  * paragraph) shall be included in all copies or substantial portions of the
  14.  * Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22.  * IN THE SOFTWARE.
  23.  */
  24.  
  25. /**
  26.  * @file vc4_qpu_schedule.c
  27.  *
  28.  * The basic model of the list scheduler is to take a basic block, compute a
  29.  * DAG of the dependencies, and make a list of the DAG heads.  Heuristically
  30.  * pick a DAG head, then put all the children that are now DAG heads into the
  31.  * list of things to schedule.
  32.  *
  33.  * The goal of scheduling here is to pack pairs of operations together in a
  34.  * single QPU instruction.
  35.  */
  36.  
  37. #include "vc4_qir.h"
  38. #include "vc4_qpu.h"
  39. #include "util/ralloc.h"
  40.  
  41. static bool debug;
  42.  
  43. struct schedule_node_child;
  44.  
  45. struct schedule_node {
  46.         struct simple_node link;
  47.         struct queued_qpu_inst *inst;
  48.         struct schedule_node_child *children;
  49.         uint32_t child_count;
  50.         uint32_t child_array_size;
  51.         uint32_t parent_count;
  52.  
  53.         /**
  54.          * Minimum number of cycles from scheduling this instruction until the
  55.          * end of the program, based on the slowest dependency chain through
  56.          * the children.
  57.          */
  58.         uint32_t delay;
  59.  
  60.         /**
  61.          * cycles between this instruction being scheduled and when its result
  62.          * can be consumed.
  63.          */
  64.         uint32_t latency;
  65.  
  66.         /**
  67.          * Which uniform from uniform_data[] this instruction read, or -1 if
  68.          * not reading a uniform.
  69.          */
  70.         int uniform;
  71. };
  72.  
  73. struct schedule_node_child {
  74.         struct schedule_node *node;
  75.         bool write_after_read;
  76. };
  77.  
  78. /* When walking the instructions in reverse, we need to swap before/after in
  79.  * add_dep().
  80.  */
  81. enum direction { F, R };
  82.  
  83. struct schedule_state {
  84.         struct schedule_node *last_r[6];
  85.         struct schedule_node *last_ra[32];
  86.         struct schedule_node *last_rb[32];
  87.         struct schedule_node *last_sf;
  88.         struct schedule_node *last_vpm_read;
  89.         struct schedule_node *last_tmu_write;
  90.         struct schedule_node *last_tlb;
  91.         struct schedule_node *last_vpm;
  92.         enum direction dir;
  93. };
  94.  
  95. static void
  96. add_dep(struct schedule_state *state,
  97.         struct schedule_node *before,
  98.         struct schedule_node *after,
  99.         bool write)
  100. {
  101.         bool write_after_read = !write && state->dir == R;
  102.  
  103.         if (!before || !after)
  104.                 return;
  105.  
  106.         assert(before != after);
  107.  
  108.         if (state->dir == R) {
  109.                 struct schedule_node *t = before;
  110.                 before = after;
  111.                 after = t;
  112.         }
  113.  
  114.         for (int i = 0; i < before->child_count; i++) {
  115.                 if (before->children[i].node == after &&
  116.                     (before->children[i].write_after_read == write_after_read)) {
  117.                         return;
  118.                 }
  119.         }
  120.  
  121.         if (before->child_array_size <= before->child_count) {
  122.                 before->child_array_size = MAX2(before->child_array_size * 2, 16);
  123.                 before->children = reralloc(before, before->children,
  124.                                             struct schedule_node_child,
  125.                                             before->child_array_size);
  126.         }
  127.  
  128.         before->children[before->child_count].node = after;
  129.         before->children[before->child_count].write_after_read =
  130.                 write_after_read;
  131.         before->child_count++;
  132.         after->parent_count++;
  133. }
  134.  
  135. static void
  136. add_read_dep(struct schedule_state *state,
  137.               struct schedule_node *before,
  138.               struct schedule_node *after)
  139. {
  140.         add_dep(state, before, after, false);
  141. }
  142.  
  143. static void
  144. add_write_dep(struct schedule_state *state,
  145.               struct schedule_node **before,
  146.               struct schedule_node *after)
  147. {
  148.         add_dep(state, *before, after, true);
  149.         *before = after;
  150. }
  151.  
  152. static bool
  153. qpu_writes_r4(uint64_t inst)
  154. {
  155.         uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
  156.  
  157.         switch(sig) {
  158.         case QPU_SIG_COLOR_LOAD:
  159.         case QPU_SIG_LOAD_TMU0:
  160.         case QPU_SIG_LOAD_TMU1:
  161.         case QPU_SIG_ALPHA_MASK_LOAD:
  162.                 return true;
  163.         default:
  164.                 return false;
  165.         }
  166. }
  167.  
  168. static void
  169. process_raddr_deps(struct schedule_state *state, struct schedule_node *n,
  170.                    uint32_t raddr, bool is_a)
  171. {
  172.         switch (raddr) {
  173.         case QPU_R_VARY:
  174.                 add_write_dep(state, &state->last_r[5], n);
  175.                 break;
  176.  
  177.         case QPU_R_VPM:
  178.                 add_write_dep(state, &state->last_vpm_read, n);
  179.                 break;
  180.  
  181.         case QPU_R_UNIF:
  182.         case QPU_R_NOP:
  183.         case QPU_R_ELEM_QPU:
  184.         case QPU_R_XY_PIXEL_COORD:
  185.         case QPU_R_MS_REV_FLAGS:
  186.                 break;
  187.  
  188.         default:
  189.                 if (raddr < 32) {
  190.                         if (is_a)
  191.                                 add_read_dep(state, state->last_ra[raddr], n);
  192.                         else
  193.                                 add_read_dep(state, state->last_rb[raddr], n);
  194.                 } else {
  195.                         fprintf(stderr, "unknown raddr %d\n", raddr);
  196.                         abort();
  197.                 }
  198.                 break;
  199.         }
  200. }
  201.  
  202. static bool
  203. is_tmu_write(uint32_t waddr)
  204. {
  205.         switch (waddr) {
  206.         case QPU_W_TMU0_S:
  207.         case QPU_W_TMU0_T:
  208.         case QPU_W_TMU0_R:
  209.         case QPU_W_TMU0_B:
  210.         case QPU_W_TMU1_S:
  211.         case QPU_W_TMU1_T:
  212.         case QPU_W_TMU1_R:
  213.         case QPU_W_TMU1_B:
  214.                 return true;
  215.         default:
  216.                 return false;
  217.         }
  218. }
  219.  
  220. static bool
  221. reads_uniform(uint64_t inst)
  222. {
  223.         if (QPU_GET_FIELD(inst, QPU_SIG) == QPU_SIG_LOAD_IMM)
  224.                 return false;
  225.  
  226.         return (QPU_GET_FIELD(inst, QPU_RADDR_A) == QPU_R_UNIF ||
  227.                 (QPU_GET_FIELD(inst, QPU_RADDR_B) == QPU_R_UNIF &&
  228.                  QPU_GET_FIELD(inst, QPU_SIG) != QPU_SIG_SMALL_IMM) ||
  229.                 is_tmu_write(QPU_GET_FIELD(inst, QPU_WADDR_ADD)) ||
  230.                 is_tmu_write(QPU_GET_FIELD(inst, QPU_WADDR_MUL)));
  231. }
  232.  
  233. static void
  234. process_mux_deps(struct schedule_state *state, struct schedule_node *n,
  235.                  uint32_t mux)
  236. {
  237.         if (mux != QPU_MUX_A && mux != QPU_MUX_B)
  238.                 add_read_dep(state, state->last_r[mux], n);
  239. }
  240.  
  241.  
  242. static void
  243. process_waddr_deps(struct schedule_state *state, struct schedule_node *n,
  244.                    uint32_t waddr, bool is_add)
  245. {
  246.         uint64_t inst = n->inst->inst;
  247.         bool is_a = is_add ^ ((inst & QPU_WS) != 0);
  248.  
  249.         if (waddr < 32) {
  250.                 if (is_a) {
  251.                         add_write_dep(state, &state->last_ra[waddr], n);
  252.                 } else {
  253.                         add_write_dep(state, &state->last_rb[waddr], n);
  254.                 }
  255.         } else if (is_tmu_write(waddr)) {
  256.                 add_write_dep(state, &state->last_tmu_write, n);
  257.         } else if (qpu_waddr_is_tlb(waddr)) {
  258.                 add_write_dep(state, &state->last_tlb, n);
  259.         } else {
  260.                 switch (waddr) {
  261.                 case QPU_W_ACC0:
  262.                 case QPU_W_ACC1:
  263.                 case QPU_W_ACC2:
  264.                 case QPU_W_ACC3:
  265.                 case QPU_W_ACC5:
  266.                         add_write_dep(state, &state->last_r[waddr - QPU_W_ACC0],
  267.                                       n);
  268.                         break;
  269.  
  270.                 case QPU_W_VPM:
  271.                         add_write_dep(state, &state->last_vpm, n);
  272.                         break;
  273.  
  274.                 case QPU_W_VPMVCD_SETUP:
  275.                         if (is_a)
  276.                                 add_write_dep(state, &state->last_vpm_read, n);
  277.                         else
  278.                                 add_write_dep(state, &state->last_vpm, n);
  279.                         break;
  280.  
  281.                 case QPU_W_SFU_RECIP:
  282.                 case QPU_W_SFU_RECIPSQRT:
  283.                 case QPU_W_SFU_EXP:
  284.                 case QPU_W_SFU_LOG:
  285.                         add_write_dep(state, &state->last_r[4], n);
  286.                         break;
  287.  
  288.                 case QPU_W_TLB_STENCIL_SETUP:
  289.                         /* This isn't a TLB operation that does things like
  290.                          * implicitly lock the scoreboard, but it does have to
  291.                          * appear before TLB_Z, and each of the TLB_STENCILs
  292.                          * have to schedule in the same order relative to each
  293.                          * other.
  294.                          */
  295.                         add_write_dep(state, &state->last_tlb, n);
  296.                         break;
  297.  
  298.                 case QPU_W_NOP:
  299.                         break;
  300.  
  301.                 default:
  302.                         fprintf(stderr, "Unknown waddr %d\n", waddr);
  303.                         abort();
  304.                 }
  305.         }
  306. }
  307.  
  308. static void
  309. process_cond_deps(struct schedule_state *state, struct schedule_node *n,
  310.                   uint32_t cond)
  311. {
  312.         switch (cond) {
  313.         case QPU_COND_NEVER:
  314.         case QPU_COND_ALWAYS:
  315.                 break;
  316.         default:
  317.                 add_read_dep(state, state->last_sf, n);
  318.                 break;
  319.         }
  320. }
  321.  
  322. /**
  323.  * Common code for dependencies that need to be tracked both forward and
  324.  * backward.
  325.  *
  326.  * This is for things like "all reads of r4 have to happen between the r4
  327.  * writes that surround them".
  328.  */
  329. static void
  330. calculate_deps(struct schedule_state *state, struct schedule_node *n)
  331. {
  332.         uint64_t inst = n->inst->inst;
  333.         uint32_t add_op = QPU_GET_FIELD(inst, QPU_OP_ADD);
  334.         uint32_t mul_op = QPU_GET_FIELD(inst, QPU_OP_MUL);
  335.         uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
  336.         uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
  337.         uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
  338.         uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
  339.         uint32_t add_a = QPU_GET_FIELD(inst, QPU_ADD_A);
  340.         uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
  341.         uint32_t mul_a = QPU_GET_FIELD(inst, QPU_MUL_A);
  342.         uint32_t mul_b = QPU_GET_FIELD(inst, QPU_MUL_B);
  343.         uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
  344.  
  345.         if (sig != QPU_SIG_LOAD_IMM) {
  346.                 process_raddr_deps(state, n, raddr_a, true);
  347.                 if (sig != QPU_SIG_SMALL_IMM)
  348.                         process_raddr_deps(state, n, raddr_b, false);
  349.         }
  350.  
  351.         if (add_op != QPU_A_NOP) {
  352.                 process_mux_deps(state, n, add_a);
  353.                 process_mux_deps(state, n, add_b);
  354.         }
  355.         if (mul_op != QPU_M_NOP) {
  356.                 process_mux_deps(state, n, mul_a);
  357.                 process_mux_deps(state, n, mul_b);
  358.         }
  359.  
  360.         process_waddr_deps(state, n, waddr_add, true);
  361.         process_waddr_deps(state, n, waddr_mul, false);
  362.         if (qpu_writes_r4(inst))
  363.                 add_write_dep(state, &state->last_r[4], n);
  364.  
  365.         switch (sig) {
  366.         case QPU_SIG_SW_BREAKPOINT:
  367.         case QPU_SIG_NONE:
  368.         case QPU_SIG_THREAD_SWITCH:
  369.         case QPU_SIG_LAST_THREAD_SWITCH:
  370.         case QPU_SIG_SMALL_IMM:
  371.         case QPU_SIG_LOAD_IMM:
  372.                 break;
  373.  
  374.         case QPU_SIG_LOAD_TMU0:
  375.         case QPU_SIG_LOAD_TMU1:
  376.                 /* TMU loads are coming from a FIFO, so ordering is important.
  377.                  */
  378.                 add_write_dep(state, &state->last_tmu_write, n);
  379.                 break;
  380.  
  381.         case QPU_SIG_COLOR_LOAD:
  382.                 add_read_dep(state, state->last_tlb, n);
  383.                 break;
  384.  
  385.         case QPU_SIG_PROG_END:
  386.         case QPU_SIG_WAIT_FOR_SCOREBOARD:
  387.         case QPU_SIG_SCOREBOARD_UNLOCK:
  388.         case QPU_SIG_COVERAGE_LOAD:
  389.         case QPU_SIG_COLOR_LOAD_END:
  390.         case QPU_SIG_ALPHA_MASK_LOAD:
  391.         case QPU_SIG_BRANCH:
  392.                 fprintf(stderr, "Unhandled signal bits %d\n", sig);
  393.                 abort();
  394.         }
  395.  
  396.         process_cond_deps(state, n, QPU_GET_FIELD(inst, QPU_COND_ADD));
  397.         process_cond_deps(state, n, QPU_GET_FIELD(inst, QPU_COND_ADD));
  398.         if (inst & QPU_SF)
  399.                 add_write_dep(state, &state->last_sf, n);
  400. }
  401.  
  402. static void
  403. calculate_forward_deps(struct vc4_compile *c, struct simple_node *schedule_list)
  404. {
  405.         struct simple_node *node;
  406.         struct schedule_state state;
  407.  
  408.         memset(&state, 0, sizeof(state));
  409.         state.dir = F;
  410.  
  411.         foreach(node, schedule_list)
  412.                 calculate_deps(&state, (struct schedule_node *)node);
  413. }
  414.  
  415. static void
  416. calculate_reverse_deps(struct vc4_compile *c, struct simple_node *schedule_list)
  417. {
  418.         struct simple_node *node;
  419.         struct schedule_state state;
  420.  
  421.         memset(&state, 0, sizeof(state));
  422.         state.dir = R;
  423.  
  424.         for (node = schedule_list->prev; schedule_list != node; node = node->prev) {
  425.                 calculate_deps(&state, (struct schedule_node *)node);
  426.         }
  427. }
  428.  
  429. struct choose_scoreboard {
  430.         int tick;
  431.         int last_sfu_write_tick;
  432.         uint32_t last_waddr_a, last_waddr_b;
  433. };
  434.  
  435. static bool
  436. reads_too_soon_after_write(struct choose_scoreboard *scoreboard, uint64_t inst)
  437. {
  438.         uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
  439.         uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
  440.         uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
  441.         uint32_t src_muxes[] = {
  442.                 QPU_GET_FIELD(inst, QPU_ADD_A),
  443.                 QPU_GET_FIELD(inst, QPU_ADD_B),
  444.                 QPU_GET_FIELD(inst, QPU_MUL_A),
  445.                 QPU_GET_FIELD(inst, QPU_MUL_B),
  446.         };
  447.         for (int i = 0; i < ARRAY_SIZE(src_muxes); i++) {
  448.                 if ((src_muxes[i] == QPU_MUX_A &&
  449.                      raddr_a < 32 &&
  450.                      scoreboard->last_waddr_a == raddr_a) ||
  451.                     (src_muxes[i] == QPU_MUX_B &&
  452.                      sig != QPU_SIG_SMALL_IMM &&
  453.                      raddr_b < 32 &&
  454.                      scoreboard->last_waddr_b == raddr_b)) {
  455.                         return true;
  456.                 }
  457.  
  458.                 if (src_muxes[i] == QPU_MUX_R4) {
  459.                         if (scoreboard->tick -
  460.                             scoreboard->last_sfu_write_tick <= 2) {
  461.                                 return true;
  462.                         }
  463.                 }
  464.         }
  465.  
  466.         return false;
  467. }
  468.  
  469. static bool
  470. pixel_scoreboard_too_soon(struct choose_scoreboard *scoreboard, uint64_t inst)
  471. {
  472.         return (scoreboard->tick < 2 && qpu_inst_is_tlb(inst));
  473. }
  474.  
  475. static int
  476. get_instruction_priority(uint64_t inst)
  477. {
  478.         uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
  479.         uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
  480.         uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
  481.         uint32_t baseline_score;
  482.         uint32_t next_score = 0;
  483.  
  484.         /* Schedule TLB operations as late as possible, to get more
  485.          * parallelism between shaders.
  486.          */
  487.         if (qpu_inst_is_tlb(inst))
  488.                 return next_score;
  489.         next_score++;
  490.  
  491.         /* Schedule texture read results collection late to hide latency. */
  492.         if (sig == QPU_SIG_LOAD_TMU0 || sig == QPU_SIG_LOAD_TMU1)
  493.                 return next_score;
  494.         next_score++;
  495.  
  496.         /* Default score for things that aren't otherwise special. */
  497.         baseline_score = next_score;
  498.         next_score++;
  499.  
  500.         /* Schedule texture read setup early to hide their latency better. */
  501.         if (is_tmu_write(waddr_add) || is_tmu_write(waddr_mul))
  502.                 return next_score;
  503.         next_score++;
  504.  
  505.         return baseline_score;
  506. }
  507.  
  508. static struct schedule_node *
  509. choose_instruction_to_schedule(struct choose_scoreboard *scoreboard,
  510.                                struct simple_node *schedule_list,
  511.                                struct schedule_node *prev_inst)
  512. {
  513.         struct schedule_node *chosen = NULL;
  514.         struct simple_node *node;
  515.         int chosen_prio = 0;
  516.  
  517.         foreach(node, schedule_list) {
  518.                 struct schedule_node *n = (struct schedule_node *)node;
  519.                 uint64_t inst = n->inst->inst;
  520.  
  521.                 /* "An instruction must not read from a location in physical
  522.                  *  regfile A or B that was written to by the previous
  523.                  *  instruction."
  524.                  */
  525.                 if (reads_too_soon_after_write(scoreboard, inst))
  526.                         continue;
  527.  
  528.                 /* "A scoreboard wait must not occur in the first two
  529.                  *  instructions of a fragment shader. This is either the
  530.                  *  explicit Wait for Scoreboard signal or an implicit wait
  531.                  *  with the first tile-buffer read or write instruction."
  532.                  */
  533.                 if (pixel_scoreboard_too_soon(scoreboard, inst))
  534.                         continue;
  535.  
  536.                 /* If we're trying to pair with another instruction, check
  537.                  * that they're compatible.
  538.                  */
  539.                 if (prev_inst) {
  540.                         if (prev_inst->uniform != -1 && n->uniform != -1)
  541.                                 continue;
  542.  
  543.                         inst = qpu_merge_inst(prev_inst->inst->inst, inst);
  544.                         if (!inst)
  545.                                 continue;
  546.                 }
  547.  
  548.                 int prio = get_instruction_priority(inst);
  549.  
  550.                 /* Found a valid instruction.  If nothing better comes along,
  551.                  * this one works.
  552.                  */
  553.                 if (!chosen) {
  554.                         chosen = n;
  555.                         chosen_prio = prio;
  556.                         continue;
  557.                 }
  558.  
  559.                 if (prio > chosen_prio) {
  560.                         chosen = n;
  561.                         chosen_prio = prio;
  562.                 } else if (prio < chosen_prio) {
  563.                         continue;
  564.                 }
  565.  
  566.                 if (n->delay > chosen->delay) {
  567.                         chosen = n;
  568.                         chosen_prio = prio;
  569.                 } else if (n->delay < chosen->delay) {
  570.                         continue;
  571.                 }
  572.         }
  573.  
  574.         return chosen;
  575. }
  576.  
  577. static void
  578. update_scoreboard_for_chosen(struct choose_scoreboard *scoreboard,
  579.                              uint64_t inst)
  580. {
  581.         uint32_t waddr_add = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
  582.         uint32_t waddr_mul = QPU_GET_FIELD(inst, QPU_WADDR_MUL);
  583.  
  584.         if (!(inst & QPU_WS)) {
  585.                 scoreboard->last_waddr_a = waddr_add;
  586.                 scoreboard->last_waddr_b = waddr_mul;
  587.         } else {
  588.                 scoreboard->last_waddr_b = waddr_add;
  589.                 scoreboard->last_waddr_a = waddr_mul;
  590.         }
  591.  
  592.         if ((waddr_add >= QPU_W_SFU_RECIP && waddr_add <= QPU_W_SFU_LOG) ||
  593.             (waddr_mul >= QPU_W_SFU_RECIP && waddr_mul <= QPU_W_SFU_LOG)) {
  594.                 scoreboard->last_sfu_write_tick = scoreboard->tick;
  595.         }
  596. }
  597.  
  598. static void
  599. dump_state(struct simple_node *schedule_list)
  600. {
  601.         struct simple_node *node;
  602.  
  603.         uint32_t i = 0;
  604.         foreach(node, schedule_list) {
  605.                 struct schedule_node *n = (struct schedule_node *)node;
  606.  
  607.                 fprintf(stderr, "%3d: ", i++);
  608.                 vc4_qpu_disasm(&n->inst->inst, 1);
  609.                 fprintf(stderr, "\n");
  610.  
  611.                 for (int i = 0; i < n->child_count; i++) {
  612.                         struct schedule_node *child = n->children[i].node;
  613.                         if (!child)
  614.                                 continue;
  615.  
  616.                         fprintf(stderr, "   - ");
  617.                         vc4_qpu_disasm(&child->inst->inst, 1);
  618.                         fprintf(stderr, " (%d parents, %c)\n",
  619.                                 child->parent_count,
  620.                                 n->children[i].write_after_read ? 'w' : 'r');
  621.                 }
  622.         }
  623. }
  624.  
  625. /** Recursive computation of the delay member of a node. */
  626. static void
  627. compute_delay(struct schedule_node *n)
  628. {
  629.         if (!n->child_count) {
  630.                 n->delay = 1;
  631.         } else {
  632.                 for (int i = 0; i < n->child_count; i++) {
  633.                         if (!n->children[i].node->delay)
  634.                                 compute_delay(n->children[i].node);
  635.                         n->delay = MAX2(n->delay,
  636.                                         n->children[i].node->delay + n->latency);
  637.                 }
  638.         }
  639. }
  640.  
  641. static void
  642. mark_instruction_scheduled(struct simple_node *schedule_list,
  643.                            struct schedule_node *node,
  644.                            bool war_only)
  645. {
  646.         if (!node)
  647.                 return;
  648.  
  649.         for (int i = node->child_count - 1; i >= 0; i--) {
  650.                 struct schedule_node *child =
  651.                         node->children[i].node;
  652.  
  653.                 if (!child)
  654.                         continue;
  655.  
  656.                 if (war_only && !node->children[i].write_after_read)
  657.                         continue;
  658.  
  659.                 child->parent_count--;
  660.                 if (child->parent_count == 0)
  661.                         insert_at_head(schedule_list, &child->link);
  662.  
  663.                 node->children[i].node = NULL;
  664.         }
  665. }
  666.  
  667. static void
  668. schedule_instructions(struct vc4_compile *c, struct simple_node *schedule_list)
  669. {
  670.         struct simple_node *node, *t;
  671.         struct choose_scoreboard scoreboard;
  672.  
  673.         /* We reorder the uniforms as we schedule instructions, so save the
  674.          * old data off and replace it.
  675.          */
  676.         uint32_t *uniform_data = c->uniform_data;
  677.         enum quniform_contents *uniform_contents = c->uniform_contents;
  678.         c->uniform_contents = ralloc_array(c, enum quniform_contents,
  679.                                            c->num_uniforms);
  680.         c->uniform_data = ralloc_array(c, uint32_t, c->num_uniforms);
  681.         c->uniform_array_size = c->num_uniforms;
  682.         uint32_t next_uniform = 0;
  683.  
  684.         memset(&scoreboard, 0, sizeof(scoreboard));
  685.         scoreboard.last_waddr_a = ~0;
  686.         scoreboard.last_waddr_b = ~0;
  687.         scoreboard.last_sfu_write_tick = -10;
  688.  
  689.         if (debug) {
  690.                 fprintf(stderr, "initial deps:\n");
  691.                 dump_state(schedule_list);
  692.                 fprintf(stderr, "\n");
  693.         }
  694.  
  695.         /* Remove non-DAG heads from the list. */
  696.         foreach_s(node, t, schedule_list) {
  697.                 struct schedule_node *n = (struct schedule_node *)node;
  698.  
  699.                 if (n->parent_count != 0)
  700.                         remove_from_list(&n->link);
  701.         }
  702.  
  703.         while (!is_empty_list(schedule_list)) {
  704.                 struct schedule_node *chosen =
  705.                         choose_instruction_to_schedule(&scoreboard,
  706.                                                        schedule_list,
  707.                                                        NULL);
  708.                 struct schedule_node *merge = NULL;
  709.  
  710.                 /* If there are no valid instructions to schedule, drop a NOP
  711.                  * in.
  712.                  */
  713.                 uint64_t inst = chosen ? chosen->inst->inst : qpu_NOP();
  714.  
  715.                 if (debug) {
  716.                         fprintf(stderr, "current list:\n");
  717.                         dump_state(schedule_list);
  718.                         fprintf(stderr, "chose: ");
  719.                         vc4_qpu_disasm(&inst, 1);
  720.                         fprintf(stderr, "\n");
  721.                 }
  722.  
  723.                 /* Schedule this instruction onto the QPU list. Also try to
  724.                  * find an instruction to pair with it.
  725.                  */
  726.                 if (chosen) {
  727.                         remove_from_list(&chosen->link);
  728.                         mark_instruction_scheduled(schedule_list, chosen, true);
  729.                         if (chosen->uniform != -1) {
  730.                                 c->uniform_data[next_uniform] =
  731.                                         uniform_data[chosen->uniform];
  732.                                 c->uniform_contents[next_uniform] =
  733.                                         uniform_contents[chosen->uniform];
  734.                                 next_uniform++;
  735.                         }
  736.  
  737.                         merge = choose_instruction_to_schedule(&scoreboard,
  738.                                                                schedule_list,
  739.                                                                chosen);
  740.                         if (merge) {
  741.                                 remove_from_list(&merge->link);
  742.                                 inst = qpu_merge_inst(inst, merge->inst->inst);
  743.                                 assert(inst != 0);
  744.                                 if (merge->uniform != -1) {
  745.                                         c->uniform_data[next_uniform] =
  746.                                                 uniform_data[merge->uniform];
  747.                                         c->uniform_contents[next_uniform] =
  748.                                                 uniform_contents[merge->uniform];
  749.                                         next_uniform++;
  750.                                 }
  751.  
  752.                                 if (debug) {
  753.                                         fprintf(stderr, "merging: ");
  754.                                         vc4_qpu_disasm(&merge->inst->inst, 1);
  755.                                         fprintf(stderr, "\n");
  756.                                         fprintf(stderr, "resulting in: ");
  757.                                         vc4_qpu_disasm(&inst, 1);
  758.                                         fprintf(stderr, "\n");
  759.                                 }
  760.                         }
  761.                 }
  762.  
  763.                 if (debug) {
  764.                         fprintf(stderr, "\n");
  765.                 }
  766.  
  767.                 qpu_serialize_one_inst(c, inst);
  768.  
  769.                 update_scoreboard_for_chosen(&scoreboard, inst);
  770.  
  771.                 /* Now that we've scheduled a new instruction, some of its
  772.                  * children can be promoted to the list of instructions ready to
  773.                  * be scheduled.  Update the children's unblocked time for this
  774.                  * DAG edge as we do so.
  775.                  */
  776.                 mark_instruction_scheduled(schedule_list, chosen, false);
  777.                 mark_instruction_scheduled(schedule_list, merge, false);
  778.  
  779.                 scoreboard.tick++;
  780.         }
  781.  
  782.         assert(next_uniform == c->num_uniforms);
  783. }
  784.  
  785. static uint32_t waddr_latency(uint32_t waddr)
  786. {
  787.         if (waddr < 32)
  788.                 return 2;
  789.  
  790.         /* Some huge number, really. */
  791.         if (waddr >= QPU_W_TMU0_S && waddr <= QPU_W_TMU1_B)
  792.                 return 10;
  793.  
  794.         switch(waddr) {
  795.         case QPU_W_SFU_RECIP:
  796.         case QPU_W_SFU_RECIPSQRT:
  797.         case QPU_W_SFU_EXP:
  798.         case QPU_W_SFU_LOG:
  799.                 return 3;
  800.         default:
  801.                 return 1;
  802.         }
  803. }
  804.  
  805. static uint32_t
  806. instruction_latency(uint64_t inst)
  807. {
  808.         return MAX2(waddr_latency(QPU_GET_FIELD(inst, QPU_WADDR_ADD)),
  809.                     waddr_latency(QPU_GET_FIELD(inst, QPU_WADDR_MUL)));
  810. }
  811.  
  812. void
  813. qpu_schedule_instructions(struct vc4_compile *c)
  814. {
  815.         void *mem_ctx = ralloc_context(NULL);
  816.         struct simple_node schedule_list;
  817.         struct simple_node *node;
  818.  
  819.         make_empty_list(&schedule_list);
  820.  
  821.         if (debug) {
  822.                 fprintf(stderr, "Pre-schedule instructions\n");
  823.                 foreach(node, &c->qpu_inst_list) {
  824.                         struct queued_qpu_inst *q =
  825.                                 (struct queued_qpu_inst *)node;
  826.                         vc4_qpu_disasm(&q->inst, 1);
  827.                         fprintf(stderr, "\n");
  828.                 }
  829.                 fprintf(stderr, "\n");
  830.         }
  831.  
  832.         /* Wrap each instruction in a scheduler structure. */
  833.         uint32_t next_uniform = 0;
  834.         while (!is_empty_list(&c->qpu_inst_list)) {
  835.                 struct queued_qpu_inst *inst =
  836.                         (struct queued_qpu_inst *)c->qpu_inst_list.next;
  837.                 struct schedule_node *n = rzalloc(mem_ctx, struct schedule_node);
  838.  
  839.                 n->inst = inst;
  840.                 n->latency = instruction_latency(inst->inst);
  841.  
  842.                 if (reads_uniform(inst->inst)) {
  843.                         n->uniform = next_uniform++;
  844.                 } else {
  845.                         n->uniform = -1;
  846.                 }
  847.                 remove_from_list(&inst->link);
  848.                 insert_at_tail(&schedule_list, &n->link);
  849.         }
  850.         assert(next_uniform == c->num_uniforms);
  851.  
  852.         calculate_forward_deps(c, &schedule_list);
  853.         calculate_reverse_deps(c, &schedule_list);
  854.  
  855.         foreach(node, &schedule_list) {
  856.                 struct schedule_node *n = (struct schedule_node *)node;
  857.                 compute_delay(n);
  858.         }
  859.  
  860.         schedule_instructions(c, &schedule_list);
  861.  
  862.         if (debug) {
  863.                 fprintf(stderr, "Post-schedule instructions\n");
  864.                 vc4_qpu_disasm(c->qpu_insts, c->qpu_inst_count);
  865.                 fprintf(stderr, "\n");
  866.         }
  867.  
  868.         ralloc_free(mem_ctx);
  869. }
  870.