I extracted the MFPGPR hunks from Peter Bergner's "[PATCH] Add POWER6
machine description", posted on 2006-11-01 and dropped them into
gcc-4.0.3, but the result fails with "error: insn does not satisfy its
constraints":
.../src/gcc-4.0.3/gcc/config/rs6000/darwin-ldouble.c: In function
'__gcc_qadd':
.../src/gcc-4.0.3/gcc/config/rs6000/darwin-ldouble.c:127: error: insn
does not satisfy its constraints:
(insn 193 64 152 4
.../src/gcc-4.0.3/gcc/config/rs6000/darwin-ldouble.c:110 (set (reg:DF 10 10)
(plus:DF (reg:DF 34 2 [orig:124 D.1365 ] [124])
(reg:DF 32 0 [146]))) 177 {*adddf3_fpr} (nil)
(expr_list:REG_DEAD (reg:DF 34 2 [orig:124 D.1365 ] [124])
(expr_list:REG_DEAD (reg:DF 32 0 [146])
(nil))))
.../src/gcc-4.0.3/gcc/config/rs6000/darwin-ldouble.c:127: internal
compiler error: in copyprop_hardreg_forward_1, at regrename.c:1583
Please submit a full bug report,
with preprocessed source if appropriate.
The complaint is about operand[0], which is an integer register with
DFmode. FYI, I did my own work to put mftgpr/mffgpr into GCC-4.0.x last
year, and ran into this same problem. I solved it by changing the
operand predicates everywhere I found an "f" constraint so that the
predicate only allowed FP regs rather than the permissive
gpc_reg_operand. Alhough this worked, I didn't like it because the
change was very invasive, so when I saw that Peter's patch didn't muck
with the FP operand predicates, I wanted to use it instead. Alas, I
have the same problem with integer registers matching gpc_reg_operand,
but not satisfying the "f" constraint. What am I missing? Is there
something inhospitable about GCC-4.0 vs. the trunk for Peter's
changes? The patch I used is attached.
Thanks, Greg
2006-11-01 Pete Steinmetz <[EMAIL PROTECTED]>
Peter Bergner <[EMAIL PROTECTED]>
* config/rs6000/rs6000.md (define_attr "type"): Add mffgpr
and mftgpr attributes.
(floatsidf2,fix_truncdfsi2): use TARGET_MFPGPR.
(fix_truncdfsi2_mfpgpr): New.
(floatsidf_ppc64_mfpgpr): New.
(floatsidf_ppc64): Added !TARGET_MFPGPR condition.
(movdf_hardfloat64_mfpgpr,movdi_mfpgpr): New.
(movdf_hardfloat64): Added !TARGET_MFPGPR condition.
(movdi_internal64): Added !TARGET_MFPGPR and related conditions.
* config/rs6000/rs6000.h (TARGET_MFPGPR): New.
(SECONDARY_MEMORY_NEEDED): Use TARGET_MFPGPR.
(SECONDARY_MEMORY_NEEDED): Added mode!=DFmode and mode!=DImode
conditions.
Index: gcc-4.0.3/gcc/config/rs6000/rs6000.h
===================================================================
--- gcc-4.0.3.orig/gcc/config/rs6000/rs6000.h
+++ gcc-4.0.3/gcc/config/rs6000/rs6000.h
@@ -201,6 +201,9 @@ extern int target_flags;
/* Use single field mfcr instruction. */
#define MASK_MFCRF 0x00080000
+/* Use FP <-> GP register moves. */
+#define MASK_MFPGPR 0x00200000
+
/* The only remaining free bits are 0x00600000. linux64.h uses
0x00100000, and sysv4.h uses 0x00800000 -> 0x40000000.
0x80000000 is not available because target_flags is signed. */
@@ -223,6 +226,7 @@ extern int target_flags;
#define TARGET_SCHED_PROLOG (target_flags & MASK_SCHED_PROLOG)
#define TARGET_ALTIVEC (target_flags & MASK_ALTIVEC)
#define TARGET_AIX_STRUCT_RET (target_flags & MASK_AIX_STRUCT_RET)
+#define TARGET_MFPGPR (target_flags & MASK_MFPGPR)
/* Define TARGET_MFCRF if the target assembler supports the optional
field operand for mfcr and the target processor supports the
@@ -234,7 +238,6 @@ extern int target_flags;
#define TARGET_MFCRF 0
#endif
-
#define TARGET_32BIT (! TARGET_64BIT)
#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT)
#define TARGET_UPDATE (! TARGET_NO_UPDATE)
@@ -365,6 +368,10 @@ extern int target_flags;
N_("Generate single field mfcr instruction")}, \
{"no-mfcrf", - MASK_MFCRF, \
N_("Do not generate single field mfcr instruction")},\
+ {"mfpgpr", MASK_MFPGPR, \
+ N_("Generate moves between floating and general
registers")}, \
+ {"no-mfpgpr", - MASK_MFPGPR,
\
+ N_("Do not generate moves between floating and general
registers")},\
SUBTARGET_SWITCHES \
{"", TARGET_DEFAULT | MASK_SCHED_PROLOG, \
""}}
@@ -1413,12 +1420,18 @@ enum reg_class
secondary_reload_class (CLASS, MODE, IN)
/* If we are copying between FP or AltiVec registers and anything
- else, we need a memory location. */
-
-#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
- ((CLASS1) != (CLASS2) && ((CLASS1) == FLOAT_REGS \
- || (CLASS2) == FLOAT_REGS \
- || (CLASS1) == ALTIVEC_REGS \
+ else, we need a memory location. The exception is when we are
+ targeting ppc64 and the move to/from fpr to gpr instructions
+ are available.*/
+
+#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
+ ((CLASS1) != (CLASS2) && (((CLASS1) == FLOAT_REGS \
+ && (!TARGET_MFPGPR || !TARGET_POWERPC64 \
+ || ((MODE != DFmode) && (MODE != DImode)))) \
+ || ((CLASS2) == FLOAT_REGS \
+ && (!TARGET_MFPGPR || !TARGET_POWERPC64 \
+ || ((MODE != DFmode) && (MODE != DImode)))) \
+ || (CLASS1) == ALTIVEC_REGS \
|| (CLASS2) == ALTIVEC_REGS))
/* Return the maximum number of consecutive registers
Index: gcc-4.0.3/gcc/config/rs6000/rs6000.md
===================================================================
--- gcc-4.0.3.orig/gcc/config/rs6000/rs6000.md
+++ gcc-4.0.3/gcc/config/rs6000/rs6000.md
@@ -5120,6 +5120,12 @@
emit_insn (gen_spe_floatsidf2 (operands[0], operands[1]));
DONE;
}
+ if (TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS)
+ {
+ rtx t1 = gen_reg_rtx (DImode);
+ emit_insn (gen_floatsidf_ppc64_mfpgpr (operands[0], operands[1], t1));
+ DONE;
+ }
if (TARGET_POWERPC64)
{
rtx mem = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
@@ -5283,6 +5289,14 @@
DONE;
}
operands[2] = gen_reg_rtx (DImode);
+ if (TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
+ && gpc_reg_operand(operands[0], GET_MODE (operands[0])))
+ {
+ operands[3] = gen_reg_rtx (DImode);
+ emit_insn (gen_fix_truncdfsi2_mfpgpr (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+ }
operands[3] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
}")
@@ -5320,6 +5334,20 @@
DONE;
}")
+(define_insn_and_split "fix_truncdfsi2_mfpgpr"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
+ (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
+ (clobber (match_operand:DI 3 "gpc_reg_operand" "=r"))]
+ "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS"
+ "#"
+ "&& 1"
+ [(set (match_dup 2) (unspec:DI [(fix:SI (match_dup 1))] UNSPEC_FCTIWZ))
+ (set (match_dup 3) (match_dup 2))
+ (set (match_dup 0) (subreg:SI (match_dup 3) 4))]
+ ""
+ [(set_attr "length" "12")])
+
; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
; rather than (set (subreg:SI (reg)) (fix:SI ...))
; because the first makes it clear that operand 0 is not live
@@ -5345,13 +5373,24 @@
"fcfid %0,%1"
[(set_attr "type" "fp")])
+(define_insn_and_split "floatsidf_ppc64_mfpgpr"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (clobber (match_operand:DI 2 "gpc_reg_operand" "=r"))]
+ "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS"
+ "#"
+ "&& 1"
+ [(set (match_dup 2) (sign_extend:DI (match_dup 1)))
+ (set (match_dup 0) (float:DF (match_dup 2)))]
+ "")
+
(define_insn_and_split "floatsidf_ppc64"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
(clobber (match_operand:DI 2 "memory_operand" "=o"))
(clobber (match_operand:DI 3 "gpc_reg_operand" "=r"))
(clobber (match_operand:DI 4 "gpc_reg_operand" "=f"))]
- "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+ "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS"
"#"
"&& 1"
[(set (match_dup 3) (sign_extend:DI (match_dup 1)))
@@ -8223,10 +8262,36 @@
; ld/std require word-aligned displacements -> 'Y' constraint.
; List Y->r and r->Y before r->r for reload.
+(define_insn "*movdf_hardfloat64_mfpgpr"
+ [(set (match_operand:DF 0 "nonimmediate_operand"
"=Y,r,!r,f,f,m,*c*l,!r,*h,!r,!r,!r,r,f")
+ (match_operand:DF 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F,f,r"))]
+ "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
+ && (gpc_reg_operand (operands[0], DFmode)
+ || gpc_reg_operand (operands[1], DFmode))"
+ "@
+ std%U0%X0 %1,%0
+ ld%U1%X1 %0,%1
+ mr %0,%1
+ fmr %0,%1
+ lfd%U1%X1 %0,%1
+ stfd%U0%X0 %1,%0
+ mt%0 %1
+ mf%1 %0
+ {cror 0,0,0|nop}
+ #
+ #
+ #
+ mftgpr %0,%1
+ mffgpr %0,%1"
+ [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*,*,*")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
+
+; ld/std require word-aligned displacements -> 'Y' constraint.
+; List Y->r and r->Y before r->r for reload.
(define_insn "*movdf_hardfloat64"
[(set (match_operand:DF 0 "nonimmediate_operand"
"=Y,r,!r,f,f,m,!cl,!r,!h,!r,!r,!r")
(match_operand:DF 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F"))]
- "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
+ "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
"@
@@ -8574,10 +8639,35 @@
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
+(define_insn "*movdi_mfpgpr"
+ [(set (match_operand:DI 0 "nonimmediate_operand"
"=r,r,m,r,r,r,r,*f,*f,m,r,*h,*h,r,*f")
+ (match_operand:DI 1 "input_operand"
"r,m,r,I,L,nF,R,f,m,f,*h,r,0,*f,r"))]
+ "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
+ && (gpc_reg_operand (operands[0], DImode)
+ || gpc_reg_operand (operands[1], DImode))"
+ "@
+ mr %0,%1
+ ld%U1%X1 %0,%1
+ std%U0%X0 %1,%0
+ li %0,%1
+ lis %0,%v1
+ #
+ {cal|la} %0,%a1
+ fmr %0,%1
+ lfd%U1%X1 %0,%1
+ stfd%U0%X0 %1,%0
+ mf%1 %0
+ mt%0 %1
+ {cror 0,0,0|nop}
+ mftgpr %0,%1
+ mffgpr %0,%1"
+ [(set_attr "type"
"*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,*,*")
+ (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4,4")])
+
(define_insn "*movdi_internal64"
[(set (match_operand:DI 0 "nonimmediate_operand"
"=r,r,m,r,r,r,r,*f,*f,m,r,*h,*h")
(match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,f,m,f,*h,r,0"))]
- "TARGET_POWERPC64
+ "TARGET_POWERPC64 && (!TARGET_MFPGPR || !TARGET_HARD_FLOAT || !TARGET_FPRS)
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@