Annotation of tme/libtme/recode-insns.c, revision 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.