aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2002-03-29 09:25:10 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2002-03-29 09:25:10 +0100
commitf17f93326d7d690113c87abf1532bd9f4be8301f (patch)
tree27472513448efb25e1c2f9cda0600c46b459b56e /gcc
parent13992acae2173c407373b2a71f29f565db596324 (diff)
downloadgcc-f17f93326d7d690113c87abf1532bd9f4be8301f.zip
gcc-f17f93326d7d690113c87abf1532bd9f4be8301f.tar.gz
gcc-f17f93326d7d690113c87abf1532bd9f4be8301f.tar.bz2
re PR c++/5964 (g++ generates code that results in "word displacement will not fit in 16 bits" on sparcv9)
PR c++/5964 * config/sparc/sparc.md (empty_delay_slot, branch_type): New attributes. (length): Compute variable length for branches/calls/jumps here. (branch, inverted_branch, normal_fp_branch, inverted_fp_branch, normal_fpe_branch, inverted_fpe_branch): Remove length attribute, define branch_type attribute. (divsi3_sp32): Maximum length is 6 not 7. (call_address_struct_value_sp32, call_symbolic_struct_value_sp32, call_address_untyped_struct_value_sp32, call_symbolic_untyped_struct_value_sp32): Set length to 3 not 2. * config/sparc/sparc.c (empty_delay_slot): New function. * config/sparc/sparc.h (ADJUST_INSN_LENGTH): Remove. * config/sparc/sparc-protos.h (empty_delay_slot): Add prototype. * g++.dg/opt/longbranch1.C: New test. From-SVN: r51557
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/config/sparc/sparc-protos.h1
-rw-r--r--gcc/config/sparc/sparc.c20
-rw-r--r--gcc/config/sparc/sparc.h8
-rw-r--r--gcc/config/sparc/sparc.md179
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/g++.dg/opt/longbranch1.C36
7 files changed, 157 insertions, 106 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 48a7dcf..effce52 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
2002-03-29 Jakub Jelinek <jakub@redhat.com>
+ PR c++/5964
+ * config/sparc/sparc.md (empty_delay_slot, branch_type): New
+ attributes.
+ (length): Compute variable length for branches/calls/jumps here.
+ (branch, inverted_branch, normal_fp_branch, inverted_fp_branch,
+ normal_fpe_branch, inverted_fpe_branch): Remove length attribute,
+ define branch_type attribute.
+ (divsi3_sp32): Maximum length is 6 not 7.
+ (call_address_struct_value_sp32, call_symbolic_struct_value_sp32,
+ call_address_untyped_struct_value_sp32,
+ call_symbolic_untyped_struct_value_sp32): Set length to 3 not 2.
+ * config/sparc/sparc.c (empty_delay_slot): New function.
+ * config/sparc/sparc.h (ADJUST_INSN_LENGTH): Remove.
+ * config/sparc/sparc-protos.h (empty_delay_slot): Add prototype.
+
+2002-03-29 Jakub Jelinek <jakub@redhat.com>
+
* combine.c (set_nonzero_bits_and_sign_copies): Don't call
nonzero_bits if not needed.
(nonzero_bits) [XOR]: Likewise.
diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h
index 269844e..d7433d4 100644
--- a/gcc/config/sparc/sparc-protos.h
+++ b/gcc/config/sparc/sparc-protos.h
@@ -99,6 +99,7 @@ extern int arith_4096_operand PARAMS ((rtx, enum machine_mode));
extern int zero_operand PARAMS ((rtx, enum machine_mode));
extern int fp_zero_operand PARAMS ((rtx, enum machine_mode));
extern int reg_or_0_operand PARAMS ((rtx, enum machine_mode));
+extern int empty_delay_slot PARAMS ((rtx));
extern int eligible_for_epilogue_delay PARAMS ((rtx, int));
extern int eligible_for_return_delay PARAMS ((rtx));
extern int eligible_for_sibcall_delay PARAMS ((rtx));
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index f6de9c5..a6a99c7 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -2459,6 +2459,26 @@ leaf_return_peephole_ok ()
return (actual_fsize == 0);
}
+/* Return nonzero if a branch/jump/call instruction will be emitting
+ nop into its delay slot. */
+
+int
+empty_delay_slot (insn)
+ rtx insn;
+{
+ rtx seq;
+
+ /* If no previous instruction (should not happen), return true. */
+ if (PREV_INSN (insn) == NULL)
+ return 1;
+
+ seq = NEXT_INSN (PREV_INSN (insn));
+ if (GET_CODE (PATTERN (seq)) == SEQUENCE)
+ return 0;
+
+ return 1;
+}
+
/* Return nonzero if TRIAL can go into the function epilogue's
delay slot. SLOT is the slot we are trying to fill. */
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index 9fed03c..e8b9cc3 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -2654,14 +2654,6 @@ do { \
case FLOAT: \
case FIX: \
return 19;
-
-/* Conditional branches with empty delay slots have a length of two. */
-#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
-do { \
- if (GET_CODE (INSN) == CALL_INSN \
- || (GET_CODE (INSN) == JUMP_INSN && ! simplejump_p (insn))) \
- LENGTH += 1; \
-} while (0)
/* Control the assembler format that we output. */
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index e1810f6..a7769e3 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -87,8 +87,75 @@
"ialu,compare,shift,load,sload,store,uncond_branch,branch,call,sibcall,call_no_delay_slot,return,imul,idiv,fpload,fpstore,fp,fpmove,fpcmove,fpcmp,fpmul,fpdivs,fpdivd,fpsqrts,fpsqrtd,cmove,multi,misc"
(const_string "ialu"))
+;; true if branch/call has empty delay slot and will emit a nop in it
+(define_attr "empty_delay_slot" "false,true"
+ (symbol_ref "empty_delay_slot (insn)"))
+
+(define_attr "branch_type" "none,icc,fcc,reg" (const_string "none"))
+
;; Length (in # of insns).
-(define_attr "length" "" (const_int 1))
+(define_attr "length" ""
+ (cond [(eq_attr "type" "uncond_branch,call,sibcall")
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (eq_attr "branch_type" "icc")
+ (if_then_else (match_operand 0 "noov_compare64_op" "")
+ (if_then_else (lt (pc) (match_dup 1))
+ (if_then_else (lt (minus (match_dup 1) (pc)) (const_int 260000))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 4)
+ (const_int 3)))
+ (if_then_else (lt (minus (pc) (match_dup 1)) (const_int 260000))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 4)
+ (const_int 3))))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1)))
+ (eq_attr "branch_type" "fcc")
+ (if_then_else (match_operand 0 "fcc0_reg_operand" "")
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (lt (pc) (match_dup 2))
+ (if_then_else (lt (minus (match_dup 2) (pc)) (const_int 260000))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 4)
+ (const_int 3)))
+ (if_then_else (lt (minus (pc) (match_dup 2)) (const_int 260000))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 4)
+ (const_int 3)))))
+ (eq_attr "branch_type" "reg")
+ (if_then_else (lt (pc) (match_dup 2))
+ (if_then_else (lt (minus (match_dup 2) (pc)) (const_int 32000))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 4)
+ (const_int 3)))
+ (if_then_else (lt (minus (pc) (match_dup 2)) (const_int 32000))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 4)
+ (const_int 3))))
+ ] (const_int 1)))
;; FP precision.
(define_attr "fptype" "single,double" (const_string "single"))
@@ -1898,18 +1965,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (match_operand 0 "noov_compare64_op" "")
- (if_then_else (lt (pc) (match_dup 1))
- (if_then_else (lt (minus (match_dup 1) (pc))
- (const_int 260000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 1))
- (const_int 260000))
- (const_int 1)
- (const_int 3)))
- (const_int 1)))])
+ (set_attr "branch_type" "icc")])
;; XXX fpcmp nop braindamage
(define_insn "*inverted_branch"
@@ -1926,18 +1982,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (match_operand 0 "noov_compare64_op" "")
- (if_then_else (lt (pc) (match_dup 1))
- (if_then_else (lt (minus (match_dup 1) (pc))
- (const_int 260000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 1))
- (const_int 260000))
- (const_int 1)
- (const_int 3)))
- (const_int 1)))])
+ (set_attr "branch_type" "icc")])
;; XXX fpcmp nop braindamage
(define_insn "*normal_fp_branch"
@@ -1955,18 +2000,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (match_operand 0 "fcc0_reg_operand" "")
- (const_int 1)
- (if_then_else (lt (pc) (match_dup 2))
- (if_then_else (lt (minus (match_dup 2) (pc))
- (const_int 260000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 2))
- (const_int 260000))
- (const_int 1)
- (const_int 3)))))])
+ (set_attr "branch_type" "fcc")])
;; XXX fpcmp nop braindamage
(define_insn "*inverted_fp_branch"
@@ -1984,18 +2018,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (match_operand 0 "fcc0_reg_operand" "")
- (const_int 1)
- (if_then_else (lt (pc) (match_dup 2))
- (if_then_else (lt (minus (match_dup 2) (pc))
- (const_int 260000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 2))
- (const_int 260000))
- (const_int 1)
- (const_int 3)))))])
+ (set_attr "branch_type" "fcc")])
;; XXX fpcmp nop braindamage
(define_insn "*normal_fpe_branch"
@@ -2013,18 +2036,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (match_operand 0 "fcc0_reg_operand" "")
- (const_int 1)
- (if_then_else (lt (pc) (match_dup 2))
- (if_then_else (lt (minus (match_dup 2) (pc))
- (const_int 260000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 2))
- (const_int 260000))
- (const_int 1)
- (const_int 3)))))])
+ (set_attr "branch_type" "fcc")])
;; XXX fpcmp nop braindamage
(define_insn "*inverted_fpe_branch"
@@ -2042,18 +2054,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (match_operand 0 "fcc0_reg_operand" "")
- (const_int 1)
- (if_then_else (lt (pc) (match_dup 2))
- (if_then_else (lt (minus (match_dup 2) (pc))
- (const_int 260000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 2))
- (const_int 260000))
- (const_int 1)
- (const_int 3)))))])
+ (set_attr "branch_type" "fcc")])
;; Sparc V9-specific jump insns. None of these are guaranteed to be
;; in the architecture.
@@ -2076,16 +2077,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (lt (pc) (match_dup 2))
- (if_then_else (lt (minus (match_dup 2) (pc))
- (const_int 32000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 2))
- (const_int 32000))
- (const_int 1)
- (const_int 3))))])
+ (set_attr "branch_type" "reg")])
;; XXX
(define_insn "*inverted_int_branch_sp64"
@@ -2103,16 +2095,7 @@
! final_sequence, insn);
}"
[(set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (lt (pc) (match_dup 2))
- (if_then_else (lt (minus (match_dup 2) (pc))
- (const_int 32000))
- (const_int 1)
- (const_int 3))
- (if_then_else (lt (minus (pc) (match_dup 2))
- (const_int 32000))
- (const_int 1)
- (const_int 3))))])
+ (set_attr "branch_type" "reg")])
;; Load program counter insns.
@@ -6473,7 +6456,7 @@
[(set_attr "type" "multi")
(set (attr "length")
(if_then_else (eq_attr "isa" "v9")
- (const_int 4) (const_int 7)))])
+ (const_int 4) (const_int 6)))])
(define_insn "divsi3_sp64"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -8499,7 +8482,7 @@
"! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
"call\\t%a0, %1\\n\\tnop\\n\\tunimp\\t%2"
[(set_attr "type" "call_no_delay_slot")
- (set_attr "length" "2")])
+ (set_attr "length" "3")])
;; This is a call that wants a structure value.
;; There is no such critter for v9 (??? we may need one anyway).
@@ -8512,7 +8495,7 @@
"! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
"call\\t%a0, %1\\n\\tnop\\n\\tunimp\\t%2"
[(set_attr "type" "call_no_delay_slot")
- (set_attr "length" "2")])
+ (set_attr "length" "3")])
;; This is a call that may want a structure value. This is used for
;; untyped_calls.
@@ -8525,7 +8508,7 @@
"! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0"
"call\\t%a0, %1\\n\\tnop\\n\\tnop"
[(set_attr "type" "call_no_delay_slot")
- (set_attr "length" "2")])
+ (set_attr "length" "3")])
;; This is a call that wants a structure value.
(define_insn "*call_symbolic_untyped_struct_value_sp32"
@@ -8537,7 +8520,7 @@
"! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0"
"call\\t%a0, %1\\n\\tnop\\n\\tnop"
[(set_attr "type" "call_no_delay_slot")
- (set_attr "length" "2")])
+ (set_attr "length" "3")])
(define_expand "call_value"
;; Note that this expression is not used for generating RTL.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7f68789..fec72b8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -2,6 +2,8 @@
* g++.dg/opt/static1.C: New test.
+ * g++.dg/opt/longbranch1.C: New test.
+
2002-03-28 Hans-Peter Nilsson <hp@bitrange.com>
* gcc.dg/weak-1.c: Fix typo in scan-assembler pattern.
diff --git a/gcc/testsuite/g++.dg/opt/longbranch1.C b/gcc/testsuite/g++.dg/opt/longbranch1.C
new file mode 100644
index 0000000..a64a57a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/longbranch1.C
@@ -0,0 +1,36 @@
+// PR c++/5964
+// This testcase failed to link on sparc -m64 -O0, because instruction
+// lengths were incorrectly computed
+// { dg-do link }
+// { dg-options "-O0" }
+
+#define makecode for (int i = 1; i < 1000; ++i) i *= 3
+#define muchcode \
+ makecode; makecode; makecode; makecode; makecode; makecode; \
+ makecode; makecode; makecode; makecode; makecode; makecode; \
+ makecode; makecode; makecode; makecode; makecode; makecode; \
+ makecode; makecode; makecode; makecode; makecode; makecode
+
+#define verymuchcode \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
+ muchcode; muchcode; muchcode; muchcode; muchcode; muchcode
+
+int
+main (int argc, char **argv)
+{
+loop:
+ verymuchcode;
+ delete[] argv;
+ goto loop;
+}