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