summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjye2 <jye2@138bc75d-0d04-0410-961f-82ee72b054a4>2013-04-15 07:41:27 +0000
committerjye2 <jye2@138bc75d-0d04-0410-961f-82ee72b054a4>2013-04-15 07:41:27 +0000
commit8d04d59efc91e68a4d2e82569b0ac00bb33a4189 (patch)
treedf5a6b0d5b2fa9c82cf54232d1868739e59ac29c
parent4f76c981f80390d1729488efe18cb0995c6b57ea (diff)
downloadgcc-8d04d59efc91e68a4d2e82569b0ac00bb33a4189.tar.gz
2013-04-15 Joey Ye <joey.ye@arm.com>
* config/arm/arm.c (thumb1_final_prescan_insn): Assert lr save for real far jump. (thumb_far_jump_used_p): Count instruction size and set far_jump_used. testsuite: * gcc.target/arm/thumb1-far-jump-1.c: New test. * gcc.target/arm/thumb1-far-jump-2.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@197956 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/arm/arm.c27
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c34
-rw-r--r--gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c57
5 files changed, 130 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 370ccbb507a..6d664610d2e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2013-04-15 Joey Ye <joey.ye@arm.com>
+
+ * config/arm/arm.c (thumb1_final_prescan_insn): Assert lr save
+ for real far jump.
+ (thumb_far_jump_used_p): Count instruction size and set
+ far_jump_used.
+
2013-04-14 Eric Botcazou <ebotcazou@adacore.com>
* reorg.c (fill_simple_delay_slots): Reindent block of code.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 982487ec22a..e0667849c70 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -22713,6 +22713,11 @@ thumb1_final_prescan_insn (rtx insn)
else if (conds != CONDS_NOCOND)
cfun->machine->thumb1_cc_insn = NULL_RTX;
}
+
+ /* Check if unexpected far jump is used. */
+ if (cfun->machine->lr_save_eliminated
+ && get_attr_far_jump (insn) == FAR_JUMP_YES)
+ internal_error("Unexpected thumb1 far jump");
}
int
@@ -22738,6 +22743,8 @@ static int
thumb_far_jump_used_p (void)
{
rtx insn;
+ bool far_jump = false;
+ unsigned int func_size = 0;
/* This test is only important for leaf functions. */
/* assert (!leaf_function_p ()); */
@@ -22788,6 +22795,26 @@ thumb_far_jump_used_p (void)
{
if (JUMP_P (insn) && get_attr_far_jump (insn) == FAR_JUMP_YES)
{
+ far_jump = true;
+ }
+ func_size += get_attr_length (insn);
+ }
+
+ /* Attribute far_jump will always be true for thumb1 before
+ shorten_branch pass. So checking far_jump attribute before
+ shorten_branch isn't much useful.
+
+ Following heuristic tries to estimate more accruately if a far jump
+ may finally be used. The heuristic is very conservative as there is
+ no chance to roll-back the decision of not to use far jump.
+
+ Thumb1 long branch offset is -2048 to 2046. The worst case is each
+ 2-byte insn is assiociated with a 4 byte constant pool. Using
+ function size 2048/3 as the threshold is conservative enough. */
+ if (far_jump)
+ {
+ if ((func_size * 3) >= 2048)
+ {
/* Record the fact that we have decided that
the function does use far jumps. */
cfun->machine->far_jump_used = 1;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cdff281c930..c8d46d5bd63 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2013-04-15 Joey Ye <joey.ye@arm.com>
+
+ * gcc.target/arm/thumb1-far-jump-1.c: New test.
+ * gcc.target/arm/thumb1-far-jump-2.c: New test.
+
2013-04-14 Mikael Morin <mikael@gcc.gnu.org>
PR fortran/56816
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c
new file mode 100644
index 00000000000..eb16d2fc99e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c
@@ -0,0 +1,34 @@
+/* Check for thumb1 far jump. Shouldn't save lr for small leaf functions
+ * even with a branch in it. */
+/* { dg-options "-Os" } */
+/* { dg-skip-if "" { ! { arm_thumb1 } } } */
+
+void f()
+{
+ for (;;);
+}
+
+volatile int g;
+void f2(int i)
+{
+ if (i) g=0;
+}
+
+void f3(int i)
+{
+ if (i) {
+ g=0;
+ g=1;
+ g=2;
+ g=3;
+ g=4;
+ g=5;
+ g=6;
+ g=7;
+ g=8;
+ g=9;
+ }
+}
+
+/* { dg-final { scan-assembler-not "push.*lr" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c
new file mode 100644
index 00000000000..c6878f8ef8b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c
@@ -0,0 +1,57 @@
+/* Check for thumb1 far jump. This is the extreme case that far jump
+ * will be used with minimum number of instructions. By passing this case
+ * it means the heuristic of saving lr for far jump meets the most extreme
+ * requirement. */
+/* { dg-options "-Os" } */
+/* { dg-skip-if "" { ! { arm_thumb1 } } } */
+
+volatile register r4 asm("r4");
+void f3(int i)
+{
+#define GO(n) \
+ extern volatile int g_##n; \
+ r4=(int)&g_##n;
+
+#define GO8(n) \
+ GO(n##_0) \
+ GO(n##_1) \
+ GO(n##_2) \
+ GO(n##_3) \
+ GO(n##_4) \
+ GO(n##_5) \
+ GO(n##_6) \
+ GO(n##_7)
+
+#define GO64(n) \
+ GO8(n##_0) \
+ GO8(n##_1) \
+ GO8(n##_2) \
+ GO8(n##_3) \
+ GO8(n##_4) \
+ GO8(n##_5) \
+ GO8(n##_6) \
+ GO8(n##_7) \
+
+#define GO498(n) \
+ GO64(n##_0) \
+ GO64(n##_1) \
+ GO64(n##_2) \
+ GO64(n##_3) \
+ GO64(n##_4) \
+ GO64(n##_5) \
+ GO64(n##_6) \
+ GO8(n##_0) \
+ GO8(n##_1) \
+ GO8(n##_2) \
+ GO8(n##_3) \
+ GO8(n##_4) \
+ GO8(n##_5) \
+ GO(n##_0) \
+ GO(n##_1) \
+
+ if (i) {
+ GO498(0);
+ }
+}
+
+/* { dg-final { scan-assembler "push.*lr" } } */