xref: /aosp_15_r20/external/mesa3d/src/panfrost/midgard/midgard_ra_pipeline.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (C) 2019 Alyssa Rosenzweig <[email protected]>
3  * Copyright (C) 2019 Collabora, Ltd.
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 FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include "compiler.h"
26 
27 /* Creates pipeline registers. This is a prepass run before the main register
28  * allocator but after scheduling, once bundles are created. It works by
29  * iterating the scheduled IR, checking if a value is ever used after the end
30  * of the current bundle. If it is not, it is promoted to a bundle-specific
31  * pipeline register.
32  *
33  * Pipeline registers are only written from the first two stages of the
34  * pipeline (vmul/sadd) lasting the duration of the bundle only. There are two
35  * 128-bit pipeline registers available (r24/r25). The upshot is that no actual
36  * register allocation is needed; we can _always_ promote a value to a pipeline
37  * register, liveness permitting. This greatly simplifies the logic of this
38  * passing, negating the need for a proper RA like work registers.
39  */
40 
41 static bool
mir_pipeline_ins(compiler_context * ctx,midgard_block * block,midgard_bundle * bundle,unsigned i,unsigned pipeline_count)42 mir_pipeline_ins(compiler_context *ctx, midgard_block *block,
43                  midgard_bundle *bundle, unsigned i, unsigned pipeline_count)
44 {
45    midgard_instruction *ins = bundle->instructions[i];
46 
47    /* Our goal is to create a pipeline register. Pipeline registers are
48     * created at the start of the bundle and are destroyed at the end. So
49     * we conservatively require:
50     *
51     *  1. Each component read in the second stage is written in the first stage.
52     *  2. The index is not live after the bundle.
53     *  3. We're not a special index (writeout, conditionals, ..)
54     *
55     * Rationale: #1 ensures that there is no need to go before the
56     * creation of the bundle, so the pipeline register can exist. #2 is
57     * since the pipeline register will be destroyed at the end. This
58     * ensures that nothing will try to read/write the pipeline register
59     * once it is not live, and that there's no need to go earlier. */
60 
61    unsigned node = ins->dest;
62    unsigned read_mask = 0;
63 
64    if (node >= SSA_FIXED_MINIMUM)
65       return false;
66 
67    if (node == ctx->blend_src1)
68       return false;
69 
70    /* Analyze the bundle for a per-byte read mask */
71 
72    for (unsigned j = 0; j < bundle->instruction_count; ++j) {
73       midgard_instruction *q = bundle->instructions[j];
74 
75       /* The fragment colour can't be pipelined (well, it is
76        * pipelined in r0, but this is a delicate dance with
77        * scheduling and RA, not for us to worry about) */
78 
79       if (q->compact_branch && q->writeout && mir_has_arg(q, node))
80          return false;
81 
82       if (q->unit < UNIT_VADD)
83          continue;
84       read_mask |= mir_bytemask_of_read_components(q, node);
85    }
86 
87    /* Now check what's written in the beginning stage  */
88    for (unsigned j = 0; j < bundle->instruction_count; ++j) {
89       midgard_instruction *q = bundle->instructions[j];
90       if (q->unit >= UNIT_VADD)
91          break;
92       if (q->dest != node)
93          continue;
94 
95       /* Remove the written mask from the read requirements */
96       read_mask &= ~mir_bytemask(q);
97    }
98 
99    /* Check for leftovers */
100    if (read_mask)
101       return false;
102 
103    /* We want to know if we live after this bundle, so check if
104     * we're live after the last instruction of the bundle */
105 
106    midgard_instruction *end =
107       bundle->instructions[bundle->instruction_count - 1];
108 
109    if (mir_is_live_after(ctx, block, end, ins->dest))
110       return false;
111 
112    /* We're only live in this bundle -- pipeline! */
113    unsigned preg = SSA_FIXED_REGISTER(24 + pipeline_count);
114 
115    for (unsigned j = 0; j < bundle->instruction_count; ++j) {
116       midgard_instruction *q = bundle->instructions[j];
117 
118       if (q->unit >= UNIT_VADD)
119          mir_rewrite_index_src_single(q, node, preg);
120       else
121          mir_rewrite_index_dst_single(q, node, preg);
122    }
123 
124    return true;
125 }
126 
127 void
mir_create_pipeline_registers(compiler_context * ctx)128 mir_create_pipeline_registers(compiler_context *ctx)
129 {
130    mir_invalidate_liveness(ctx);
131 
132    mir_foreach_block(ctx, _block) {
133       midgard_block *block = (midgard_block *)_block;
134 
135       mir_foreach_bundle_in_block(block, bundle) {
136          if (!mir_is_alu_bundle(bundle))
137             continue;
138          if (bundle->instruction_count < 2)
139             continue;
140 
141          /* Only first 2 instructions could pipeline */
142          bool succ = mir_pipeline_ins(ctx, block, bundle, 0, 0);
143          mir_pipeline_ins(ctx, block, bundle, 1, succ);
144       }
145    }
146 }
147