📄 gen86.c
字号:
ap2 = g_expr (ep->v.p[1], F_DREG); validate (ap1); /* in case push occurred */ g_code (op, (ILEN) ep->etp->size, ap2, NIL_ADDRESS); freeop (ap2); freeop (ap1); ap2 = data_register (); g_code (op_mov, IL2, mk_low (ap1), ap2); return mk_legal (ap2, flags, ep->etp); } default: return g_bin (ep, flags, op_imul); }}/* * generate code for *= node */static ADDRESS *g_asmul P2 (const EXPR *, ep, FLAGS, flags){ OPCODE op; ILEN size = IL0; FLAGS f = (FLAGS) (F_MEM | F_DREG); ADDRESS *ap1, *ap2, *ap3; switch (ep->etp->type) { case bt_charu: case bt_uchar: op = op_movzbl; f = (FLAGS) (f | F_NOEDI); goto common; case bt_char: case bt_schar: op = op_movsbl; f = (FLAGS) (f | F_NOEDI); goto common; case bt_ushort: case bt_uint16: case bt_pointer16: case bt_short: case bt_int16: op = op_mov; size = IL2; common: if (ep->v.p[0]->nodetype == en_fieldref) { return g_asbitfield (ep, flags, op_imul, FALSE); } ap1 = g_expr (ep->v.p[1], (FLAGS) (F_DREG | F_VOL)); if (size == IL0) { g_code (op, size, ap1, ap1); } ap2 = g_expr (ep->v.p[0], f); ap3 = data_register (); validate (ap1); g_code (op, size, ap2, ap3); g_code (op_imul, IL2, ap3, ap1); g_code (op_mov, (ILEN) ep->etp->size, ap1, ap2); freeop (ap3); freeop (ap2); return mk_legal (ap1, flags, ep->etp); default: return g_asbin (ep, flags, op_imul); }}/* * generate code to evaluate a condition operator node (?:) */static ADDRESS *g_hook P2 (const EXPR *, ep, FLAGS, flags){ ADDRESS *ap1, *ap2; LABEL false_label, end_label; TYP *tp = ep->etp; SIZE offset; FLAGS flagx;#ifndef NDEBUG BOOL result_is_void = FALSE;#endif /* NDEBUG */ switch (ep->etp->type) {#ifdef FLOAT_IEEE case bt_float: case bt_double: case bt_longdouble: flagx = F_FREG; break;#endif /* FLOAT_IEEE */ case bt_void:#ifndef NDEBUG result_is_void = TRUE;#endif /* NDEBUG */ flagx = (FLAGS) (F_ALL | F_NOVALUE); break; case bt_struct: case bt_union: tp = tp_pointer; /*FALLTHROUGH */ default: flagx = (FLAGS) (F_DREG | F_VOL); } false_label = nextlabel++; end_label = nextlabel++; temp_inv (); /* I do not think I can avoid that */ offset = stack_offset; stack_offset = 0L; /* all registers are void */ g_falsejp (ep->v.p[0], false_label); ep = ep->v.p[1]; /* all registers are void */ ap1 = g_expr (ep->v.p[0], flagx);#ifdef FLOAT_IEEE if (flagx == F_MEM) { ADDRESS *ap; freeop (ap1); ap = address_register (); g_code (op_lea, IL2, ap1, ap); ap1 = copy_addr (ap, am_ind); }#endif /* FLOAT_IEEE */ freeop (ap1); /* all registers are void */ g_branch (end_label); g_label (false_label); ap2 = g_expr (ep->v.p[1], flagx);#ifdef FLOAT_IEEE if (flagx == F_MEM) { ADDRESS *ap; freeop (ap2); ap = address_register (); g_code (op_lea, IL2, ap2, ap); ap1 = copy_addr (ap, am_ind); }#endif /* FLOAT_IEEE */ assert (result_is_void || is_equal_address (ap1, ap2)); g_label (end_label); g_stack (stack_offset); stack_offset = offset; return mk_legal (ap2, flags, tp);}/* * Generate the code for assign operators in bitfields */static ADDRESS *g_asbitfield P4 (const EXPR *, ep, FLAGS, flags, OPCODE, op, BOOL, mod){ ADDRESS *ap1, *ap2, *ap3; EXPR *lnode = ep->v.p[0]; int width = (int) lnode->v.bit.width; int offset = (int) lnode->v.bit.offset; ILEN ilen = (ILEN) ep->etp->size; UVAL mask; /* Evaluate the address of the LHS */ ap2 = g_expr (lnode->v.p[0], (FLAGS) (F_DREG | F_NOECX)); ap2 = copy_addr (ap2, am_indx); /* Now get the value of the LHS, rotate and mask out unwanted bits */ ap1 = data_register (); g_code (op_mov, ilen, ap2, ap1); g_rotate (ap1, ilen, offset, lnode->etp, width); /* now do the operation, masking the result back into the required size */ switch (op) { case op_div: case op_idiv: /* evaluate the RHS */ ap3 = g_expr (ep->v.p[1], (FLAGS) (F_DREG | F_IMMED | F_ECX)); validate (ap1); if (uses_temp (ap3) || ap3->mode == am_immed) {/*KDW */ g_code (op_mov, IL2, ap3, &ecx_reg); freeop (ap3); ap3 = &ecx_reg; } g_code (op_mov, IL2, ap1, &eax_reg); g_code (op, IL2, ap3, NIL_ADDRESS); if (mod) { g_code (op_mov, IL2, &edx_reg, ap1); } else { g_code (op_mov, IL2, &eax_reg, ap1); } break; case op_asr: case op_shr: case op_shl: /* evaluate the RHS */ ap3 = g_expr (ep->v.p[1], (FLAGS) (F_ALL | F_ECX)); 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 & F_NOVALUE)) { /* 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 (size == 2l) { if (ap1->mode == am_dreg) { ap1 = mk_indirect (ap1->preg, NIL_EXPR); } else { g_code (op_mov, IL2, ap1, &edi_reg); ap1 = mk_indirect (EDI, NIL_EXPR); } if (ap2->mode == am_dreg) { ap1 = mk_indirect (ap2->preg, NIL_EXPR); } else { g_code (op_mov, IL2, ap2, &esi_reg); ap2 = mk_indirect (ESI, NIL_EXPR); } ap3 = data_register (); g_code (op_mov, IL2, ap2, ap3); g_code (op_mov, IL2, ap3, ap1); freeop (ap3); } else { g_code (op_lea, IL2, ap1, &edi_reg); g_code (op_lea, IL2, ap2, &esi_reg); if (size % 2l) { 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); } else { ap3 = mk_immed ((IVAL) ((USIZE) size >> 1)); ap3 = mk_legal (ap3, (FLAGS) (F_DREG | F_ECX), tp_int); g_code (op_rep, IL0, NIL_ADDRESS, NIL_ADDRESS); g_code (op_smov, IL2, NIL_ADDRESS, NIL_ADDRESS); } freeop (ap3); }}/* * 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; FLAGS flagx = (flags & F_NOVALUE) ? F_ALL : F_ALL; switch (tp->type) { case bt_float: case bt_double: case bt_longdouble:#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, tp); } /*FALLTHRU */#endif /* FLOAT_IEEE */ case bt_struct: case bt_union: ap2 = g_expr (ep->v.p[1], F_MEM); ap1 = g_expr (ep->v.p[0], F_MEM); validate (ap2); structassign (ap1, ap2, size); freeop (ap1); return mk_legal (ap2, flags, tp_pointer);#if 0 case bt_int32: case bt_long: case bt_uint32: case bt_ulong: case bt_pointer32: ap1 = g_expr (ep->v.p[1], flagx); ap2 = g_expr (ep->v.p[0], F_ALL); validate (ap1); g_code (op_mov, IL2, mk_low (ap1), mk_low (ap2)); g_code (op_mov, IL2, mk_high (ap1), mk_high (ap2)); freeop (ap2); return mk_legal (ap1, flags, tp);#endif 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_VOL)); if (ap1->mode == am_immed) { ap1->u.offset->v.i &= (IVAL) mask; ap3 = mk_immed ((IVAL) (ap1->u.offset->v.u << (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], flagx); ap2 = g_expr (ep->v.p[0], F_ALL); validate (ap1); if (is_register_mode (ap1->mode) || is_register_mode (ap2->mode) || (ap1->mode == am_immed)) { if (size == 4L) { g_code (op_mov, IL2, mk_low (ap1), mk_low (ap2)); g_code (op_mov, IL2, mk_high (ap1), mk_high (ap2)); } else { g_code (op_mov, (ILEN) size, mk_low (ap1), ap2); } freeop (ap2); } else { if (flags & F_NOVALUE) { ap3 = data_register (); g_code (op_mov, IL2, mk_low (ap1), ap3); g_code (op_mov, IL2, ap3, mk_low (ap2)); if (size == 4L) { g_code (op_mov, IL2, mk_high (ap1), ap3); g_code (op_mov, IL2, ap3, mk_high (ap2)); } freeop (ap3); freeop (ap2); freeop (ap1); ap1 = NIL_ADDRESS; } else { if (size == 4L) { ap3 = mdata_register (); g_code (op_mov, IL2, mk_low (ap1), mk_low (ap3)); g_code (op_mov, IL2, mk_low (ap3), mk_low (ap2)); g_code (op_mov, IL2, mk_high (ap1), mk_high (ap3)); g_code (op_mov, IL2, mk_high (ap3), mk_high (ap2)); freeop (ap3); freeop (ap2); freeop (ap1); ap1 = mdata_register (); g_code (op_mov, (ILEN) size, mk_low (ap3), mk_low (ap1)); g_code (op_mov, (ILEN) size, mk_high (ap3), mk_high (ap1)); } else { ap3 = data_register (); g_code (op_mov, IL2, ap1, ap3); g_code (op_mov, IL2, ap3, ap2); freeop (ap3); freeop (ap2); freeop (ap1); ap1 = data_register (); g_code (op_mov, (ILEN) size, ap3, ap1); } } } break; } return mk_legal (ap1, flags, tp); }}/* * push the operand expression onto the stack. return the number of bytes * pushed */static SIZE push_param P1 (const EXPR *, ep){ ADDRESS *ap; FLAGS flagx;#ifdef FLOAT_IEEE ADDRESS *ap1;#endif /* FLOAT_IEEE */ SIZE size = ep->etp->size; switch (ep->etp->type) { case bt_float: case bt_double: case bt_longdouble:#ifdef FLOAT_IEEE ap = g_expr (ep, F_FREG); g_code (op_sub, IL2, mk_immed (size), &esp_reg); ap1 = mk_indirect (ESP, NIL_EXPR); g_fcode (op_fstp, (ILEN) size, ap1, NIL_ADDRESS); freeop (ap); break;#endif /* FLOAT_IEEE */ case bt_struct: case bt_union: /* pushing of structures and unions */ ap = g_expr (ep, F_ALL); g_code (op_sub, IL2, mk_immed (size), &esp_reg); structassign (&esp_reg, ap, size); freeop (ap); break; default: flagx = (target_option < target_80186) ? (FLAGS) (F_DREG | F_AREG | F_MEM) : F_ALL; switch (size) { case 1L: case 2L: ap = g_expr (ep, flagx); g_code (op_push, IL2, ap, NIL_ADDRESS); freeop (ap); break; case 4L: ap = g_expr (ep, flagx); g_code (op_push, IL2, mk_high (ap), NIL_ADDRESS); g_code (op_push, IL2, mk_low (ap), NIL_ADDRESS); freeop (ap); break; default: FATAL ( (__FILE__, "push_param", "size(%ld) != 2, ep->etp->type=%d", size, ep->etp->type)); break; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -