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