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