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