G'day all,

As I wrote previously on gcc-patches (
http://gcc.gnu.org/ml/gcc-patches/2007-06/msg00244.html ), I'm working
on code to get the MaverickCrunch Floating-Point Co-processor supported
on ARM.  I mentioned previously that you can't use the same opcodes for
testing GE on the MaverickCrunch, as you use on ARM.  See the below
table for NZCV values from MaverickCrunch.

MaverickCrunch - (cfcmp*):
        N  Z  C  V
A == B  0  1  0  0
A <  B  1  0  0  0
A >  B  1  0  0  1
unord   0  0  0  0

ARM/FPA/VFP - (cmp*):
        N  Z  C  V
A == B  0  1  1  0
A <  B  1  0  0  0
A >  B  0  0  1  0
unord   0  0  1  1

I've added a new "maverick_comparison_operator" similar to
"arm_comparison_operator" to predicates.md, and added the right bits to
arm.md, as shown below:

;; Special predication pattern for Maverick Crunch floating-point

(define_cond_exec
  [(match_operator 0 "maverick_comparison_operator"
    [(match_operand:CCFP 1 "cc_register" "")
     (const_int 0)])]
  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
  ""
)

All the other predicates are fine, since they are only used in floating
point comparisons.  But "ge" is also used for integer comparisons.  Now,
my problem is with the following code: 

; Special pattern to match GE for MAVERICK.
(define_insn "*arm_bge"
  [(set (pc)
        (if_then_else (ge (match_operand 1 "cc_register" "") (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
  "*
  gcc_assert (!arm_ccfsm_state);
  if (get_attr_cirrus (prev_active_insn(insn)) == CIRRUS_COMPARE)
      return \"beq\\t%l0\;bvs\\t%l0\"; else return \"bge\\t%l0\;nop\";
  "
  [(set_attr "conds" "jump_clob")
   (set_attr "length" "8")]
)

As you can see, I need to replace all bge with a maverick crunch
equivalent.  However, "bge" is still also used with integer comparisons,
e.g:

        double a, b;
        if (a>=b) {

produces:

        cfcmpd  r15, mvd1, mvd0
        beq     .L4
        bvs     .L4
        b       .L2
.L4:

I haven't got a good example for the integer ge, but unsidf makes use of
ge (NB, I disabled MaverickCrunch 64-bit support for clarity, and
bugfixing):

        unsigned int e = 9;
        double e_d = e;

produces:

        mov     r3, #9
        str     r3, [fp, #-32]
        ldr     r0, [fp, #-32]
        bl      __aeabi_i2d
        str     r0, [fp, #-44]
        str     r1, [fp, #-40]
        ldr     r3, [fp, #-32]
        cmp     r3, #0
        bge     .L2
        nop
        mov     r0, r0  @ nop
        mov     r0, r0  @ nop
        cfldrd  mvd0, .L4
        mov     r0, r0  @ nop
        cfldrd  mvd1, [fp, #-44]
        mov     r0, r0  @ nop
        cfaddd  mvd1, mvd1, mvd0
        cfstrd  mvd1, [fp, #-44]
.L2:

This seems to work fine for C code, but when I generate C++ code, I get
errors.  Can anyone suggest a better way of writing the above code?  I'd
rather the jump_clob didn't actually happen unless it was definitely a
cirrus compare, and not an ARM compare, but I can't seem to write the
code correctly.

Also, is "(get_attr_cirrus (prev_active_insn(insn)) == CIRRUS_COMPARE)"
the best way to find out if the last compare instruction was a cirrus
compare, or an ARM compare?  Should I add a new routine to find the last
compare insn, e.g. prev_compare_insn???  I know that a branch doesn't
have to be directly after a comparison.

This and invalid coprocessor offset issue are the only two outstanding
bugs for MaverickCrunch support on the Cirrus EP93xx.

Reply via email to