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 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 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 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 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 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 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