mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-19 01:50:34 +08:00
arm.c (count_insns_for_constant): Rework to support counting for thumb2 immediates as well.
* arm.c (count_insns_for_constant): Rework to support counting for thumb2 immediates as well. (find_best_start): Split out from arm_gen_constant. (arm_gen_constant): Rework to support XOR with immediate. From-SVN: r153698
This commit is contained in:
parent
d48a31968c
commit
162e4591aa
@ -1,3 +1,10 @@
|
||||
2009-10-29 Richard Earnshaw <rearnsha@arm.com>
|
||||
|
||||
* arm.c (count_insns_for_constant): Rework to support counting for
|
||||
thumb2 immediates as well.
|
||||
(find_best_start): Split out from arm_gen_constant.
|
||||
(arm_gen_constant): Rework to support XOR with immediate.
|
||||
|
||||
2009-10-29 Chao-ying Fu <fu@mips.com>
|
||||
|
||||
* config/mips/mips.c (mips_emit_unary, mips_force_unary): New
|
||||
|
@ -2407,20 +2407,24 @@ arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
|
||||
1);
|
||||
}
|
||||
|
||||
/* Return the number of ARM instructions required to synthesize the given
|
||||
constant. */
|
||||
/* Return the number of instructions required to synthesize the given
|
||||
constant, if we start emitting them from bit-position I. */
|
||||
static int
|
||||
count_insns_for_constant (HOST_WIDE_INT remainder, int i)
|
||||
{
|
||||
HOST_WIDE_INT temp1;
|
||||
int step_size = TARGET_ARM ? 2 : 1;
|
||||
int num_insns = 0;
|
||||
|
||||
gcc_assert (TARGET_ARM || i == 0);
|
||||
|
||||
do
|
||||
{
|
||||
int end;
|
||||
|
||||
if (i <= 0)
|
||||
i += 32;
|
||||
if (remainder & (3 << (i - 2)))
|
||||
if (remainder & (((1 << step_size) - 1) << (i - step_size)))
|
||||
{
|
||||
end = i - 8;
|
||||
if (end < 0)
|
||||
@ -2429,13 +2433,77 @@ count_insns_for_constant (HOST_WIDE_INT remainder, int i)
|
||||
| ((i < end) ? (0xff >> (32 - end)) : 0));
|
||||
remainder &= ~temp1;
|
||||
num_insns++;
|
||||
i -= 6;
|
||||
i -= 8 - step_size;
|
||||
}
|
||||
i -= 2;
|
||||
i -= step_size;
|
||||
} while (remainder);
|
||||
return num_insns;
|
||||
}
|
||||
|
||||
static int
|
||||
find_best_start (HOST_WIDE_INT remainder)
|
||||
{
|
||||
int best_consecutive_zeros = 0;
|
||||
int i;
|
||||
int best_start = 0;
|
||||
|
||||
/* If we aren't targetting ARM, the best place to start is always at
|
||||
the bottom. */
|
||||
if (! TARGET_ARM)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
{
|
||||
int consecutive_zeros = 0;
|
||||
|
||||
if (!(remainder & (3 << i)))
|
||||
{
|
||||
while ((i < 32) && !(remainder & (3 << i)))
|
||||
{
|
||||
consecutive_zeros += 2;
|
||||
i += 2;
|
||||
}
|
||||
if (consecutive_zeros > best_consecutive_zeros)
|
||||
{
|
||||
best_consecutive_zeros = consecutive_zeros;
|
||||
best_start = i - consecutive_zeros;
|
||||
}
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* So long as it won't require any more insns to do so, it's
|
||||
desirable to emit a small constant (in bits 0...9) in the last
|
||||
insn. This way there is more chance that it can be combined with
|
||||
a later addressing insn to form a pre-indexed load or store
|
||||
operation. Consider:
|
||||
|
||||
*((volatile int *)0xe0000100) = 1;
|
||||
*((volatile int *)0xe0000110) = 2;
|
||||
|
||||
We want this to wind up as:
|
||||
|
||||
mov rA, #0xe0000000
|
||||
mov rB, #1
|
||||
str rB, [rA, #0x100]
|
||||
mov rB, #2
|
||||
str rB, [rA, #0x110]
|
||||
|
||||
rather than having to synthesize both large constants from scratch.
|
||||
|
||||
Therefore, we calculate how many insns would be required to emit
|
||||
the constant starting from `best_start', and also starting from
|
||||
zero (i.e. with bit 31 first to be output). If `best_start' doesn't
|
||||
yield a shorter sequence, we may as well use zero. */
|
||||
if (best_start != 0
|
||||
&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
|
||||
&& (count_insns_for_constant (remainder, 0) <=
|
||||
count_insns_for_constant (remainder, best_start)))
|
||||
best_start = 0;
|
||||
|
||||
return best_start;
|
||||
}
|
||||
|
||||
/* Emit an instruction with the indicated PATTERN. If COND is
|
||||
non-NULL, conditionalize the execution of the instruction on COND
|
||||
being true. */
|
||||
@ -2459,6 +2527,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
{
|
||||
int can_invert = 0;
|
||||
int can_negate = 0;
|
||||
int final_invert = 0;
|
||||
int can_negate_initial = 0;
|
||||
int can_shift = 0;
|
||||
int i;
|
||||
@ -2470,6 +2539,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
int insns = 0;
|
||||
unsigned HOST_WIDE_INT temp1, temp2;
|
||||
unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
|
||||
int step_size = TARGET_ARM ? 2 : 1;
|
||||
|
||||
/* Find out which operations are safe for a given CODE. Also do a quick
|
||||
check for degenerate cases; these can occur when DImode operations
|
||||
@ -2543,14 +2613,15 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We don't know how to handle other cases yet. */
|
||||
gcc_assert (remainder == 0xffffffff);
|
||||
|
||||
if (generate)
|
||||
emit_constant_insn (cond,
|
||||
gen_rtx_SET (VOIDmode, target,
|
||||
gen_rtx_NOT (mode, source)));
|
||||
return 1;
|
||||
if (remainder == 0xffffffff)
|
||||
{
|
||||
if (generate)
|
||||
emit_constant_insn (cond,
|
||||
gen_rtx_SET (VOIDmode, target,
|
||||
gen_rtx_NOT (mode, source)));
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MINUS:
|
||||
/* We treat MINUS as (val - source), since (source - val) is always
|
||||
@ -3001,9 +3072,25 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
|
||||
if ((code == AND)
|
||||
|| (code != IOR && can_invert && num_bits_set > 16))
|
||||
remainder = (~remainder) & 0xffffffff;
|
||||
remainder ^= 0xffffffff;
|
||||
else if (code == PLUS && num_bits_set > 16)
|
||||
remainder = (-remainder) & 0xffffffff;
|
||||
|
||||
/* For XOR, if more than half the bits are set and there's a sequence
|
||||
of more than 8 consecutive ones in the pattern then we can XOR by the
|
||||
inverted constant and then invert the final result; this may save an
|
||||
instruction and might also lead to the final mvn being merged with
|
||||
some other operation. */
|
||||
else if (code == XOR && num_bits_set > 16
|
||||
&& (count_insns_for_constant (remainder ^ 0xffffffff,
|
||||
find_best_start
|
||||
(remainder ^ 0xffffffff))
|
||||
< count_insns_for_constant (remainder,
|
||||
find_best_start (remainder))))
|
||||
{
|
||||
remainder ^= 0xffffffff;
|
||||
final_invert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
can_invert = 0;
|
||||
@ -3022,63 +3109,8 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
/* ??? Use thumb2 replicated constants when the high and low halfwords are
|
||||
the same. */
|
||||
{
|
||||
int best_start = 0;
|
||||
if (!TARGET_THUMB2)
|
||||
{
|
||||
int best_consecutive_zeros = 0;
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
{
|
||||
int consecutive_zeros = 0;
|
||||
|
||||
if (!(remainder & (3 << i)))
|
||||
{
|
||||
while ((i < 32) && !(remainder & (3 << i)))
|
||||
{
|
||||
consecutive_zeros += 2;
|
||||
i += 2;
|
||||
}
|
||||
if (consecutive_zeros > best_consecutive_zeros)
|
||||
{
|
||||
best_consecutive_zeros = consecutive_zeros;
|
||||
best_start = i - consecutive_zeros;
|
||||
}
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* So long as it won't require any more insns to do so, it's
|
||||
desirable to emit a small constant (in bits 0...9) in the last
|
||||
insn. This way there is more chance that it can be combined with
|
||||
a later addressing insn to form a pre-indexed load or store
|
||||
operation. Consider:
|
||||
|
||||
*((volatile int *)0xe0000100) = 1;
|
||||
*((volatile int *)0xe0000110) = 2;
|
||||
|
||||
We want this to wind up as:
|
||||
|
||||
mov rA, #0xe0000000
|
||||
mov rB, #1
|
||||
str rB, [rA, #0x100]
|
||||
mov rB, #2
|
||||
str rB, [rA, #0x110]
|
||||
|
||||
rather than having to synthesize both large constants from scratch.
|
||||
|
||||
Therefore, we calculate how many insns would be required to emit
|
||||
the constant starting from `best_start', and also starting from
|
||||
zero (i.e. with bit 31 first to be output). If `best_start' doesn't
|
||||
yield a shorter sequence, we may as well use zero. */
|
||||
if (best_start != 0
|
||||
&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
|
||||
&& (count_insns_for_constant (remainder, 0) <=
|
||||
count_insns_for_constant (remainder, best_start)))
|
||||
best_start = 0;
|
||||
}
|
||||
|
||||
/* Now start emitting the insns. */
|
||||
i = best_start;
|
||||
i = find_best_start (remainder);
|
||||
do
|
||||
{
|
||||
int end;
|
||||
@ -3106,7 +3138,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (remainder && subtargets)
|
||||
if ((final_invert || remainder) && subtargets)
|
||||
new_src = gen_reg_rtx (mode);
|
||||
else
|
||||
new_src = target;
|
||||
@ -3141,21 +3173,23 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
|
||||
code = PLUS;
|
||||
|
||||
insns++;
|
||||
if (TARGET_ARM)
|
||||
i -= 6;
|
||||
else
|
||||
i -= 7;
|
||||
i -= 8 - step_size;
|
||||
}
|
||||
/* Arm allows rotates by a multiple of two. Thumb-2 allows arbitrary
|
||||
shifts. */
|
||||
if (TARGET_ARM)
|
||||
i -= 2;
|
||||
else
|
||||
i--;
|
||||
i -= step_size;
|
||||
}
|
||||
while (remainder);
|
||||
}
|
||||
|
||||
if (final_invert)
|
||||
{
|
||||
if (generate)
|
||||
emit_constant_insn (cond, gen_rtx_SET (VOIDmode, target,
|
||||
gen_rtx_NOT (mode, source)));
|
||||
insns++;
|
||||
}
|
||||
|
||||
return insns;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user