1 /*
2 * Copyright (C) 2020 Collabora Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors (Collabora):
24 * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
25 */
26
27 #include "compiler.h"
28
29 /* Assign dependency slots to each clause and calculate dependencies, This pass
30 * must be run after scheduling.
31 *
32 * 1. A clause that does not produce a message must use the sentinel slot #0
33 * 2a. A clause that depends on the results of a previous message-passing
34 * instruction must depend on that instruction's dependency slot, unless all
35 * reaching code paths already depended on it.
36 * 2b. More generally, any dependencies must be encoded. This includes
37 * Write-After-Write and Write-After-Read hazards with LOAD/STORE to memory.
38 * 3. The shader must wait on slot #6 before running BLEND, ATEST
39 * 4. The shader must wait on slot #7 before running BLEND, ST_TILE
40 * 5. ATEST, ZS_EMIT must be issued with slot #0
41 * 6. BARRIER must be issued with slot #7
42 * 7. Only slots #0 through #5 may be used for clauses not otherwise specified.
43 * 8. If a clause writes to a read staging register of an unresolved
44 * dependency, it must set a staging barrier.
45 *
46 * Note it _is_ legal to reuse slots for multiple message passing instructions
47 * with overlapping liveness, albeit with a slight performance penalty. As such
48 * the problem is significantly easier than register allocation, rather than
49 * spilling we may simply reuse slots. (TODO: does this have an optimal
50 * linear-time solution).
51 *
52 * Within these constraints we are free to assign slots as we like. This pass
53 * attempts to minimize stalls (TODO).
54 */
55
56 #define BI_NUM_GENERAL_SLOTS 6
57
58 /* A model for the state of the scoreboard */
59
60 struct bi_scoreboard_state {
61 /* TODO: what do we track here for a heuristic? */
62 };
63
64 /* Given a scoreboard model, choose a slot for a clause wrapping a given
65 * message passing instruction. No side effects. */
66
67 static unsigned
bi_choose_scoreboard_slot(struct bi_scoreboard_state * st,bi_instr * message)68 bi_choose_scoreboard_slot(struct bi_scoreboard_state *st, bi_instr *message)
69 {
70 /* A clause that does not produce a message must use slot #0 */
71 if (!message)
72 return 0;
73
74 switch (message->op) {
75 /* ATEST, ZS_EMIT must be issued with slot #0 */
76 case BI_OPCODE_ATEST:
77 case BI_OPCODE_ZS_EMIT:
78 return 0;
79
80 /* BARRIER must be issued with slot #7 */
81 case BI_OPCODE_BARRIER:
82 return 7;
83
84 default:
85 break;
86 }
87
88 /* TODO: Use a heuristic */
89 return 0;
90 }
91
92 void
bi_assign_scoreboard(bi_context * ctx)93 bi_assign_scoreboard(bi_context *ctx)
94 {
95 struct bi_scoreboard_state st = {};
96
97 /* Assign slots */
98 bi_foreach_block(ctx, block) {
99 bi_foreach_clause_in_block(block, clause) {
100 unsigned slot = bi_choose_scoreboard_slot(&st, clause->message);
101 clause->scoreboard_id = slot;
102
103 bi_clause *next = bi_next_clause(ctx, block, clause);
104 if (next)
105 next->dependencies |= (1 << slot);
106 }
107 }
108 }
109