+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.
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
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 ()); */
{
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;
--- /dev/null
+/* 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" } } */
+
--- /dev/null
+/* 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" } } */