--- gcc/config/i860.c 2018/04/24 17:51:36 1.1.1.1 +++ gcc/config/i860.c 2018/04/24 18:05:33 1.1.1.4 @@ -351,145 +351,6 @@ single_insn_src_p (op, mode) return 0; } } - -/* Nonzero only if this *really* is a single insn operand. */ -int -strict_single_insn_op_p (op, mode) - rtx op; - enum machine_mode mode; -{ - if (mode == VOIDmode) - mode = GET_MODE (op); - - switch (GET_CODE (op)) - { - case CC0: - return 1; - - case CONST_INT: - if (SMALL_INT (op)) - return 1; - /* We can put this set insn into delay slot, because this is one - insn; `orh'. */ - if ((INTVAL (op) & 0xffff) == 0) - return 1; - return 0; - - case SYMBOL_REF: - return 0; - - case REG: -#if 0 - /* This loses when moving an freg to a general reg. */ - return HARD_REGNO_NREGS (REGNO (op), mode) == 1; -#endif - return (mode != DFmode && mode != DImode); - - case MEM: - if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) - return (mode != DFmode && mode != DImode); - return 0; - - /* We never need to negate or complement constants. */ - case NEG: - return (mode != DFmode); - case NOT: - case ZERO_EXTEND: - return 1; - - case PLUS: - case MINUS: - /* Detect cases that require multiple instructions. */ - if (CONSTANT_P (XEXP (op, 1)) - && !(GET_CODE (XEXP (op, 1)) == CONST_INT - && SMALL_INT (XEXP (op, 1)))) - return 0; - case EQ: - case NE: - case LT: - case GT: - case LE: - case GE: - case LTU: - case GTU: - case LEU: - case GEU: - return 1; - - case AND: - if (GET_CODE (XEXP (op, 1)) == NOT) - { - rtx arg = XEXP (XEXP (op, 1), 0); - if (CONSTANT_P (arg) - && !(GET_CODE (arg) == CONST_INT - && (SMALL_INT (arg) - || INTVAL (arg) & 0xffff == 0))) - return 0; - } - case IOR: - case XOR: - /* Both small and round numbers take one instruction; - others take two. */ - if (CONSTANT_P (XEXP (op, 1)) - && !(GET_CODE (XEXP (op, 1)) == CONST_INT - && (SMALL_INT (XEXP (op, 1)) - || INTVAL (XEXP (op, 1)) & 0xffff == 0))) - return 0; - - case LSHIFT: - case ASHIFT: - case ASHIFTRT: - case LSHIFTRT: - return 1; - - case SUBREG: - if (SUBREG_WORD (op) != 0) - return 0; - return strict_single_insn_op_p (SUBREG_REG (op), mode); - - case SIGN_EXTEND: - if (GET_CODE (XEXP (op, 0)) == MEM - && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) - return 1; - return 0; - - /* Not doing floating point, since they probably - take longer than the branch slot they might fill. */ - case FLOAT_EXTEND: - case FLOAT_TRUNCATE: - case FLOAT: - case FIX: - case UNSIGNED_FLOAT: - case UNSIGNED_FIX: - return 0; - - default: - return 0; - } -} - -/* Return truth value of whether OP is a relational operator. */ -int -relop (op, mode) - rtx op; - enum machine_mode mode; -{ - switch (GET_CODE (op)) - { - case EQ: - case NE: - case GT: - case GE: - case LT: - case LE: - case GTU: - case GEU: - case LTU: - case LEU: - return 1; - } - return 0; -} /* Return non-zero only if OP is a register of mode MODE, or const0_rtx. */ @@ -669,12 +530,14 @@ singlemove_string (operands) } if (GET_CODE (operands[1]) == CONST_INT) { + if (operands[1] == const0_rtx) + return "mov %?r0,%0"; if((INTVAL (operands[1]) & 0xffff0000) == 0) return "or %L1,%?r0,%0"; + if((INTVAL (operands[1]) & 0xffff8000) == 0xffff8000) + return "adds %1,%?r0,%0"; if((INTVAL (operands[1]) & 0x0000ffff) == 0) return "orh %H1,%?r0,%0"; - if (operands[1] == const0_rtx) - return "mov %?r0,%0"; } return "mov %1,%0"; } @@ -1196,7 +1059,7 @@ output_size_for_block_move (size, reg, a #if 1 cc_status.flags &= ~ CC_KNOW_HI_R31; - output_asm_insn ("mov %1,%0", xoperands); + output_asm_insn (singlemove_string (xoperands), xoperands); #else if (GET_CODE (size) == REG) output_asm_insn ("sub %2,%1,%0", xoperands); @@ -1347,8 +1210,8 @@ output_block_move (operands) output_asm_insn ("adds %4,%?r0,%5", xoperands); /* Predecrement the loop counter. This happens again also in the `bla' - instruction which precceds the loop, but we need to have it done - two times before we enter the loop because of the bizzare semantics + instruction which precedes the loop, but we need to have it done + two times before we enter the loop because of the bizarre semantics of the bla instruction. */ output_asm_insn ("adds %5,%2,%2", xoperands); @@ -1522,7 +1385,7 @@ output_delayed_branch (template, operand output_asm_insn (template, operands); /* Now recognize the insn which we put in its delay slot. - We must do this after outputing the branch insn, + We must do this after outputting the branch insn, since operands may just be a pointer to `recog_operand'. */ INSN_CODE (delay_insn) = insn_code_number = recog (pat, delay_insn); if (insn_code_number == -1) @@ -1557,7 +1420,7 @@ output_delay_insn (delay_insn) int i; /* Now recognize the insn which we put in its delay slot. - We must do this after outputing the branch insn, + We must do this after outputting the branch insn, since operands may just be a pointer to `recog_operand'. */ insn_code_number = recog_memoized (delay_insn); if (insn_code_number == -1) @@ -1567,7 +1430,7 @@ output_delay_insn (delay_insn) INSN_CODE (delay_insn) = insn_code_number; insn_extract (delay_insn); - /* It is possible that this insn has not been properly scaned by final + /* It is possible that this insn has not been properly scanned by final yet. If this insn's operands don't appear in the peephole's actual operands, then they won't be fixed up by final, so we make sure they get fixed up here. -- This is a kludge. */ @@ -1614,21 +1477,17 @@ unsigned long sfmode_constant_to_ulong (x) rtx x; { - union { double d; unsigned long i[2]; } u; + REAL_VALUE_TYPE d; union { float f; unsigned long i; } u2; if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != SFmode) abort (); -#ifndef HOST_WORDS_BIG_ENDIAN - u.i[0] = CONST_DOUBLE_LOW (x); - u.i[1] = CONST_DOUBLE_HIGH (x); -#else - u.i[0] = CONST_DOUBLE_HIGH (x); - u.i[1] = CONST_DOUBLE_LOW (x); +#if TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT + error IEEE emulation needed #endif - - u2.f = u.d; + REAL_VALUE_FROM_CONST_DOUBLE (d, x); + u2.f = d; return u2.i; } @@ -1667,7 +1526,7 @@ sfmode_constant_to_ulong (x) offsets from the frame pointer). Previous versions of GCC also saved the "preserved" registers in the - "nagative" part of the frame, but they saved them using positive + "negative" part of the frame, but they saved them using positive offsets from the (adjusted) stack pointer (after it had been adjusted to allocate space for the new frame). That's just plain wrong because if the current function calls alloca(), the stack pointer @@ -1706,7 +1565,7 @@ sfmode_constant_to_ulong (x) There are two somewhat different ways that you can generate prologues here... i.e. pedantically ABI-compliant, and the "other" way. The - "other" way is more consistant with what is currently generated by the + "other" way is more consistent with what is currently generated by the "native" svr4 C compiler for the i860. That's important if you want to use the current (as of 8/91) incarnation of svr4 SDB for the i860. The SVR4 SDB for the i860 insists on having function prologues be @@ -2041,15 +1900,49 @@ function_prologue (asm_file, local_bytes instruction, so what the hell. */ +/* This corresponds to a version 4 TDESC structure. Lower numbered + versions successively omit the last word of the structure. We + don't try to handle version 5 here. */ + +typedef struct TDESC_flags { + int version:4; + int reg_packing:1; + int callable_block:1; + int reserved:4; + int fregs:6; /* fp regs 2-7 */ + int iregs:16; /* regs 0-15 */ +} TDESC_flags; + +typedef struct TDESC { + TDESC_flags flags; + int integer_reg_offset; /* same as must_preserve_bytes */ + int floating_point_reg_offset; + unsigned int positive_frame_size; /* same as frame_upper_bytes */ + unsigned int negative_frame_size; /* same as frame_lower_bytes */ +} TDESC; + void function_epilogue (asm_file, local_bytes) register FILE *asm_file; register unsigned local_bytes; { register unsigned frame_upper_bytes; + register unsigned frame_lower_bytes; register unsigned preserved_reg_bytes = 0; register unsigned i; register unsigned restored_so_far = 0; + register unsigned int_restored; + register unsigned mask; + unsigned intflags=0; + register TDESC_flags *flags = (TDESC_flags *) &intflags; + + flags->version = 4; + flags->reg_packing = 1; + flags->iregs = 8; /* old fp always gets saved */ + + /* Round-up the frame_lower_bytes so that it's a multiple of 16. */ + + frame_lower_bytes = (local_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT; /* Count the number of registers that were preserved in the prologue. Ignore r0. It is never preserved. */ @@ -2073,17 +1966,31 @@ function_epilogue (asm_file, local_bytes /* Restore all of the "preserved" registers that need restoring. */ - for (i = 1; i < 32; i++) - if (regs_ever_live[i] && ! call_used_regs[i]) + mask = 2; + + for (i = 1; i < 32; i++, mask<<=1) + if (regs_ever_live[i] && ! call_used_regs[i]) { fprintf (asm_file, "\tld.l %d(%sfp),%s%s\n", must_preserve_bytes + (4 * restored_so_far++), i860_reg_prefix, i860_reg_prefix, reg_names[i]); + if (i > 3 && i < 16) + flags->iregs |= mask; + } + + int_restored = restored_so_far; + mask = 1; - for (i = 32; i < 64; i++) - if (regs_ever_live[i] && ! call_used_regs[i]) + for (i = 32; i < 64; i++) { + if (regs_ever_live[i] && ! call_used_regs[i]) { fprintf (asm_file, "\tfld.l %d(%sfp),%s%s\n", must_preserve_bytes + (4 * restored_so_far++), i860_reg_prefix, i860_reg_prefix, reg_names[i]); + if (i > 33 & i < 40) + flags->fregs |= mask; + } + if (i > 33 && i < 40) + mask<<=1; + } /* Get the value we plan to use to restore the stack pointer into r31. */ @@ -2092,9 +1999,11 @@ function_epilogue (asm_file, local_bytes /* Restore the return address and the old frame pointer. */ - if (must_preserve_r1) + if (must_preserve_r1) { fprintf (asm_file, "\tld.l 4(%sfp),%sr1\n", i860_reg_prefix, i860_reg_prefix); + flags->iregs |= 2; + } fprintf (asm_file, "\tld.l 0(%sfp),%sfp\n", i860_reg_prefix, i860_reg_prefix); @@ -2103,4 +2012,37 @@ function_epilogue (asm_file, local_bytes fprintf (asm_file, "\tbri %sr1\n\tmov %sr31,%ssp\n", i860_reg_prefix, i860_reg_prefix, i860_reg_prefix); + +#ifdef OUTPUT_TDESC /* Output an ABI-compliant TDESC entry */ + if (! frame_lower_bytes) { + flags->version--; + if (! frame_upper_bytes) { + flags->version--; + if (restored_so_far == int_restored) /* No FP saves */ + flags->version--; + } + } + assemble_name(asm_file,current_function_original_name); + fputs(".TDESC:\n", asm_file); + fprintf(asm_file, "%s 0x%0x\n", ASM_LONG, intflags); + fprintf(asm_file, "%s %d\n", ASM_LONG, + int_restored ? must_preserve_bytes : 0); + if (flags->version > 1) { + fprintf(asm_file, "%s %d\n", ASM_LONG, + (restored_so_far == int_restored) ? 0 : must_preserve_bytes + + (4 * int_restored)); + if (flags->version > 2) { + fprintf(asm_file, "%s %d\n", ASM_LONG, frame_upper_bytes); + if (flags->version > 3) + fprintf(asm_file, "%s %d\n", ASM_LONG, frame_lower_bytes); + } + } + tdesc_section(); + fprintf(asm_file, "%s ", ASM_LONG); + assemble_name(asm_file, current_function_original_name); + fprintf(asm_file, "\n%s ", ASM_LONG); + assemble_name(asm_file, current_function_original_name); + fputs(".TDESC\n", asm_file); + text_section(); +#endif }