📄 regx86.c
字号:
/* * C compiler * ========== * * Copyright 1989, 1990, 1991 Christoph van Wuellen. * Credits to Matthew Brandt. * All commercial rights reserved. * * This compiler may be redistributed as long there is no * commercial interest. The compiler must not be redistributed * without its full sources. This notice must stay intact. * * History: * * 1989 starting an 68000 C compiler, starting with material * originally by M. Brandt * 1990 68000 C compiler further bug fixes * started i386 port (December) * 1991 i386 port finished (January) * further corrections in the front end and in the 68000 * code generator. * The next port will be a SPARC port *//****************************************************************************** * * Register allocation (for the expression evaluation) * This modules handles the management of scratch registers. * It keeps track of the allocated registers and of the stack * Although large parts are identical to the 68000 version, * the diffs are so big that I maintain two different files * *****************************************************************************/#include "config.h"#ifdef INTEL#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"#include "genx86.h"/********************************************************* Macro Definitions */#define MAX_REG_STACK ((DEEP)40)/*********************************************** Static Function Definitions */static void g_push P_ ((REG, DEEP));static void g_pop P_ ((REG, DEEP));/********************************************************** Static Variables */static DEEP reg_in_use[NUM_REGS];static REG next_dreg; /* next temporary register */static REG next_areg; /* next temporary register */static REG next_freg; /* next temporary register *//* * When a register is already in use then it is necessary to * save the current contents on the stack. The reg_stack * array is used to keep track of those registers which have * been pushed onto the stack. */static struct{ REG reg; DEEP depth;} reg_stack[(int) MAX_REG_STACK + 1];static DEEP stack_depth;/* * When registers are alloced it is necessary to track the * order in which they were allocated and whether an item * which should be in a register has been temporarily * pushed onto the stack. */static struct{ REG reg; REG next_reg; REGTYPE regtype; BOOL pushed;} reg_alloc[(int) MAX_REG_STACK + 1];static DEEP alloc_depth;/* * Define the registers which can be used to pass parameters. */static REG parameter_registers[] = { EAX, EBX, ECX, EDX, ESI, EDI};static REGLIST parameter_list = { (int) (sizeof (parameter_registers) / sizeof (REG)), ¶meter_registers[0]};/* * Define the registers which must be saved by a function if * they are used. * If the register is used to return a value then it needn't be * saved. * If the register is used to pass a parameter then it needn't be * saved. */static REG saved_registers[] = { EAX, EBX, ECX, EDX, ESI, EDI};static REGLIST saved_list = { (int) (sizeof (saved_registers) / sizeof (REG)), &saved_registers[0]};/* * Define the registers which are used to return the results * from a function call. */static REG result_registers[] = { EAX, EDX};static REGLIST result_list = { (int) (sizeof (result_registers) / sizeof (REG)), &result_registers[0]};static REGUSAGE rusage = { ¶meter_list, &saved_list, &result_list};REGUSAGE *reg_usage = &rusage;REGTYPE *regtypes;/*****************************************************************************//* * this routine generates code to push a register onto the stack */static void g_push P2 (REG, reg, DEEP, depth){ ADDRESS *ap;#ifdef FLOAT_IEEE ADDRESS *ap2;#endif /* FLOAT_IEEE */ sync_stack (); ap = mk_reg (reg); switch (reg_alloc[depth].regtype) { case D_REG | T_REG: case A_REG | T_REG: case X_REG | T_REG: g_code (op_push, small_option ? IL2 : IL4, ap, NIL_ADDRESS); break;#ifdef FLOAT_IEEE case F_REG | T_REG: ap2 = mk_reg (ESP); g_code (op_sub, small_option ? IL2 : IL4, mk_immed ((IVAL) 8L), ap2); ap2 = mk_reg (ESP); ap2->mode = am_ind; g_fcode (op_fstp, IL8, ap2, NIL_ADDRESS); break;#endif /* FLOAT_IEEE */ default: CANNOT_REACH_HERE (); } reg_stack[stack_depth].reg = reg; reg_stack[stack_depth].depth = depth; /* is already pushed */ if (reg_alloc[depth].pushed) { FATAL ((__FILE__, "g_push", "reg %d already pushed", (int) reg)); } reg_alloc[depth].pushed = TRUE; /* check on stack overflow */ if (++stack_depth > MAX_REG_STACK) { FATAL ((__FILE__, "g_push", "register stack overflow")); }}/* * generate code to pop a register from the stack. */static void g_pop P2 (REG, reg, DEEP, depth){ ADDRESS *ap;#ifdef FLOAT_IEEE ADDRESS *ap2;#endif /* FLOAT_IEEE */ /* check on stack underflow */ if (stack_depth-- == EMPTY) { FATAL ((__FILE__, "g_pop", "register %d stack empty", (int) reg)); } /* check if the desired register really is on stack */ if (reg_stack[stack_depth].depth != depth) { FATAL ( (__FILE__, "g_pop", "register %d order %d, %d", (int) reg, (int) reg_stack[stack_depth].depth, (int) depth)); } /* check if the register which is restored is really void */ if (reg_in_use[reg] != UNUSED) { FATAL ((__FILE__, "g_pop", "register %d in use", (int) reg)); } reg_in_use[reg] = depth; sync_stack (); ap = mk_reg (reg); switch (reg_alloc[depth].regtype) { case A_REG | T_REG: case D_REG | T_REG: case X_REG | T_REG: g_code (op_pop, small_option ? IL2 : IL4, ap, NIL_ADDRESS); break;#ifdef FLOAT_IEEE case F_REG | T_REG: ap2 = mk_reg (ESP); ap2->mode = am_ind; g_fcode (op_fld, IL8, ap2, NIL_ADDRESS); ap2 = mk_reg (ESP); g_code (op_add, small_option ? IL2 : IL4, mk_immed ((IVAL) 8L), ap2); break;#endif /* FLOAT_IEEE */ default: CANNOT_REACH_HERE (); break; } /* clear the push_flag */ reg_alloc[depth].pushed = FALSE;}/* * this routine should be called before each expression is evaluated to make * sure the stack is balanced and all of the registers are marked free. * This is also a good place to free all 'pseudo' registers in the stack frame * by clearing act_scratch. */void initstack P0 (void){ REG reg; for (reg = EAX; reg <= ST7; reg++) reg_in_use[reg] = UNUSED; next_dreg = EAX; next_areg = ESI; next_freg = ST0; stack_depth = EMPTY; alloc_depth = EMPTY; act_scratch = 0;}/* * this routine checks if all allocated registers were freed correctly */void checkstack P0 (void){ REG reg; for (reg = EAX; reg <= ST7; reg++) { if (!is_temporary_register (reg)) { continue; } if (reg_in_use[reg] != UNUSED) { FATAL ((__FILE__, "checkstack", "register %d in use", (int) reg)); } } if (next_dreg != EAX) { FATAL ( (__FILE__, "checkstack", "not all data registers deallocated (%d)", (int) next_dreg)); } if (next_areg != ESI) { FATAL ( (__FILE__, "checkstack", "not all address registers deallocated (%d)", (int) next_areg)); } if (next_freg != ST0) { FATAL ( (__FILE__, "checkstack", "not all float registers deallocated (%d)", (int) next_areg)); } if (stack_depth != EMPTY) { FATAL ( (__FILE__, "checkstack", "register stack not empty (%d)", (int) stack_depth)); } if (alloc_depth != EMPTY) { FATAL ( (__FILE__, "checkstack", "register allocation stack not empty (%d)", (int) alloc_depth)); }}/* * validate() will make sure that if a register within an address * mode has been pushed onto the stack that it is popped back at * this time. */void validate P1 (const ADDRESS *, ap){ REG reg; switch (ap->mode) { case am_mreg: reg = ap->sreg; if (is_temporary_register (reg) && reg_alloc[ap->deep].pushed) { g_pop (reg, (DEEP) ((int) ap->deep + 1)); } /*lint -fallthrough */ case am_dreg: case am_freg: reg = ap->preg; if (is_temporary_register (reg) && reg_alloc[ap->deep].pushed) { g_pop (reg, ap->deep); } break; case am_areg:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -