⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i386-asm.c

📁 tiny c compiler
💻 C
📖 第 1 页 / 共 3 页
字号:
        op = &operands[i];        str = op->constraint;        str = skip_constraint_modifiers(str);        if (isnum(*str) || *str == '[') {            /* this is a reference to another constraint */            k = find_constraint(operands, nb_operands, str, NULL);            if ((unsigned)k >= i || i < nb_outputs)                error("invalid reference in constraint %d ('%s')",                      i, str);            op->ref_index = k;            if (operands[k].input_index >= 0)                error("cannot reference twice the same operand");            operands[k].input_index = i;            op->priority = 5;        } else {            op->priority = constraint_priority(str);        }    }        /* sort operands according to their priority */    for(i=0;i<nb_operands;i++)        sorted_op[i] = i;    for(i=0;i<nb_operands - 1;i++) {        for(j=i+1;j<nb_operands;j++) {            p1 = operands[sorted_op[i]].priority;             p2 = operands[sorted_op[j]].priority;            if (p2 < p1) {                tmp = sorted_op[i];                sorted_op[i] = sorted_op[j];                sorted_op[j] = tmp;            }        }    }    for(i = 0;i < NB_ASM_REGS; i++) {        if (clobber_regs[i])            regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;        else            regs_allocated[i] = 0;    }    /* esp cannot be used */    regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK;     /* ebp cannot be used yet */    regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK;     /* allocate registers and generate corresponding asm moves */    for(i=0;i<nb_operands;i++) {        j = sorted_op[i];        op = &operands[j];        str = op->constraint;        /* no need to allocate references */        if (op->ref_index >= 0)            continue;        /* select if register is used for output, input or both */        if (op->input_index >= 0) {            reg_mask = REG_IN_MASK | REG_OUT_MASK;        } else if (j < nb_outputs) {            reg_mask = REG_OUT_MASK;        } else {            reg_mask = REG_IN_MASK;        }    try_next:        c = *str++;        switch(c) {        case '=':            goto try_next;        case '+':            op->is_rw = 1;            /* FALL THRU */        case '&':            if (j >= nb_outputs)                error("'%c' modifier can only be applied to outputs", c);            reg_mask = REG_IN_MASK | REG_OUT_MASK;            goto try_next;        case 'A':            /* allocate both eax and edx */            if (is_reg_allocated(TREG_EAX) ||                 is_reg_allocated(TREG_EDX))                goto try_next;            op->is_llong = 1;            op->reg = TREG_EAX;            regs_allocated[TREG_EAX] |= reg_mask;            regs_allocated[TREG_EDX] |= reg_mask;            break;        case 'a':            reg = TREG_EAX;            goto alloc_reg;        case 'b':            reg = 3;            goto alloc_reg;        case 'c':            reg = TREG_ECX;            goto alloc_reg;        case 'd':            reg = TREG_EDX;            goto alloc_reg;        case 'S':            reg = 6;            goto alloc_reg;        case 'D':            reg = 7;        alloc_reg:            if (is_reg_allocated(reg))                goto try_next;            goto reg_found;        case 'q':            /* eax, ebx, ecx or edx */            for(reg = 0; reg < 4; reg++) {                if (!is_reg_allocated(reg))                    goto reg_found;            }            goto try_next;        case 'r':            /* any general register */            for(reg = 0; reg < 8; reg++) {                if (!is_reg_allocated(reg))                    goto reg_found;            }            goto try_next;        reg_found:            /* now we can reload in the register */            op->is_llong = 0;            op->reg = reg;            regs_allocated[reg] |= reg_mask;            break;        case 'i':            if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))                goto try_next;            break;        case 'I':        case 'N':        case 'M':            if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))                goto try_next;            break;        case 'm':        case 'g':            /* nothing special to do because the operand is already in               memory, except if the pointer itself is stored in a               memory variable (VT_LLOCAL case) */            /* XXX: fix constant case */            /* if it is a reference to a memory zone, it must lie               in a register, so we reserve the register in the               input registers and a load will be generated               later */            if (j < nb_outputs || c == 'm') {                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {                    /* any general register */                    for(reg = 0; reg < 8; reg++) {                        if (!(regs_allocated[reg] & REG_IN_MASK))                            goto reg_found1;                    }                    goto try_next;                reg_found1:                    /* now we can reload in the register */                    regs_allocated[reg] |= REG_IN_MASK;                    op->reg = reg;                    op->is_memory = 1;                }            }            break;        default:            error("asm constraint %d ('%s') could not be satisfied",                   j, op->constraint);            break;        }        /* if a reference is present for that operand, we assign it too */        if (op->input_index >= 0) {            operands[op->input_index].reg = op->reg;            operands[op->input_index].is_llong = op->is_llong;        }    }        /* compute out_reg. It is used to store outputs registers to memory       locations references by pointers (VT_LLOCAL case) */    *pout_reg = -1;    for(i=0;i<nb_operands;i++) {        op = &operands[i];        if (op->reg >= 0 &&             (op->vt->r & VT_VALMASK) == VT_LLOCAL  &&            !op->is_memory) {            for(reg = 0; reg < 8; reg++) {                if (!(regs_allocated[reg] & REG_OUT_MASK))                    goto reg_found2;            }            error("could not find free output register for reloading");        reg_found2:            *pout_reg = reg;            break;        }    }        /* print sorted constraints */#ifdef ASM_DEBUG    for(i=0;i<nb_operands;i++) {        j = sorted_op[i];        op = &operands[j];        printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",                j,                               op->id ? get_tok_str(op->id, NULL) : "",                op->constraint,               op->vt->r,               op->reg);    }    if (*pout_reg >= 0)        printf("out_reg=%d\n", *pout_reg);#endif}static void subst_asm_operand(CString *add_str,                               SValue *sv, int modifier){    int r, reg, size, val;    char buf[64];    r = sv->r;    if ((r & VT_VALMASK) == VT_CONST) {        if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n')            cstr_ccat(add_str, '$');        if (r & VT_SYM) {            cstr_cat(add_str, get_tok_str(sv->sym->v, NULL));            if (sv->c.i != 0) {                cstr_ccat(add_str, '+');            } else {                return;            }        }        val = sv->c.i;        if (modifier == 'n')            val = -val;        snprintf(buf, sizeof(buf), "%d", sv->c.i);        cstr_cat(add_str, buf);    } else if ((r & VT_VALMASK) == VT_LOCAL) {        snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i);        cstr_cat(add_str, buf);    } else if (r & VT_LVAL) {        reg = r & VT_VALMASK;        if (reg >= VT_CONST)            error("internal compiler error");        snprintf(buf, sizeof(buf), "(%%%s)",                  get_tok_str(TOK_ASM_eax + reg, NULL));        cstr_cat(add_str, buf);    } else {        /* register case */        reg = r & VT_VALMASK;        if (reg >= VT_CONST)            error("internal compiler error");        /* choose register operand size */        if ((sv->type.t & VT_BTYPE) == VT_BYTE)            size = 1;        else if ((sv->type.t & VT_BTYPE) == VT_SHORT)            size = 2;        else            size = 4;        if (size == 1 && reg >= 4)            size = 4;        if (modifier == 'b') {            if (reg >= 4)                error("cannot use byte register");            size = 1;        } else if (modifier == 'h') {            if (reg >= 4)                error("cannot use byte register");            size = -1;        } else if (modifier == 'w') {            size = 2;        }        switch(size) {        case -1:            reg = TOK_ASM_ah + reg;            break;        case 1:            reg = TOK_ASM_al + reg;            break;        case 2:            reg = TOK_ASM_ax + reg;            break;        default:            reg = TOK_ASM_eax + reg;            break;        }        snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL));        cstr_cat(add_str, buf);    }}/* generate prolog and epilog code for asm statment */static void asm_gen_code(ASMOperand *operands, int nb_operands,                          int nb_outputs, int is_output,                         uint8_t *clobber_regs,                         int out_reg){    uint8_t regs_allocated[NB_ASM_REGS];    ASMOperand *op;    int i, reg;    static uint8_t reg_saved[NB_SAVED_REGS] = { 3, 6, 7 };    /* mark all used registers */    memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));    for(i = 0; i < nb_operands;i++) {        op = &operands[i];        if (op->reg >= 0)            regs_allocated[op->reg] = 1;    }    if (!is_output) {        /* generate reg save code */        for(i = 0; i < NB_SAVED_REGS; i++) {            reg = reg_saved[i];            if (regs_allocated[reg])                 g(0x50 + reg);        }        /* generate load code */        for(i = 0; i < nb_operands; i++) {            op = &operands[i];            if (op->reg >= 0) {                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&                    op->is_memory) {                    /* memory reference case (for both input and                       output cases) */                    SValue sv;                    sv = *op->vt;                    sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;                    load(op->reg, &sv);                } else if (i >= nb_outputs || op->is_rw) {                    /* load value in register */                    load(op->reg, op->vt);                    if (op->is_llong) {                        SValue sv;                        sv = *op->vt;                        sv.c.ul += 4;                        load(TREG_EDX, &sv);                    }                }            }        }    } else {        /* generate save code */        for(i = 0 ; i < nb_outputs; i++) {            op = &operands[i];            if (op->reg >= 0) {                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {                    if (!op->is_memory) {                        SValue sv;                        sv = *op->vt;                        sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;                        load(out_reg, &sv);                        sv.r = (sv.r & ~VT_VALMASK) | out_reg;                        store(op->reg, &sv);                    }                } else {                    store(op->reg, op->vt);                    if (op->is_llong) {                        SValue sv;                        sv = *op->vt;                        sv.c.ul += 4;                        store(TREG_EDX, &sv);                    }                }            }        }        /* generate reg restore code */        for(i = NB_SAVED_REGS - 1; i >= 0; i--) {            reg = reg_saved[i];            if (regs_allocated[reg])                 g(0x58 + reg);        }    }}static void asm_clobber(uint8_t *clobber_regs, const char *str){    int reg;    TokenSym *ts;    if (!strcmp(str, "memory") ||         !strcmp(str, "cc"))        return;    ts = tok_alloc(str, strlen(str));    reg = ts->tok;    if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {        reg -= TOK_ASM_eax;    } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {        reg -= TOK_ASM_ax;    } else {        error("invalid clobber register '%s'", str);    }    clobber_regs[reg] = 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -