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 uint16_t def_opcode;
32
33 for (i = 1; i < pkt->num_insns; i++) {
34 uint16_t use_opcode = pkt->insn[i].opcode;
35 if (GET_ATTRIB(use_opcode, A_DOTNEWVALUE) &&
36 GET_ATTRIB(use_opcode, A_CVI) &&
37 GET_ATTRIB(use_opcode, A_STORE)) {
38 int use_regidx = pkt->insn[i].new_read_idx;
39 g_assert(pkt->insn[i].new_read_idx != -1);
40 /*
41 * What's encoded at the N-field is the offset to who's producing
42 * the value.
43 * Shift off the LSB which indicates odd/even register.
44 */
45 int def_off = ((pkt->insn[i].regno[use_regidx]) >> 1);
46 int def_oreg = pkt->insn[i].regno[use_regidx] & 1;
47 int def_idx = -1;
48 for (j = i - 1; (j >= 0) && (def_off >= 0); j--) {
49 if (!GET_ATTRIB(pkt->insn[j].opcode, A_CVI)) {
50 continue;
51 }
52 def_off--;
53 if (def_off == 0) {
54 def_idx = j;
55 break;
56 }
57 }
58 /*
59 * Check for a badly encoded N-field which points to an instruction
60 * out-of-range
61 */
62 g_assert(!((def_off != 0) || (def_idx < 0) ||
63 (def_idx > (pkt->num_insns - 1))));
64
65 /* def_idx is the index of the producer */
66 def_opcode = pkt->insn[def_idx].opcode;
67 if ((pkt->insn[def_idx].dest_idx == -1) &&
68 GET_ATTRIB(def_opcode, A_CVI_GATHER)) {
69 pkt->insn[i].regno[use_regidx] = def_oreg;
70 pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot;
71 } else {
72 if (pkt->insn[def_idx].dest_idx == -1) {
73 /* still not there, we have a bad packet */
74 g_assert_not_reached();
75 }
76 int def_regnum =
77 pkt->insn[def_idx].regno[pkt->insn[def_idx].dest_idx];
78 /* Now patch up the consumer with the register number */
79 pkt->insn[i].regno[use_regidx] = def_regnum ^ def_oreg;
80 /*
81 * We need to remember who produces this value to later
82 * check if it was dynamically cancelled
83 */
84 pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot;
85 }
86 }
87 }
88 }
89
90 /*
91 * We don't want to reorder slot1/slot0 with respect to each other.
92 * So in our shuffling, we don't want to move the .cur / .tmp vmem earlier
93 * Instead, we should move the producing instruction later
94 * But the producing instruction might feed a .new store!
95 * So we may need to move that even later.
96 */
97
98 static void
decode_mmvec_move_cvi_to_end(Packet * pkt,int max)99 decode_mmvec_move_cvi_to_end(Packet *pkt, int max)
100 {
101 int i;
102 for (i = 0; i < max; i++) {
103 if (GET_ATTRIB(pkt->insn[i].opcode, A_CVI)) {
104 int last_inst = pkt->num_insns - 1;
105 uint16_t last_opcode = pkt->insn[last_inst].opcode;
106
107 /*
108 * If the last instruction is an endloop, move to the one before it
109 * Keep endloop as the last thing always
110 */
111 if ((last_opcode == J2_endloop0) ||
112 (last_opcode == J2_endloop1) ||
113 (last_opcode == J2_endloop01)) {
114 last_inst--;
115 }
116
117 decode_send_insn_to(pkt, i, last_inst);
118 max--;
119 i--; /* Retry this index now that packet has rotated */
120 }
121 }
122 }
123
124 static void
decode_shuffle_for_execution_vops(Packet * pkt)125 decode_shuffle_for_execution_vops(Packet *pkt)
126 {
127 /*
128 * Sort for .new
129 */
130 int i;
131 for (i = 0; i < pkt->num_insns; i++) {
132 uint16_t opcode = pkt->insn[i].opcode;
133 if ((GET_ATTRIB(opcode, A_LOAD) &&
134 GET_ATTRIB(opcode, A_CVI_NEW)) ||
135 GET_ATTRIB(opcode, A_CVI_TMP)) {
136 /*
137 * Find prior consuming vector instructions
138 * Move to end of packet
139 */
140 decode_mmvec_move_cvi_to_end(pkt, i);
141 break;
142 }
143 }
144
145 /* Move HVX new value stores to the end of the packet */
146 for (i = 0; i < pkt->num_insns - 1; i++) {
147 uint16_t opcode = pkt->insn[i].opcode;
148 if (GET_ATTRIB(opcode, A_STORE) &&
149 GET_ATTRIB(opcode, A_CVI_NEW) &&
150 !GET_ATTRIB(opcode, A_CVI_SCATTER_RELEASE)) {
151 int last_inst = pkt->num_insns - 1;
152 uint16_t last_opcode = pkt->insn[last_inst].opcode;
153
154 /*
155 * If the last instruction is an endloop, move to the one before it
156 * Keep endloop as the last thing always
157 */
158 if ((last_opcode == J2_endloop0) ||
159 (last_opcode == J2_endloop1) ||
160 (last_opcode == J2_endloop01)) {
161 last_inst--;
162 }
163
164 decode_send_insn_to(pkt, i, last_inst);
165 break;
166 }
167 }
168 }
169
170 static void
check_for_vhist(Packet * pkt)171 check_for_vhist(Packet *pkt)
172 {
173 pkt->vhist_insn = NULL;
174 for (int i = 0; i < pkt->num_insns; i++) {
175 Insn *insn = &pkt->insn[i];
176 int opcode = insn->opcode;
177 if (GET_ATTRIB(opcode, A_CVI) && GET_ATTRIB(opcode, A_CVI_4SLOT)) {
178 pkt->vhist_insn = insn;
179 return;
180 }
181 }
182 }
183
184 /*
185 * Public Functions
186 */
187
mmvec_ext_decode_find_iclass_slots(int opcode)188 SlotMask mmvec_ext_decode_find_iclass_slots(int opcode)
189 {
190 if (GET_ATTRIB(opcode, A_CVI_VM)) {
191 /* HVX memory instruction */
192 if (GET_ATTRIB(opcode, A_RESTRICT_SLOT0ONLY)) {
193 return SLOTS_0;
194 } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT1ONLY)) {
195 return SLOTS_1;
196 }
197 return SLOTS_01;
198 } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT2ONLY)) {
199 return SLOTS_2;
200 } else if (GET_ATTRIB(opcode, A_CVI_VX)) {
201 /* HVX multiply instruction */
202 return SLOTS_23;
203 } else if (GET_ATTRIB(opcode, A_CVI_VS_VX)) {
204 /* HVX permute/shift instruction */
205 return SLOTS_23;
206 } else {
207 return SLOTS_0123;
208 }
209 }
210
mmvec_ext_decode_checks(Packet * pkt,bool disas_only)211 void mmvec_ext_decode_checks(Packet *pkt, bool disas_only)
212 {
213 check_new_value(pkt);
214 if (!disas_only) {
215 decode_shuffle_for_execution_vops(pkt);
216 }
217 check_for_vhist(pkt);
218 }
219