diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b91468a64b2..2365199cc0b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2000-11-25 Alexandre Oliva , NIIBE Yutaka + + * config/sh/sh-protos.h (symbol_ref_operand): Declare. + * config/sh/sh.md (UNSPEC_CALLER): New constant. + (calli_pcrel, call_valuei_pcrel): Use PIC_REG. + (call_pcrel, call_value_pcrel): New insn_and_splits. + (call, call_value): Use them. + (call_site): New expand. + (sym_label2reg, symPLT_label2reg): Adjust to hold call_sites. + * config/sh/sh.h (OUTPUT_ADDR_CONST_EXTRA) [UNSPEC_CALLER]: + Output call_site label. + (PREDICATE_CODES): Added symbol_ref_operand. + * config/sh/sh.c (symbol_ref_operand): Define. + * emit-rtl.c (try_split): Propagate CALL_INSN_FUNCTION_USAGE + to CALL_INSNs in the split sequence. + 2000-11-24 Nick Clifton * config.gcc (v850-*-*): Define c_target_objs and diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 21872ac7f80..79b66773f84 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -77,6 +77,7 @@ extern int regs_used PARAMS ((rtx, int)); extern void fixup_addr_diff_vecs PARAMS ((rtx)); extern int get_dest_uid PARAMS ((rtx, int)); extern void final_prescan_insn PARAMS ((rtx, rtx *, int)); +extern int symbol_ref_operand PARAMS ((rtx, enum machine_mode)); extern int system_reg_operand PARAMS ((rtx, enum machine_mode)); extern int general_movsrc_operand PARAMS ((rtx, enum machine_mode)); extern int general_movdst_operand PARAMS ((rtx, enum machine_mode)); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 87601c6d6af..259e1480e46 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -4821,6 +4821,14 @@ fpul_operand (op, mode) && GET_MODE (op) == mode); } +int +symbol_ref_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == SYMBOL_REF); +} + int commutative_float_operator (op, mode) rtx op; diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 618f98cd265..9c516fc9a3e 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -2201,6 +2201,15 @@ do { char dstr[30]; \ output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ fputs ("@PLT", (STREAM)); \ break; \ + case UNSPEC_CALLER: \ + { \ + char name[32]; \ + /* LPCS stands for Label for PIC Call Site. */ \ + ASM_GENERATE_INTERNAL_LABEL \ + (name, "LPCS", XINT (XVECEXP ((X), 0, 0), 0)); \ + assemble_name ((STREAM), name); \ + } \ + break; \ default: \ goto FAIL; \ } \ @@ -2297,7 +2306,8 @@ extern struct rtx_def *fpscr_rtx; {"general_movdst_operand", {SUBREG, REG, MEM}}, \ {"logical_operand", {SUBREG, REG, CONST_INT}}, \ {"noncommutative_float_operator", {MINUS, DIV}}, \ - {"register_operand", {SUBREG, REG}}, + {"register_operand", {SUBREG, REG}}, \ + {"symbol_ref_operand", {SYMBOL_REF}}, /* Define this macro if it is advisable to hold scalars in registers in a wider mode than that declared by the program. In such cases, diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index c3a93946ef0..2c0ba5d36fe 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -108,6 +108,7 @@ (UNSPEC_GOT 7) (UNSPEC_GOTOFF 8) (UNSPEC_PLT 9) + (UNSPEC_CALLER 10) (UNSPEC_ICACHE 12) ;; These are used with unspec_volatile. @@ -3389,6 +3390,7 @@ [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r")) (match_operand 1 "" "")) (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) (use (match_operand 2 "" "")) (clobber (reg:SI PR_REG))] "TARGET_SH2" @@ -3399,6 +3401,34 @@ (const_string "single") (const_string "double"))) (set_attr "needs_delay_slot" "yes")]) +(define_insn_and_split "call_pcrel" + [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "")) + (match_operand 1 "" "")) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (clobber (reg:SI PR_REG)) + (clobber (match_scratch:SI 2 "=r"))] + "TARGET_SH2 && optimize" + "#" + "reload_completed" + [(const_int 0)] + " +{ + rtx lab = gen_call_site (); + + if (SYMBOL_REF_FLAG (operands[0])) + emit_insn (gen_sym_label2reg (operands[2], operands[0], lab)); + else + emit_insn (gen_symPLT_label2reg (operands[2], operands[0], lab)); + emit_call_insn (gen_calli_pcrel (operands[2], operands[1], lab)); + DONE; +}" + [(set_attr "type" "call") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "needs_delay_slot" "yes")]) + (define_insn "call_valuei" [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")) @@ -3418,6 +3448,7 @@ (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")) (match_operand 2 "" ""))) (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) (use (match_operand 3 "" "")) (clobber (reg:SI PR_REG))] "TARGET_SH2" @@ -3428,6 +3459,36 @@ (const_string "single") (const_string "double"))) (set_attr "needs_delay_slot" "yes")]) +(define_insn_and_split "call_value_pcrel" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "")) + (match_operand 2 "" ""))) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (clobber (reg:SI PR_REG)) + (clobber (match_scratch:SI 3 "=r"))] + "TARGET_SH2 && optimize" + "#" + "reload_completed" + [(const_int 0)] + " +{ + rtx lab = gen_call_site (); + + if (SYMBOL_REF_FLAG (operands[1])) + emit_insn (gen_sym_label2reg (operands[3], operands[1], lab)); + else + emit_insn (gen_symPLT_label2reg (operands[3], operands[1], lab)); + emit_call_insn (gen_call_valuei_pcrel (operands[0], operands[3], + operands[2], lab)); + DONE; +}" + [(set_attr "type" "call") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "needs_delay_slot" "yes")]) + (define_expand "call" [(parallel [(call (mem:SI (match_operand 0 "arith_reg_operand" "")) (match_operand 1 "" "")) @@ -3436,18 +3497,12 @@ "" " { - if (flag_pic && TARGET_SH2 && ! flag_unroll_loops + if (flag_pic && TARGET_SH2 && optimize && GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) { - rtx reg = gen_reg_rtx (SImode), lab = gen_label_rtx (); - - if (SYMBOL_REF_FLAG (XEXP (operands[0], 0))) - emit_insn (gen_sym_label2reg (reg, XEXP (operands[0], 0), lab)); - else - emit_insn (gen_symPLT_label2reg (reg, XEXP (operands[0], 0), lab)); - operands[0] = reg; - emit_call_insn (gen_calli_pcrel (operands[0], operands[1], lab)); + emit_call_insn (gen_call_pcrel (XEXP (operands[0], 0), operands[1])); + current_function_uses_pic_offset_table = 1; DONE; } else @@ -3463,19 +3518,13 @@ "" " { - if (flag_pic && TARGET_SH2 && ! flag_unroll_loops + if (flag_pic && TARGET_SH2 && optimize && GET_CODE (operands[1]) == MEM && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) { - rtx reg = gen_reg_rtx (SImode), lab = gen_label_rtx (); - - if (SYMBOL_REF_FLAG (XEXP (operands[1], 0))) - emit_insn (gen_sym_label2reg (reg, XEXP (operands[1], 0), lab)); - else - emit_insn (gen_symPLT_label2reg (reg, XEXP (operands[1], 0), lab)); - operands[1] = reg; - emit_call_insn (gen_call_valuei_pcrel (operands[0], operands[1], - operands[2], lab)); + emit_call_insn (gen_call_value_pcrel (operands[0], XEXP (operands[1], 0), + operands[2])); + current_function_uses_pic_offset_table = 1; DONE; } else @@ -3597,13 +3646,22 @@ } ") +(define_expand "call_site" + [(unspec [(match_dup 0)] UNSPEC_CALLER)] + "" + " +{ + static HOST_WIDE_INT i = 0; + operands[0] = GEN_INT (i); + i++; +}") + (define_expand "sym_label2reg" [(set (match_operand:SI 0 "" "") (const (minus:SI (const (unspec [(match_operand:SI 1 "" "")] UNSPEC_PIC)) (const (plus:SI - (unspec [(label_ref (match_operand:SI 2 "" ""))] - UNSPEC_PIC) + (match_operand:SI 2 "" "") (const_int 2))))))] "" "") @@ -3637,8 +3695,7 @@ (unspec [(match_operand:SI 1 "" "")] UNSPEC_PLT) (pc))) (const (plus:SI - (unspec [(label_ref (match_operand:SI 2 "" ""))] - UNSPEC_PIC) + (match_operand:SI 2 "" "") (const_int 2)))))) (use (match_dup 3))] ;; Even though the PIC register is not really used by the call diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 4329346260a..f658ec2cb9a 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -2438,6 +2438,14 @@ try_split (pat, trial, last) LABEL_NUSES (JUMP_LABEL (trial))++; } + /* If we are splitting a CALL_INSN, look for the CALL_INSN + in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it. */ + if (GET_CODE (trial) == CALL_INSN) + for (i = XVECLEN (seq, 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (seq, 0, i)) == CALL_INSN) + CALL_INSN_FUNCTION_USAGE (XVECEXP (seq, 0, i)) + = CALL_INSN_FUNCTION_USAGE (trial); + tem = emit_insn_after (seq, before); delete_insn (trial);