1 /*
2 * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "qemu/osdep.h"
19 #include "decode.h"
20 #include "opcodes.h"
21 #include "insn.h"
22 #include "iclass.h"
23 #include "mmvec/mmvec.h"
24 #include "mmvec/decode_ext_mmvec.h"
25
26 static void
check_new_value(Packet * pkt)27 check_new_value(Packet *pkt)
28 {
29 /* .new value for a MMVector store */
30 int i, j;
31 const char *reginfo;
32 const char *destletters;
33 const char *dststr = NULL;
34 uint16_t def_opcode;
35 char letter;
36 int def_regnum;
37
38 for (i = 1; i < pkt->num_insns; i++) {
39 uint16_t use_opcode = pkt->insn[i].opcode;
40 if (GET_ATTRIB(use_opcode, A_DOTNEWVALUE) &&
41 GET_ATTRIB(use_opcode, A_CVI) &&
42 GET_ATTRIB(use_opcode, A_STORE)) {
43 int use_regidx = strchr(opcode_reginfo[use_opcode], 's') -
44 opcode_reginfo[use_opcode];
45 /*
46 * What's encoded at the N-field is the offset to who's producing
47 * the value.
48 * Shift off the LSB which indicates odd/even register.
49 */
50 int def_off = ((pkt->insn[i].regno[use_regidx]) >> 1);
51 int def_oreg = pkt->insn[i].regno[use_regidx] & 1;
52 int def_idx = -1;
53 for (j = i - 1; (j >= 0) && (def_off >= 0); j--) {
54 if (!GET_ATTRIB(pkt->insn[j].opcode, A_CVI)) {
55 continue;
56 }
57 def_off--;
58 if (def_off == 0) {
59 def_idx = j;
60 break;
61 }
62 }
63 /*
64 * Check for a badly encoded N-field which points to an instruction
65 * out-of-range
66 */
67 g_assert(!((def_off != 0) || (def_idx < 0) ||
68 (def_idx > (pkt->num_insns - 1))));
69
70 /* def_idx is the index of the producer */
71 def_opcode = pkt->insn[def_idx].opcode;
72 reginfo = opcode_reginfo[def_opcode];
73 destletters = "dexy";
74 for (j = 0; (letter = destletters[j]) != 0; j++) {
75 dststr = strchr(reginfo, letter);
76 if (dststr != NULL) {
77 break;
78 }
79 }
80 if ((dststr == NULL) && GET_ATTRIB(def_opcode, A_CVI_GATHER)) {
81 def_regnum = 0;
82 pkt->insn[i].regno[use_regidx] = def_oreg;
83 pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot;
84 } else {
85 if (dststr == NULL) {
86 /* still not there, we have a bad packet */
87 g_assert_not_reached();
88 }
89 def_regnum = pkt->insn[def_idx].regno[dststr - reginfo];
90 /* Now patch up the consumer with the register number */
91 pkt->insn[i].regno[use_regidx] = def_regnum ^ def_oreg;
92 /* special case for (Vx,Vy) */
93 dststr = strchr(reginfo, 'y');
94 if (def_oreg && strchr(reginfo, 'x') && dststr) {
95 def_regnum = pkt->insn[def_idx].regno[dststr - reginfo];
96 pkt->insn[i].regno[use_regidx] = def_regnum;
97 }
98 /*
99 * We need to remember who produces this value to later
100 * check if it was dynamically cancelled
101 */
102 pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot;
103 }
104 }
105 }
106 }
107
108 /*
109 * We don't want to reorder slot1/slot0 with respect to each other.
110 * So in our shuffling, we don't want to move the .cur / .tmp vmem earlier
111 * Instead, we should move the producing instruction later
112 * But the producing instruction might feed a .new store!
113 * So we may need to move that even later.
114 */
115
116 static void
decode_mmvec_move_cvi_to_end(Packet * pkt,int max)117 decode_mmvec_move_cvi_to_end(Packet *pkt, int max)
118 {
119 int i;
120 for (i = 0; i < max; i++) {
121 if (GET_ATTRIB(pkt->insn[i].opcode, A_CVI)) {
122 int last_inst = pkt->num_insns - 1;
123 uint16_t last_opcode = pkt->insn[last_inst].opcode;
124
125 /*
126 * If the last instruction is an endloop, move to the one before it
127 * Keep endloop as the last thing always
128 */
129 if ((last_opcode == J2_endloop0) ||
130 (last_opcode == J2_endloop1) ||
131 (last_opcode == J2_endloop01)) {
132 last_inst--;
133 }
134
135 decode_send_insn_to(pkt, i, last_inst);
136 max--;
137 i--; /* Retry this index now that packet has rotated */
138 }
139 }
140 }
141
142 static void
decode_shuffle_for_execution_vops(Packet * pkt)143 decode_shuffle_for_execution_vops(Packet *pkt)
144 {
145 /*
146 * Sort for .new
147 */
148 int i;
149 for (i = 0; i < pkt->num_insns; i++) {
150 uint16_t opcode = pkt->insn[i].opcode;
151 if ((GET_ATTRIB(opcode, A_LOAD) &&
152 GET_ATTRIB(opcode, A_CVI_NEW)) ||
153 GET_ATTRIB(opcode, A_CVI_TMP)) {
154 /*
155 * Find prior consuming vector instructions
156 * Move to end of packet
157 */
158 decode_mmvec_move_cvi_to_end(pkt, i);
159 break;
160 }
161 }
162
163 /* Move HVX new value stores to the end of the packet */
164 for (i = 0; i < pkt->num_insns - 1; i++) {
165 uint16_t opcode = pkt->insn[i].opcode;
166 if (GET_ATTRIB(opcode, A_STORE) &&
167 GET_ATTRIB(opcode, A_CVI_NEW) &&
168 !GET_ATTRIB(opcode, A_CVI_SCATTER_RELEASE)) {
169 int last_inst = pkt->num_insns - 1;
170 uint16_t last_opcode = pkt->insn[last_inst].opcode;
171
172 /*
173 * If the last instruction is an endloop, move to the one before it
174 * Keep endloop as the last thing always
175 */
176 if ((last_opcode == J2_endloop0) ||
177 (last_opcode == J2_endloop1) ||
178 (last_opcode == J2_endloop01)) {
179 last_inst--;
180 }
181
182 decode_send_insn_to(pkt, i, last_inst);
183 break;
184 }
185 }
186 }
187
188 static void
check_for_vhist(Packet * pkt)189 check_for_vhist(Packet *pkt)
190 {
191 pkt->vhist_insn = NULL;
192 for (int i = 0; i < pkt->num_insns; i++) {
193 Insn *insn = &pkt->insn[i];
194 int opcode = insn->opcode;
195 if (GET_ATTRIB(opcode, A_CVI) && GET_ATTRIB(opcode, A_CVI_4SLOT)) {
196 pkt->vhist_insn = insn;
197 return;
198 }
199 }
200 }
201
202 /*
203 * Public Functions
204 */
205
mmvec_ext_decode_find_iclass_slots(int opcode)206 SlotMask mmvec_ext_decode_find_iclass_slots(int opcode)
207 {
208 if (GET_ATTRIB(opcode, A_CVI_VM)) {
209 /* HVX memory instruction */
210 if (GET_ATTRIB(opcode, A_RESTRICT_SLOT0ONLY)) {
211 return SLOTS_0;
212 } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT1ONLY)) {
213 return SLOTS_1;
214 }
215 return SLOTS_01;
216 } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT2ONLY)) {
217 return SLOTS_2;
218 } else if (GET_ATTRIB(opcode, A_CVI_VX)) {
219 /* HVX multiply instruction */
220 return SLOTS_23;
221 } else if (GET_ATTRIB(opcode, A_CVI_VS_VX)) {
222 /* HVX permute/shift instruction */
223 return SLOTS_23;
224 } else {
225 return SLOTS_0123;
226 }
227 }
228
mmvec_ext_decode_checks(Packet * pkt,bool disas_only)229 void mmvec_ext_decode_checks(Packet *pkt, bool disas_only)
230 {
231 check_new_value(pkt);
232 if (!disas_only) {
233 decode_shuffle_for_execution_vops(pkt);
234 }
235 check_for_vhist(pkt);
236 }
237