1 /*
2 * Copyright © 2024 Imagination Technologies Ltd.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 /**
8 * \file pco_binary.c
9 *
10 * \brief PCO binary-specific functions.
11 */
12
13 #include "pco.h"
14 #include "pco_internal.h"
15 #include "pco_isa.h"
16 #include "pco_map.h"
17 #include "util/u_dynarray.h"
18
19 #include <assert.h>
20 #include <stdint.h>
21 #include <stdio.h>
22
23 /**
24 * \brief Encodes instruction group alignment.
25 *
26 * \param[in,out] buf Binary buffer.
27 * \param[in] igrp PCO instruction group.
28 */
pco_encode_align(struct util_dynarray * buf,pco_igrp * igrp)29 static inline unsigned pco_encode_align(struct util_dynarray *buf,
30 pco_igrp *igrp)
31 {
32 unsigned bytes_encoded = 0;
33
34 if (igrp->enc.len.word_padding) {
35 util_dynarray_append(buf, uint8_t, 0xff);
36 bytes_encoded += 1;
37 }
38
39 if (igrp->enc.len.align_padding) {
40 assert(!(igrp->enc.len.align_padding % 2));
41
42 unsigned align_words = igrp->enc.len.align_padding / 2;
43 util_dynarray_append(buf, uint8_t, 0xf0 | align_words);
44 bytes_encoded += 1;
45
46 for (unsigned u = 0; u < igrp->enc.len.align_padding - 1; ++u) {
47 util_dynarray_append(buf, uint8_t, 0xff);
48 bytes_encoded += 1;
49 }
50 }
51
52 return bytes_encoded;
53 }
54
55 /**
56 * \brief Encodes a PCO instruction group into binary.
57 *
58 * \param[in,out] buf Binary buffer.
59 * \param[in] igrp PCO instruction group.
60 * \return The number of bytes encoded.
61 */
pco_encode_igrp(struct util_dynarray * buf,pco_igrp * igrp)62 static unsigned pco_encode_igrp(struct util_dynarray *buf, pco_igrp *igrp)
63 {
64 uint8_t *ptr;
65 unsigned bytes_encoded = 0;
66
67 /* Header. */
68 ptr = util_dynarray_grow(buf, uint8_t, igrp->enc.len.hdr);
69 bytes_encoded += pco_igrp_hdr_map_encode(ptr, igrp);
70
71 /* Instructions. */
72 for (enum pco_op_phase p = _PCO_OP_PHASE_COUNT; p-- > 0;) {
73 if (!igrp->enc.len.instrs[p])
74 continue;
75
76 ptr = util_dynarray_grow(buf, uint8_t, igrp->enc.len.instrs[p]);
77 bytes_encoded += pco_instr_map_encode(ptr, igrp, p);
78 }
79
80 /* I/O. */
81 if (igrp->enc.len.lower_srcs) {
82 ptr = util_dynarray_grow(buf, uint8_t, igrp->enc.len.lower_srcs);
83 bytes_encoded += pco_srcs_map_encode(ptr, igrp, false);
84 }
85
86 if (igrp->enc.len.upper_srcs) {
87 ptr = util_dynarray_grow(buf, uint8_t, igrp->enc.len.upper_srcs);
88 bytes_encoded += pco_srcs_map_encode(ptr, igrp, true);
89 }
90
91 if (igrp->enc.len.iss) {
92 ptr = util_dynarray_grow(buf, uint8_t, igrp->enc.len.iss);
93 bytes_encoded += pco_iss_map_encode(ptr, igrp);
94 }
95
96 if (igrp->enc.len.dests) {
97 ptr = util_dynarray_grow(buf, uint8_t, igrp->enc.len.dests);
98 bytes_encoded += pco_dests_map_encode(ptr, igrp);
99 }
100
101 /* Word/alignment padding. */
102 bytes_encoded += pco_encode_align(buf, igrp);
103
104 assert(bytes_encoded == igrp->enc.len.total);
105
106 return bytes_encoded;
107 }
108
109 /**
110 * \brief Encodes a PCO shader into binary.
111 *
112 * \param[in] ctx PCO compiler context.
113 * \param[in,out] shader PCO shader.
114 */
pco_encode_ir(pco_ctx * ctx,pco_shader * shader)115 void pco_encode_ir(pco_ctx *ctx, pco_shader *shader)
116 {
117 assert(shader->is_grouped);
118
119 util_dynarray_init(&shader->binary.buf, shader);
120
121 unsigned bytes_encoded = 0;
122 pco_foreach_func_in_shader (func, shader) {
123 func->enc_offset = bytes_encoded;
124 pco_foreach_block_in_func (block, func) {
125 pco_foreach_igrp_in_block (igrp, block) {
126 bytes_encoded += pco_encode_igrp(&shader->binary.buf, igrp);
127 }
128 }
129 }
130
131 if (pco_should_print_binary(shader))
132 pco_print_binary(shader, stdout, "after encoding");
133 }
134
135 /**
136 * \brief Finalizes a PCO shader binary.
137 *
138 * \param[in] ctx PCO compiler context.
139 * \param[in,out] shader PCO shader.
140 */
pco_shader_finalize(pco_ctx * ctx,pco_shader * shader)141 void pco_shader_finalize(pco_ctx *ctx, pco_shader *shader)
142 {
143 puts("finishme: pco_shader_finalize");
144
145 pco_func *entry = pco_entrypoint(shader);
146 shader->data.common.entry_offset = entry->enc_offset;
147
148 if (pco_should_print_binary(shader))
149 pco_print_binary(shader, stdout, "after finalizing");
150 }
151
152 /**
153 * \brief Returns the size in bytes of a PCO shader binary.
154 *
155 * \param[in] shader PCO shader.
156 * \return The size in bytes of the PCO shader binary.
157 */
pco_shader_binary_size(pco_shader * shader)158 unsigned pco_shader_binary_size(pco_shader *shader)
159 {
160 return shader->binary.buf.size;
161 }
162
163 /**
164 * \brief Returns the PCO shader binary data.
165 *
166 * \param[in] shader PCO shader.
167 * \return The PCO shader binary data.
168 */
pco_shader_binary_data(pco_shader * shader)169 const void *pco_shader_binary_data(pco_shader *shader)
170 {
171 return shader->binary.buf.data;
172 }
173