Path: 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 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