Article View: gnu.gcc.bug
Article #2763(none)
From: Michael Meissner
Date: Fri, 15 Dec 1989 15:27
Date: Fri, 15 Dec 1989 15:27
434 lines
14437 bytes
14437 bytes
Ing-simmons@micro.ti.com writes:
> There seems to be snag in re-targeting to a processor
> which does not define FRAME_GROWS_DOWNWARD but attempts
> to set ARG_POINTER_REGNUM and FRAME_POINTER_REGNUM equal.
> In this case FIRST_PARM_OFFSET should be the frame size
> of the function - but get_frame_size() returns zero at
> this point.
>
> high address
>
> | arg n |
> . .
> | arg 1 |
> +---------+ <---- sp at start of prolog +
> | local n | |
> . . > Frame size
> | local 1 | |
> +---------+ <---- fp +
> | reg n |
> . .
> | reg n |
> +---------+ <---- sp at end of prolog
>
> low address
>
> This shows up in the (incomplete) 88000 version and
> my own experimental version.
>
> Am I missing something? or do I need an explicit argument
> pointer?
>
> (Reason for not defining FRAME_GROWS_DOWNWARD is that target
> does not support negative immediate offsets.)
>
> Is bug-gcc@prep.ai.mit.edu the right address for re-targeting
> questions ?
This 'feature' of GNU C has caused numerous headaches in finishing the
88k port, since the machine has no negative offsets.
Originally, we set up register r25 to be the arg pointer registers,
and set up code in the prologue to save the previous r25's value, and
initialize it appropriately.
Later, we added a pass that would attempt to eliminitate the argument
pointer and replace it with references to the frame pointer, which in
turn would be eliminated, and replaced with references to the stack
pointer. We never could get all of the bugs out of eliminating the
argument pointer, and RMS objected to the code as well.
So finally, I rewrote the stuff to create a pseduo register to hold
the argument pointer (using register 0 which in the machine is
hardwired to 0, and is unusable as a normal register). I went through
every memory reference in the output patterns and added a fixup macro
to do any appropriate instructions before emitting the final
instruction (actually this was already done to deal with referencing
static memory directly). Some of this stuff will probably have to be
rethought when we have real instruction scheduling in GCC, but for now
it seems to work. You can FTP the entire 88k compiler from
dg-rtp.dg.com if you wish to use it as a reference. For 88k stuff,
contact: wood@dg-rtp.dg.com, to contact me personally, use:
meissner@osf.org.
The FIX_ADDRESS_IF_NEEDED macro looks like:
/* Generalized macro to fix up any addresses that need it, possibly
emitting output_asm_insn's. Presently it does literal synthesis
and argument pointer conversion. */
#define FIX_ADDRESS_IF_NEEDED(op) \
do { \
rtx op2 = (GET_CODE (op) == MEM) ? XEXP (op, 0) : op; \
\
if (REG_P (op2) && REGNO (op2) == ARG_POINTER_REGNUM) \
output_arg_ptr (0); \
\
else if (GET_CODE (op2) == PLUS && \
REG_P (XEXP (op2, 0)) && \
REGNO (XEXP (op2, 0)) == ARG_POINTER_REGNUM && \
GET_CODE (XEXP (op2, 1)) == CONST_INT) \
output_arg_ptr (INTVAL (XEXP (op2, 1))); \
\
else if (GET_CODE (op2) == PLUS && \
REG_P (XEXP (op2, 1)) && \
REGNO (XEXP (op2, 1)) == ARG_POINTER_REGNUM && \
GET_CODE (XEXP (op2, 0)) == CONST_INT) \
output_arg_ptr (INTVAL (XEXP (op2, 0))); \
\
else if (TARGET_EITHER_LIT_SYNTH) \
{ \
if (GET_CODE (op2) == SYMBOL_REF || \
GET_CODE (op2) == LABEL_REF || \
GET_CODE (op2) == CONST) \
output_ls_address (op2, 1); \
} \
} while (0)
A simple pattern that uses FIX_ADDRESS_IF_NEEDED looks like:
(define_insn ""
[(set (match_operand:QI 0 "memory_operand" "=m")
(truncate:QI
(match_operand:HI 1 "register_operand" "r")))]
""
"*
{
FIX_ADDRESS_IF_NEEDED (operands[0]);
return \"st.b %1,%0\";
}")
The procedure that resolves the argument pointer looks like:
/* Resolve an offset based on the pseudo argument pointer to one based
off of either the frame pointer or stack pointer as appropriate. */
void
output_arg_ptr (offset)
int offset; /* offset from the arg. pointer in bytes */
{
int ptr_num, mask;
rtx operands[10];
/* delayed branches and calls might have already done the arg ptr
stuff or literal synthesis, if so just return now. */
if ((cc_status.mdep & MDEP_LS_DELAY) != 0)
{
cc_status.mdep &= ~ MDEP_LS_DELAY;
return;
}
if ((cc_status.mdep & MDEP_LS_CHANGE) != 0)
error ("output_arg_ptr MDEP_LS_CHANGE bits were set");
offset += m88k_stack_size;
if (!m88k_frame_used)
{
if (m88k_variable_stack)
error ("Arg pointer referenced when frame omitted and variable stack allocated");
offset += m88k_stack_extra;
mask = MDEP_AP_USE_SP | MDEP_AP_IN_USE;
}
else
{
offset -= m88k_fp_offset;
mask = MDEP_AP_IN_USE;
}
if (INT_FITS_16_BITS (offset))
{
m88k_ap_offset = offset;
mask |= MDEP_AP_64K;
}
else
{
/* Offset too large, find an appropriate temp */
if (TARGET_LITERAL_SYNTHESIS)
{
cc_status.mdep &= ~ MDEP_LS_MASK;
ptr_num = LITERAL_SYNTHESIS_REGNUM;
mask |= MDEP_AP_USE_LS;
}
else
{
CC_STATUS_INIT;
ptr_num = CONDITION_CODE_REGNUM;
mask |= MDEP_AP_USE_CC;
}
operands[0] = gen_rtx (REG, SImode, ptr_num);
operands[1] = gen_rtx (CONST_INT, VOIDmode, offset);
output_asm_insn (output_load_const_int (SImode, operands, m88k_comment_int),
operands);
}
cc_status.mdep |= mask;
return;
}
The PRINT_OPERAND_ADDRESS was modified to deal with the flags set by
the output_arg_ptr function, to use the appropriate stack pointer,
frame pointer , or temporary register as appropriate.
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
{ register rtx base, index = 0; \
register rtx addr = ADDR; \
register rtx reg0, reg1; \
\
switch (GET_CODE (addr)) \
{ \
\
case REG: \
if (REGNO (addr) == ARG_POINTER_REGNUM) \
{ \
char *base; \
if ((cc_status.mdep & MDEP_AP_IN_USE) == 0) \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #1"); \
\
base = ((cc_status.mdep & MDEP_AP_USE_SP) == 0) \
? reg_names [FRAME_POINTER_REGNUM] \
: reg_names [STACK_POINTER_REGNUM]; \
\
if ((cc_status.mdep & MDEP_AP_64K) != 0) \
fprintf (FILE, "%s,0x%0.4x\t\t\t; %d", base, \
m88k_ap_offset, m88k_ap_offset); \
\
else if ((cc_status.mdep & MDEP_AP_USE_LS) != 0) \
fprintf (FILE, "%s,%s", \
reg_names[LITERAL_SYNTHESIS_REGNUM], base); \
\
else if ((cc_status.mdep & MDEP_AP_USE_CC) != 0) \
fprintf (FILE, "%s,%s", \
reg_names[CONDITION_CODE_REGNUM], base); \
\
else \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #2"); \
\
cc_status.mdep &= ~ MDEP_AP_MASK; \
} \
else \
fprintf (FILE, "r0,%s", reg_names [REGNO (addr)]); \
break; \
\
case PLUS: \
reg0 = XEXP (addr, 0); \
reg1 = XEXP (addr, 1); \
if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT) \
{ rtx tmp = reg0; reg0 = reg1; reg1 = tmp; } \
\
if (REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM && \
GET_CODE (reg1) == CONST_INT) \
{ \
char *base; \
if ((cc_status.mdep & MDEP_AP_IN_USE) == 0) \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #3"); \
\
base = ((cc_status.mdep & MDEP_AP_USE_SP) == 0) \
? reg_names [FRAME_POINTER_REGNUM] \
: reg_names [STACK_POINTER_REGNUM]; \
\
if ((cc_status.mdep & MDEP_AP_64K) != 0) \
fprintf (FILE, "%s,0x%0.4x\t\t\t; %d", base, \
m88k_ap_offset, m88k_ap_offset); \
\
else if ((cc_status.mdep & MDEP_AP_USE_LS) != 0) \
fprintf (FILE, "%s,%s", \
reg_names[LITERAL_SYNTHESIS_REGNUM], base); \
\
else if ((cc_status.mdep & MDEP_AP_USE_CC) != 0) \
fprintf (FILE, "%s,%s", \
reg_names[CONDITION_CODE_REGNUM], base); \
\
else \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #4"); \
\
cc_status.mdep &= ~ MDEP_AP_MASK; \
} \
\
else if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM) || \
(REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM)) \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #5"); \
\
else if (REG_P (reg0)) \
{ \
if (REG_P (reg1)) \
fprintf (FILE, "%s,%s", \
reg_names [REGNO (reg0)], \
reg_names [REGNO (reg1)]); \
\
else if (GET_CODE (reg1) == CONST_INT) \
fprintf (FILE, "%s,0x%.4x\t\t\t; %d", \
reg_names [REGNO (reg0)], INTVAL (reg1), \
INTVAL (reg1)); \
\
else if (GET_CODE (reg1) == MULT) \
{ \
rtx mreg = XEXP (reg1, 0); \
if (REGNO (mreg) == ARG_POINTER_REGNUM) \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #6"); \
\
fprintf (FILE, "%s[%s]", reg_names[REGNO (reg0)], \
reg_names[REGNO (mreg)]); \
} \
\
else if (GET_CODE (reg1) == ZERO_EXTRACT) \
{ \
fprintf (FILE, "%s,lo16(", reg_names[REGNO (reg0)]); \
output_addr_const (FILE, XEXP (reg1, 0)); \
fputc (')', FILE); \
} \
\
else fatal ("bad XEXP (1) to PRINT_OPERAND_ADDRESS"); \
} \
\
else \
fatal ("unknown PLUS case in PRINT_OPERAND_ADDRESS"); \
break; \
\
case MULT: \
if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM) \
fatal ("PRINT_OPERAND_ADDRESS, arg pointer #7"); \
\
fprintf (FILE, "r0[%s]", reg_names[REGNO (XEXP (addr, 0))]); \
break; \
\
case LSHIFT: \
fprintf (FILE, "r0,hi16("); \
output_addr_const (FILE, XEXP (addr, 0)); \
fprintf (FILE, ")"); \
break; \
\
case CONST_INT: \
fprintf (FILE, "r0,0x%.4x\t\t\t; %d", INTVAL (addr), INTVAL (addr)); \
break; \
\
default: \
if ((cc_status.mdep & MDEP_LS_LO16) != 0) \
{ \
cc_status.mdep &= ~ MDEP_LS_LO16; \
fprintf (FILE, "%s,lo16(", reg_names[LITERAL_SYNTHESIS_REGNUM]); \
output_addr_const (FILE, addr); \
fprintf (FILE, ")"); \
} \
\
else if ((cc_status.mdep & MDEP_LS_STATIC) != 0) \
{ \
cc_status.mdep &= ~ MDEP_LS_STATIC; \
fprintf (FILE, "%s,lo16(", reg_names[STATIC_LIT_SYNTH_REGNUM]); \
output_addr_const (FILE, addr); \
fprintf (FILE, ")"); \
} \
\
else \
{ \
fprintf (FILE, "r0,"); \
output_addr_const (FILE, addr); \
} \
} \
\
if ((cc_status.mdep & MDEP_LS_CHANGE) != 0) \
fatal ("PRINT_OPERAND_ADDRESS, MDEP_LS_CHANGE bits set at end"); \
}
Finally rtl was added to handle the cases dealing with the arg
pointer that did not involve addressing, such as setting a register
(these rtl need to come before the general rtl, so that the rtl
recoginition will match these instead of the general stuff).
;; Virtual argument pointer handling. We use register 0 internally to
;; indicate usage of the argument pointer. The following patterns need
;; to occur before the normal patterns, and should be the only ones that
;; deal with the argument pointer in a non-address fashion. The operand
;; is changed to refer to the frame pointer (r30) or stack pointer (r31)
;; as appropriate.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(reg:SI 0))]
""
"*
{
output_arg_ptr (0);
operands[1] = gen_rtx (REG, SImode, ARG_POINTER_REGNUM);
return \"addu %0,%a1\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (reg:SI 0)
(match_operand:SI 1 "int32_operand" "n")))]
""
"*
{
output_arg_ptr (INTVAL (operands[1]));
operands[1] = gen_rtx (REG, SImode, ARG_POINTER_REGNUM);
return \"addu %0,%a1\";
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (reg:SI 0)
(match_operand:SI 1 "register_operand" "r")))]
""
"*
{
output_arg_ptr (0);
if ((cc_status.mdep & MDEP_AP_64K) != 0 && m88k_ap_offset == 0)
{
cc_status.mdep &= ~ MDEP_AP_MASK;
operands[2] = ((cc_status.mdep & MDEP_AP_USE_SP) != 0)
? stack_pointer_rtx
: frame_pointer_rtx;
return \"addu %0,%1,%2\";
}
else
{
operands[2] = gen_rtx (REG, SImode, ARG_POINTER_REGNUM);
return \"addu %0,%a2\\n\\taddu %0,%0,%1\";
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "register_operand" "r")
(reg:SI 0)))]
""
"*
{
output_arg_ptr (0);
if ((cc_status.mdep & MDEP_AP_64K) != 0 && m88k_ap_offset == 0)
{
cc_status.mdep &= ~ MDEP_AP_MASK;
operands[2] = ((cc_status.mdep & MDEP_AP_USE_SP) != 0)
? stack_pointer_rtx
: frame_pointer_rtx;
return \"addu %0,%1,%2\";
}
else
{
operands[2] = gen_rtx (REG, SImode, ARG_POINTER_REGNUM);
return \"addu %0,%a2\\n\\taddu %0,%0,%1\";
}
}")
--
Michael Meissner, Data General.
Until 12/15: meissner@dg-rtp.DG.COM
After 12/15: meissner@osf.org
Technical Details
Message-ID:
<8912151527.AA05234@tiktok.rtp.dg.com>Path:
arc1-ca.pugleaf.net!utzoo!telly!philmtl!uunet!tut.cis.ohio-state.edu!DG-RTP.DG.COM!meissnerShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!telly!philmtl!uunet!tut.cis.ohio-state.edu!DG-RTP.DG.COM!meissner From: meissner@DG-RTP.DG.COM (Michael Meissner) Newsgroups: gnu.gcc.bug Subject: (none) Message-ID: <8912151527.AA05234@tiktok.rtp.dg.com> Date: 15 Dec 89 15:27:49 GMT Sender: daemon@tut.cis.ohio-state.edu Reply-To: meissner@osf.org Distribution: gnu Organization: GNUs Not Usenet Lines: 434