if (regs_ever_live[first_reg])
break;
- /* If profiling, then we must save/restore every register that contains
- a parameter before/after the .__mcount call. Use registers from 30 down
- to 23 to do this. Don't use the frame pointer in reg 31.
+ if (profile_flag)
+ {
+ /* AIX must save/restore every register that contains a parameter
+ before/after the .__mcount call plus an additional register
+ for the static chain, if needed; use registers from 30 down to 22
+ to do this. */
+ if (DEFAULT_ABI == ABI_AIX)
+ {
+ int last_parm_reg, profile_first_reg;
+
+ /* Figure out last used parameter register. The proper thing
+ to do is to walk incoming args of the function. A function
+ might have live parameter registers even if it has no
+ incoming args. */
+ for (last_parm_reg = 10;
+ last_parm_reg > 2 && ! regs_ever_live [last_parm_reg];
+ last_parm_reg--)
+ ;
+
+ /* Calculate first reg for saving parameter registers
+ and static chain.
+ Skip reg 31 which may contain the frame pointer. */
+ profile_first_reg = (33 - last_parm_reg
+ - (current_function_needs_context ? 1 : 0));
+ /* Do not save frame pointer if no parameters needs to be saved. */
+ if (profile_first_reg == 31)
+ profile_first_reg = 32;
+
+ if (first_reg > profile_first_reg)
+ first_reg = profile_first_reg;
+ }
- For now, save enough room for all of the parameter registers. */
- if (DEFAULT_ABI == ABI_AIX && profile_flag)
- if (first_reg > 23)
- first_reg = 23;
+ /* SVR4 may need one register to preserve the static chain. */
+ else if (current_function_needs_context)
+ {
+ /* Skip reg 31 which may contain the frame pointer. */
+ if (first_reg > 30)
+ first_reg = 30;
+ }
+ }
return first_reg;
}
asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
assemble_name (file, buf);
fputs ("@ha\n", file);
- asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+ reg_names[0], reg_names[1]);
asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
assemble_name (file, buf);
asm_fprintf (file, "@l(%s)\n", reg_names[12]);
}
+ if (current_function_needs_context)
+ asm_fprintf (file, "\tmr %s,%s\n",
+ reg_names[30], reg_names[STATIC_CHAIN_REGNUM]);
fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+ if (current_function_needs_context)
+ asm_fprintf (file, "\tmr %s,%s\n",
+ reg_names[STATIC_CHAIN_REGNUM], reg_names[30]);
break;
case ABI_AIX:
last_parm_reg--)
;
- /* Save parameter registers in regs 23-30. Don't overwrite reg 31, since
- it might be set up as the frame pointer. */
+ /* Save parameter registers in regs 23-30 and static chain in r22.
+ Don't overwrite reg 31, since it might be set up as the frame pointer. */
for (i = 3, j = 30; i <= last_parm_reg; i++, j--)
asm_fprintf (file, "\tmr %d,%d\n", j, i);
+ if (current_function_needs_context)
+ asm_fprintf (file, "\tmr %d,%d\n", j, STATIC_CHAIN_REGNUM);
/* Load location address into r3, and call mcount. */
asm_fprintf (file, "(%s)\n\tbl %s\n\t%s\n",
reg_names[2], RS6000_MCOUNT, RS6000_CALL_GLUE);
- /* Restore parameter registers. */
+ /* Restore parameter registers and static chain. */
for (i = 3, j = 30; i <= last_parm_reg; i++, j--)
asm_fprintf (file, "\tmr %d,%d\n", i, j);
+ if (current_function_needs_context)
+ asm_fprintf (file, "\tmr %d,%d\n", STATIC_CHAIN_REGNUM, j);
+
break;
}
}
/* This is how to output an assembler line defining a `double' constant. */
-#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
- { \
- if (REAL_VALUE_ISINF (VALUE) \
- || REAL_VALUE_ISNAN (VALUE) \
- || REAL_VALUE_MINUS_ZERO (VALUE)) \
- { \
- long t[2]; \
- REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
- fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", \
- t[0] & 0xffffffff, t[1] & 0xffffffff); \
- } \
- else \
- { \
- char str[30]; \
- REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
- fprintf (FILE, "\t.double 0d%s\n", str); \
- } \
+#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
+ { \
+ long t[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", \
+ t[0] & 0xffffffff, t[1] & 0xffffffff); \
}
/* This is how to output an assembler line defining a `float' constant. */
-#define ASM_OUTPUT_FLOAT(FILE, VALUE) \
- { \
- if (REAL_VALUE_ISINF (VALUE) \
- || REAL_VALUE_ISNAN (VALUE) \
- || REAL_VALUE_MINUS_ZERO (VALUE)) \
- { \
- long t; \
- REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
- fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
- } \
- else \
- { \
- char str[30]; \
- REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
- fprintf (FILE, "\t.float 0d%s\n", str); \
- } \
+#define ASM_OUTPUT_FLOAT(FILE, VALUE) \
+ { \
+ long t; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
}
/* This is how to output an assembler line defining an `int' constant. */
#define ASM_OUTPUT_ASCII(FILE, P, N) output_ascii ((FILE), (P), (N))
-/* This is how to output code to push a register on the stack.
- It need not be very fast code.
-
- On the rs6000, we must keep the backchain up to date. In order
- to simplify things, always allocate 16 bytes for a push (System V
- wants to keep stack aligned to a 16 byte boundary). */
-
-#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
-do { \
- extern char *reg_names[]; \
- asm_fprintf (FILE, \
- (TARGET_32BIT) \
- ? "\t{stu|stwu} %s,-16(%s)\n\t{st|stw} %s,12(%s)\n" \
- : "\tstdu %s,-32(%s)\n\tstd %s,24(%s)\n", \
- reg_names[1], reg_names[1], reg_names[REGNO], \
- reg_names[1]); \
-} while (0)
-
-/* This is how to output an insn to pop a register from the stack.
- It need not be very fast code. */
-
-#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
-do { \
- extern char *reg_names[]; \
- asm_fprintf (FILE, \
- (TARGET_32BIT) \
- ? "\t{l|lwz} %s,12(%s)\n\t{ai|addic} %s,%s,16\n" \
- : "\tld %s,24(%s)\n\t{ai|addic} %s,%s,32\n", \
- reg_names[REGNO], reg_names[1], reg_names[1], \
- reg_names[1]); \
-} while (0)
-
/* This is how to output an element of a case-vector that is absolute.
(RS/6000 does not use such vectors, but we must define this macro
anyway.) */