summaryrefslogtreecommitdiff
path: root/gcc/config/sh
diff options
context:
space:
mode:
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2004-01-12 12:59:38 +0000
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2004-01-12 12:59:38 +0000
commit05e0956519aefe7929b081da944059e20a11a79f (patch)
treef09f63e49d892db0078f774f0763051f1cacb399 /gcc/config/sh
parentb28a376c5ed3119834ffd0d50e5b883b82e271e3 (diff)
downloadgcc-05e0956519aefe7929b081da944059e20a11a79f.tar.gz
PR target/13585
* sh-protos.h (check_use_sfunc_addr): Declare. * sh.c (extract_sfunc_addr, check_use_sfunc_addr): New functions. * sh.md (use_sfunc_addr): Use check_use_sfunc_addr in insn predicate. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@75717 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sh')
-rw-r--r--gcc/config/sh/sh-protos.h1
-rw-r--r--gcc/config/sh/sh.c47
-rw-r--r--gcc/config/sh/sh.md2
3 files changed, 49 insertions, 1 deletions
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index ec723bda127..fc96b193777 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -125,6 +125,7 @@ extern bool sh_cannot_change_mode_class
extern void sh_mark_label (rtx, int);
extern int sh_register_move_cost
(enum machine_mode mode, enum reg_class, enum reg_class);
+extern int check_use_sfunc_addr (rtx, rtx);
#ifdef HARD_CONST
extern void fpscr_set_from_mem (int, HARD_REG_SET);
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 1c58712a00c..85f4aa6e639 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -9167,4 +9167,51 @@ sh_expand_t_scc (enum rtx_code code, rtx target)
return 1;
}
+/* INSN is an sfunc; return the rtx that describes the address used. */
+static rtx
+extract_sfunc_addr (rtx insn)
+{
+ rtx pattern, part = NULL_RTX;
+ int len, i;
+
+ pattern = PATTERN (insn);
+ len = XVECLEN (pattern, 0);
+ for (i = 0; i < len; i++)
+ {
+ part = XVECEXP (pattern, 0, i);
+ if (GET_CODE (part) == USE && GET_MODE (XEXP (part, 0)) == Pmode
+ && GENERAL_REGISTER_P (true_regnum (XEXP (part, 0))))
+ return XEXP (part, 0);
+ }
+ if (GET_CODE (XVECEXP (pattern, 0, 0)) == UNSPEC_VOLATILE)
+ return XVECEXP (XVECEXP (pattern, 0, 0), 0, 1);
+ abort ();
+}
+
+/* Verify that the register in use_sfunc_addr still agrees with the address
+ used in the sfunc. This prevents fill_slots_from_thread from changing
+ use_sfunc_addr.
+ INSN is the use_sfunc_addr instruction, and REG is the register it
+ guards. */
+int
+check_use_sfunc_addr (rtx insn, rtx reg)
+{
+ /* Search for the sfunc. It should really come right after INSN. */
+ while ((insn = NEXT_INSN (insn)))
+ {
+ if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN)
+ break;
+ if (! INSN_P (insn))
+ continue;
+
+ if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ insn = XVECEXP (PATTERN (insn), 0, 0);
+ if (GET_CODE (PATTERN (insn)) != PARALLEL
+ || get_attr_type (insn) != TYPE_SFUNC)
+ continue;
+ return rtx_equal_p (extract_sfunc_addr (insn), reg);
+ }
+ abort ();
+}
+
#include "gt-sh.h"
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index aa63209dbf6..099d930a6c2 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -1245,7 +1245,7 @@
(define_insn "use_sfunc_addr"
[(set (reg:SI PR_REG)
(unspec:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_SFUNC))]
- "TARGET_SH1"
+ "TARGET_SH1 && check_use_sfunc_addr (insn, operands[0])"
""
[(set_attr "length" "0")])