diff options
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 43 |
2 files changed, 48 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 51b74eb..2cb26b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2004-11-18 Nicolas Pitre <nico@cam.org> + + * config/arm/arm.c (const_double_needs_minipool): New function to + determine if a CONST_DOUBLE should be pushed to the minipool. + (note_invalid_constants): Use it. + 2004-11-18 Paul Brook <paul@codesourcery.com> * config/arm/arm.c (target_float_switch): New variable.. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 80f1f58..192fdb4 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -7258,6 +7258,45 @@ push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc, minipool_fix_tail = fix; } +/* Determine if a CONST_DOUBLE should be pushed to the minipool */ +static bool +const_double_needs_minipool (rtx val) +{ + long parts[2]; + + /* thumb only knows to load a CONST_DOUBLE from memory at the moment */ + if (TARGET_THUMB) + return true; + + if (GET_MODE (val) == DFmode) + { + REAL_VALUE_TYPE r; + if (!TARGET_SOFT_FLOAT) + return true; + REAL_VALUE_FROM_CONST_DOUBLE (r, val); + REAL_VALUE_TO_TARGET_DOUBLE (r, parts); + } + else if (GET_MODE (val) != VOIDmode) + return true; + else + { + parts[0] = CONST_DOUBLE_LOW (val); + parts[1] = CONST_DOUBLE_HIGH (val); + } + + /* Don't push anything to the minipool if a CONST_DOUBLE can be built with + a few ALU insns directly. On balance, the optimum is likely to be around + 3 insns, except when there are no load delay slots where it should be 4. + When optimizing for size, a limit of 3 allows saving at least one word + except for cases where a single minipool entry could be shared more than + 2 times which is rather unlikely to outweight the overall savings. */ + return ( arm_gen_constant (SET, SImode, NULL_RTX, parts[0], + NULL_RTX, NULL_RTX, 0, 0) + + arm_gen_constant (SET, SImode, NULL_RTX, parts[1], + NULL_RTX, NULL_RTX, 0, 0) + > ((optimize_size || (tune_flags & FL_LDSCHED)) ? 3 : 4)); +} + /* Scan INSN and note any of its operands that need fixing. If DO_PUSHES is false we do not actually push any of the fixups needed. The function returns TRUE is any fixups were needed/pushed. @@ -7294,7 +7333,9 @@ note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes) { rtx op = recog_data.operand[opno]; - if (CONSTANT_P (op)) + if (CONSTANT_P (op) + && (GET_CODE (op) != CONST_DOUBLE + || const_double_needs_minipool (op))) { if (do_pushes) push_minipool_fix (insn, address, recog_data.operand_loc[opno], |