aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard>2004-10-18 00:13:39 +0000
committerbellard <bellard>2004-10-18 00:13:39 +0000
commitd65463809c214413d9b1943a0474133122f7fe77 (patch)
tree1d7d79472e17f262e66b0606a5b5bdd48fae359e
parent62f99adb71f7715076e4f5ef0ed689443391ceba (diff)
downloadtinycc-d65463809c214413d9b1943a0474133122f7fe77.tar.gz
tinycc-d65463809c214413d9b1943a0474133122f7fe77.tar.bz2
fixed 'no base' modrm generation - better asm constraints handling
-rw-r--r--i386-asm.c241
1 files changed, 158 insertions, 83 deletions
diff --git a/i386-asm.c b/i386-asm.c
index 43c2b07..5c7c1de 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -364,7 +364,7 @@ static void gen_le16(int v)
/* generate the modrm operand */
static inline void asm_modrm(int reg, Operand *op)
{
- int mod, reg1, reg2;
+ int mod, reg1, reg2, sib_reg1;
if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
g(0xc0 + (reg << 3) + op->reg);
@@ -373,8 +373,12 @@ static inline void asm_modrm(int reg, Operand *op)
g(0x05 + (reg << 3));
gen_expr32(&op->e);
} else {
+ sib_reg1 = op->reg;
/* fist compute displacement encoding */
- if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
+ if (sib_reg1 == -1) {
+ sib_reg1 = 5;
+ mod = 0x00;
+ } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
mod = 0x00;
} else if (op->e.v == (int8_t)op->e.v && !op->e.sym) {
mod = 0x40;
@@ -391,13 +395,13 @@ static inline void asm_modrm(int reg, Operand *op)
reg2 = op->reg2;
if (reg2 == -1)
reg2 = 4; /* indicate no index */
- g((op->shift << 6) + (reg2 << 3) + op->reg);
+ g((op->shift << 6) + (reg2 << 3) + sib_reg1);
}
/* add offset */
if (mod == 0x40) {
g(op->e.v);
- } else if (mod == 0x80) {
+ } else if (mod == 0x80 || op->reg == -1) {
gen_expr32(&op->e);
}
}
@@ -517,7 +521,11 @@ static void asm_opcode(TCCState *s1, int opcode)
s = reg_to_size[ops[i].type & OP_REG];
}
if (s == 3) {
- error("cannot infer opcode suffix");
+ if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
+ (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
+ s = 2;
+ else
+ error("cannot infer opcode suffix");
}
}
@@ -752,50 +760,56 @@ static const char *skip_constraint_modifiers(const char *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)
+#define REG_OUT_MASK 0x01
+#define REG_IN_MASK 0x02
+
+#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
+
+static void asm_compute_constraints(ASMOperand *operands,
+ int nb_operands, int nb_outputs,
+ const uint8_t *clobber_regs,
+ int *pout_reg)
{
ASMOperand *op;
int sorted_op[MAX_ASM_OPERANDS];
- int i, j, k, p1, p2, tmp, reg, c, base, nb_operands;
+ int i, j, k, p1, p2, tmp, reg, c, reg_mask;
const char *str;
+ uint8_t regs_allocated[NB_ASM_REGS];
- if (is_output) {
- base = 0;
- nb_operands = nb_outputs;
- } else {
- base = nb_outputs;
- nb_operands = nb_operands1 - nb_outputs;
+ /* init fields */
+ for(i=0;i<nb_operands;i++) {
+ op = &operands[i];
+ op->input_index = -1;
+ op->ref_index = -1;
+ op->reg = -1;
+ op->is_memory = 0;
+ op->is_rw = 0;
}
-
/* 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];
+ op = &operands[i];
str = op->constraint;
- op->ref_index = -1;
- op->reg = -1;
str = skip_constraint_modifiers(str);
- if (!is_output && (isnum(*str) || *str == '[')) {
+ if (isnum(*str) || *str == '[') {
/* this is a reference to another constraint */
- k = find_constraint(operands, nb_operands1, str, NULL);
- if ((unsigned)k >= j)
+ k = find_constraint(operands, nb_operands, str, NULL);
+ if ((unsigned)k >= i || i < nb_outputs)
error("invalid reference in constraint %d ('%s')",
- j, str);
+ i, str);
op->ref_index = k;
- str = operands[k].constraint;
- str = skip_constraint_modifiers(str);
+ 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);
}
- op->priority = constraint_priority(str);
}
/* sort operands according to their priority */
for(i=0;i<nb_operands;i++)
- sorted_op[i] = base + 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;
@@ -808,32 +822,55 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
}
}
- memset(regs_allocated, 0, NB_ASM_REGS);
- regs_allocated[4] = 1; /* esp cannot be used */
- regs_allocated[5] = 1; /* ebp cannot be used yet */
-
+ 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;
-
- if (op->ref_index >= 0) {
- str = operands[op->ref_index].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;
}
-
- str = skip_constraint_modifiers(str);
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 (regs_allocated[TREG_EAX] || regs_allocated[TREG_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] = 1;
- regs_allocated[TREG_EDX] = 1;
+ regs_allocated[TREG_EAX] |= reg_mask;
+ regs_allocated[TREG_EDX] |= reg_mask;
break;
case 'a':
reg = TREG_EAX;
@@ -853,20 +890,20 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
case 'D':
reg = 7;
alloc_reg:
- if (regs_allocated[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 (!regs_allocated[reg])
+ if (!is_reg_allocated(reg))
goto reg_found;
}
goto try_next;
case 'r':
/* any general register */
for(reg = 0; reg < 8; reg++) {
- if (!regs_allocated[reg])
+ if (!is_reg_allocated(reg))
goto reg_found;
}
goto try_next;
@@ -874,7 +911,7 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
/* now we can reload in the register */
op->is_llong = 0;
op->reg = reg;
- regs_allocated[reg] = 1;
+ regs_allocated[reg] |= reg_mask;
break;
case 'i':
if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
@@ -888,25 +925,27 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
break;
case 'm':
case 'g':
- /* nothing special to do because the operand is
- already in memory */
+ /* 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 (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 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 (!input_regs_allocated[reg])
+ if (!(regs_allocated[reg] & REG_IN_MASK))
goto reg_found1;
}
goto try_next;
reg_found1:
/* now we can reload in the register */
- input_regs_allocated[reg] = 1;
+ regs_allocated[reg] |= REG_IN_MASK;
op->reg = reg;
+ op->is_memory = 1;
}
}
break;
@@ -915,14 +954,34 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
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
- if (is_output)
- printf("outputs=\n");
- else
- printf("inputs=\n");
for(i=0;i<nb_operands;i++) {
j = sorted_op[i];
op = &operands[j];
@@ -933,6 +992,8 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
op->vt->r,
op->reg);
}
+ if (*pout_reg >= 0)
+ printf("out_reg=%d\n", *pout_reg);
#endif
}
@@ -1019,7 +1080,8 @@ static void subst_asm_operand(CString *add_str,
/* 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 *clobber_regs,
+ int out_reg)
{
uint8_t regs_allocated[NB_ASM_REGS];
ASMOperand *op;
@@ -1042,39 +1104,52 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
}
/* generate load code */
- for(i = nb_outputs ; i < nb_operands; i++) {
+ for(i = 0; i < nb_operands; i++) {
op = &operands[i];
if (op->reg >= 0) {
- load(op->reg, op->vt);
- if (op->is_llong) {
+ 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.c.ul += 4;
- load(TREG_EDX, &sv);
+ 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);
+ }
}
}
}
- /* 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);
+ 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);
+ }
}
}
}