This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH ARM] Improve neg[sd]f2 for vfp
- From: Richard Earnshaw <Richard dot Earnshaw at buzzard dot freeserve dot co dot uk>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Richard dot Earnshaw at buzzard dot freeserve dot co dot uk
- Date: Thu, 12 May 2005 09:17:19 +0100
- Subject: [PATCH ARM] Improve neg[sd]f2 for vfp
This patch improves the code we generate when we have VFP and are using
negation in some circumstances where the value has to go via integer
registers. For exmaple, if we are compiling -with -mfpu=vfp
-mfloat-abi=softfp and have:
double f;
double a () { return -f; }
we would previously load f into a VFP register, negate it, transfer it to
r0,r1 and return. With this patch we can do all that in integer
registers, generating
a: ldr r3, .L3
ldmia r3, {r0-r1}
eor r0, r0, #-2147483648
bx lr
.L3:
.word f
Similarly, if we have
double x(void);
void p (int, double);
void q()
{
p(1, -x());
}
we would end up doing similar contortions. With the patch we now generate:
q:
str lr, [sp, #-4]!
bl x
mov r2, r1
eor r1, r0, #-2147483648
mov r0, #1
ldr lr, [sp], #4
b p
However, if we are already using VFP registers (or if there's an equal
choice for the register allocator) then we'll still use the VFP fneg[sd]
instructions.
double a,c;
void z()
{
c = -a;
}
z:
ldr r3, .L11
fldd d7, [r3, #0]
ldr r3, .L11+4
fnegd d7, d7
fstd d7, [r3, #0]
bx lr
Fully tested on arm-elf and by a series of inspections for VFP code.
Oh, finally I fixed a latent bug. The constraints on these two patterns
were using + on operand zero. That was just bogus.
2005-05-12 Richard Earnshaw <richard.earnshaw@arm.com>
* arm/vfp.md (negsf2_vfp): Add alternative using integer registers.
(negdf2_vfp): Likewise. Convert to define_insn_and_split and split
the alternatives using integer registers into the appropriate
primitives.
Index: config/arm/vfp.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/vfp.md,v
retrieving revision 1.11
diff -p -p -r1.11 vfp.md
*** config/arm/vfp.md 27 Apr 2005 16:09:03 -0000 1.11
--- config/arm/vfp.md 12 May 2005 08:02:08 -0000
***************
*** 298,317 ****
)
(define_insn "*negsf2_vfp"
! [(set (match_operand:SF 0 "s_register_operand" "+w")
! (neg:SF (match_operand:SF 1 "s_register_operand" "w")))]
"TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
! "fnegs%?\\t%0, %1"
[(set_attr "predicable" "yes")
(set_attr "type" "ffarith")]
)
! (define_insn "*negdf2_vfp"
! [(set (match_operand:DF 0 "s_register_operand" "+w")
! (neg:DF (match_operand:DF 1 "s_register_operand" "w")))]
"TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
! "fnegd%?\\t%P0, %P1"
[(set_attr "predicable" "yes")
(set_attr "type" "ffarith")]
)
--- 298,356 ----
)
(define_insn "*negsf2_vfp"
! [(set (match_operand:SF 0 "s_register_operand" "=w,?r")
! (neg:SF (match_operand:SF 1 "s_register_operand" "w,r")))]
"TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
! "@
! fnegs%?\\t%0, %1
! eor%?\\t%0, %1, #-2147483648"
[(set_attr "predicable" "yes")
(set_attr "type" "ffarith")]
)
! (define_insn_and_split "*negdf2_vfp"
! [(set (match_operand:DF 0 "s_register_operand" "=w,?r,?r")
! (neg:DF (match_operand:DF 1 "s_register_operand" "w,0,r")))]
"TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
! "@
! fnegd%?\\t%P0, %P1
! #
! #"
! "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP && reload_completed
! && arm_general_register_operand (operands[0], DFmode)"
! [(set (match_dup 0) (match_dup 1))]
! "
! if (REGNO (operands[0]) == REGNO (operands[1]))
! {
! operands[0] = gen_highpart (SImode, operands[0]);
! operands[1] = gen_rtx_XOR (SImode, operands[0], GEN_INT (0x80000000));
! }
! else
! {
! rtx in_hi, in_lo, out_hi, out_lo;
!
! in_hi = gen_rtx_XOR (SImode, gen_highpart (SImode, operands[1]),
! GEN_INT (0x80000000));
! in_lo = gen_lowpart (SImode, operands[1]);
! out_hi = gen_highpart (SImode, operands[0]);
! out_lo = gen_lowpart (SImode, operands[0]);
!
! if (REGNO (in_lo) == REGNO (out_hi))
! {
! emit_insn (gen_rtx_SET (SImode, out_lo, in_lo));
! operands[0] = out_hi;
! operands[1] = in_hi;
! }
! else
! {
! emit_insn (gen_rtx_SET (SImode, out_hi, in_hi));
! operands[0] = out_lo;
! operands[1] = in_lo;
! }
! }
! "
[(set_attr "predicable" "yes")
+ (set_attr "length" "4,4,8")
(set_attr "type" "ffarith")]
)