2 * Copyright © 2016 Broadcom
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:
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
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #include "compiler/v3d_compiler.h"
25 #include "qpu/qpu_instr.h"
26 #include "qpu/qpu_disasm.h"
28 static inline struct qpu_reg
31 struct qpu_reg reg
= {
38 static inline struct qpu_reg
39 qpu_magic(enum v3d_qpu_waddr waddr
)
41 struct qpu_reg reg
= {
48 static inline struct qpu_reg
51 return qpu_magic(V3D_QPU_WADDR_R0
+ acc
);
57 struct v3d_qpu_instr instr
= {
58 .type
= V3D_QPU_INSTR_TYPE_ALU
,
62 .waddr
= V3D_QPU_WADDR_NOP
,
67 .waddr
= V3D_QPU_WADDR_NOP
,
79 struct qreg undef
= { QFILE_NULL
, 0 };
80 struct qinst
*qinst
= vir_add_inst(V3D_QPU_A_NOP
, undef
, undef
, undef
);
86 new_qpu_nop_before(struct qinst
*inst
)
88 struct qinst
*q
= vir_nop();
90 list_addtail(&q
->link
, &inst
->link
);
96 new_ldunif_instr(struct qinst
*inst
, int i
)
98 struct qinst
*ldunif
= new_qpu_nop_before(inst
);
100 ldunif
->qpu
.sig
.ldunif
= true;
101 assert(inst
->src
[i
].file
== QFILE_UNIF
);
102 ldunif
->uniform
= inst
->src
[i
].index
;
106 * Allocates the src register (accumulator or register file) into the RADDR
107 * fields of the instruction.
110 set_src(struct v3d_qpu_instr
*instr
, enum v3d_qpu_mux
*mux
, struct qpu_reg src
)
113 assert(src
.index
>= V3D_QPU_WADDR_R0
&&
114 src
.index
<= V3D_QPU_WADDR_R5
);
115 *mux
= src
.index
- V3D_QPU_WADDR_R0
+ V3D_QPU_MUX_R0
;
119 if (instr
->alu
.add
.a
!= V3D_QPU_MUX_A
&&
120 instr
->alu
.add
.b
!= V3D_QPU_MUX_A
&&
121 instr
->alu
.mul
.a
!= V3D_QPU_MUX_A
&&
122 instr
->alu
.mul
.b
!= V3D_QPU_MUX_A
) {
123 instr
->raddr_a
= src
.index
;
124 *mux
= V3D_QPU_MUX_A
;
126 if (instr
->raddr_a
== src
.index
) {
127 *mux
= V3D_QPU_MUX_A
;
129 assert(!(instr
->alu
.add
.a
== V3D_QPU_MUX_B
&&
130 instr
->alu
.add
.b
== V3D_QPU_MUX_B
&&
131 instr
->alu
.mul
.a
== V3D_QPU_MUX_B
&&
132 instr
->alu
.mul
.b
== V3D_QPU_MUX_B
) ||
133 src
.index
== instr
->raddr_b
);
135 instr
->raddr_b
= src
.index
;
136 *mux
= V3D_QPU_MUX_B
;
142 v3d_generate_code_block(struct v3d_compile
*c
,
143 struct qblock
*block
,
144 struct qpu_reg
*temp_registers
)
146 int last_vpm_read_index
= -1;
148 vir_for_each_inst(qinst
, block
) {
150 fprintf(stderr
, "translating qinst to qpu: ");
151 vir_dump_inst(c
, qinst
);
152 fprintf(stderr
, "\n");
157 if (vir_has_implicit_uniform(qinst
)) {
158 int src
= vir_get_implicit_uniform_src(qinst
);
159 assert(qinst
->src
[src
].file
== QFILE_UNIF
);
160 qinst
->uniform
= qinst
->src
[src
].index
;
164 int nsrc
= vir_get_non_sideband_nsrc(qinst
);
165 struct qpu_reg src
[ARRAY_SIZE(qinst
->src
)];
166 bool emitted_ldunif
= false;
167 for (int i
= 0; i
< nsrc
; i
++) {
168 int index
= qinst
->src
[i
].index
;
169 switch (qinst
->src
[i
].file
) {
171 src
[i
] = qpu_reg(qinst
->src
[i
].index
);
174 src
[i
] = qpu_magic(qinst
->src
[i
].index
);
181 src
[i
] = temp_registers
[index
];
184 if (!emitted_ldunif
) {
185 new_ldunif_instr(qinst
, i
);
187 emitted_ldunif
= true;
192 case QFILE_SMALL_IMM
:
195 src
[i
].mux
= QPU_MUX_SMALL_IMM
;
196 src
[i
].addr
= qpu_encode_small_immediate(qinst
->src
[i
].index
);
197 /* This should only have returned a valid
198 * small immediate field, not ~0 for failure.
200 assert(src
[i
].addr
<= 47);
205 assert((int)qinst
->src
[i
].index
>=
206 last_vpm_read_index
);
207 (void)last_vpm_read_index
;
208 last_vpm_read_index
= qinst
->src
[i
].index
;
210 temp
= new_qpu_nop_before(qinst
);
211 temp
->qpu
.sig
.ldvpm
= true;
218 unreachable("bad vir src file");
223 switch (qinst
->dst
.file
) {
225 dst
= qpu_magic(V3D_QPU_WADDR_NOP
);
229 dst
= qpu_reg(qinst
->dst
.index
);
233 dst
= qpu_magic(qinst
->dst
.index
);
237 dst
= temp_registers
[qinst
->dst
.index
];
241 dst
= qpu_magic(V3D_QPU_WADDR_VPM
);
245 dst
= qpu_magic(V3D_QPU_WADDR_TLB
);
249 dst
= qpu_magic(V3D_QPU_WADDR_TLBU
);
253 case QFILE_SMALL_IMM
:
255 assert(!"not reached");
259 if (qinst
->qpu
.type
== V3D_QPU_INSTR_TYPE_ALU
) {
260 if (v3d_qpu_sig_writes_address(c
->devinfo
,
262 assert(qinst
->qpu
.alu
.add
.op
== V3D_QPU_A_NOP
);
263 assert(qinst
->qpu
.alu
.mul
.op
== V3D_QPU_M_NOP
);
265 qinst
->qpu
.sig_addr
= dst
.index
;
266 qinst
->qpu
.sig_magic
= dst
.magic
;
267 } else if (qinst
->qpu
.alu
.add
.op
!= V3D_QPU_A_NOP
) {
268 assert(qinst
->qpu
.alu
.mul
.op
== V3D_QPU_M_NOP
);
271 &qinst
->qpu
.alu
.add
.a
, src
[0]);
275 &qinst
->qpu
.alu
.add
.b
, src
[1]);
278 qinst
->qpu
.alu
.add
.waddr
= dst
.index
;
279 qinst
->qpu
.alu
.add
.magic_write
= dst
.magic
;
283 &qinst
->qpu
.alu
.mul
.a
, src
[0]);
287 &qinst
->qpu
.alu
.mul
.b
, src
[1]);
290 qinst
->qpu
.alu
.mul
.waddr
= dst
.index
;
291 qinst
->qpu
.alu
.mul
.magic_write
= dst
.magic
;
294 assert(qinst
->qpu
.type
== V3D_QPU_INSTR_TYPE_BRANCH
);
301 v3d_dump_qpu(struct v3d_compile
*c
)
303 fprintf(stderr
, "%s prog %d/%d QPU:\n",
304 vir_get_stage_name(c
),
305 c
->program_id
, c
->variant_id
);
307 for (int i
= 0; i
< c
->qpu_inst_count
; i
++) {
308 const char *str
= v3d_qpu_disasm(c
->devinfo
, c
->qpu_insts
[i
]);
309 fprintf(stderr
, "0x%016"PRIx64
" %s\n", c
->qpu_insts
[i
], str
);
311 fprintf(stderr
, "\n");
315 v3d_vir_to_qpu(struct v3d_compile
*c
, struct qpu_reg
*temp_registers
)
317 /* Reset the uniform count to how many will be actually loaded by the
318 * generated QPU code.
322 vir_for_each_block(block
, c
)
323 v3d_generate_code_block(c
, block
, temp_registers
);
325 uint32_t cycles
= v3d_qpu_schedule_instructions(c
);
327 c
->qpu_insts
= rzalloc_array(c
, uint64_t, c
->qpu_inst_count
);
329 vir_for_each_inst_inorder(inst
, c
) {
330 bool ok
= v3d_qpu_instr_pack(c
->devinfo
, &inst
->qpu
,
332 assert(ok
); (void) ok
;
334 assert(i
== c
->qpu_inst_count
);
336 if (V3D_DEBUG
& V3D_DEBUG_SHADERDB
) {
337 fprintf(stderr
, "SHADER-DB: %s prog %d/%d: %d estimated cycles\n",
338 vir_get_stage_name(c
),
339 c
->program_id
, c
->variant_id
,
343 if (V3D_DEBUG
& (V3D_DEBUG_QPU
|
344 v3d_debug_flag_for_shader_stage(c
->s
->info
.stage
))) {
350 free(temp_registers
);