panfrost/midgard: Implement txl
[mesa.git] / src / gallium / drivers / panfrost / midgard / midgard_emit.c
1 /*
2 * Copyright (C) 2018-2019 Alyssa Rosenzweig <alyssa@rosenzweig.io>
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
24 #include "compiler.h"
25 #include "midgard_ops.h"
26
27 /* Midgard IR only knows vector ALU types, but we sometimes need to actually
28 * use scalar ALU instructions, for functional or performance reasons. To do
29 * this, we just demote vector ALU payloads to scalar. */
30
31 static int
32 component_from_mask(unsigned mask)
33 {
34 for (int c = 0; c < 4; ++c) {
35 if (mask & (3 << (2 * c)))
36 return c;
37 }
38
39 assert(0);
40 return 0;
41 }
42
43 static unsigned
44 vector_to_scalar_source(unsigned u, bool is_int)
45 {
46 midgard_vector_alu_src v;
47 memcpy(&v, &u, sizeof(v));
48
49 /* TODO: Integers */
50
51 midgard_scalar_alu_src s = {
52 .full = !v.half,
53 .component = (v.swizzle & 3) << 1
54 };
55
56 if (is_int) {
57 /* TODO */
58 } else {
59 s.abs = v.mod & MIDGARD_FLOAT_MOD_ABS;
60 s.negate = v.mod & MIDGARD_FLOAT_MOD_NEG;
61 }
62
63 unsigned o;
64 memcpy(&o, &s, sizeof(s));
65
66 return o & ((1 << 6) - 1);
67 }
68
69 static midgard_scalar_alu
70 vector_to_scalar_alu(midgard_vector_alu v, midgard_instruction *ins)
71 {
72 bool is_int = midgard_is_integer_op(v.op);
73
74 /* The output component is from the mask */
75 midgard_scalar_alu s = {
76 .op = v.op,
77 .src1 = vector_to_scalar_source(v.src1, is_int),
78 .src2 = vector_to_scalar_source(v.src2, is_int),
79 .unknown = 0,
80 .outmod = v.outmod,
81 .output_full = 1, /* TODO: Half */
82 .output_component = component_from_mask(v.mask) << 1,
83 };
84
85 /* Inline constant is passed along rather than trying to extract it
86 * from v */
87
88 if (ins->ssa_args.inline_constant) {
89 uint16_t imm = 0;
90 int lower_11 = ins->inline_constant & ((1 << 12) - 1);
91 imm |= (lower_11 >> 9) & 3;
92 imm |= (lower_11 >> 6) & 4;
93 imm |= (lower_11 >> 2) & 0x38;
94 imm |= (lower_11 & 63) << 6;
95
96 s.src2 = imm;
97 }
98
99 return s;
100 }
101
102 static void
103 emit_alu_bundle(compiler_context *ctx,
104 midgard_bundle *bundle,
105 struct util_dynarray *emission,
106 unsigned lookahead)
107 {
108 /* Emit the control word */
109 util_dynarray_append(emission, uint32_t, bundle->control | lookahead);
110
111 /* Next up, emit register words */
112 for (unsigned i = 0; i < bundle->instruction_count; ++i) {
113 midgard_instruction *ins = bundle->instructions[i];
114
115 /* Check if this instruction has registers */
116 if (ins->compact_branch || ins->prepacked_branch) continue;
117
118 /* Otherwise, just emit the registers */
119 uint16_t reg_word = 0;
120 memcpy(&reg_word, &ins->registers, sizeof(uint16_t));
121 util_dynarray_append(emission, uint16_t, reg_word);
122 }
123
124 /* Now, we emit the body itself */
125 for (unsigned i = 0; i < bundle->instruction_count; ++i) {
126 midgard_instruction *ins = bundle->instructions[i];
127
128 /* Where is this body */
129 unsigned size = 0;
130 void *source = NULL;
131
132 /* In case we demote to a scalar */
133 midgard_scalar_alu scalarized;
134
135 if (ins->unit & UNITS_ANY_VECTOR) {
136 size = sizeof(midgard_vector_alu);
137 source = &ins->alu;
138 } else if (ins->unit == ALU_ENAB_BR_COMPACT) {
139 size = sizeof(midgard_branch_cond);
140 source = &ins->br_compact;
141 } else if (ins->compact_branch) { /* misnomer */
142 size = sizeof(midgard_branch_extended);
143 source = &ins->branch_extended;
144 } else {
145 size = sizeof(midgard_scalar_alu);
146 scalarized = vector_to_scalar_alu(ins->alu, ins);
147 source = &scalarized;
148 }
149
150 memcpy(util_dynarray_grow(emission, size), source, size);
151 }
152
153 /* Emit padding (all zero) */
154 memset(util_dynarray_grow(emission, bundle->padding), 0, bundle->padding);
155
156 /* Tack on constants */
157
158 if (bundle->has_embedded_constants) {
159 util_dynarray_append(emission, float, bundle->constants[0]);
160 util_dynarray_append(emission, float, bundle->constants[1]);
161 util_dynarray_append(emission, float, bundle->constants[2]);
162 util_dynarray_append(emission, float, bundle->constants[3]);
163 }
164 }
165
166 /* After everything is scheduled, emit whole bundles at a time */
167
168 void
169 emit_binary_bundle(compiler_context *ctx,
170 midgard_bundle *bundle,
171 struct util_dynarray *emission,
172 int next_tag)
173 {
174 int lookahead = next_tag << 4;
175
176 switch (bundle->tag) {
177 case TAG_ALU_4:
178 case TAG_ALU_8:
179 case TAG_ALU_12:
180 case TAG_ALU_16:
181 emit_alu_bundle(ctx, bundle, emission, lookahead);
182 break;
183
184 case TAG_LOAD_STORE_4: {
185 /* One or two composing instructions */
186
187 uint64_t current64, next64 = LDST_NOP;
188
189 memcpy(&current64, &bundle->instructions[0]->load_store, sizeof(current64));
190
191 if (bundle->instruction_count == 2)
192 memcpy(&next64, &bundle->instructions[1]->load_store, sizeof(next64));
193
194 midgard_load_store instruction = {
195 .type = bundle->tag,
196 .next_type = next_tag,
197 .word1 = current64,
198 .word2 = next64
199 };
200
201 util_dynarray_append(emission, midgard_load_store, instruction);
202
203 break;
204 }
205
206 case TAG_TEXTURE_4: {
207 /* Texture instructions are easy, since there is no pipelining
208 * nor VLIW to worry about. We may need to set .last flag */
209
210 midgard_instruction *ins = bundle->instructions[0];
211
212 ins->texture.type = TAG_TEXTURE_4;
213 ins->texture.next_type = next_tag;
214
215 ctx->texture_op_count--;
216
217 if (ins->texture.op == TEXTURE_OP_NORMAL) {
218 bool continues = ctx->texture_op_count > 0;
219 ins->texture.cont = continues;
220 ins->texture.last = !continues;
221 } else {
222 ins->texture.cont = ins->texture.last = 1;
223 }
224
225 util_dynarray_append(emission, midgard_texture_word, ins->texture);
226 break;
227 }
228
229 default:
230 unreachable("Unknown midgard instruction type\n");
231 }
232 }