Annotation of qemu/tcg/tcg.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Tiny Code Generator for QEMU
        !             3:  *
        !             4:  * Copyright (c) 2008 Fabrice Bellard
        !             5:  *
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !             7:  * of this software and associated documentation files (the "Software"), to deal
        !             8:  * in the Software without restriction, including without limitation the rights
        !             9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            10:  * copies of the Software, and to permit persons to whom the Software is
        !            11:  * furnished to do so, subject to the following conditions:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included in
        !            14:  * all copies or substantial portions of the Software.
        !            15:  *
        !            16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            22:  * THE SOFTWARE.
        !            23:  */
        !            24: 
        !            25: /* define it to suppress various consistency checks (faster) */
        !            26: #define NDEBUG
        !            27: 
        !            28: /* define it to use liveness analysis (better code) */
        !            29: #define USE_LIVENESS_ANALYSIS
        !            30: 
        !            31: #include <assert.h>
        !            32: #include <stdarg.h>
        !            33: #include <stdlib.h>
        !            34: #include <stdio.h>
        !            35: #include <string.h>
        !            36: #include <inttypes.h>
        !            37: #ifdef _WIN32
        !            38: #include <malloc.h>
        !            39: #endif
        !            40: #ifdef _AIX
        !            41: #include <alloca.h>
        !            42: #endif
        !            43: 
        !            44: #include "config.h"
        !            45: #include "qemu-common.h"
        !            46: #include "cache-utils.h"
        !            47: 
        !            48: /* Note: the long term plan is to reduce the dependancies on the QEMU
        !            49:    CPU definitions. Currently they are used for qemu_ld/st
        !            50:    instructions */
        !            51: #define NO_CPU_IO_DEFS
        !            52: #include "cpu.h"
        !            53: #include "exec-all.h"
        !            54: 
        !            55: #include "tcg-op.h"
        !            56: #include "elf.h"
        !            57: 
        !            58: 
        !            59: static void patch_reloc(uint8_t *code_ptr, int type, 
        !            60:                         tcg_target_long value, tcg_target_long addend);
        !            61: 
        !            62: static TCGOpDef tcg_op_defs[] = {
        !            63: #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
        !            64: #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
        !            65: #include "tcg-opc.h"
        !            66: #undef DEF
        !            67: #undef DEF2
        !            68: };
        !            69: 
        !            70: static TCGRegSet tcg_target_available_regs[2];
        !            71: static TCGRegSet tcg_target_call_clobber_regs;
        !            72: 
        !            73: /* XXX: move that inside the context */
        !            74: uint16_t *gen_opc_ptr;
        !            75: TCGArg *gen_opparam_ptr;
        !            76: 
        !            77: static inline void tcg_out8(TCGContext *s, uint8_t v)
        !            78: {
        !            79:     *s->code_ptr++ = v;
        !            80: }
        !            81: 
        !            82: static inline void tcg_out16(TCGContext *s, uint16_t v)
        !            83: {
        !            84:     *(uint16_t *)s->code_ptr = v;
        !            85:     s->code_ptr += 2;
        !            86: }
        !            87: 
        !            88: static inline void tcg_out32(TCGContext *s, uint32_t v)
        !            89: {
        !            90:     *(uint32_t *)s->code_ptr = v;
        !            91:     s->code_ptr += 4;
        !            92: }
        !            93: 
        !            94: /* label relocation processing */
        !            95: 
        !            96: void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, 
        !            97:                    int label_index, long addend)
        !            98: {
        !            99:     TCGLabel *l;
        !           100:     TCGRelocation *r;
        !           101: 
        !           102:     l = &s->labels[label_index];
        !           103:     if (l->has_value) {
        !           104:         /* FIXME: This may break relocations on RISC targets that
        !           105:            modify instruction fields in place.  The caller may not have 
        !           106:            written the initial value.  */
        !           107:         patch_reloc(code_ptr, type, l->u.value, addend);
        !           108:     } else {
        !           109:         /* add a new relocation entry */
        !           110:         r = tcg_malloc(sizeof(TCGRelocation));
        !           111:         r->type = type;
        !           112:         r->ptr = code_ptr;
        !           113:         r->addend = addend;
        !           114:         r->next = l->u.first_reloc;
        !           115:         l->u.first_reloc = r;
        !           116:     }
        !           117: }
        !           118: 
        !           119: static void tcg_out_label(TCGContext *s, int label_index, 
        !           120:                           tcg_target_long value)
        !           121: {
        !           122:     TCGLabel *l;
        !           123:     TCGRelocation *r;
        !           124: 
        !           125:     l = &s->labels[label_index];
        !           126:     if (l->has_value)
        !           127:         tcg_abort();
        !           128:     r = l->u.first_reloc;
        !           129:     while (r != NULL) {
        !           130:         patch_reloc(r->ptr, r->type, value, r->addend);
        !           131:         r = r->next;
        !           132:     }
        !           133:     l->has_value = 1;
        !           134:     l->u.value = value;
        !           135: }
        !           136: 
        !           137: int gen_new_label(void)
        !           138: {
        !           139:     TCGContext *s = &tcg_ctx;
        !           140:     int idx;
        !           141:     TCGLabel *l;
        !           142: 
        !           143:     if (s->nb_labels >= TCG_MAX_LABELS)
        !           144:         tcg_abort();
        !           145:     idx = s->nb_labels++;
        !           146:     l = &s->labels[idx];
        !           147:     l->has_value = 0;
        !           148:     l->u.first_reloc = NULL;
        !           149:     return idx;
        !           150: }
        !           151: 
        !           152: #include "tcg-target.c"
        !           153: 
        !           154: /* pool based memory allocation */
        !           155: void *tcg_malloc_internal(TCGContext *s, int size)
        !           156: {
        !           157:     TCGPool *p;
        !           158:     int pool_size;
        !           159:     
        !           160:     if (size > TCG_POOL_CHUNK_SIZE) {
        !           161:         /* big malloc: insert a new pool (XXX: could optimize) */
        !           162:         p = qemu_malloc(sizeof(TCGPool) + size);
        !           163:         p->size = size;
        !           164:         if (s->pool_current)
        !           165:             s->pool_current->next = p;
        !           166:         else
        !           167:             s->pool_first = p;
        !           168:         p->next = s->pool_current;
        !           169:     } else {
        !           170:         p = s->pool_current;
        !           171:         if (!p) {
        !           172:             p = s->pool_first;
        !           173:             if (!p)
        !           174:                 goto new_pool;
        !           175:         } else {
        !           176:             if (!p->next) {
        !           177:             new_pool:
        !           178:                 pool_size = TCG_POOL_CHUNK_SIZE;
        !           179:                 p = qemu_malloc(sizeof(TCGPool) + pool_size);
        !           180:                 p->size = pool_size;
        !           181:                 p->next = NULL;
        !           182:                 if (s->pool_current) 
        !           183:                     s->pool_current->next = p;
        !           184:                 else
        !           185:                     s->pool_first = p;
        !           186:             } else {
        !           187:                 p = p->next;
        !           188:             }
        !           189:         }
        !           190:     }
        !           191:     s->pool_current = p;
        !           192:     s->pool_cur = p->data + size;
        !           193:     s->pool_end = p->data + p->size;
        !           194:     return p->data;
        !           195: }
        !           196: 
        !           197: void tcg_pool_reset(TCGContext *s)
        !           198: {
        !           199:     s->pool_cur = s->pool_end = NULL;
        !           200:     s->pool_current = NULL;
        !           201: }
        !           202: 
        !           203: void tcg_context_init(TCGContext *s)
        !           204: {
        !           205:     int op, total_args, n;
        !           206:     TCGOpDef *def;
        !           207:     TCGArgConstraint *args_ct;
        !           208:     int *sorted_args;
        !           209: 
        !           210:     memset(s, 0, sizeof(*s));
        !           211:     s->temps = s->static_temps;
        !           212:     s->nb_globals = 0;
        !           213:     
        !           214:     /* Count total number of arguments and allocate the corresponding
        !           215:        space */
        !           216:     total_args = 0;
        !           217:     for(op = 0; op < NB_OPS; op++) {
        !           218:         def = &tcg_op_defs[op];
        !           219:         n = def->nb_iargs + def->nb_oargs;
        !           220:         total_args += n;
        !           221:     }
        !           222: 
        !           223:     args_ct = qemu_malloc(sizeof(TCGArgConstraint) * total_args);
        !           224:     sorted_args = qemu_malloc(sizeof(int) * total_args);
        !           225: 
        !           226:     for(op = 0; op < NB_OPS; op++) {
        !           227:         def = &tcg_op_defs[op];
        !           228:         def->args_ct = args_ct;
        !           229:         def->sorted_args = sorted_args;
        !           230:         n = def->nb_iargs + def->nb_oargs;
        !           231:         sorted_args += n;
        !           232:         args_ct += n;
        !           233:     }
        !           234:     
        !           235:     tcg_target_init(s);
        !           236: 
        !           237:     /* init global prologue and epilogue */
        !           238:     s->code_buf = code_gen_prologue;
        !           239:     s->code_ptr = s->code_buf;
        !           240:     tcg_target_qemu_prologue(s);
        !           241:     flush_icache_range((unsigned long)s->code_buf, 
        !           242:                        (unsigned long)s->code_ptr);
        !           243: }
        !           244: 
        !           245: void tcg_set_frame(TCGContext *s, int reg,
        !           246:                    tcg_target_long start, tcg_target_long size)
        !           247: {
        !           248:     s->frame_start = start;
        !           249:     s->frame_end = start + size;
        !           250:     s->frame_reg = reg;
        !           251: }
        !           252: 
        !           253: void tcg_func_start(TCGContext *s)
        !           254: {
        !           255:     int i;
        !           256:     tcg_pool_reset(s);
        !           257:     s->nb_temps = s->nb_globals;
        !           258:     for(i = 0; i < (TCG_TYPE_COUNT * 2); i++)
        !           259:         s->first_free_temp[i] = -1;
        !           260:     s->labels = tcg_malloc(sizeof(TCGLabel) * TCG_MAX_LABELS);
        !           261:     s->nb_labels = 0;
        !           262:     s->current_frame_offset = s->frame_start;
        !           263: 
        !           264:     gen_opc_ptr = gen_opc_buf;
        !           265:     gen_opparam_ptr = gen_opparam_buf;
        !           266: }
        !           267: 
        !           268: static inline void tcg_temp_alloc(TCGContext *s, int n)
        !           269: {
        !           270:     if (n > TCG_MAX_TEMPS)
        !           271:         tcg_abort();
        !           272: }
        !           273: 
        !           274: static inline int tcg_global_reg_new_internal(TCGType type, int reg,
        !           275:                                               const char *name)
        !           276: {
        !           277:     TCGContext *s = &tcg_ctx;
        !           278:     TCGTemp *ts;
        !           279:     int idx;
        !           280: 
        !           281: #if TCG_TARGET_REG_BITS == 32
        !           282:     if (type != TCG_TYPE_I32)
        !           283:         tcg_abort();
        !           284: #endif
        !           285:     if (tcg_regset_test_reg(s->reserved_regs, reg))
        !           286:         tcg_abort();
        !           287:     idx = s->nb_globals;
        !           288:     tcg_temp_alloc(s, s->nb_globals + 1);
        !           289:     ts = &s->temps[s->nb_globals];
        !           290:     ts->base_type = type;
        !           291:     ts->type = type;
        !           292:     ts->fixed_reg = 1;
        !           293:     ts->reg = reg;
        !           294:     ts->name = name;
        !           295:     s->nb_globals++;
        !           296:     tcg_regset_set_reg(s->reserved_regs, reg);
        !           297:     return idx;
        !           298: }
        !           299: 
        !           300: TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
        !           301: {
        !           302:     int idx;
        !           303: 
        !           304:     idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
        !           305:     return MAKE_TCGV_I32(idx);
        !           306: }
        !           307: 
        !           308: TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
        !           309: {
        !           310:     int idx;
        !           311: 
        !           312:     idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
        !           313:     return MAKE_TCGV_I64(idx);
        !           314: }
        !           315: 
        !           316: static inline int tcg_global_mem_new_internal(TCGType type, int reg,
        !           317:                                               tcg_target_long offset,
        !           318:                                               const char *name)
        !           319: {
        !           320:     TCGContext *s = &tcg_ctx;
        !           321:     TCGTemp *ts;
        !           322:     int idx;
        !           323: 
        !           324:     idx = s->nb_globals;
        !           325: #if TCG_TARGET_REG_BITS == 32
        !           326:     if (type == TCG_TYPE_I64) {
        !           327:         char buf[64];
        !           328:         tcg_temp_alloc(s, s->nb_globals + 2);
        !           329:         ts = &s->temps[s->nb_globals];
        !           330:         ts->base_type = type;
        !           331:         ts->type = TCG_TYPE_I32;
        !           332:         ts->fixed_reg = 0;
        !           333:         ts->mem_allocated = 1;
        !           334:         ts->mem_reg = reg;
        !           335: #ifdef TCG_TARGET_WORDS_BIGENDIAN
        !           336:         ts->mem_offset = offset + 4;
        !           337: #else
        !           338:         ts->mem_offset = offset;
        !           339: #endif
        !           340:         pstrcpy(buf, sizeof(buf), name);
        !           341:         pstrcat(buf, sizeof(buf), "_0");
        !           342:         ts->name = strdup(buf);
        !           343:         ts++;
        !           344: 
        !           345:         ts->base_type = type;
        !           346:         ts->type = TCG_TYPE_I32;
        !           347:         ts->fixed_reg = 0;
        !           348:         ts->mem_allocated = 1;
        !           349:         ts->mem_reg = reg;
        !           350: #ifdef TCG_TARGET_WORDS_BIGENDIAN
        !           351:         ts->mem_offset = offset;
        !           352: #else
        !           353:         ts->mem_offset = offset + 4;
        !           354: #endif
        !           355:         pstrcpy(buf, sizeof(buf), name);
        !           356:         pstrcat(buf, sizeof(buf), "_1");
        !           357:         ts->name = strdup(buf);
        !           358: 
        !           359:         s->nb_globals += 2;
        !           360:     } else
        !           361: #endif
        !           362:     {
        !           363:         tcg_temp_alloc(s, s->nb_globals + 1);
        !           364:         ts = &s->temps[s->nb_globals];
        !           365:         ts->base_type = type;
        !           366:         ts->type = type;
        !           367:         ts->fixed_reg = 0;
        !           368:         ts->mem_allocated = 1;
        !           369:         ts->mem_reg = reg;
        !           370:         ts->mem_offset = offset;
        !           371:         ts->name = name;
        !           372:         s->nb_globals++;
        !           373:     }
        !           374:     return idx;
        !           375: }
        !           376: 
        !           377: TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
        !           378:                                 const char *name)
        !           379: {
        !           380:     int idx;
        !           381: 
        !           382:     idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
        !           383:     return MAKE_TCGV_I32(idx);
        !           384: }
        !           385: 
        !           386: TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
        !           387:                                 const char *name)
        !           388: {
        !           389:     int idx;
        !           390: 
        !           391:     idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
        !           392:     return MAKE_TCGV_I64(idx);
        !           393: }
        !           394: 
        !           395: static inline int tcg_temp_new_internal(TCGType type, int temp_local)
        !           396: {
        !           397:     TCGContext *s = &tcg_ctx;
        !           398:     TCGTemp *ts;
        !           399:     int idx, k;
        !           400: 
        !           401:     k = type;
        !           402:     if (temp_local)
        !           403:         k += TCG_TYPE_COUNT;
        !           404:     idx = s->first_free_temp[k];
        !           405:     if (idx != -1) {
        !           406:         /* There is already an available temp with the
        !           407:            right type */
        !           408:         ts = &s->temps[idx];
        !           409:         s->first_free_temp[k] = ts->next_free_temp;
        !           410:         ts->temp_allocated = 1;
        !           411:         assert(ts->temp_local == temp_local);
        !           412:     } else {
        !           413:         idx = s->nb_temps;
        !           414: #if TCG_TARGET_REG_BITS == 32
        !           415:         if (type == TCG_TYPE_I64) {
        !           416:             tcg_temp_alloc(s, s->nb_temps + 2);
        !           417:             ts = &s->temps[s->nb_temps];
        !           418:             ts->base_type = type;
        !           419:             ts->type = TCG_TYPE_I32;
        !           420:             ts->temp_allocated = 1;
        !           421:             ts->temp_local = temp_local;
        !           422:             ts->name = NULL;
        !           423:             ts++;
        !           424:             ts->base_type = TCG_TYPE_I32;
        !           425:             ts->type = TCG_TYPE_I32;
        !           426:             ts->temp_allocated = 1;
        !           427:             ts->temp_local = temp_local;
        !           428:             ts->name = NULL;
        !           429:             s->nb_temps += 2;
        !           430:         } else
        !           431: #endif
        !           432:         {
        !           433:             tcg_temp_alloc(s, s->nb_temps + 1);
        !           434:             ts = &s->temps[s->nb_temps];
        !           435:             ts->base_type = type;
        !           436:             ts->type = type;
        !           437:             ts->temp_allocated = 1;
        !           438:             ts->temp_local = temp_local;
        !           439:             ts->name = NULL;
        !           440:             s->nb_temps++;
        !           441:         }
        !           442:     }
        !           443:     return idx;
        !           444: }
        !           445: 
        !           446: TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
        !           447: {
        !           448:     int idx;
        !           449: 
        !           450:     idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
        !           451:     return MAKE_TCGV_I32(idx);
        !           452: }
        !           453: 
        !           454: TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
        !           455: {
        !           456:     int idx;
        !           457: 
        !           458:     idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
        !           459:     return MAKE_TCGV_I64(idx);
        !           460: }
        !           461: 
        !           462: static inline void tcg_temp_free_internal(int idx)
        !           463: {
        !           464:     TCGContext *s = &tcg_ctx;
        !           465:     TCGTemp *ts;
        !           466:     int k;
        !           467: 
        !           468:     assert(idx >= s->nb_globals && idx < s->nb_temps);
        !           469:     ts = &s->temps[idx];
        !           470:     assert(ts->temp_allocated != 0);
        !           471:     ts->temp_allocated = 0;
        !           472:     k = ts->base_type;
        !           473:     if (ts->temp_local)
        !           474:         k += TCG_TYPE_COUNT;
        !           475:     ts->next_free_temp = s->first_free_temp[k];
        !           476:     s->first_free_temp[k] = idx;
        !           477: }
        !           478: 
        !           479: void tcg_temp_free_i32(TCGv_i32 arg)
        !           480: {
        !           481:     tcg_temp_free_internal(GET_TCGV_I32(arg));
        !           482: }
        !           483: 
        !           484: void tcg_temp_free_i64(TCGv_i64 arg)
        !           485: {
        !           486:     tcg_temp_free_internal(GET_TCGV_I64(arg));
        !           487: }
        !           488: 
        !           489: TCGv_i32 tcg_const_i32(int32_t val)
        !           490: {
        !           491:     TCGv_i32 t0;
        !           492:     t0 = tcg_temp_new_i32();
        !           493:     tcg_gen_movi_i32(t0, val);
        !           494:     return t0;
        !           495: }
        !           496: 
        !           497: TCGv_i64 tcg_const_i64(int64_t val)
        !           498: {
        !           499:     TCGv_i64 t0;
        !           500:     t0 = tcg_temp_new_i64();
        !           501:     tcg_gen_movi_i64(t0, val);
        !           502:     return t0;
        !           503: }
        !           504: 
        !           505: TCGv_i32 tcg_const_local_i32(int32_t val)
        !           506: {
        !           507:     TCGv_i32 t0;
        !           508:     t0 = tcg_temp_local_new_i32();
        !           509:     tcg_gen_movi_i32(t0, val);
        !           510:     return t0;
        !           511: }
        !           512: 
        !           513: TCGv_i64 tcg_const_local_i64(int64_t val)
        !           514: {
        !           515:     TCGv_i64 t0;
        !           516:     t0 = tcg_temp_local_new_i64();
        !           517:     tcg_gen_movi_i64(t0, val);
        !           518:     return t0;
        !           519: }
        !           520: 
        !           521: void tcg_register_helper(void *func, const char *name)
        !           522: {
        !           523:     TCGContext *s = &tcg_ctx;
        !           524:     int n;
        !           525:     if ((s->nb_helpers + 1) > s->allocated_helpers) {
        !           526:         n = s->allocated_helpers;
        !           527:         if (n == 0) {
        !           528:             n = 4;
        !           529:         } else {
        !           530:             n *= 2;
        !           531:         }
        !           532:         s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
        !           533:         s->allocated_helpers = n;
        !           534:     }
        !           535:     s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
        !           536:     s->helpers[s->nb_helpers].name = name;
        !           537:     s->nb_helpers++;
        !           538: }
        !           539: 
        !           540: /* Note: we convert the 64 bit args to 32 bit and do some alignment
        !           541:    and endian swap. Maybe it would be better to do the alignment
        !           542:    and endian swap in tcg_reg_alloc_call(). */
        !           543: void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
        !           544:                    int sizemask, TCGArg ret, int nargs, TCGArg *args)
        !           545: {
        !           546:     int call_type;
        !           547:     int i;
        !           548:     int real_args;
        !           549:     int nb_rets;
        !           550:     TCGArg *nparam;
        !           551:     *gen_opc_ptr++ = INDEX_op_call;
        !           552:     nparam = gen_opparam_ptr++;
        !           553:     call_type = (flags & TCG_CALL_TYPE_MASK);
        !           554:     if (ret != TCG_CALL_DUMMY_ARG) {
        !           555: #if TCG_TARGET_REG_BITS < 64
        !           556:         if (sizemask & 1) {
        !           557: #ifdef TCG_TARGET_WORDS_BIGENDIAN
        !           558:             *gen_opparam_ptr++ = ret + 1;
        !           559:             *gen_opparam_ptr++ = ret;
        !           560: #else
        !           561:             *gen_opparam_ptr++ = ret;
        !           562:             *gen_opparam_ptr++ = ret + 1;
        !           563: #endif
        !           564:             nb_rets = 2;
        !           565:         } else
        !           566: #endif
        !           567:         {
        !           568:             *gen_opparam_ptr++ = ret;
        !           569:             nb_rets = 1;
        !           570:         }
        !           571:     } else {
        !           572:         nb_rets = 0;
        !           573:     }
        !           574:     real_args = 0;
        !           575:     for (i = 0; i < nargs; i++) {
        !           576: #if TCG_TARGET_REG_BITS < 64
        !           577:         if (sizemask & (2 << i)) {
        !           578: #ifdef TCG_TARGET_I386
        !           579:             /* REGPARM case: if the third parameter is 64 bit, it is
        !           580:                allocated on the stack */
        !           581:             if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
        !           582:                 call_type = TCG_CALL_TYPE_REGPARM_2;
        !           583:                 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
        !           584:             }
        !           585: #endif
        !           586: #ifdef TCG_TARGET_CALL_ALIGN_ARGS
        !           587:             /* some targets want aligned 64 bit args */
        !           588:             if (real_args & 1) {
        !           589:                 *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
        !           590:                 real_args++;
        !           591:             }
        !           592: #endif
        !           593: #ifdef TCG_TARGET_WORDS_BIGENDIAN
        !           594:             *gen_opparam_ptr++ = args[i] + 1;
        !           595:             *gen_opparam_ptr++ = args[i];
        !           596: #else
        !           597:             *gen_opparam_ptr++ = args[i];
        !           598:             *gen_opparam_ptr++ = args[i] + 1;
        !           599: #endif
        !           600:             real_args += 2;
        !           601:         } else
        !           602: #endif
        !           603:         {
        !           604:             *gen_opparam_ptr++ = args[i];
        !           605:             real_args++;
        !           606:         }
        !           607:     }
        !           608:     *gen_opparam_ptr++ = GET_TCGV_PTR(func);
        !           609: 
        !           610:     *gen_opparam_ptr++ = flags;
        !           611: 
        !           612:     *nparam = (nb_rets << 16) | (real_args + 1);
        !           613: 
        !           614:     /* total parameters, needed to go backward in the instruction stream */
        !           615:     *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
        !           616: }
        !           617: 
        !           618: #if TCG_TARGET_REG_BITS == 32
        !           619: void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
        !           620:                         int c, int right, int arith)
        !           621: {
        !           622:     if (c == 0) {
        !           623:         tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
        !           624:         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
        !           625:     } else if (c >= 32) {
        !           626:         c -= 32;
        !           627:         if (right) {
        !           628:             if (arith) {
        !           629:                 tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
        !           630:                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
        !           631:             } else {
        !           632:                 tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
        !           633:                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
        !           634:             }
        !           635:         } else {
        !           636:             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
        !           637:             tcg_gen_movi_i32(TCGV_LOW(ret), 0);
        !           638:         }
        !           639:     } else {
        !           640:         TCGv_i32 t0, t1;
        !           641: 
        !           642:         t0 = tcg_temp_new_i32();
        !           643:         t1 = tcg_temp_new_i32();
        !           644:         if (right) {
        !           645:             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
        !           646:             if (arith)
        !           647:                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
        !           648:             else
        !           649:                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
        !           650:             tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
        !           651:             tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
        !           652:             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
        !           653:         } else {
        !           654:             tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
        !           655:             /* Note: ret can be the same as arg1, so we use t1 */
        !           656:             tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
        !           657:             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
        !           658:             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
        !           659:             tcg_gen_mov_i32(TCGV_LOW(ret), t1);
        !           660:         }
        !           661:         tcg_temp_free_i32(t0);
        !           662:         tcg_temp_free_i32(t1);
        !           663:     }
        !           664: }
        !           665: #endif
        !           666: 
        !           667: static void tcg_reg_alloc_start(TCGContext *s)
        !           668: {
        !           669:     int i;
        !           670:     TCGTemp *ts;
        !           671:     for(i = 0; i < s->nb_globals; i++) {
        !           672:         ts = &s->temps[i];
        !           673:         if (ts->fixed_reg) {
        !           674:             ts->val_type = TEMP_VAL_REG;
        !           675:         } else {
        !           676:             ts->val_type = TEMP_VAL_MEM;
        !           677:         }
        !           678:     }
        !           679:     for(i = s->nb_globals; i < s->nb_temps; i++) {
        !           680:         ts = &s->temps[i];
        !           681:         ts->val_type = TEMP_VAL_DEAD;
        !           682:         ts->mem_allocated = 0;
        !           683:         ts->fixed_reg = 0;
        !           684:     }
        !           685:     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
        !           686:         s->reg_to_temp[i] = -1;
        !           687:     }
        !           688: }
        !           689: 
        !           690: static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
        !           691:                                  int idx)
        !           692: {
        !           693:     TCGTemp *ts;
        !           694: 
        !           695:     ts = &s->temps[idx];
        !           696:     if (idx < s->nb_globals) {
        !           697:         pstrcpy(buf, buf_size, ts->name);
        !           698:     } else {
        !           699:         if (ts->temp_local) 
        !           700:             snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
        !           701:         else
        !           702:             snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
        !           703:     }
        !           704:     return buf;
        !           705: }
        !           706: 
        !           707: char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
        !           708: {
        !           709:     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
        !           710: }
        !           711: 
        !           712: char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
        !           713: {
        !           714:     return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
        !           715: }
        !           716: 
        !           717: static int helper_cmp(const void *p1, const void *p2)
        !           718: {
        !           719:     const TCGHelperInfo *th1 = p1;
        !           720:     const TCGHelperInfo *th2 = p2;
        !           721:     if (th1->func < th2->func)
        !           722:         return -1;
        !           723:     else if (th1->func == th2->func)
        !           724:         return 0;
        !           725:     else
        !           726:         return 1;
        !           727: }
        !           728: 
        !           729: /* find helper definition (Note: A hash table would be better) */
        !           730: static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
        !           731: {
        !           732:     int m, m_min, m_max;
        !           733:     TCGHelperInfo *th;
        !           734:     tcg_target_ulong v;
        !           735: 
        !           736:     if (unlikely(!s->helpers_sorted)) {
        !           737:         qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), 
        !           738:               helper_cmp);
        !           739:         s->helpers_sorted = 1;
        !           740:     }
        !           741: 
        !           742:     /* binary search */
        !           743:     m_min = 0;
        !           744:     m_max = s->nb_helpers - 1;
        !           745:     while (m_min <= m_max) {
        !           746:         m = (m_min + m_max) >> 1;
        !           747:         th = &s->helpers[m];
        !           748:         v = th->func;
        !           749:         if (v == val)
        !           750:             return th;
        !           751:         else if (val < v) {
        !           752:             m_max = m - 1;
        !           753:         } else {
        !           754:             m_min = m + 1;
        !           755:         }
        !           756:     }
        !           757:     return NULL;
        !           758: }
        !           759: 
        !           760: static const char * const cond_name[] =
        !           761: {
        !           762:     [TCG_COND_EQ] = "eq",
        !           763:     [TCG_COND_NE] = "ne",
        !           764:     [TCG_COND_LT] = "lt",
        !           765:     [TCG_COND_GE] = "ge",
        !           766:     [TCG_COND_LE] = "le",
        !           767:     [TCG_COND_GT] = "gt",
        !           768:     [TCG_COND_LTU] = "ltu",
        !           769:     [TCG_COND_GEU] = "geu",
        !           770:     [TCG_COND_LEU] = "leu",
        !           771:     [TCG_COND_GTU] = "gtu"
        !           772: };
        !           773: 
        !           774: void tcg_dump_ops(TCGContext *s, FILE *outfile)
        !           775: {
        !           776:     const uint16_t *opc_ptr;
        !           777:     const TCGArg *args;
        !           778:     TCGArg arg;
        !           779:     int c, i, k, nb_oargs, nb_iargs, nb_cargs, first_insn;
        !           780:     const TCGOpDef *def;
        !           781:     char buf[128];
        !           782: 
        !           783:     first_insn = 1;
        !           784:     opc_ptr = gen_opc_buf;
        !           785:     args = gen_opparam_buf;
        !           786:     while (opc_ptr < gen_opc_ptr) {
        !           787:         c = *opc_ptr++;
        !           788:         def = &tcg_op_defs[c];
        !           789:         if (c == INDEX_op_debug_insn_start) {
        !           790:             uint64_t pc;
        !           791: #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
        !           792:             pc = ((uint64_t)args[1] << 32) | args[0];
        !           793: #else
        !           794:             pc = args[0];
        !           795: #endif
        !           796:             if (!first_insn) 
        !           797:                 fprintf(outfile, "\n");
        !           798:             fprintf(outfile, " ---- 0x%" PRIx64, pc);
        !           799:             first_insn = 0;
        !           800:             nb_oargs = def->nb_oargs;
        !           801:             nb_iargs = def->nb_iargs;
        !           802:             nb_cargs = def->nb_cargs;
        !           803:         } else if (c == INDEX_op_call) {
        !           804:             TCGArg arg;
        !           805: 
        !           806:             /* variable number of arguments */
        !           807:             arg = *args++;
        !           808:             nb_oargs = arg >> 16;
        !           809:             nb_iargs = arg & 0xffff;
        !           810:             nb_cargs = def->nb_cargs;
        !           811: 
        !           812:             fprintf(outfile, " %s ", def->name);
        !           813: 
        !           814:             /* function name */
        !           815:             fprintf(outfile, "%s",
        !           816:                     tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + nb_iargs - 1]));
        !           817:             /* flags */
        !           818:             fprintf(outfile, ",$0x%" TCG_PRIlx,
        !           819:                     args[nb_oargs + nb_iargs]);
        !           820:             /* nb out args */
        !           821:             fprintf(outfile, ",$%d", nb_oargs);
        !           822:             for(i = 0; i < nb_oargs; i++) {
        !           823:                 fprintf(outfile, ",");
        !           824:                 fprintf(outfile, "%s",
        !           825:                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
        !           826:             }
        !           827:             for(i = 0; i < (nb_iargs - 1); i++) {
        !           828:                 fprintf(outfile, ",");
        !           829:                 if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) {
        !           830:                     fprintf(outfile, "<dummy>");
        !           831:                 } else {
        !           832:                     fprintf(outfile, "%s",
        !           833:                             tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i]));
        !           834:                 }
        !           835:             }
        !           836:         } else if (c == INDEX_op_movi_i32 
        !           837: #if TCG_TARGET_REG_BITS == 64
        !           838:                    || c == INDEX_op_movi_i64
        !           839: #endif
        !           840:                    ) {
        !           841:             tcg_target_ulong val;
        !           842:             TCGHelperInfo *th;
        !           843: 
        !           844:             nb_oargs = def->nb_oargs;
        !           845:             nb_iargs = def->nb_iargs;
        !           846:             nb_cargs = def->nb_cargs;
        !           847:             fprintf(outfile, " %s %s,$", def->name, 
        !           848:                     tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
        !           849:             val = args[1];
        !           850:             th = tcg_find_helper(s, val);
        !           851:             if (th) {
        !           852:                 fprintf(outfile, "%s", th->name);
        !           853:             } else {
        !           854:                 if (c == INDEX_op_movi_i32)
        !           855:                     fprintf(outfile, "0x%x", (uint32_t)val);
        !           856:                 else
        !           857:                     fprintf(outfile, "0x%" PRIx64 , (uint64_t)val);
        !           858:             }
        !           859:         } else {
        !           860:             fprintf(outfile, " %s ", def->name);
        !           861:             if (c == INDEX_op_nopn) {
        !           862:                 /* variable number of arguments */
        !           863:                 nb_cargs = *args;
        !           864:                 nb_oargs = 0;
        !           865:                 nb_iargs = 0;
        !           866:             } else {
        !           867:                 nb_oargs = def->nb_oargs;
        !           868:                 nb_iargs = def->nb_iargs;
        !           869:                 nb_cargs = def->nb_cargs;
        !           870:             }
        !           871:             
        !           872:             k = 0;
        !           873:             for(i = 0; i < nb_oargs; i++) {
        !           874:                 if (k != 0)
        !           875:                     fprintf(outfile, ",");
        !           876:                 fprintf(outfile, "%s",
        !           877:                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
        !           878:             }
        !           879:             for(i = 0; i < nb_iargs; i++) {
        !           880:                 if (k != 0)
        !           881:                     fprintf(outfile, ",");
        !           882:                 fprintf(outfile, "%s",
        !           883:                         tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
        !           884:             }
        !           885:             if (c == INDEX_op_brcond_i32
        !           886: #if TCG_TARGET_REG_BITS == 32
        !           887:                 || c == INDEX_op_brcond2_i32
        !           888: #elif TCG_TARGET_REG_BITS == 64
        !           889:                 || c == INDEX_op_brcond_i64
        !           890: #endif
        !           891:                 ) {
        !           892:                 if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]])
        !           893:                     fprintf(outfile, ",%s", cond_name[args[k++]]);
        !           894:                 else
        !           895:                     fprintf(outfile, ",$0x%" TCG_PRIlx, args[k++]);
        !           896:                 i = 1;
        !           897:             }
        !           898:             else
        !           899:                 i = 0;
        !           900:             for(; i < nb_cargs; i++) {
        !           901:                 if (k != 0)
        !           902:                     fprintf(outfile, ",");
        !           903:                 arg = args[k++];
        !           904:                 fprintf(outfile, "$0x%" TCG_PRIlx, arg);
        !           905:             }
        !           906:         }
        !           907:         fprintf(outfile, "\n");
        !           908:         args += nb_iargs + nb_oargs + nb_cargs;
        !           909:     }
        !           910: }
        !           911: 
        !           912: /* we give more priority to constraints with less registers */
        !           913: static int get_constraint_priority(const TCGOpDef *def, int k)
        !           914: {
        !           915:     const TCGArgConstraint *arg_ct;
        !           916: 
        !           917:     int i, n;
        !           918:     arg_ct = &def->args_ct[k];
        !           919:     if (arg_ct->ct & TCG_CT_ALIAS) {
        !           920:         /* an alias is equivalent to a single register */
        !           921:         n = 1;
        !           922:     } else {
        !           923:         if (!(arg_ct->ct & TCG_CT_REG))
        !           924:             return 0;
        !           925:         n = 0;
        !           926:         for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
        !           927:             if (tcg_regset_test_reg(arg_ct->u.regs, i))
        !           928:                 n++;
        !           929:         }
        !           930:     }
        !           931:     return TCG_TARGET_NB_REGS - n + 1;
        !           932: }
        !           933: 
        !           934: /* sort from highest priority to lowest */
        !           935: static void sort_constraints(TCGOpDef *def, int start, int n)
        !           936: {
        !           937:     int i, j, p1, p2, tmp;
        !           938: 
        !           939:     for(i = 0; i < n; i++)
        !           940:         def->sorted_args[start + i] = start + i;
        !           941:     if (n <= 1)
        !           942:         return;
        !           943:     for(i = 0; i < n - 1; i++) {
        !           944:         for(j = i + 1; j < n; j++) {
        !           945:             p1 = get_constraint_priority(def, def->sorted_args[start + i]);
        !           946:             p2 = get_constraint_priority(def, def->sorted_args[start + j]);
        !           947:             if (p1 < p2) {
        !           948:                 tmp = def->sorted_args[start + i];
        !           949:                 def->sorted_args[start + i] = def->sorted_args[start + j];
        !           950:                 def->sorted_args[start + j] = tmp;
        !           951:             }
        !           952:         }
        !           953:     }
        !           954: }
        !           955: 
        !           956: void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
        !           957: {
        !           958:     int op;
        !           959:     TCGOpDef *def;
        !           960:     const char *ct_str;
        !           961:     int i, nb_args;
        !           962: 
        !           963:     for(;;) {
        !           964:         if (tdefs->op < 0)
        !           965:             break;
        !           966:         op = tdefs->op;
        !           967:         assert(op >= 0 && op < NB_OPS);
        !           968:         def = &tcg_op_defs[op];
        !           969:         nb_args = def->nb_iargs + def->nb_oargs;
        !           970:         for(i = 0; i < nb_args; i++) {
        !           971:             ct_str = tdefs->args_ct_str[i];
        !           972:             tcg_regset_clear(def->args_ct[i].u.regs);
        !           973:             def->args_ct[i].ct = 0;
        !           974:             if (ct_str[0] >= '0' && ct_str[0] <= '9') {
        !           975:                 int oarg;
        !           976:                 oarg = ct_str[0] - '0';
        !           977:                 assert(oarg < def->nb_oargs);
        !           978:                 assert(def->args_ct[oarg].ct & TCG_CT_REG);
        !           979:                 /* TCG_CT_ALIAS is for the output arguments. The input
        !           980:                    argument is tagged with TCG_CT_IALIAS. */
        !           981:                 def->args_ct[i] = def->args_ct[oarg];
        !           982:                 def->args_ct[oarg].ct = TCG_CT_ALIAS;
        !           983:                 def->args_ct[oarg].alias_index = i;
        !           984:                 def->args_ct[i].ct |= TCG_CT_IALIAS;
        !           985:                 def->args_ct[i].alias_index = oarg;
        !           986:             } else {
        !           987:                 for(;;) {
        !           988:                     if (*ct_str == '\0')
        !           989:                         break;
        !           990:                     switch(*ct_str) {
        !           991:                     case 'i':
        !           992:                         def->args_ct[i].ct |= TCG_CT_CONST;
        !           993:                         ct_str++;
        !           994:                         break;
        !           995:                     default:
        !           996:                         if (target_parse_constraint(&def->args_ct[i], &ct_str) < 0) {
        !           997:                             fprintf(stderr, "Invalid constraint '%s' for arg %d of operation '%s'\n",
        !           998:                                     ct_str, i, def->name);
        !           999:                             exit(1);
        !          1000:                         }
        !          1001:                     }
        !          1002:                 }
        !          1003:             }
        !          1004:         }
        !          1005: 
        !          1006:         /* sort the constraints (XXX: this is just an heuristic) */
        !          1007:         sort_constraints(def, 0, def->nb_oargs);
        !          1008:         sort_constraints(def, def->nb_oargs, def->nb_iargs);
        !          1009: 
        !          1010: #if 0
        !          1011:         {
        !          1012:             int i;
        !          1013: 
        !          1014:             printf("%s: sorted=", def->name);
        !          1015:             for(i = 0; i < def->nb_oargs + def->nb_iargs; i++)
        !          1016:                 printf(" %d", def->sorted_args[i]);
        !          1017:             printf("\n");
        !          1018:         }
        !          1019: #endif
        !          1020:         tdefs++;
        !          1021:     }
        !          1022: 
        !          1023: }
        !          1024: 
        !          1025: #ifdef USE_LIVENESS_ANALYSIS
        !          1026: 
        !          1027: /* set a nop for an operation using 'nb_args' */
        !          1028: static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, 
        !          1029:                                TCGArg *args, int nb_args)
        !          1030: {
        !          1031:     if (nb_args == 0) {
        !          1032:         *opc_ptr = INDEX_op_nop;
        !          1033:     } else {
        !          1034:         *opc_ptr = INDEX_op_nopn;
        !          1035:         args[0] = nb_args;
        !          1036:         args[nb_args - 1] = nb_args;
        !          1037:     }
        !          1038: }
        !          1039: 
        !          1040: /* liveness analysis: end of function: globals are live, temps are
        !          1041:    dead. */
        !          1042: /* XXX: at this stage, not used as there would be little gains because
        !          1043:    most TBs end with a conditional jump. */
        !          1044: static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps)
        !          1045: {
        !          1046:     memset(dead_temps, 0, s->nb_globals);
        !          1047:     memset(dead_temps + s->nb_globals, 1, s->nb_temps - s->nb_globals);
        !          1048: }
        !          1049: 
        !          1050: /* liveness analysis: end of basic block: globals are live, temps are
        !          1051:    dead, local temps are live. */
        !          1052: static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps)
        !          1053: {
        !          1054:     int i;
        !          1055:     TCGTemp *ts;
        !          1056: 
        !          1057:     memset(dead_temps, 0, s->nb_globals);
        !          1058:     ts = &s->temps[s->nb_globals];
        !          1059:     for(i = s->nb_globals; i < s->nb_temps; i++) {
        !          1060:         if (ts->temp_local)
        !          1061:             dead_temps[i] = 0;
        !          1062:         else
        !          1063:             dead_temps[i] = 1;
        !          1064:         ts++;
        !          1065:     }
        !          1066: }
        !          1067: 
        !          1068: /* Liveness analysis : update the opc_dead_iargs array to tell if a
        !          1069:    given input arguments is dead. Instructions updating dead
        !          1070:    temporaries are removed. */
        !          1071: static void tcg_liveness_analysis(TCGContext *s)
        !          1072: {
        !          1073:     int i, op_index, op, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
        !          1074:     TCGArg *args;
        !          1075:     const TCGOpDef *def;
        !          1076:     uint8_t *dead_temps;
        !          1077:     unsigned int dead_iargs;
        !          1078:     
        !          1079:     gen_opc_ptr++; /* skip end */
        !          1080: 
        !          1081:     nb_ops = gen_opc_ptr - gen_opc_buf;
        !          1082: 
        !          1083:     /* XXX: make it really dynamic */
        !          1084:     s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t));
        !          1085:     
        !          1086:     dead_temps = tcg_malloc(s->nb_temps);
        !          1087:     memset(dead_temps, 1, s->nb_temps);
        !          1088: 
        !          1089:     args = gen_opparam_ptr;
        !          1090:     op_index = nb_ops - 1;
        !          1091:     while (op_index >= 0) {
        !          1092:         op = gen_opc_buf[op_index];
        !          1093:         def = &tcg_op_defs[op];
        !          1094:         switch(op) {
        !          1095:         case INDEX_op_call:
        !          1096:             {
        !          1097:                 int call_flags;
        !          1098: 
        !          1099:                 nb_args = args[-1];
        !          1100:                 args -= nb_args;
        !          1101:                 nb_iargs = args[0] & 0xffff;
        !          1102:                 nb_oargs = args[0] >> 16;
        !          1103:                 args++;
        !          1104:                 call_flags = args[nb_oargs + nb_iargs];
        !          1105: 
        !          1106:                 /* pure functions can be removed if their result is not
        !          1107:                    used */
        !          1108:                 if (call_flags & TCG_CALL_PURE) {
        !          1109:                     for(i = 0; i < nb_oargs; i++) {
        !          1110:                         arg = args[i];
        !          1111:                         if (!dead_temps[arg])
        !          1112:                             goto do_not_remove_call;
        !          1113:                     }
        !          1114:                     tcg_set_nop(s, gen_opc_buf + op_index, 
        !          1115:                                 args - 1, nb_args);
        !          1116:                 } else {
        !          1117:                 do_not_remove_call:
        !          1118: 
        !          1119:                     /* output args are dead */
        !          1120:                     for(i = 0; i < nb_oargs; i++) {
        !          1121:                         arg = args[i];
        !          1122:                         dead_temps[arg] = 1;
        !          1123:                     }
        !          1124:                     
        !          1125:                     /* globals are live (they may be used by the call) */
        !          1126:                     memset(dead_temps, 0, s->nb_globals);
        !          1127:                     
        !          1128:                     /* input args are live */
        !          1129:                     dead_iargs = 0;
        !          1130:                     for(i = 0; i < nb_iargs; i++) {
        !          1131:                         arg = args[i + nb_oargs];
        !          1132:                         if (arg != TCG_CALL_DUMMY_ARG) {
        !          1133:                             if (dead_temps[arg]) {
        !          1134:                                 dead_iargs |= (1 << i);
        !          1135:                             }
        !          1136:                             dead_temps[arg] = 0;
        !          1137:                         }
        !          1138:                     }
        !          1139:                     s->op_dead_iargs[op_index] = dead_iargs;
        !          1140:                 }
        !          1141:                 args--;
        !          1142:             }
        !          1143:             break;
        !          1144:         case INDEX_op_set_label:
        !          1145:             args--;
        !          1146:             /* mark end of basic block */
        !          1147:             tcg_la_bb_end(s, dead_temps);
        !          1148:             break;
        !          1149:         case INDEX_op_debug_insn_start:
        !          1150:             args -= def->nb_args;
        !          1151:             break;
        !          1152:         case INDEX_op_nopn:
        !          1153:             nb_args = args[-1];
        !          1154:             args -= nb_args;
        !          1155:             break;
        !          1156:         case INDEX_op_discard:
        !          1157:             args--;
        !          1158:             /* mark the temporary as dead */
        !          1159:             dead_temps[args[0]] = 1;
        !          1160:             break;
        !          1161:         case INDEX_op_end:
        !          1162:             break;
        !          1163:             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
        !          1164:         default:
        !          1165:             args -= def->nb_args;
        !          1166:             nb_iargs = def->nb_iargs;
        !          1167:             nb_oargs = def->nb_oargs;
        !          1168: 
        !          1169:             /* Test if the operation can be removed because all
        !          1170:                its outputs are dead. We assume that nb_oargs == 0
        !          1171:                implies side effects */
        !          1172:             if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
        !          1173:                 for(i = 0; i < nb_oargs; i++) {
        !          1174:                     arg = args[i];
        !          1175:                     if (!dead_temps[arg])
        !          1176:                         goto do_not_remove;
        !          1177:                 }
        !          1178:                 tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
        !          1179: #ifdef CONFIG_PROFILER
        !          1180:                 s->del_op_count++;
        !          1181: #endif
        !          1182:             } else {
        !          1183:             do_not_remove:
        !          1184: 
        !          1185:                 /* output args are dead */
        !          1186:                 for(i = 0; i < nb_oargs; i++) {
        !          1187:                     arg = args[i];
        !          1188:                     dead_temps[arg] = 1;
        !          1189:                 }
        !          1190: 
        !          1191:                 /* if end of basic block, update */
        !          1192:                 if (def->flags & TCG_OPF_BB_END) {
        !          1193:                     tcg_la_bb_end(s, dead_temps);
        !          1194:                 } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
        !          1195:                     /* globals are live */
        !          1196:                     memset(dead_temps, 0, s->nb_globals);
        !          1197:                 }
        !          1198: 
        !          1199:                 /* input args are live */
        !          1200:                 dead_iargs = 0;
        !          1201:                 for(i = 0; i < nb_iargs; i++) {
        !          1202:                     arg = args[i + nb_oargs];
        !          1203:                     if (dead_temps[arg]) {
        !          1204:                         dead_iargs |= (1 << i);
        !          1205:                     }
        !          1206:                     dead_temps[arg] = 0;
        !          1207:                 }
        !          1208:                 s->op_dead_iargs[op_index] = dead_iargs;
        !          1209:             }
        !          1210:             break;
        !          1211:         }
        !          1212:         op_index--;
        !          1213:     }
        !          1214: 
        !          1215:     if (args != gen_opparam_buf)
        !          1216:         tcg_abort();
        !          1217: }
        !          1218: #else
        !          1219: /* dummy liveness analysis */
        !          1220: void tcg_liveness_analysis(TCGContext *s)
        !          1221: {
        !          1222:     int nb_ops;
        !          1223:     nb_ops = gen_opc_ptr - gen_opc_buf;
        !          1224: 
        !          1225:     s->op_dead_iargs = tcg_malloc(nb_ops * sizeof(uint16_t));
        !          1226:     memset(s->op_dead_iargs, 0, nb_ops * sizeof(uint16_t));
        !          1227: }
        !          1228: #endif
        !          1229: 
        !          1230: #ifndef NDEBUG
        !          1231: static void dump_regs(TCGContext *s)
        !          1232: {
        !          1233:     TCGTemp *ts;
        !          1234:     int i;
        !          1235:     char buf[64];
        !          1236: 
        !          1237:     for(i = 0; i < s->nb_temps; i++) {
        !          1238:         ts = &s->temps[i];
        !          1239:         printf("  %10s: ", tcg_get_arg_str_idx(s, buf, sizeof(buf), i));
        !          1240:         switch(ts->val_type) {
        !          1241:         case TEMP_VAL_REG:
        !          1242:             printf("%s", tcg_target_reg_names[ts->reg]);
        !          1243:             break;
        !          1244:         case TEMP_VAL_MEM:
        !          1245:             printf("%d(%s)", (int)ts->mem_offset, tcg_target_reg_names[ts->mem_reg]);
        !          1246:             break;
        !          1247:         case TEMP_VAL_CONST:
        !          1248:             printf("$0x%" TCG_PRIlx, ts->val);
        !          1249:             break;
        !          1250:         case TEMP_VAL_DEAD:
        !          1251:             printf("D");
        !          1252:             break;
        !          1253:         default:
        !          1254:             printf("???");
        !          1255:             break;
        !          1256:         }
        !          1257:         printf("\n");
        !          1258:     }
        !          1259: 
        !          1260:     for(i = 0; i < TCG_TARGET_NB_REGS; i++) {
        !          1261:         if (s->reg_to_temp[i] >= 0) {
        !          1262:             printf("%s: %s\n", 
        !          1263:                    tcg_target_reg_names[i], 
        !          1264:                    tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i]));
        !          1265:         }
        !          1266:     }
        !          1267: }
        !          1268: 
        !          1269: static void check_regs(TCGContext *s)
        !          1270: {
        !          1271:     int reg, k;
        !          1272:     TCGTemp *ts;
        !          1273:     char buf[64];
        !          1274: 
        !          1275:     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
        !          1276:         k = s->reg_to_temp[reg];
        !          1277:         if (k >= 0) {
        !          1278:             ts = &s->temps[k];
        !          1279:             if (ts->val_type != TEMP_VAL_REG ||
        !          1280:                 ts->reg != reg) {
        !          1281:                 printf("Inconsistency for register %s:\n", 
        !          1282:                        tcg_target_reg_names[reg]);
        !          1283:                 goto fail;
        !          1284:             }
        !          1285:         }
        !          1286:     }
        !          1287:     for(k = 0; k < s->nb_temps; k++) {
        !          1288:         ts = &s->temps[k];
        !          1289:         if (ts->val_type == TEMP_VAL_REG &&
        !          1290:             !ts->fixed_reg &&
        !          1291:             s->reg_to_temp[ts->reg] != k) {
        !          1292:                 printf("Inconsistency for temp %s:\n", 
        !          1293:                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
        !          1294:         fail:
        !          1295:                 printf("reg state:\n");
        !          1296:                 dump_regs(s);
        !          1297:                 tcg_abort();
        !          1298:         }
        !          1299:     }
        !          1300: }
        !          1301: #endif
        !          1302: 
        !          1303: static void temp_allocate_frame(TCGContext *s, int temp)
        !          1304: {
        !          1305:     TCGTemp *ts;
        !          1306:     ts = &s->temps[temp];
        !          1307:     s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1);
        !          1308:     if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end)
        !          1309:         tcg_abort();
        !          1310:     ts->mem_offset = s->current_frame_offset;
        !          1311:     ts->mem_reg = s->frame_reg;
        !          1312:     ts->mem_allocated = 1;
        !          1313:     s->current_frame_offset += sizeof(tcg_target_long);
        !          1314: }
        !          1315: 
        !          1316: /* free register 'reg' by spilling the corresponding temporary if necessary */
        !          1317: static void tcg_reg_free(TCGContext *s, int reg)
        !          1318: {
        !          1319:     TCGTemp *ts;
        !          1320:     int temp;
        !          1321: 
        !          1322:     temp = s->reg_to_temp[reg];
        !          1323:     if (temp != -1) {
        !          1324:         ts = &s->temps[temp];
        !          1325:         assert(ts->val_type == TEMP_VAL_REG);
        !          1326:         if (!ts->mem_coherent) {
        !          1327:             if (!ts->mem_allocated) 
        !          1328:                 temp_allocate_frame(s, temp);
        !          1329:             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1330:         }
        !          1331:         ts->val_type = TEMP_VAL_MEM;
        !          1332:         s->reg_to_temp[reg] = -1;
        !          1333:     }
        !          1334: }
        !          1335: 
        !          1336: /* Allocate a register belonging to reg1 & ~reg2 */
        !          1337: static int tcg_reg_alloc(TCGContext *s, TCGRegSet reg1, TCGRegSet reg2)
        !          1338: {
        !          1339:     int i, reg;
        !          1340:     TCGRegSet reg_ct;
        !          1341: 
        !          1342:     tcg_regset_andnot(reg_ct, reg1, reg2);
        !          1343: 
        !          1344:     /* first try free registers */
        !          1345:     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
        !          1346:         reg = tcg_target_reg_alloc_order[i];
        !          1347:         if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == -1)
        !          1348:             return reg;
        !          1349:     }
        !          1350: 
        !          1351:     /* XXX: do better spill choice */
        !          1352:     for(i = 0; i < ARRAY_SIZE(tcg_target_reg_alloc_order); i++) {
        !          1353:         reg = tcg_target_reg_alloc_order[i];
        !          1354:         if (tcg_regset_test_reg(reg_ct, reg)) {
        !          1355:             tcg_reg_free(s, reg);
        !          1356:             return reg;
        !          1357:         }
        !          1358:     }
        !          1359: 
        !          1360:     tcg_abort();
        !          1361: }
        !          1362: 
        !          1363: /* save a temporary to memory. 'allocated_regs' is used in case a
        !          1364:    temporary registers needs to be allocated to store a constant. */
        !          1365: static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs)
        !          1366: {
        !          1367:     TCGTemp *ts;
        !          1368:     int reg;
        !          1369: 
        !          1370:     ts = &s->temps[temp];
        !          1371:     if (!ts->fixed_reg) {
        !          1372:         switch(ts->val_type) {
        !          1373:         case TEMP_VAL_REG:
        !          1374:             tcg_reg_free(s, ts->reg);
        !          1375:             break;
        !          1376:         case TEMP_VAL_DEAD:
        !          1377:             ts->val_type = TEMP_VAL_MEM;
        !          1378:             break;
        !          1379:         case TEMP_VAL_CONST:
        !          1380:             reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
        !          1381:                                 allocated_regs);
        !          1382:             if (!ts->mem_allocated) 
        !          1383:                 temp_allocate_frame(s, temp);
        !          1384:             tcg_out_movi(s, ts->type, reg, ts->val);
        !          1385:             tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1386:             ts->val_type = TEMP_VAL_MEM;
        !          1387:             break;
        !          1388:         case TEMP_VAL_MEM:
        !          1389:             break;
        !          1390:         default:
        !          1391:             tcg_abort();
        !          1392:         }
        !          1393:     }
        !          1394: }
        !          1395: 
        !          1396: /* save globals to their cannonical location and assume they can be
        !          1397:    modified be the following code. 'allocated_regs' is used in case a
        !          1398:    temporary registers needs to be allocated to store a constant. */
        !          1399: static void save_globals(TCGContext *s, TCGRegSet allocated_regs)
        !          1400: {
        !          1401:     int i;
        !          1402: 
        !          1403:     for(i = 0; i < s->nb_globals; i++) {
        !          1404:         temp_save(s, i, allocated_regs);
        !          1405:     }
        !          1406: }
        !          1407: 
        !          1408: /* at the end of a basic block, we assume all temporaries are dead and
        !          1409:    all globals are stored at their canonical location. */
        !          1410: static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
        !          1411: {
        !          1412:     TCGTemp *ts;
        !          1413:     int i;
        !          1414: 
        !          1415:     for(i = s->nb_globals; i < s->nb_temps; i++) {
        !          1416:         ts = &s->temps[i];
        !          1417:         if (ts->temp_local) {
        !          1418:             temp_save(s, i, allocated_regs);
        !          1419:         } else {
        !          1420:             if (ts->val_type == TEMP_VAL_REG) {
        !          1421:                 s->reg_to_temp[ts->reg] = -1;
        !          1422:             }
        !          1423:             ts->val_type = TEMP_VAL_DEAD;
        !          1424:         }
        !          1425:     }
        !          1426: 
        !          1427:     save_globals(s, allocated_regs);
        !          1428: }
        !          1429: 
        !          1430: #define IS_DEAD_IARG(n) ((dead_iargs >> (n)) & 1)
        !          1431: 
        !          1432: static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args)
        !          1433: {
        !          1434:     TCGTemp *ots;
        !          1435:     tcg_target_ulong val;
        !          1436: 
        !          1437:     ots = &s->temps[args[0]];
        !          1438:     val = args[1];
        !          1439: 
        !          1440:     if (ots->fixed_reg) {
        !          1441:         /* for fixed registers, we do not do any constant
        !          1442:            propagation */
        !          1443:         tcg_out_movi(s, ots->type, ots->reg, val);
        !          1444:     } else {
        !          1445:         /* The movi is not explicitly generated here */
        !          1446:         if (ots->val_type == TEMP_VAL_REG)
        !          1447:             s->reg_to_temp[ots->reg] = -1;
        !          1448:         ots->val_type = TEMP_VAL_CONST;
        !          1449:         ots->val = val;
        !          1450:     }
        !          1451: }
        !          1452: 
        !          1453: static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
        !          1454:                               const TCGArg *args,
        !          1455:                               unsigned int dead_iargs)
        !          1456: {
        !          1457:     TCGTemp *ts, *ots;
        !          1458:     int reg;
        !          1459:     const TCGArgConstraint *arg_ct;
        !          1460: 
        !          1461:     ots = &s->temps[args[0]];
        !          1462:     ts = &s->temps[args[1]];
        !          1463:     arg_ct = &def->args_ct[0];
        !          1464: 
        !          1465:     /* XXX: always mark arg dead if IS_DEAD_IARG(0) */
        !          1466:     if (ts->val_type == TEMP_VAL_REG) {
        !          1467:         if (IS_DEAD_IARG(0) && !ts->fixed_reg && !ots->fixed_reg) {
        !          1468:             /* the mov can be suppressed */
        !          1469:             if (ots->val_type == TEMP_VAL_REG)
        !          1470:                 s->reg_to_temp[ots->reg] = -1;
        !          1471:             reg = ts->reg;
        !          1472:             s->reg_to_temp[reg] = -1;
        !          1473:             ts->val_type = TEMP_VAL_DEAD;
        !          1474:         } else {
        !          1475:             if (ots->val_type == TEMP_VAL_REG) {
        !          1476:                 reg = ots->reg;
        !          1477:             } else {
        !          1478:                 reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
        !          1479:             }
        !          1480:             if (ts->reg != reg) {
        !          1481:                 tcg_out_mov(s, reg, ts->reg);
        !          1482:             }
        !          1483:         }
        !          1484:     } else if (ts->val_type == TEMP_VAL_MEM) {
        !          1485:         if (ots->val_type == TEMP_VAL_REG) {
        !          1486:             reg = ots->reg;
        !          1487:         } else {
        !          1488:             reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
        !          1489:         }
        !          1490:         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1491:     } else if (ts->val_type == TEMP_VAL_CONST) {
        !          1492:         if (ots->fixed_reg) {
        !          1493:             reg = ots->reg;
        !          1494:             tcg_out_movi(s, ots->type, reg, ts->val);
        !          1495:         } else {
        !          1496:             /* propagate constant */
        !          1497:             if (ots->val_type == TEMP_VAL_REG)
        !          1498:                 s->reg_to_temp[ots->reg] = -1;
        !          1499:             ots->val_type = TEMP_VAL_CONST;
        !          1500:             ots->val = ts->val;
        !          1501:             return;
        !          1502:         }
        !          1503:     } else {
        !          1504:         tcg_abort();
        !          1505:     }
        !          1506:     s->reg_to_temp[reg] = args[0];
        !          1507:     ots->reg = reg;
        !          1508:     ots->val_type = TEMP_VAL_REG;
        !          1509:     ots->mem_coherent = 0;
        !          1510: }
        !          1511: 
        !          1512: static void tcg_reg_alloc_op(TCGContext *s, 
        !          1513:                              const TCGOpDef *def, int opc,
        !          1514:                              const TCGArg *args,
        !          1515:                              unsigned int dead_iargs)
        !          1516: {
        !          1517:     TCGRegSet allocated_regs;
        !          1518:     int i, k, nb_iargs, nb_oargs, reg;
        !          1519:     TCGArg arg;
        !          1520:     const TCGArgConstraint *arg_ct;
        !          1521:     TCGTemp *ts;
        !          1522:     TCGArg new_args[TCG_MAX_OP_ARGS];
        !          1523:     int const_args[TCG_MAX_OP_ARGS];
        !          1524: 
        !          1525:     nb_oargs = def->nb_oargs;
        !          1526:     nb_iargs = def->nb_iargs;
        !          1527: 
        !          1528:     /* copy constants */
        !          1529:     memcpy(new_args + nb_oargs + nb_iargs, 
        !          1530:            args + nb_oargs + nb_iargs, 
        !          1531:            sizeof(TCGArg) * def->nb_cargs);
        !          1532: 
        !          1533:     /* satisfy input constraints */ 
        !          1534:     tcg_regset_set(allocated_regs, s->reserved_regs);
        !          1535:     for(k = 0; k < nb_iargs; k++) {
        !          1536:         i = def->sorted_args[nb_oargs + k];
        !          1537:         arg = args[i];
        !          1538:         arg_ct = &def->args_ct[i];
        !          1539:         ts = &s->temps[arg];
        !          1540:         if (ts->val_type == TEMP_VAL_MEM) {
        !          1541:             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1542:             tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1543:             ts->val_type = TEMP_VAL_REG;
        !          1544:             ts->reg = reg;
        !          1545:             ts->mem_coherent = 1;
        !          1546:             s->reg_to_temp[reg] = arg;
        !          1547:         } else if (ts->val_type == TEMP_VAL_CONST) {
        !          1548:             if (tcg_target_const_match(ts->val, arg_ct)) {
        !          1549:                 /* constant is OK for instruction */
        !          1550:                 const_args[i] = 1;
        !          1551:                 new_args[i] = ts->val;
        !          1552:                 goto iarg_end;
        !          1553:             } else {
        !          1554:                 /* need to move to a register */
        !          1555:                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1556:                 tcg_out_movi(s, ts->type, reg, ts->val);
        !          1557:                 ts->val_type = TEMP_VAL_REG;
        !          1558:                 ts->reg = reg;
        !          1559:                 ts->mem_coherent = 0;
        !          1560:                 s->reg_to_temp[reg] = arg;
        !          1561:             }
        !          1562:         }
        !          1563:         assert(ts->val_type == TEMP_VAL_REG);
        !          1564:         if (arg_ct->ct & TCG_CT_IALIAS) {
        !          1565:             if (ts->fixed_reg) {
        !          1566:                 /* if fixed register, we must allocate a new register
        !          1567:                    if the alias is not the same register */
        !          1568:                 if (arg != args[arg_ct->alias_index])
        !          1569:                     goto allocate_in_reg;
        !          1570:             } else {
        !          1571:                 /* if the input is aliased to an output and if it is
        !          1572:                    not dead after the instruction, we must allocate
        !          1573:                    a new register and move it */
        !          1574:                 if (!IS_DEAD_IARG(i - nb_oargs)) 
        !          1575:                     goto allocate_in_reg;
        !          1576:             }
        !          1577:         }
        !          1578:         reg = ts->reg;
        !          1579:         if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
        !          1580:             /* nothing to do : the constraint is satisfied */
        !          1581:         } else {
        !          1582:         allocate_in_reg:
        !          1583:             /* allocate a new register matching the constraint 
        !          1584:                and move the temporary register into it */
        !          1585:             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1586:             tcg_out_mov(s, reg, ts->reg);
        !          1587:         }
        !          1588:         new_args[i] = reg;
        !          1589:         const_args[i] = 0;
        !          1590:         tcg_regset_set_reg(allocated_regs, reg);
        !          1591:     iarg_end: ;
        !          1592:     }
        !          1593:     
        !          1594:     if (def->flags & TCG_OPF_BB_END) {
        !          1595:         tcg_reg_alloc_bb_end(s, allocated_regs);
        !          1596:     } else {
        !          1597:         /* mark dead temporaries and free the associated registers */
        !          1598:         for(i = 0; i < nb_iargs; i++) {
        !          1599:             arg = args[nb_oargs + i];
        !          1600:             if (IS_DEAD_IARG(i)) {
        !          1601:                 ts = &s->temps[arg];
        !          1602:                 if (!ts->fixed_reg) {
        !          1603:                     if (ts->val_type == TEMP_VAL_REG)
        !          1604:                         s->reg_to_temp[ts->reg] = -1;
        !          1605:                     ts->val_type = TEMP_VAL_DEAD;
        !          1606:                 }
        !          1607:             }
        !          1608:         }
        !          1609:         
        !          1610:         if (def->flags & TCG_OPF_CALL_CLOBBER) {
        !          1611:             /* XXX: permit generic clobber register list ? */ 
        !          1612:             for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
        !          1613:                 if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
        !          1614:                     tcg_reg_free(s, reg);
        !          1615:                 }
        !          1616:             }
        !          1617:             /* XXX: for load/store we could do that only for the slow path
        !          1618:                (i.e. when a memory callback is called) */
        !          1619:             
        !          1620:             /* store globals and free associated registers (we assume the insn
        !          1621:                can modify any global. */
        !          1622:             save_globals(s, allocated_regs);
        !          1623:         }
        !          1624:         
        !          1625:         /* satisfy the output constraints */
        !          1626:         tcg_regset_set(allocated_regs, s->reserved_regs);
        !          1627:         for(k = 0; k < nb_oargs; k++) {
        !          1628:             i = def->sorted_args[k];
        !          1629:             arg = args[i];
        !          1630:             arg_ct = &def->args_ct[i];
        !          1631:             ts = &s->temps[arg];
        !          1632:             if (arg_ct->ct & TCG_CT_ALIAS) {
        !          1633:                 reg = new_args[arg_ct->alias_index];
        !          1634:             } else {
        !          1635:                 /* if fixed register, we try to use it */
        !          1636:                 reg = ts->reg;
        !          1637:                 if (ts->fixed_reg &&
        !          1638:                     tcg_regset_test_reg(arg_ct->u.regs, reg)) {
        !          1639:                     goto oarg_end;
        !          1640:                 }
        !          1641:                 reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1642:             }
        !          1643:             tcg_regset_set_reg(allocated_regs, reg);
        !          1644:             /* if a fixed register is used, then a move will be done afterwards */
        !          1645:             if (!ts->fixed_reg) {
        !          1646:                 if (ts->val_type == TEMP_VAL_REG)
        !          1647:                     s->reg_to_temp[ts->reg] = -1;
        !          1648:                 ts->val_type = TEMP_VAL_REG;
        !          1649:                 ts->reg = reg;
        !          1650:                 /* temp value is modified, so the value kept in memory is
        !          1651:                    potentially not the same */
        !          1652:                 ts->mem_coherent = 0; 
        !          1653:                 s->reg_to_temp[reg] = arg;
        !          1654:             }
        !          1655:         oarg_end:
        !          1656:             new_args[i] = reg;
        !          1657:         }
        !          1658:     }
        !          1659: 
        !          1660:     /* emit instruction */
        !          1661:     tcg_out_op(s, opc, new_args, const_args);
        !          1662:     
        !          1663:     /* move the outputs in the correct register if needed */
        !          1664:     for(i = 0; i < nb_oargs; i++) {
        !          1665:         ts = &s->temps[args[i]];
        !          1666:         reg = new_args[i];
        !          1667:         if (ts->fixed_reg && ts->reg != reg) {
        !          1668:             tcg_out_mov(s, ts->reg, reg);
        !          1669:         }
        !          1670:     }
        !          1671: }
        !          1672: 
        !          1673: #ifdef TCG_TARGET_STACK_GROWSUP
        !          1674: #define STACK_DIR(x) (-(x))
        !          1675: #else
        !          1676: #define STACK_DIR(x) (x)
        !          1677: #endif
        !          1678: 
        !          1679: static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
        !          1680:                               int opc, const TCGArg *args,
        !          1681:                               unsigned int dead_iargs)
        !          1682: {
        !          1683:     int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
        !          1684:     TCGArg arg, func_arg;
        !          1685:     TCGTemp *ts;
        !          1686:     tcg_target_long stack_offset, call_stack_size, func_addr;
        !          1687:     int const_func_arg, allocate_args;
        !          1688:     TCGRegSet allocated_regs;
        !          1689:     const TCGArgConstraint *arg_ct;
        !          1690: 
        !          1691:     arg = *args++;
        !          1692: 
        !          1693:     nb_oargs = arg >> 16;
        !          1694:     nb_iargs = arg & 0xffff;
        !          1695:     nb_params = nb_iargs - 1;
        !          1696: 
        !          1697:     flags = args[nb_oargs + nb_iargs];
        !          1698: 
        !          1699:     nb_regs = tcg_target_get_call_iarg_regs_count(flags);
        !          1700:     if (nb_regs > nb_params)
        !          1701:         nb_regs = nb_params;
        !          1702: 
        !          1703:     /* assign stack slots first */
        !          1704:     /* XXX: preallocate call stack */
        !          1705:     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
        !          1706:     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 
        !          1707:         ~(TCG_TARGET_STACK_ALIGN - 1);
        !          1708:     allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
        !          1709:     if (allocate_args) {
        !          1710:         tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
        !          1711:     }
        !          1712: 
        !          1713:     stack_offset = TCG_TARGET_CALL_STACK_OFFSET;
        !          1714:     for(i = nb_regs; i < nb_params; i++) {
        !          1715:         arg = args[nb_oargs + i];
        !          1716: #ifdef TCG_TARGET_STACK_GROWSUP
        !          1717:         stack_offset -= sizeof(tcg_target_long);
        !          1718: #endif
        !          1719:         if (arg != TCG_CALL_DUMMY_ARG) {
        !          1720:             ts = &s->temps[arg];
        !          1721:             if (ts->val_type == TEMP_VAL_REG) {
        !          1722:                 tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
        !          1723:             } else if (ts->val_type == TEMP_VAL_MEM) {
        !          1724:                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
        !          1725:                                     s->reserved_regs);
        !          1726:                 /* XXX: not correct if reading values from the stack */
        !          1727:                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1728:                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
        !          1729:             } else if (ts->val_type == TEMP_VAL_CONST) {
        !          1730:                 reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], 
        !          1731:                                     s->reserved_regs);
        !          1732:                 /* XXX: sign extend may be needed on some targets */
        !          1733:                 tcg_out_movi(s, ts->type, reg, ts->val);
        !          1734:                 tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset);
        !          1735:             } else {
        !          1736:                 tcg_abort();
        !          1737:             }
        !          1738:         }
        !          1739: #ifndef TCG_TARGET_STACK_GROWSUP
        !          1740:         stack_offset += sizeof(tcg_target_long);
        !          1741: #endif
        !          1742:     }
        !          1743:     
        !          1744:     /* assign input registers */
        !          1745:     tcg_regset_set(allocated_regs, s->reserved_regs);
        !          1746:     for(i = 0; i < nb_regs; i++) {
        !          1747:         arg = args[nb_oargs + i];
        !          1748:         if (arg != TCG_CALL_DUMMY_ARG) {
        !          1749:             ts = &s->temps[arg];
        !          1750:             reg = tcg_target_call_iarg_regs[i];
        !          1751:             tcg_reg_free(s, reg);
        !          1752:             if (ts->val_type == TEMP_VAL_REG) {
        !          1753:                 if (ts->reg != reg) {
        !          1754:                     tcg_out_mov(s, reg, ts->reg);
        !          1755:                 }
        !          1756:             } else if (ts->val_type == TEMP_VAL_MEM) {
        !          1757:                 tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1758:             } else if (ts->val_type == TEMP_VAL_CONST) {
        !          1759:                 /* XXX: sign extend ? */
        !          1760:                 tcg_out_movi(s, ts->type, reg, ts->val);
        !          1761:             } else {
        !          1762:                 tcg_abort();
        !          1763:             }
        !          1764:             tcg_regset_set_reg(allocated_regs, reg);
        !          1765:         }
        !          1766:     }
        !          1767:     
        !          1768:     /* assign function address */
        !          1769:     func_arg = args[nb_oargs + nb_iargs - 1];
        !          1770:     arg_ct = &def->args_ct[0];
        !          1771:     ts = &s->temps[func_arg];
        !          1772:     func_addr = ts->val;
        !          1773:     const_func_arg = 0;
        !          1774:     if (ts->val_type == TEMP_VAL_MEM) {
        !          1775:         reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1776:         tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
        !          1777:         func_arg = reg;
        !          1778:         tcg_regset_set_reg(allocated_regs, reg);
        !          1779:     } else if (ts->val_type == TEMP_VAL_REG) {
        !          1780:         reg = ts->reg;
        !          1781:         if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
        !          1782:             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1783:             tcg_out_mov(s, reg, ts->reg);
        !          1784:         }
        !          1785:         func_arg = reg;
        !          1786:         tcg_regset_set_reg(allocated_regs, reg);
        !          1787:     } else if (ts->val_type == TEMP_VAL_CONST) {
        !          1788:         if (tcg_target_const_match(func_addr, arg_ct)) {
        !          1789:             const_func_arg = 1;
        !          1790:             func_arg = func_addr;
        !          1791:         } else {
        !          1792:             reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
        !          1793:             tcg_out_movi(s, ts->type, reg, func_addr);
        !          1794:             func_arg = reg;
        !          1795:             tcg_regset_set_reg(allocated_regs, reg);
        !          1796:         }
        !          1797:     } else {
        !          1798:         tcg_abort();
        !          1799:     }
        !          1800:         
        !          1801:     
        !          1802:     /* mark dead temporaries and free the associated registers */
        !          1803:     for(i = 0; i < nb_iargs; i++) {
        !          1804:         arg = args[nb_oargs + i];
        !          1805:         if (IS_DEAD_IARG(i)) {
        !          1806:             ts = &s->temps[arg];
        !          1807:             if (!ts->fixed_reg) {
        !          1808:                 if (ts->val_type == TEMP_VAL_REG)
        !          1809:                     s->reg_to_temp[ts->reg] = -1;
        !          1810:                 ts->val_type = TEMP_VAL_DEAD;
        !          1811:             }
        !          1812:         }
        !          1813:     }
        !          1814:     
        !          1815:     /* clobber call registers */
        !          1816:     for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
        !          1817:         if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
        !          1818:             tcg_reg_free(s, reg);
        !          1819:         }
        !          1820:     }
        !          1821:     
        !          1822:     /* store globals and free associated registers (we assume the call
        !          1823:        can modify any global. */
        !          1824:     save_globals(s, allocated_regs);
        !          1825: 
        !          1826:     tcg_out_op(s, opc, &func_arg, &const_func_arg);
        !          1827:     
        !          1828:     if (allocate_args) {
        !          1829:         tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
        !          1830:     }
        !          1831: 
        !          1832:     /* assign output registers and emit moves if needed */
        !          1833:     for(i = 0; i < nb_oargs; i++) {
        !          1834:         arg = args[i];
        !          1835:         ts = &s->temps[arg];
        !          1836:         reg = tcg_target_call_oarg_regs[i];
        !          1837:         assert(s->reg_to_temp[reg] == -1);
        !          1838:         if (ts->fixed_reg) {
        !          1839:             if (ts->reg != reg) {
        !          1840:                 tcg_out_mov(s, ts->reg, reg);
        !          1841:             }
        !          1842:         } else {
        !          1843:             if (ts->val_type == TEMP_VAL_REG)
        !          1844:                 s->reg_to_temp[ts->reg] = -1;
        !          1845:             ts->val_type = TEMP_VAL_REG;
        !          1846:             ts->reg = reg;
        !          1847:             ts->mem_coherent = 0; 
        !          1848:             s->reg_to_temp[reg] = arg;
        !          1849:         }
        !          1850:     }
        !          1851:     
        !          1852:     return nb_iargs + nb_oargs + def->nb_cargs + 1;
        !          1853: }
        !          1854: 
        !          1855: #ifdef CONFIG_PROFILER
        !          1856: 
        !          1857: static int64_t tcg_table_op_count[NB_OPS];
        !          1858: 
        !          1859: void dump_op_count(void)
        !          1860: {
        !          1861:     int i;
        !          1862:     FILE *f;
        !          1863:     f = fopen("/tmp/op.log", "w");
        !          1864:     for(i = INDEX_op_end; i < NB_OPS; i++) {
        !          1865:         fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
        !          1866:     }
        !          1867:     fclose(f);
        !          1868: }
        !          1869: #endif
        !          1870: 
        !          1871: 
        !          1872: static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,
        !          1873:                                       long search_pc)
        !          1874: {
        !          1875:     int opc, op_index;
        !          1876:     const TCGOpDef *def;
        !          1877:     unsigned int dead_iargs;
        !          1878:     const TCGArg *args;
        !          1879: 
        !          1880: #ifdef DEBUG_DISAS
        !          1881:     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
        !          1882:         qemu_log("OP:\n");
        !          1883:         tcg_dump_ops(s, logfile);
        !          1884:         qemu_log("\n");
        !          1885:     }
        !          1886: #endif
        !          1887: 
        !          1888: #ifdef CONFIG_PROFILER
        !          1889:     s->la_time -= profile_getclock();
        !          1890: #endif
        !          1891:     tcg_liveness_analysis(s);
        !          1892: #ifdef CONFIG_PROFILER
        !          1893:     s->la_time += profile_getclock();
        !          1894: #endif
        !          1895: 
        !          1896: #ifdef DEBUG_DISAS
        !          1897:     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
        !          1898:         qemu_log("OP after la:\n");
        !          1899:         tcg_dump_ops(s, logfile);
        !          1900:         qemu_log("\n");
        !          1901:     }
        !          1902: #endif
        !          1903: 
        !          1904:     tcg_reg_alloc_start(s);
        !          1905: 
        !          1906:     s->code_buf = gen_code_buf;
        !          1907:     s->code_ptr = gen_code_buf;
        !          1908: 
        !          1909:     args = gen_opparam_buf;
        !          1910:     op_index = 0;
        !          1911: 
        !          1912:     for(;;) {
        !          1913:         opc = gen_opc_buf[op_index];
        !          1914: #ifdef CONFIG_PROFILER
        !          1915:         tcg_table_op_count[opc]++;
        !          1916: #endif
        !          1917:         def = &tcg_op_defs[opc];
        !          1918: #if 0
        !          1919:         printf("%s: %d %d %d\n", def->name,
        !          1920:                def->nb_oargs, def->nb_iargs, def->nb_cargs);
        !          1921:         //        dump_regs(s);
        !          1922: #endif
        !          1923:         switch(opc) {
        !          1924:         case INDEX_op_mov_i32:
        !          1925: #if TCG_TARGET_REG_BITS == 64
        !          1926:         case INDEX_op_mov_i64:
        !          1927: #endif
        !          1928:             dead_iargs = s->op_dead_iargs[op_index];
        !          1929:             tcg_reg_alloc_mov(s, def, args, dead_iargs);
        !          1930:             break;
        !          1931:         case INDEX_op_movi_i32:
        !          1932: #if TCG_TARGET_REG_BITS == 64
        !          1933:         case INDEX_op_movi_i64:
        !          1934: #endif
        !          1935:             tcg_reg_alloc_movi(s, args);
        !          1936:             break;
        !          1937:         case INDEX_op_debug_insn_start:
        !          1938:             /* debug instruction */
        !          1939:             break;
        !          1940:         case INDEX_op_nop:
        !          1941:         case INDEX_op_nop1:
        !          1942:         case INDEX_op_nop2:
        !          1943:         case INDEX_op_nop3:
        !          1944:             break;
        !          1945:         case INDEX_op_nopn:
        !          1946:             args += args[0];
        !          1947:             goto next;
        !          1948:         case INDEX_op_discard:
        !          1949:             {
        !          1950:                 TCGTemp *ts;
        !          1951:                 ts = &s->temps[args[0]];
        !          1952:                 /* mark the temporary as dead */
        !          1953:                 if (!ts->fixed_reg) {
        !          1954:                     if (ts->val_type == TEMP_VAL_REG)
        !          1955:                         s->reg_to_temp[ts->reg] = -1;
        !          1956:                     ts->val_type = TEMP_VAL_DEAD;
        !          1957:                 }
        !          1958:             }
        !          1959:             break;
        !          1960:         case INDEX_op_set_label:
        !          1961:             tcg_reg_alloc_bb_end(s, s->reserved_regs);
        !          1962:             tcg_out_label(s, args[0], (long)s->code_ptr);
        !          1963:             break;
        !          1964:         case INDEX_op_call:
        !          1965:             dead_iargs = s->op_dead_iargs[op_index];
        !          1966:             args += tcg_reg_alloc_call(s, def, opc, args, dead_iargs);
        !          1967:             goto next;
        !          1968:         case INDEX_op_end:
        !          1969:             goto the_end;
        !          1970:         default:
        !          1971:             /* Note: in order to speed up the code, it would be much
        !          1972:                faster to have specialized register allocator functions for
        !          1973:                some common argument patterns */
        !          1974:             dead_iargs = s->op_dead_iargs[op_index];
        !          1975:             tcg_reg_alloc_op(s, def, opc, args, dead_iargs);
        !          1976:             break;
        !          1977:         }
        !          1978:         args += def->nb_args;
        !          1979:     next:
        !          1980:         if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) {
        !          1981:             return op_index;
        !          1982:         }
        !          1983:         op_index++;
        !          1984: #ifndef NDEBUG
        !          1985:         check_regs(s);
        !          1986: #endif
        !          1987:     }
        !          1988:  the_end:
        !          1989:     return -1;
        !          1990: }
        !          1991: 
        !          1992: int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
        !          1993: {
        !          1994: #ifdef CONFIG_PROFILER
        !          1995:     {
        !          1996:         int n;
        !          1997:         n = (gen_opc_ptr - gen_opc_buf);
        !          1998:         s->op_count += n;
        !          1999:         if (n > s->op_count_max)
        !          2000:             s->op_count_max = n;
        !          2001: 
        !          2002:         s->temp_count += s->nb_temps;
        !          2003:         if (s->nb_temps > s->temp_count_max)
        !          2004:             s->temp_count_max = s->nb_temps;
        !          2005:     }
        !          2006: #endif
        !          2007: 
        !          2008:     tcg_gen_code_common(s, gen_code_buf, -1);
        !          2009: 
        !          2010:     /* flush instruction cache */
        !          2011:     flush_icache_range((unsigned long)gen_code_buf, 
        !          2012:                        (unsigned long)s->code_ptr);
        !          2013:     return s->code_ptr -  gen_code_buf;
        !          2014: }
        !          2015: 
        !          2016: /* Return the index of the micro operation such as the pc after is <
        !          2017:    offset bytes from the start of the TB.  The contents of gen_code_buf must
        !          2018:    not be changed, though writing the same values is ok.
        !          2019:    Return -1 if not found. */
        !          2020: int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
        !          2021: {
        !          2022:     return tcg_gen_code_common(s, gen_code_buf, offset);
        !          2023: }
        !          2024: 
        !          2025: #ifdef CONFIG_PROFILER
        !          2026: void tcg_dump_info(FILE *f,
        !          2027:                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
        !          2028: {
        !          2029:     TCGContext *s = &tcg_ctx;
        !          2030:     int64_t tot;
        !          2031: 
        !          2032:     tot = s->interm_time + s->code_time;
        !          2033:     cpu_fprintf(f, "JIT cycles          %" PRId64 " (%0.3f s at 2.4 GHz)\n",
        !          2034:                 tot, tot / 2.4e9);
        !          2035:     cpu_fprintf(f, "translated TBs      %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", 
        !          2036:                 s->tb_count, 
        !          2037:                 s->tb_count1 - s->tb_count,
        !          2038:                 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
        !          2039:     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n", 
        !          2040:                 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
        !          2041:     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
        !          2042:                 s->tb_count ? 
        !          2043:                 (double)s->del_op_count / s->tb_count : 0);
        !          2044:     cpu_fprintf(f, "avg temps/TB        %0.2f max=%d\n",
        !          2045:                 s->tb_count ? 
        !          2046:                 (double)s->temp_count / s->tb_count : 0,
        !          2047:                 s->temp_count_max);
        !          2048:     
        !          2049:     cpu_fprintf(f, "cycles/op           %0.1f\n", 
        !          2050:                 s->op_count ? (double)tot / s->op_count : 0);
        !          2051:     cpu_fprintf(f, "cycles/in byte      %0.1f\n", 
        !          2052:                 s->code_in_len ? (double)tot / s->code_in_len : 0);
        !          2053:     cpu_fprintf(f, "cycles/out byte     %0.1f\n", 
        !          2054:                 s->code_out_len ? (double)tot / s->code_out_len : 0);
        !          2055:     if (tot == 0)
        !          2056:         tot = 1;
        !          2057:     cpu_fprintf(f, "  gen_interm time   %0.1f%%\n", 
        !          2058:                 (double)s->interm_time / tot * 100.0);
        !          2059:     cpu_fprintf(f, "  gen_code time     %0.1f%%\n", 
        !          2060:                 (double)s->code_time / tot * 100.0);
        !          2061:     cpu_fprintf(f, "liveness/code time  %0.1f%%\n", 
        !          2062:                 (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0);
        !          2063:     cpu_fprintf(f, "cpu_restore count   %" PRId64 "\n",
        !          2064:                 s->restore_count);
        !          2065:     cpu_fprintf(f, "  avg cycles        %0.1f\n",
        !          2066:                 s->restore_count ? (double)s->restore_time / s->restore_count : 0);
        !          2067:     {
        !          2068:         extern void dump_op_count(void);
        !          2069:         dump_op_count();
        !          2070:     }
        !          2071: }
        !          2072: #else
        !          2073: void tcg_dump_info(FILE *f,
        !          2074:                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
        !          2075: {
        !          2076:     cpu_fprintf(f, "[TCG profiler not compiled]\n");
        !          2077: }
        !          2078: #endif

unix.superglobalmegacorp.com

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