diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index ddfb4ee64ea..3133a36db6b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -74,8 +74,120 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = /* Test and compare insns in i386.md store the information needed to generate branch and scc insns here. */ -struct rtx_def *i386_compare_op0, *i386_compare_op1; +struct rtx_def *i386_compare_op0 = NULL_RTX; +struct rtx_def *i386_compare_op1 = NULL_RTX; struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); + +/* Register allocation order */ +char *i386_reg_alloc_order = (char *)0; +static char regs_allocated[FIRST_PSEUDO_REGISTER]; + + +/* Sometimes certain combinations of command options do not make + sense on a particular target machine. You can define a macro + `OVERRIDE_OPTIONS' to take account of this. This macro, if + defined, is executed once just after all the command options have + been parsed. + + Don't use this macro to turn on various extra optimizations for + `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ + +void +override_options () +{ + int ch, i, regno; + +#ifdef SUBTARGET_OVERRIDE_OPTIONS + SUBTARGET_OVERRIDE_OPTIONS; +#endif + + /* Validate registers in register allocation order */ + if (i386_reg_alloc_order) + { + for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) + { + switch (ch) + { + case 'a': regno = 0; break; + case 'd': regno = 1; break; + case 'c': regno = 2; break; + case 'b': regno = 3; break; + case 'S': regno = 4; break; + case 'D': regno = 5; break; + case 'B': regno = 6; break; + + default: fatal ("Register '%c' is unknown", ch); + } + + if (regs_allocated[regno]) + fatal ("Register '%c' was already specified in the allocation order", ch); + + regs_allocated[regno] = 1; + } + } +} + +/* A C statement (sans semicolon) to choose the order in which to + allocate hard registers for pseudo-registers local to a basic + block. + + Store the desired register order in the array `reg_alloc_order'. + Element 0 should be the register to allocate first; element 1, the + next register; and so on. + + The macro body should not assume anything about the contents of + `reg_alloc_order' before execution of the macro. + + On most machines, it is not necessary to define this macro. */ + +void +order_regs_for_local_alloc () +{ + int i, ch, order, regno; + + /* User specified the register allocation order */ + if (i386_reg_alloc_order) + { + for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) + { + switch (ch) + { + case 'a': regno = 0; break; + case 'd': regno = 1; break; + case 'c': regno = 2; break; + case 'b': regno = 3; break; + case 'S': regno = 4; break; + case 'D': regno = 5; break; + case 'B': regno = 6; break; + } + + reg_alloc_order[order++] = regno; + } + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (!regs_allocated[i]) + reg_alloc_order[order++] = i; + } + } + + /* If users did not specify a register allocation order, favor eax + normally except if cse is following jumps, then favor edx so + that function returns are cse'ed */ + else + { + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + reg_alloc_order[i] = i; + + if (optimize && flag_cse_follow_jumps && !leaf_function_p ()) + { + reg_alloc_order[0] = 1; /* edx */ + reg_alloc_order[1] = 2; /* ecx */ + reg_alloc_order[2] = 0; /* eax */ + } + } +} + /* Output an insn whose source is a 386 integer register. SRC is the rtx for the register, and TEMPLATE is the op-code template. SRC may diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 1bc8048f81d..c68b32d6b84 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -158,16 +158,34 @@ extern int target_flags; SUBTARGET_SWITCHES \ { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}} -/* This is meant to be redefined in the host dependent files */ +/* This macro is similar to `TARGET_SWITCHES' but defines names of + command options that have values. Its definition is an + initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + fixed part of the option name, and the address of a variable. The + variable, type `char *', is set to the variable part of the given + option if the fixed part matches. The actual option name is made + by appending `-m' to the specified name. */ +#define TARGET_OPTIONS \ +{ { "reg-alloc=", &i386_reg_alloc_order }, \ + SUBTARGET_OPTIONS } + +/* Sometimes certain combinations of command options do not make + sense on a particular target machine. You can define a macro + `OVERRIDE_OPTIONS' to take account of this. This macro, if + defined, is executed once just after all the command options have + been parsed. + + Don't use this macro to turn on various extra optimizations for + `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ + +#define OVERRIDE_OPTIONS override_options () + +/* These are meant to be redefined in the host dependent files */ #define SUBTARGET_SWITCHES +#define SUBTARGET_OPTIONS -#define OVERRIDE_OPTIONS \ -{ \ - SUBTARGET_OVERRIDE_OPTIONS \ -} - -/* This is meant to be redefined in the host dependent files */ -#define SUBTARGET_OVERRIDE_OPTIONS /* target machine storage layout */ @@ -313,11 +331,24 @@ extern int target_flags; functions, and a slightly slower compiler. Users complained about the code generated by allocating edx first, so restore the 'natural' order of things. */ -#if 0 #define REG_ALLOC_ORDER \ -/*dx,cx,ax,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ -{ 1, 2, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } -#endif +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } + +/* A C statement (sans semicolon) to choose the order in which to + allocate hard registers for pseudo-registers local to a basic + block. + + Store the desired register order in the array `reg_alloc_order'. + Element 0 should be the register to allocate first; element 1, the + next register; and so on. + + The macro body should not assume anything about the contents of + `reg_alloc_order' before execution of the macro. + + On most machines, it is not necessary to define this macro. */ + +#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () /* Macro to conditionally modify fixed_regs/call_used_regs. */ #define CONDITIONAL_REGISTER_USAGE \ @@ -509,7 +540,6 @@ enum reg_class reg number REGNO. This could be a conditional expression or could index an array. */ -extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; #define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO]) /* When defined, the compiler allows registers explicitly used in the @@ -641,6 +671,32 @@ extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; #define CLASS_MAX_NREGS(CLASS, MODE) \ (FLOAT_CLASS_P (CLASS) ? 1 : \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* A C expression whose value is nonzero if pseudos that have been + assigned to registers of class CLASS would likely be spilled + because registers of CLASS are needed for spill registers. + + The default value of this macro returns 1 if CLASS has exactly one + register and zero otherwise. On most machines, this default + should be used. Only define this macro to some other expression + if pseudo allocated by `local-alloc.c' end up in memory because + their hard registers were needed for spill regisers. If this + macro returns nonzero for those classes, those pseudos will only + be allocated by `global.c', which knows how to reallocate the + pseudo to another register. If there would not be another + register available for reallocation, you should not change the + definition of this macro since the only effect of such a + definition would be to slow down register allocation. */ + +#define CLASS_LIKELY_SPILLED_P(CLASS) \ + (((CLASS) == AREG) \ + || ((CLASS) == DREG) \ + || ((CLASS) == CREG) \ + || ((CLASS) == BREG) \ + || ((CLASS) == AD_REGS) \ + || ((CLASS) == SIREG) \ + || ((CLASS) == DIREG)) + /* Stack layout; function entry, exit and calling. */ @@ -1296,7 +1352,6 @@ while (0) stored from the compare operation. Note that we can't use "rtx" here since it hasn't been defined! */ -extern struct rtx_def *i386_compare_op0, *i386_compare_op1; extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); /* Tell final.c how to eliminate redundant test instructions. */ @@ -1643,6 +1698,8 @@ extern char *qi_high_reg_name[]; #define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx)) /* Functions in i386.c */ +extern void override_options (); +extern void order_regs_for_local_alloc (); extern void output_op_from_reg (); extern void output_to_reg (); extern char *singlemove_string (); @@ -1676,9 +1733,18 @@ extern void restore_386_machine_status (); extern void clear_386_stack_locals (); extern struct rtx_def *assign_386_stack_local (); +/* Variables in i386.c */ +extern char *i386_reg_alloc_order; /* register allocation order */ +extern char *hi_reg_name[]; /* names for 16 bit regs */ +extern char *qi_reg_name[]; /* names for 8 bit regs (low) */ +extern char *qi_high_reg_name[]; /* names for 8 bit regs (high) */ +extern enum reg_class regclass_map[]; /* smalled class containing REGNO */ +extern struct rtx_def *i386_compare_op0; /* operand 0 for comparisons */ +extern struct rtx_def *i386_compare_op1; /* operand 1 for comparisons */ + /* External variables used */ -extern int optimize; /* optimization level */ -extern int obey_regdecls; /* TRUE if stupid register allocation */ +extern int optimize; /* optimization level */ +extern int obey_regdecls; /* TRUE if stupid register allocation */ /* External functions used */ extern struct rtx_def *force_operand ();