1 /*
2 * Copyright (c) 2019 Zodiac Inflight Innovations
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, sub license,
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
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the 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 NON-INFRINGEMENT. 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
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Jonathan Marek <jonathan@marek.ca>
25 */
26
27 #include "etnaviv_compiler_nir.h"
28
29 /* to map nir srcs should to etna_inst srcs */
30 enum {
31 SRC_0_1_2 = (0 << 0) | (1 << 2) | (2 << 4),
32 SRC_0_1_X = (0 << 0) | (1 << 2) | (3 << 4),
33 SRC_0_X_X = (0 << 0) | (3 << 2) | (3 << 4),
34 SRC_0_X_1 = (0 << 0) | (3 << 2) | (1 << 4),
35 SRC_0_1_0 = (0 << 0) | (1 << 2) | (0 << 4),
36 SRC_X_X_0 = (3 << 0) | (3 << 2) | (0 << 4),
37 SRC_0_X_0 = (0 << 0) | (3 << 2) | (0 << 4),
38 };
39
40 /* info to translate a nir op to etna_inst */
41 struct etna_op_info {
42 uint8_t opcode; /* INST_OPCODE_ */
43 uint8_t src; /* SRC_ enum */
44 uint8_t cond; /* INST_CONDITION_ */
45 uint8_t type; /* INST_TYPE_ */
46 };
47
48 static const struct etna_op_info etna_ops[] = {
49 [0 ... nir_num_opcodes - 1] = {0xff},
50 #undef TRUE
51 #undef FALSE
52 #define OPCT(nir, op, src, cond, type) [nir_op_##nir] = { \
53 INST_OPCODE_##op, \
54 SRC_##src, \
55 INST_CONDITION_##cond, \
56 INST_TYPE_##type \
57 }
58 #define OPC(nir, op, src, cond) OPCT(nir, op, src, cond, F32)
59 #define IOPC(nir, op, src, cond) OPCT(nir, op, src, cond, S32)
60 #define UOPC(nir, op, src, cond) OPCT(nir, op, src, cond, U32)
61 #define OP(nir, op, src) OPC(nir, op, src, TRUE)
62 #define IOP(nir, op, src) IOPC(nir, op, src, TRUE)
63 #define UOP(nir, op, src) UOPC(nir, op, src, TRUE)
64 OP(mov, MOV, X_X_0), OP(fneg, MOV, X_X_0), OP(fabs, MOV, X_X_0), OP(fsat, MOV, X_X_0),
65 OP(fmul, MUL, 0_1_X), OP(fadd, ADD, 0_X_1), OP(ffma, MAD, 0_1_2),
66 OP(fdot2, DP2, 0_1_X), OP(fdot3, DP3, 0_1_X), OP(fdot4, DP4, 0_1_X),
67 OPC(fmin, SELECT, 0_1_0, GT), OPC(fmax, SELECT, 0_1_0, LT),
68 OP(ffract, FRC, X_X_0), OP(frcp, RCP, X_X_0), OP(frsq, RSQ, X_X_0),
69 OP(fsqrt, SQRT, X_X_0), OP(fsin, SIN, X_X_0), OP(fcos, COS, X_X_0),
70 OP(fsign, SIGN, X_X_0), OP(ffloor, FLOOR, X_X_0), OP(fceil, CEIL, X_X_0),
71 OP(flog2, LOG, X_X_0), OP(fexp2, EXP, X_X_0),
72 OPC(seq, SET, 0_1_X, EQ), OPC(sne, SET, 0_1_X, NE), OPC(sge, SET, 0_1_X, GE), OPC(slt, SET, 0_1_X, LT),
73 OPC(fcsel, SELECT, 0_1_2, NZ),
74 OP(fdiv, DIV, 0_1_X),
75 OP(fddx, DSX, 0_X_0), OP(fddy, DSY, 0_X_0),
76
77 /* type convert */
78 IOP(i2f32, I2F, 0_X_X),
79 UOP(u2f32, I2F, 0_X_X),
80 IOP(f2i32, F2I, 0_X_X),
81 UOP(f2u32, F2I, 0_X_X),
82 UOP(b2f32, AND, 0_X_X), /* AND with fui(1.0f) */
83 UOP(b2i32, AND, 0_X_X), /* AND with 1 */
84 OPC(f2b32, CMP, 0_X_X, NE), /* != 0.0 */
85 UOPC(i2b32, CMP, 0_X_X, NE), /* != 0 */
86
87 /* arithmetic */
88 IOP(iadd, ADD, 0_X_1),
89 IOP(imul, IMULLO0, 0_1_X),
90 /* IOP(imad, IMADLO0, 0_1_2), */
91 IOP(ineg, ADD, X_X_0), /* ADD 0, -x */
92 IOP(iabs, IABS, X_X_0),
93 IOP(isign, SIGN, X_X_0),
94 IOPC(imin, SELECT, 0_1_0, GT),
95 IOPC(imax, SELECT, 0_1_0, LT),
96 UOPC(umin, SELECT, 0_1_0, GT),
97 UOPC(umax, SELECT, 0_1_0, LT),
98
99 /* select */
100 UOPC(b32csel, SELECT, 0_1_2, NZ),
101
102 /* compare with int result */
103 OPC(feq32, CMP, 0_1_X, EQ),
104 OPC(fneu32, CMP, 0_1_X, NE),
105 OPC(fge32, CMP, 0_1_X, GE),
106 OPC(flt32, CMP, 0_1_X, LT),
107 IOPC(ieq32, CMP, 0_1_X, EQ),
108 IOPC(ine32, CMP, 0_1_X, NE),
109 IOPC(ige32, CMP, 0_1_X, GE),
110 IOPC(ilt32, CMP, 0_1_X, LT),
111 UOPC(uge32, CMP, 0_1_X, GE),
112 UOPC(ult32, CMP, 0_1_X, LT),
113
114 /* bit ops */
115 IOP(ior, OR, 0_X_1),
116 IOP(iand, AND, 0_X_1),
117 IOP(ixor, XOR, 0_X_1),
118 IOP(inot, NOT, X_X_0),
119 IOP(ishl, LSHIFT, 0_X_1),
120 IOP(ishr, RSHIFT, 0_X_1),
121 UOP(ushr, RSHIFT, 0_X_1),
122 };
123
124 void
etna_emit_alu(struct etna_compile * c,nir_op op,struct etna_inst_dst dst,struct etna_inst_src src[3],bool saturate)125 etna_emit_alu(struct etna_compile *c, nir_op op, struct etna_inst_dst dst,
126 struct etna_inst_src src[3], bool saturate)
127 {
128 struct etna_op_info ei = etna_ops[op];
129 unsigned swiz_scalar = INST_SWIZ_BROADCAST(ffs(dst.write_mask) - 1);
130
131 if (ei.opcode == 0xff)
132 compile_error(c, "Unhandled ALU op: %s\n", nir_op_infos[op].name);
133
134 struct etna_inst inst = {
135 .opcode = ei.opcode,
136 .type = ei.type,
137 .cond = ei.cond,
138 .dst = dst,
139 .sat = saturate,
140 };
141
142 switch (op) {
143 case nir_op_fdiv:
144 case nir_op_flog2:
145 case nir_op_fsin:
146 case nir_op_fcos:
147 if (c->specs->has_new_transcendentals)
148 inst.tex.amode = 1;
149 /* fall through */
150 case nir_op_frsq:
151 case nir_op_frcp:
152 case nir_op_fexp2:
153 case nir_op_fsqrt:
154 case nir_op_imul:
155 /* scalar instructions we want src to be in x component */
156 src[0].swiz = inst_swiz_compose(src[0].swiz, swiz_scalar);
157 src[1].swiz = inst_swiz_compose(src[1].swiz, swiz_scalar);
158 break;
159 /* deal with instructions which don't have 1:1 mapping */
160 case nir_op_b2f32:
161 inst.src[2] = etna_immediate_float(1.0f);
162 break;
163 case nir_op_b2i32:
164 inst.src[2] = etna_immediate_int(1);
165 break;
166 case nir_op_f2b32:
167 inst.src[1] = etna_immediate_float(0.0f);
168 break;
169 case nir_op_i2b32:
170 inst.src[1] = etna_immediate_int(0);
171 break;
172 case nir_op_ineg:
173 inst.src[0] = etna_immediate_int(0);
174 src[0].neg = 1;
175 break;
176 default:
177 break;
178 }
179
180 /* set the "true" value for CMP instructions */
181 if (inst.opcode == INST_OPCODE_CMP)
182 inst.src[2] = etna_immediate_int(-1);
183
184 for (unsigned j = 0; j < 3; j++) {
185 unsigned i = ((ei.src >> j*2) & 3);
186 if (i < 3)
187 inst.src[j] = src[i];
188 }
189
190 emit_inst(c, &inst);
191 }
192
193 void
etna_emit_tex(struct etna_compile * c,nir_texop op,unsigned texid,unsigned dst_swiz,struct etna_inst_dst dst,struct etna_inst_src coord,struct etna_inst_src lod_bias,struct etna_inst_src compare)194 etna_emit_tex(struct etna_compile *c, nir_texop op, unsigned texid, unsigned dst_swiz,
195 struct etna_inst_dst dst, struct etna_inst_src coord,
196 struct etna_inst_src lod_bias, struct etna_inst_src compare)
197 {
198 struct etna_inst inst = {
199 .dst = dst,
200 .tex.id = texid + (is_fs(c) ? 0 : c->specs->vertex_sampler_offset),
201 .tex.swiz = dst_swiz,
202 .src[0] = coord,
203 };
204
205 if (lod_bias.use)
206 inst.src[1] = lod_bias;
207
208 if (compare.use)
209 inst.src[2] = compare;
210
211 switch (op) {
212 case nir_texop_tex: inst.opcode = INST_OPCODE_TEXLD; break;
213 case nir_texop_txb: inst.opcode = INST_OPCODE_TEXLDB; break;
214 case nir_texop_txl: inst.opcode = INST_OPCODE_TEXLDL; break;
215 default:
216 compile_error(c, "Unhandled NIR tex type: %d\n", op);
217 }
218
219 emit_inst(c, &inst);
220 }
221
222 void
etna_emit_jump(struct etna_compile * c,unsigned block,struct etna_inst_src condition)223 etna_emit_jump(struct etna_compile *c, unsigned block, struct etna_inst_src condition)
224 {
225 if (!condition.use) {
226 emit_inst(c, &(struct etna_inst) {.opcode = INST_OPCODE_BRANCH, .imm = block });
227 return;
228 }
229
230 struct etna_inst inst = {
231 .opcode = INST_OPCODE_BRANCH,
232 .cond = INST_CONDITION_NOT,
233 .type = INST_TYPE_U32,
234 .src[0] = condition,
235 .imm = block,
236 };
237 inst.src[0].swiz = INST_SWIZ_BROADCAST(inst.src[0].swiz & 3);
238 emit_inst(c, &inst);
239 }
240
241 void
etna_emit_discard(struct etna_compile * c,struct etna_inst_src condition)242 etna_emit_discard(struct etna_compile *c, struct etna_inst_src condition)
243 {
244 if (!condition.use) {
245 emit_inst(c, &(struct etna_inst) { .opcode = INST_OPCODE_TEXKILL });
246 return;
247 }
248
249 struct etna_inst inst = {
250 .opcode = INST_OPCODE_TEXKILL,
251 .cond = INST_CONDITION_NZ,
252 .type = (c->specs->halti < 2) ? INST_TYPE_F32 : INST_TYPE_U32,
253 .src[0] = condition,
254 };
255 inst.src[0].swiz = INST_SWIZ_BROADCAST(inst.src[0].swiz & 3);
256 emit_inst(c, &inst);
257 }
258