qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

decode_ext_mmvec.c (7890B)


      1 /*
      2  *  Copyright(c) 2019-2021 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 }