Annotation of tme/libtme/recode-insns.c, revision 1.1.1.1

1.1       root        1: /* $Id: recode-insns.c,v 1.4 2010/02/07 17:32:01 fredette Exp $ */
                      2: 
                      3: /* libtme/recode-insns.c - generic recode instruction support: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2008 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
                     37: _TME_RCSID("$Id: recode-insns.c,v 1.4 2010/02/07 17:32:01 fredette Exp $");
                     38: 
                     39: #if TME_HAVE_RECODE
                     40: 
                     41: /* includes: */
                     42: #include "recode-impl.h"
                     43: 
                     44: /* macros: */
                     45: 
                     46: /* the undefined flags offset: */
                     47: #define TME_RECODE_FLAGS_OFFSET_UNDEF  (0 - (tme_uint32_t) 1)
                     48: 
                     49: /* this returns the thunk offset for a new instructions thunk.  it
                     50:    returns less than zero when thunks memory is exhausted and all
                     51:    instructions thunks are flushed: */
                     52: tme_recode_thunk_off_t
                     53: tme_recode_insns_thunk(struct tme_recode_ic *ic,
                     54:                       const struct tme_recode_insns_group *insns_group)
                     55: {
                     56:   signed long reg_guest;
                     57:   signed long ruses_record_tmp;
                     58:   signed long ruses_record_right;
                     59:   tme_uint32_t flags_offset;
                     60:   tme_recode_uguest_t flags_needed;
                     61:   tme_uint32_t flags_offset_else;
                     62:   tme_recode_uguest_t flags_needed_else;
                     63:   struct tme_recode_insn *insns;
                     64:   struct tme_recode_insn *insn;
                     65:   tme_uint32_t opcode_mask;
                     66:   signed long operand_i;
                     67:   tme_uint32_t ruses;
                     68:   const struct tme_recode_flags_thunk *flags_thunk;
                     69:   const struct tme_recode_conds_thunk *conds_thunk;
                     70: 
                     71:   /* initialize the mapping from host register to read-uses count for
                     72:      a cached guest register, to all host registers free: */
                     73: #if TME_RECODE_REG_RUSES_FREE != 0
                     74: #error "TME_RECODE_REG_RUSES_FREE changed"
                     75: #endif
                     76:   memset(ic->tme_recode_ic_reg_host_to_ruses,
                     77:         TME_RECODE_REG_RUSES_FREE, 
                     78:         sizeof(ic->tme_recode_ic_reg_host_to_ruses));
                     79: 
                     80:   /* there are no reserved registers: */
                     81:   ic->tme_recode_ic_reg_host_reserve_next = 0;
                     82: 
                     83:   /* initialize the read-uses counts for all guest registers.  this
                     84:      also marks the guest register tags as invalid: */
                     85:   reg_guest = TME_RECODE_REG_GUEST(ic->tme_recode_ic_reg_count - 1);
                     86:   do {
                     87:     ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses = (TME_RECODE_REG_RUSES_FREE + 1);
                     88:   } while (--reg_guest >= TME_RECODE_REG_GUEST(0));
                     89: 
                     90:   /* the largest guest register number must fit in
                     91:      [TME_RECODE_REG_RUSES_RECORD_REG_GUEST(0)..TME_RECODE_REG_RUSES_RECORD_UNDEF): */
                     92:   assert (ic->tme_recode_ic_reg_count
                     93:          < (TME_RECODE_REG_RUSES_RECORD_UNDEF
                     94:             - TME_RECODE_REG_RUSES_RECORD_REG_GUEST(0)));
                     95: 
                     96:   /* reset the read-uses records: */
                     97:   ruses_record_tmp = 0;
                     98:   ruses_record_right = ic->tme_recode_ic_reg_guest_ruses_record_count;
                     99:   assert (ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_right]
                    100:          == TME_RECODE_REG_RUSES_RECORD_UNDEF);
                    101: 
                    102:   /* we haven't found any flags register yet: */
                    103:   flags_offset = TME_RECODE_FLAGS_OFFSET_UNDEF;
                    104:   flags_needed = 0;
                    105:   flags_offset_else = TME_RECODE_FLAGS_OFFSET_UNDEF;
                    106:   flags_needed_else = 0;
                    107: 
                    108:   /* loop over the instructions, from last to first: */
                    109:   insns = insns_group->tme_recode_insns_group_insns;
                    110:   insn = insns_group->tme_recode_insns_group_insns_end;
                    111:   do {
                    112:     insn--;
                    113: 
                    114:     /* get the bitmask for this instruction's opcode: */
                    115:     opcode_mask = (1 << insn->tme_recode_insn_opcode);
                    116: 
                    117:     /* if this is an else instruction, or an endif instruction, or a
                    118:        guest instruction with unknown destination registers: */
                    119:     if ((opcode_mask
                    120:         & ((1 << TME_RECODE_OPCODE_ELSE)
                    121:            | (1 << TME_RECODE_OPCODE_ENDIF)))
                    122:        || ((opcode_mask & (1 << TME_RECODE_OPCODE_GUEST))
                    123:            && insn->tme_recode_insn_operand_dst == TME_RECODE_OPERAND_NULL)) {
                    124: 
                    125:       /* if there are no guest register writes between this else,
                    126:         endif, or guest instruction and the next else, endif, or
                    127:         guest instruction: */
                    128:       if (ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_right]
                    129:          >= TME_RECODE_REG_RUSES_RECORD_REG_GUEST(0)) {
                    130: 
                    131:        /* if we can, make a delimiter between any initial read-uses
                    132:           records that we're about to make, and the initial read-uses
                    133:           records that we previously made: */
                    134:        if (ruses_record_right > 0) {
                    135:          ruses_record_right--;
                    136:          ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_right]
                    137:            = TME_RECODE_REG_RUSES_RECORD_UNDEF;
                    138:        }
                    139:       }
                    140: 
                    141:       /* loop over any temporary read-uses records: */
                    142:       for (; ruses_record_tmp > 0; ) {
                    143: 
                    144:        /* if this temporary read-uses record was overwritten by a
                    145:           write read-uses record: */
                    146:        ruses_record_tmp--;
                    147:        if (ruses_record_tmp >= ruses_record_right) {
                    148: 
                    149:          /* skip to the last temporary read-uses record that hasn't
                    150:             been overwritten yet: */
                    151:          ruses_record_tmp = ruses_record_right;
                    152:          continue;
                    153:        }
                    154: 
                    155:        /* get the guest register: */
                    156:        reg_guest = ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_tmp];
                    157: 
                    158:        /* get this guest register's read-uses count: */
                    159:        ruses = ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses;
                    160: 
                    161:        /* if this guest register has a read use before any first
                    162:           write after this else, endif, or guest instruction: */
                    163:        if (ruses > (TME_RECODE_REG_RUSES_FREE + 1)) {
                    164: 
                    165:          /* reset this guest register's read-uses count: */
                    166:          ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses = (TME_RECODE_REG_RUSES_FREE + 1);
                    167: 
                    168:          /* if we can't make another initial read-uses record, stop now: */
                    169:          if (ruses_record_right < 2) {
                    170:            break;
                    171:          }
                    172: 
                    173:          /* make the initial read-uses record: */
                    174:          ruses_record_right -= 2;
                    175:          ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_right + 0]
                    176:            = TME_RECODE_REG_RUSES_RECORD_REG_GUEST(reg_guest);
                    177:          ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_right + 1] = ruses;
                    178:        }
                    179:       }
                    180:     }
                    181: 
                    182:     /* if this is an integer, or guest, or read/write instruction: */
                    183:     if (opcode_mask
                    184:        & (((1 << TME_RECODE_OPCODES_INTEGER) - 1)
                    185:           | (1 << TME_RECODE_OPCODE_GUEST)
                    186:           | (1 << TME_RECODE_OPCODE_RW))) {
                    187: 
                    188:       /* if the destination operand is a guest register: */
                    189:       reg_guest = insn->tme_recode_insn_operand_dst;
                    190:       if (reg_guest >= TME_RECODE_REG_GUEST(0)) {
                    191: 
                    192:        /* if this guest register is not fixed: */
                    193:        if ((ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_all
                    194:             & TME_RECODE_REGINFO_TYPE_FIXED) == 0) {
                    195: 
                    196:          /* get and reset this guest register's read-uses count: */
                    197:          ruses = ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses;
                    198:          ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses = (TME_RECODE_REG_RUSES_FREE + 1);
                    199: 
                    200:          /* make a write read-uses record: */
                    201:          if (ruses_record_right > 0) {
                    202:            ruses_record_right--;
                    203:          }
                    204:          ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_right] = ruses;
                    205:        }
                    206:       }
                    207: 
                    208:       /* all integer and guest instructions can have a guest register
                    209:         as the first source operand.  all of those instructions can
                    210:         also have a guest register as the second source operand,
                    211:         except for the zero- and sign-extension instructions, which
                    212:         always have a TME_RECODE_SIZE for their second source
                    213:         operand: */
                    214:       operand_i
                    215:        = ((opcode_mask
                    216:            & ((1 << TME_RECODE_OPCODE_EXTZ)
                    217:               | (1 << TME_RECODE_OPCODE_EXTS)))
                    218:           == 0);
                    219: 
                    220:       /* loop over the source operands that can be guest registers: */
                    221:       do {
                    222: 
                    223:        /* if this source operand is a guest register: */
                    224:        reg_guest = insn->tme_recode_insn_operand_src[operand_i];
                    225:        if (reg_guest >= TME_RECODE_REG_GUEST(0)) {
                    226: 
                    227:          /* get this guest register's current read-uses count: */
                    228:          ruses = ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses;
                    229: 
                    230:          /* if this guest register's current read-uses count is the
                    231:             minimum: */
                    232:          if (ruses == (TME_RECODE_REG_RUSES_FREE + 1)) {
                    233: 
                    234:            /* if we can, make a temporary read-uses record for this
                    235:               guest register: */
                    236:            if (ruses_record_tmp < ruses_record_right) {
                    237:              ic->tme_recode_ic_reg_guest_ruses_records[ruses_record_tmp] = reg_guest;
                    238:              ruses_record_tmp++;
                    239:            }
                    240:          }
                    241: 
                    242:          /* increment the guest register's current read-uses count,
                    243:             unless it would become TME_RECODE_REG_RUSES_RESERVED: */
                    244:          if (__tme_predict_true(ruses < (TME_RECODE_REG_RUSES_RESERVED - 1))) {
                    245:            ruses++;
                    246:          }
                    247:          ic->tme_recode_ic_reginfo[reg_guest].tme_recode_reginfo_tags_ruses = ruses;
                    248:        }
                    249:       } while (--operand_i >= 0);
                    250:     }
                    251: 
                    252:     /* if this is an integer instruction: */
                    253:     if (opcode_mask & ((1 << TME_RECODE_OPCODES_INTEGER) - 1)) {
                    254: 
                    255:       /* if the second source operand is a zero, and the operation is
                    256:         commutative: */
                    257:       if (insn->tme_recode_insn_operand_src[1] == TME_RECODE_OPERAND_ZERO) {
                    258:        if (opcode_mask
                    259:            & ((1 << TME_RECODE_OPCODE_AND)
                    260:               | (1 << TME_RECODE_OPCODE_OR)
                    261:               | (1 << TME_RECODE_OPCODE_XOR)
                    262:               | (1 << TME_RECODE_OPCODE_ADD)
                    263:               | (1 << TME_RECODE_OPCODE_ADDC))) {
                    264: 
                    265:          /* we have the convention of always putting a zero source
                    266:             operand first whenever possible, so swap the first and
                    267:             second source operands: */
                    268:          insn->tme_recode_insn_operand_src[1] = insn->tme_recode_insn_operand_src[0];
                    269:          insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO;
                    270:        }
                    271:       }
                    272: 
                    273:       /* if this integer instruction can change flags: */
                    274:       flags_thunk = insn->tme_recode_insn_flags_thunk;
                    275:       if (flags_thunk != NULL) {
                    276: 
                    277:        /* if this integer instruction changes flags in a different
                    278:           flags register: */
                    279:        if (__tme_predict_false(flags_offset != flags_thunk->tme_recode_flags_thunk_flags_offset)) {
                    280: 
                    281:          /* switch to this different flags register, and need all of
                    282:             its flags: */
                    283:          flags_offset = flags_thunk->tme_recode_flags_thunk_flags_offset;
                    284:          flags_needed = 0 - (tme_recode_uguest_t) 1;
                    285:        }
                    286: 
                    287:        /* if this integer instruction doesn't define any of the flags
                    288:           in this flags register needed by later instructions: */
                    289:        if ((flags_needed & flags_thunk->tme_recode_flags_thunk_flags_defined) == 0) {
                    290: 
                    291:          /* this integer instruction doesn't need to define flags any
                    292:             more: */
                    293:          insn->tme_recode_insn_flags_thunk = NULL;
                    294:        }
                    295: 
                    296:        /* any earlier instruction that also defines flags in this
                    297:           flags register, doesn't need to define any of the flags
                    298:           that this instruction changes: */
                    299:        flags_needed &= ~flags_thunk->tme_recode_flags_thunk_flags_changed;
                    300:       }
                    301:     }
                    302: 
                    303:     /* if this is a defc instruction: */
                    304:     else if (opcode_mask == (1 << TME_RECODE_OPCODE_DEFC)) {
                    305: 
                    306:       /* get the conditions thunk for this instruction: */
                    307:       conds_thunk = insn->tme_recode_insn_conds_thunk;
                    308: 
                    309:       /* if this defc instruction tests flags in a different flags register: */
                    310:       if (__tme_predict_false(flags_offset != conds_thunk->tme_recode_conds_thunk_flags_offset)) {
                    311: 
                    312:        /* switch to this different flags register, and need all of
                    313:           its flags: */
                    314:        flags_offset = conds_thunk->tme_recode_conds_thunk_flags_offset;
                    315:        flags_needed = 0 - (tme_recode_uguest_t) 1;
                    316:       }
                    317: 
                    318:       /* any earlier instruction that can define flags tested by this
                    319:         defc instruction, needs to define those flags: */
                    320:       flags_needed |= conds_thunk->tme_recode_conds_thunk_flags;
                    321:     }
                    322: 
                    323:     /* if this is an endif instruction: */
                    324:     else if (opcode_mask == (1 << TME_RECODE_OPCODE_ENDIF)) {
                    325: 
                    326:       /* if we find an earlier else, as an optimization we can restore
                    327:         the flags needed by the instructions after the endif, so save
                    328:         them now: */
                    329:       flags_offset_else = flags_offset;
                    330:       flags_needed_else = flags_needed;
                    331:     }
                    332: 
                    333:     /* if this is an else instruction: */
                    334:     else if (opcode_mask == (1 << TME_RECODE_OPCODE_ELSE)) {
                    335: 
                    336:       /* restore the flags needed by the instructions after the endif: */
                    337:       flags_offset = flags_offset_else;
                    338:       flags_needed = flags_needed_else;
                    339:     }
                    340: 
                    341:     /* otherwise, this must be a guest, read/write, or if instruction: */
                    342:     else {
                    343:       assert (opcode_mask
                    344:              & ((1 << TME_RECODE_OPCODE_GUEST)
                    345:                 | (1 << TME_RECODE_OPCODE_RW)
                    346:                 | (1 << TME_RECODE_OPCODE_IF)
                    347:                 ));
                    348: 
                    349:       /* since a guest function may fault and never return, we have to
                    350:         make sure that all flags are correct in the guest ic state at
                    351:         the time of the fault.
                    352: 
                    353:         since a read/write instruction may fault and never return, we
                    354:         have to make sure that all flags are correct in the guest ic
                    355:         state at the time of the fault.
                    356: 
                    357:         since an if body may not run, we have to make sure that all
                    358:         flags are correct in the guest ic state at the time of the
                    359:         if.
                    360: 
                    361:         since a jump may never return, we have to make sure that all
                    362:         flags are correct in the guest ic state at the time of the
                    363:         jump.
                    364: 
                    365:         in all of these cases, we need any earlier instruction that
                    366:         can define flags to do so: */
                    367:       flags_needed = 0 - (tme_recode_uguest_t) 1;
                    368:     }
                    369: 
                    370:   } while (insn > insns);
                    371: 
                    372:   /* set the next read-uses record: */
                    373:   ic->tme_recode_ic_reg_guest_ruses_record_next = ruses_record_right;
                    374: 
                    375:   /* build the new instructions thunk: */
                    376:   return (tme_recode_host_insns_thunk_new(ic,
                    377:                                          insns_group));
                    378: }
                    379: 
                    380: /* this invalidates all instructions thunks: */
                    381: void
                    382: tme_recode_insns_thunk_invalidate_all(struct tme_recode_ic *ic)
                    383: {
                    384: 
                    385:   /* invalidate all instructions thunks: */
                    386:   tme_recode_host_thunk_invalidate_all(ic, ic->tme_recode_ic_thunk_off_variable);
                    387: }
                    388: 
                    389: #endif /* TME_HAVE_RECODE */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.