📄 i386-asm.c
字号:
} if (pr > priority) priority = pr; } return priority;}static const char *skip_constraint_modifiers(const char *p){ while (*p == '=' || *p == '&' || *p == '+' || *p == '%') p++; return p;}static void asm_compute_constraints(uint8_t *regs_allocated, ASMOperand *operands, int nb_operands1, int nb_outputs, int is_output, uint8_t *input_regs_allocated){ ASMOperand *op; int sorted_op[MAX_ASM_OPERANDS]; int i, j, k, p1, p2, tmp, reg, c, base, nb_operands; const char *str; if (is_output) { base = 0; nb_operands = nb_outputs; } else { base = nb_outputs; nb_operands = nb_operands1 - nb_outputs; } /* compute constraint priority and evaluate references to output constraints if input constraints */ for(i=0;i<nb_operands;i++) { j = base + i; op = &operands[j]; str = op->constraint; op->ref_index = -1; op->reg = -1; str = skip_constraint_modifiers(str); if (!is_output && (isnum(*str) || *str == '[')) { /* this is a reference to another constraint */ k = find_constraint(operands, nb_operands1, str, NULL); if ((unsigned)k >= j) error("invalid reference in constraint %d ('%s')", j, str); op->ref_index = k; str = operands[k].constraint; str = skip_constraint_modifiers(str); } op->priority = constraint_priority(str); } /* sort operands according to their priority */ for(i=0;i<nb_operands;i++) sorted_op[i] = base + 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; } } } memset(regs_allocated, 0, NB_ASM_REGS); regs_allocated[4] = 1; /* esp cannot be used */ regs_allocated[5] = 1; /* ebp cannot be used yet */ /* allocate registers and generate corresponding asm moves */ for(i=0;i<nb_operands;i++) { j = sorted_op[i]; op = &operands[j]; str = op->constraint; if (op->ref_index >= 0) { str = operands[op->ref_index].constraint; } str = skip_constraint_modifiers(str); try_next: c = *str++; switch(c) { case 'A': /* allocate both eax and edx */ if (regs_allocated[TREG_EAX] || regs_allocated[TREG_EDX]) goto try_next; op->is_llong = 1; op->reg = TREG_EAX; regs_allocated[TREG_EAX] = 1; regs_allocated[TREG_EDX] = 1; 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 (regs_allocated[reg]) goto try_next; goto reg_found; case 'q': /* eax, ebx, ecx or edx */ for(reg = 0; reg < 4; reg++) { if (!regs_allocated[reg]) goto reg_found; } goto try_next; case 'r': /* any general register */ for(reg = 0; reg < 8; reg++) { if (!regs_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] = 1; 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 */ /* XXX: fix constant case */ if (is_output) { /* 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 ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { /* any general register */ for(reg = 0; reg < 8; reg++) { if (!input_regs_allocated[reg]) goto reg_found1; } goto try_next; reg_found1: /* now we can reload in the register */ input_regs_allocated[reg] = 1; op->reg = reg; } } break; default: error("asm constraint %d ('%s') could not be satisfied", j, op->constraint); break; } } /* print sorted constraints */#ifdef ASM_DEBUG if (is_output) printf("outputs=\n"); else printf("inputs=\n"); 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); }#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){ 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 = nb_outputs ; i < nb_operands; i++) { op = &operands[i]; if (op->reg >= 0) { load(op->reg, op->vt); if (op->is_llong) { SValue sv; sv = *op->vt; sv.c.ul += 4; load(TREG_EDX, &sv); } } } /* generate load code for output memory references */ for(i = 0 ; i < nb_outputs; i++) { op = &operands[i]; if (op->reg >= 0 && ((op->vt->r & VT_VALMASK) == VT_LLOCAL)) { SValue sv; sv = *op->vt; sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; load(op->reg, &sv); } } } else { /* generate save code */ for(i = 0 ; i < nb_outputs; i++) { op = &operands[i]; if (op->reg >= 0 && ((op->vt->r & VT_VALMASK) != VT_LLOCAL)) { 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 + -