📄 gen386.c
字号:
default: g_code (op_xor, IL4, &edx_reg, &edx_reg); break; } g_code (op, IL4, ap3, NIL_ADDRESS); if (mod) { g_code (op_mov, IL4, &edx_reg, ap1); } else { g_code (op_mov, IL4, &eax_reg, ap1); } break; case op_asr: case op_shr: case op_shl: /* evaluate the RHS */ ap3 = g_expr (ep->v.p[1], F_ALL); validate (ap1); if (ap3->mode != am_immed) { g_code (op_mov, ilen, ap3, &ecx_reg); g_code (op, ilen, &ecx_reg, ap1); freeop (ap3); break; } /*FALLTHRU */ default: /* evaluate the RHS */ ap3 = g_expr (ep->v.p[1], F_ALL); validate (ap1); g_code (op, ilen, ap3, ap1); freeop (ap3); } mask = (UVAL) bitmask ((BITSIZE) width); g_code (op_and, ilen, mk_immed ((IVAL) mask), ap1); /* rotate result back into position, and store */ g_rotate (ap1, ilen, -offset, tp_void, 0); validate (ap2); g_code (op_and, ilen, mk_immed ((IVAL) ~(mask << offset)), ap2); g_code (op_or, ilen, ap1, ap2); freeop (ap1); freeop (ap2); /* return a result */ ap2 = data_register (); g_code (op_mov, ilen, ap1, ap2); ap1 = ap2; if ((FLAGS) (flags & F_NOVALUE) == F_NONE) { /* result value needed */ g_rotate (ap1, ilen, offset, tp_void, 0); if (mod) { /* post increment/decrement restore original value */ switch (op) { case op_add: g_code (op_sub, ilen, mk_immed (1L), ap1); g_code (op_and, ilen, mk_immed ((IVAL) mask), ap1); break; case op_sub: g_code (op_add, ilen, mk_immed (1L), ap1); g_code (op_and, ilen, mk_immed ((IVAL) mask), ap1); break; default: break; } } } return mk_legal (ap1, flags, ep->etp);}/* * assign structures: ap1=dest, ap2=source */static void structassign P3 (ADDRESS *, ap1, ADDRESS *, ap2, SIZE, size){ ADDRESS *ap3; if (!uses_structassign) { FATAL ((__FILE__, "structassign", "USES")); } if (size == 4L) { if (ap1->mode == am_dreg) { ap1 = mk_indirect (ap1->preg, NIL_EXPR); } else { g_code (op_mov, IL4, ap1, &edi_reg); ap1 = mk_indirect (EDI, NIL_EXPR); } if (ap2->mode == am_dreg) { ap2 = mk_indirect (ap2->preg, NIL_EXPR); } else { g_code (op_mov, IL4, ap2, &esi_reg); ap2 = mk_indirect (ESI, NIL_EXPR); } ap3 = data_register (); g_code (op_mov, IL4, ap2, ap3); g_code (op_mov, IL4, ap3, ap1); freeop (ap3); } else { switch (ap2->mode) { case am_mreg: g_code (op_mov, IL4, mk_high (ap1), mk_high (ap2)); g_code (op_mov, IL4, mk_low (ap1), mk_low (ap2)); break; default: g_code (op_lea, IL4, ap1, &edi_reg); g_code (op_lea, IL4, ap2, &esi_reg); if ((size % 4L) == 0L) { ap3 = mk_immed ((SIZE) ((USIZE) size >> 2)); ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_long); g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_smov, IL4, NIL_ADDRESS, NIL_ADDRESS); } else if ((size % 2L) == 0L) { ap3 = mk_immed ((SIZE) ((USIZE) size >> 1)); ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_short); g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_smov, IL2, NIL_ADDRESS, NIL_ADDRESS); } else { ap3 = mk_immed (size); ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_char); g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_smov, IL1, NIL_ADDRESS, NIL_ADDRESS); } freeop (ap3); break; } }}/* * generate code for an assignment node. */static ADDRESS *g_assign P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap1, *ap2, *ap3; TYP *tp = ep->etp; SIZE size = tp->size; UVAL mask; switch (tp->type) { case bt_longdouble: case bt_double: case bt_float:#ifdef FLOAT_IEEE if (fpu_option) { ap1 = g_expr (ep->v.p[0], F_MEM); ap2 = g_expr (ep->v.p[1], F_FREG); validate (ap1); g_fcode ((flags & F_NOVALUE ? op_fstp : op_fst), (ILEN) size, ap1, NIL_ADDRESS); freeop (ap2); freeop (ap1); ap1 = flags & F_NOVALUE ? NIL_ADDRESS : float_register (); return mk_legal (ap1, flags, ep->etp); } /* FALLTHRU */#endif /* FLOAT_IEEE */ case bt_struct: case bt_union: array: ap2 = g_expr (ep->v.p[1], F_ALL); ap1 = g_expr (ep->v.p[0], F_ALL); validate (ap2); structassign (ap1, ap2, size); freeop (ap1); return mk_legal (ap2, flags, tp_pointer); case bt_pointer32: if (is_array_type (tp) || is_array_assignment (tp)) { goto array; } /*FALLTHRU */ default: switch (ep->v.p[0]->nodetype) { case en_fieldref: /* * Field assignment */ /* get the value */ mask = bitmask (ep->v.p[0]->v.bit.width); ap1 = g_expr (ep->v.p[1], (FLAGS) (F_DREG | F_IMMED | F_VOL)); if (ap1->mode == am_immed) { ap1->u.offset->v.i &= (IVAL) mask; ap3 = mk_immed ((IVAL) ((USIZE) ap1->u.offset->v.i << (int) ep->v.p [0]->v.bit.offset)); } else { if (flags & F_NOVALUE) { ap3 = ap1; g_code (op_and, (ILEN) size, mk_immed ((IVAL) mask), ap3); } else { if (is_signed_type (tp)) { SIZE i = tp_int->size * 8L - (SIZE) ep->v.p[0]->v.bit.width - (SIZE) ep->v.p[0]->v.bit.offset; g_code (op_asl, (ILEN) size, mk_immed (i), ap1); g_code (op_asr, (ILEN) size, mk_immed (i), ap1); ap3 = data_register (); g_code (op_mov, IL4, ap1, ap3); g_code (op_and, (ILEN) size, mk_immed ((IVAL) mask), ap3); } else { g_code (op_and, (ILEN) size, mk_immed ((IVAL) mask), ap1); ap3 = data_register (); g_code (op_mov, IL4, ap1, ap3); } } g_rotate (ap3, (ILEN) size, -(int) ep->v.p[0]->v.bit.offset, tp_void, 0); } mask <<= (int) ep->v.p[0]->v.bit.offset; ap2 = g_deref (ep->v.p[0]->v.p[0], ep->v.p[0]->etp); validate (ap3); g_code (op_and, (ILEN) size, mk_immed ((IVAL) ~mask), ap2); g_code (op_or, (ILEN) size, ap3, ap2); freeop (ap2); if (!(flags & F_NOVALUE)) { freeop (ap3); validate (ap1); } break; /* * (uns.) char, (uns.) short, (uns.) long, float * * we want to pass the right hand side as the expression value. * This can''t be done if the left side is a register variable on * which the right hand side addressing mode depends. But if the * left side IS a register variable, it is desirable to pass the * left side, so no problem. */ case en_register: /* pass the left side as expr. value */ ap1 = g_expr (ep->v.p[0], F_ALL); ap2 = g_expr (ep->v.p[1], F_ALL); validate (ap1); g_code (op_mov, (ILEN) size, ap2, ap1); freeop (ap2); break; default: /* pass the right side as expr. value */ /* normally, this is more efficient */ ap1 = g_expr (ep->v.p[1], F_ALL); ap2 = g_expr (ep->v.p[0], F_ALL); validate (ap1); switch (ap1->mode) { default: if (ap2->mode != am_dreg) { ap3 = data_register (); g_code (op_mov, (ILEN) size, ap1, ap3); g_code (op_mov, (ILEN) size, ap3, ap2); freeop (ap3); freeop (ap2); freeop (ap1); if (flags & F_NOVALUE) { ap1 = NIL_ADDRESS; } else { ap1 = data_register (); g_code (op_mov, (ILEN) size, ap3, ap1); } break; } /*FALLTHRU */ case am_dreg: case am_immed: g_code (op_mov, (ILEN) size, ap1, ap2); freeop (ap2); break; case am_mreg: g_code (op_mov, (ILEN) size, mk_high (ap1), mk_high (ap2)); g_code (op_mov, (ILEN) size, mk_low (ap1), mk_low (ap2)); freeop (ap2); break; } break; } return mk_legal (ap1, flags, ep->etp); }}/* * push the operand expression onto the stack. return the number of bytes * pushed */static SIZE push_param P1 (const EXPR *, ep){ ADDRESS *ap;#ifdef FLOAT_IEEE ADDRESS *ap1;#endif /* FLOAT_IEEE */ SIZE size = ep->etp->size; switch (size) { case 1L: case 2L: case 3L: ap = g_expr (ep, F_DREG); g_code (op_push, IL4, ap, NIL_ADDRESS); break; case 4L: ap = g_expr (ep, F_ALL); switch (ap->mode) {#ifdef FLOAT_IEEE case am_freg: g_code (op_sub, IL4, mk_immed (size), &esp_reg); ap1 = mk_indirect (ESP, NIL_EXPR); g_fcode (op_fstp, (ILEN) size, ap1, NIL_ADDRESS); break;#endif /* FLOAT_IEEE */ default: g_code (op_push, IL4, ap, NIL_ADDRESS); break; } break; case 8L: ap = g_expr (ep, F_ALL); switch (ap->mode) {#ifdef FLOAT_IEEE case am_freg: g_code (op_sub, IL4, mk_immed (size), &esp_reg); ap1 = mk_indirect (ESP, NIL_EXPR); g_fcode (op_fstp, (ILEN) size, ap1, NIL_ADDRESS); break;#endif /* FLOAT_IEEE */ default: g_code (op_push, IL4, mk_high (ap), NIL_ADDRESS); g_code (op_push, IL4, mk_low (ap), NIL_ADDRESS); break; } break; default: ap = g_expr (ep, F_ALL); g_code (op_sub, IL4, mk_immed (size), &esp_reg); structassign (&esp_reg, ap, size); break; } freeop (ap); return size;}/* * push a list of parameters onto the stack and return the number of * bytes that the parameters occupy. */static SIZE g_parms P1 (const EXPR *, ep){ SIZE size; is_parameter++; for (size = 0L; ep != NIL_EXPR; ep = ep->v.p[1]) { size += push_param (ep->v.p[0]); } is_parameter--; return size;}static ADDRESS *func_result P3 (FLAGS, flags, SIZE, bytes, TYP *, tp){ ADDRESS *ap; stack_offset += bytes; if (is_parameter) { g_stack (bytes); } if (flags & F_NOVALUE) {#if 0 if (ap->mode == am_freg) { g_fcode (op_fstp, IL10, mk_reg (ST0), NIL_ADDRESS); }#endif return NIL_ADDRESS; } switch (tp->type) {#ifdef FLOAT_IEEE case bt_float: if (fpu_option && fpu_return_option) { ap = float_register (); } else { ap = data_register (); } return ap; case bt_double: case bt_longdouble: if (fpu_option && fpu_return_option) { ap = float_register (); } else { ap = mdata_register (); } return ap;#endif /* FLOAT_IEEE */ default: if (flags & F_DREG) { ap = data_register (); if (ap->preg != reg_usage->result->reg[0]) { g_code (op_mov, IL4, &eax_reg, ap); } return ap; } } FATAL ((__FILE__, "func_result", "flags = 0x%x", flags)); return NIL_ADDRESS;}/* * generate a function call node and return the address mode of the result. */static ADDRESS *g_fcall P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap, *ap1; SIZE size; EXPR *ep0 = ep->v.p[0]; if (!is_parameter && ep->nodetype != en_call) { switch (stackopt_option) { case OPT_SAFE: /* * no stack optimisation */ g_stack (stack_offset); break; case OPT_MINIMUM: /* * "Minimum" stack optimisation. Perform a stack optimisation * unless: * 1. The alloca() routine is called * 2. The function call is via a variable * 3. The function starts with an underscore character */ if ((ep0->nodetype != en_nacon) || (ep0->v.str[0] == (CHAR) '_') || (ep0->v.str == alloca_name)) { g_stack (stack_offset); } break; case OPT_AVERAGE: /* * "Forced" stack optimisation. This will not suppress * the optimisation on encountering calls to functions * whose names begin with underscore. */ if ((ep0->nodetype != en_nacon) || (ep0->v.str == alloca_name)) { g_stack (stack_offset); } break; case OPT_MAXIMUM: /* * "Maximum" stack optimisation. This will not suppress * the optimisation on encountering calls to functions * whose names begin with underscore or via a function * variable. */ if ((ep0->nodetype == en_nacon) && (ep0->v.str == alloca_name)) { g_stack (stack_offset); } break; default: CANNOT_REACH_HERE (); break; } } /* push any used registers */ temp_inv (); size = g_parms (ep->v.p[1]); /* generate parameters */ /* * for functions returning a structure or a union, push a pointer to the * return value as additional argument The scratch space will be * allocated in the stack frame of the calling function. */ if (is_structure_type (ep->etp)) { ap = mk_scratch (ep->etp->size); ap1 = data_register (); g_code (op_lea, IL4, ap, ap1); g_code (op_push, IL4, ap1, NIL_ADDRESS); freeop (ap1); freeop (ap); size += tp_pointer->size; } if (ep->nodetype == en_call) { size = 0L; } /* call the function */ switch (ep0->nodetype) { case en_nacon: case en_labcon: ap = mk_direct (ep0); break; default: ap = g_expr (ep0, F_AREG); ap = copy_addr (ap, am_ind); ap->u.offset = NIL_EXPR; freeop (ap); break; } g_code (op_call, IL0, ap, NIL_ADDRESS); ap = func_result (flags, size, ep->etp); return mk_legal (ap, flags, ep->etp);}/* * generates code for a en_cast node */static ADDRESS *g_cast P4 (ADDRESS *, ap, TYP *, tp1, TYP *, tp2, FLAGS, flags){#ifdef FLOAT_IEEE ADDRESS *ap1;#endif /* FLOAT_IEEE */ if (flags & F_NOVALUE) {#ifdef FLOAT_IEEE if (ap->mode == am_freg) { g_fcode (op_fstp, IL10, mk_reg (ST0), NIL_ADDRESS); }#endif /* FLOAT_IEEE */ freeop (ap); return NIL_ADDRESS; } /* casts to a narrower integer type are no-ops since the 386 is low-endian */ /* to avoid code duplication, float/double is shared */ switch (tp2->type) { /* type to cast to */#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: switch (tp1->type) { case bt_float: case bt_double: case bt_longdouble: ap = mk_legal (ap, F_FREG, tp1); return mk_legal (ap, flags, tp2); case bt_uchar: case bt_schar: case bt_char: case bt_charu: case bt_short: case bt_ushort: case bt_int16:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -