===================================================================
@@ -31,7 +31,11 @@
extern const char *output_block_move (rtx *);
extern const char *output_jump (enum rtx_code, int, int);
extern void print_operand_address (FILE *, rtx);
-extern int pdp11_register_move_cost (enum reg_class, enum reg_class);
+extern bool pdp11_cannot_change_mode_class (enum machine_mode,
+ enum machine_mode, enum reg_class);
+extern bool pdp11_secondary_memory_needed (reg_class_t, reg_class_t,
+ enum machine_mode);
+
#endif /* RTX_CODE */
extern void output_ascii (FILE *, const char *, int);
===================================================================
@@ -35,3 +35,12 @@
sh = INTVAL (op);
return (abs (sh) > 1 && abs (sh) <= 4);
})
+
+;; Accept anything general-operand accepts, except that registers must
+;; be FPU registers.
+(define_predicate "float_operand"
+ (if_then_else (match_code "reg")
+ (ior
+ (match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS")
+ (match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS"))
+ (match_test "general_operand (op, mode)")))
===================================================================
@@ -25,6 +25,7 @@
(define_constants
[
;; Register numbers
+ (RETVAL_REGNUM 0)
(FRAME_POINTER_REGNUM 5)
(STACK_POINTER_REGNUM 6)
(PC_REGNUM 7)
@@ -196,7 +197,7 @@
(define_expand "cbranchdf4"
[(set (cc0)
(compare (match_operand:DF 1 "general_operand")
- (match_operand:DF 2 "general_operand")))
+ (match_operand:DF 2 "register_or_const0_operand")))
(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator"
[(cc0) (const_int 0)])
@@ -318,11 +319,9 @@
}"
[(set_attr "length" "2,4,4,6")])
-;; do we have to supply all these moves? e.g. to
-;; NO_LOAD_FPU_REGs ?
(define_insn "movdf"
- [(set (match_operand:DF 0 "general_operand" "=a,fR,a,Q,g")
- (match_operand:DF 1 "general_operand" "fFR,a,Q,a,g"))]
+ [(set (match_operand:DF 0 "float_operand" "=a,fR,a,Q,g")
+ (match_operand:DF 1 "float_operand" "fFR,a,Q,a,g"))]
"TARGET_FPU"
"* if (which_alternative ==0 || which_alternative == 2)
return \"ldd %1, %0\";
@@ -334,11 +333,17 @@
[(set_attr "length" "2,2,10,10,32")])
(define_insn "movsf"
- [(set (match_operand:SF 0 "general_operand" "=g,r,g")
- (match_operand:SF 1 "general_operand" "r,rmF,g"))]
+ [(set (match_operand:SF 0 "float_operand" "=a,fR,a,Q,g")
+ (match_operand:SF 1 "float_operand" "fFR,a,Q,a,g"))]
"TARGET_FPU"
- "* return output_move_double (operands);"
- [(set_attr "length" "16,16,16")])
+ "* if (which_alternative ==0 || which_alternative == 2)
+ return \"{ldcfd|movof} %1, %0\";
+ else if (which_alternative == 1 || which_alternative == 3)
+ return \"{stcdf|movfo} %1, %0\";
+ else
+ return output_move_double (operands); "
+;; just a guess..
+ [(set_attr "length" "2,2,10,10,16")])
;; maybe fiddle a bit with move_ratio, then
;; let constraints only accept a register ...
@@ -386,15 +391,11 @@
;;- truncation instructions
(define_insn "truncdfsf2"
- [(set (match_operand:SF 0 "general_operand" "=r,R,Q")
- (float_truncate:SF (match_operand:DF 1 "register_operand" "a,a,a")))]
+ [(set (match_operand:SF 0 "general_operand" "=f,R,Q")
+ (float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))]
"TARGET_FPU"
"* if (which_alternative ==0)
{
- output_asm_insn(\"{stcdf|movfo} %1, -(sp)\", operands);
- output_asm_insn(\"mov (sp)+, %0\", operands);
- operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+1);
- output_asm_insn(\"mov (sp)+, %0\", operands);
return \"\";
}
else if (which_alternative == 1)
@@ -402,7 +403,7 @@
else
return \"{stcdf|movfo} %1, %0\";
"
- [(set_attr "length" "6,2,4")])
+ [(set_attr "length" "0,2,4")])
(define_expand "truncsihi2"
@@ -439,14 +440,14 @@
;;- sign extension instructions
(define_insn "extendsfdf2"
- [(set (match_operand:DF 0 "register_operand" "=a,a,a")
- (float_extend:DF (match_operand:SF 1 "general_operand" "r,R,Q")))]
+ [(set (match_operand:DF 0 "register_operand" "=f,a,a")
+ (float_extend:DF (match_operand:SF 1 "general_operand" "f,R,Q")))]
"TARGET_FPU"
"@
- mov %1, -(sp)\;{ldcfd|movof} (sp)+,%0
+ /* nothing */
{ldcfd|movof} %1, %0
{ldcfd|movof} %1, %0"
- [(set_attr "length" "4,2,4")])
+ [(set_attr "length" "0,2,4")])
;; does movb sign extend in register-to-register move?
(define_insn "extendqihi2"
@@ -856,6 +857,7 @@
}"
[(set_attr "length" "4,8,8,12,4,4,8,6,6,12")])
+;; FIXME This definition is wrong, PR/41822
(define_insn "andhi3"
[(set (match_operand:HI 0 "general_operand" "=rR,rR,Q,Q")
(and:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
===================================================================
@@ -216,7 +216,17 @@
#undef TARGET_TRAMPOLINE_INIT
#define TARGET_TRAMPOLINE_INIT pdp11_trampoline_init
-struct gcc_target targetm = TARGET_INITIALIZER;
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD pdp11_secondary_reload
+
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST pdp11_register_move_cost
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS pdp11_preferred_reload_class
+
+#undef TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS pdp11_preferred_output_reload_class
/* Implement TARGET_HANDLE_OPTION. */
@@ -417,7 +427,7 @@
/* get ACs */
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
- if (df_regs_ever_live_p (i) && call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ! call_used_regs[i])
via_ac = i;
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--)
@@ -1054,22 +1064,23 @@
/* NO MUL GEN LFPU NLFPU FPU ALL */
/* NO */ { 0, 0, 0, 0, 0, 0, 0},
-/* MUL */ { 0, 2, 2, 10, 22, 22, 22},
-/* GEN */ { 0, 2, 2, 10, 22, 22, 22},
-/* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
-/* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
-/* FPU */ { 0, 22, 22, 2, 2, 2, 22},
-/* ALL */ { 0, 22, 22, 10, 22, 22, 22}
+/* MUL */ { 0, 2, 2, 22, 22, 22, 22},
+/* GEN */ { 0, 2, 2, 22, 22, 22, 22},
+/* LFPU */ { 0, 22, 22, 2, 2, 2, 22},
+/* NLFPU */ { 0, 22, 22, 2, 10, 10, 22},
+/* FPU */ { 0, 22, 22, 2, 10, 10, 22},
+/* ALL */ { 0, 22, 22, 22, 22, 22, 22}
} ;
/* -- note that some moves are tremendously expensive,
because they require lots of tricks! do we have to
charge the costs incurred by secondary reload class
- -- as we do here with 22 -- or not ? */
+ -- as we do here with 10 -- or not ? */
-int
-pdp11_register_move_cost (enum reg_class c1, enum reg_class c2)
+static int
+pdp11_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t c1, reg_class_t c2)
{
return move_costs[(int)c1][(int)c2];
}
@@ -1634,6 +1645,108 @@
return 0;
}
+/* Implement CANNOT_CHANGE_MODE_CLASS. */
+bool
+pdp11_cannot_change_mode_class (enum machine_mode from,
+ enum machine_mode to,
+ enum reg_class rclass)
+{
+ /* Also, FPU registers contain a whole float value and the parts of
+ it are not separately accessible.
+
+ So we disallow all mode changes involving FPRs. */
+ if (FLOAT_MODE_P (from) != FLOAT_MODE_P (to))
+ return true;
+
+ return reg_classes_intersect_p (FPU_REGS, rclass);
+}
+
+/* TARGET_PREFERRED_RELOAD_CLASS
+
+ Given an rtx X being reloaded into a reg required to be
+ in class CLASS, return the class of reg to actually use.
+ In general this is just CLASS; but on some machines
+ in some cases it is preferable to use a more restrictive class.
+
+loading is easier into LOAD_FPU_REGS than FPU_REGS! */
+
+static reg_class_t
+pdp11_preferred_reload_class (rtx x, reg_class_t class)
+{
+ if (class == FPU_REGS)
+ return LOAD_FPU_REGS;
+ if (class == ALL_REGS)
+ {
+ if (FLOAT_MODE_P (GET_MODE (x)))
+ return LOAD_FPU_REGS;
+ else
+ return GENERAL_REGS;
+ }
+ return class;
+}
+
+/* TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
+
+ Given an rtx X being reloaded into a reg required to be
+ in class CLASS, return the class of reg to actually use.
+ In general this is just CLASS; but on some machines
+ in some cases it is preferable to use a more restrictive class.
+
+loading is easier into LOAD_FPU_REGS than FPU_REGS! */
+
+static reg_class_t
+pdp11_preferred_output_reload_class (rtx x, reg_class_t class)
+{
+ if (class == FPU_REGS)
+ return LOAD_FPU_REGS;
+ if (class == ALL_REGS)
+ {
+ if (FLOAT_MODE_P (GET_MODE (x)))
+ return LOAD_FPU_REGS;
+ else
+ return GENERAL_REGS;
+ }
+ return class;
+}
+
+
+/* TARGET_SECONDARY_RELOAD.
+
+ FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an
+ intermediate register (AC0-AC3: LOAD_FPU_REGS). Everything else
+ can be loade/stored directly. */
+reg_class_t
+pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
+ rtx x,
+ reg_class_t reload_class,
+ enum machine_mode reload_mode ATTRIBUTE_UNUSED,
+ secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+ if (reload_class != NO_LOAD_FPU_REGS || GET_CODE (x) != REG ||
+ REGNO_REG_CLASS (REGNO (x)) == LOAD_FPU_REGS)
+ return NO_REGS;
+
+ return LOAD_FPU_REGS;
+}
+
+/* Target routine to check if register to register move requires memory.
+
+ The answer is yes if we're going between general register and FPU
+ registers. The mode doesn't matter in making this check.
+*/
+bool
+pdp11_secondary_memory_needed (reg_class_t c1, reg_class_t c2,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ int fromfloat = (c1 == LOAD_FPU_REGS || c1 == NO_LOAD_FPU_REGS ||
+ c1 == FPU_REGS);
+ int tofloat = (c2 == LOAD_FPU_REGS || c2 == NO_LOAD_FPU_REGS ||
+ c2 == FPU_REGS);
+
+ return (fromfloat != tofloat);
+}
+
+
/* A copy of output_addr_const modified for pdp11 expression syntax.
output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
use, and for debugging output, which we don't support with this port either.
@@ -1751,7 +1864,7 @@
ac0 if DFmode and FPU present - compatibility problem with
libraries for non-floating point.... */
return (TYPE_MODE (type) == DImode
- || (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
+ || (FLOAT_MODE_P (TYPE_MODE (type)) && ! TARGET_AC0));
}
/* Worker function for TARGET_FUNCTION_VALUE.
@@ -1854,3 +1967,5 @@
? GET_MODE_SIZE (mode)
: int_size_in_bytes (type));
}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
===================================================================
@@ -215,15 +215,19 @@
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
- On the pdp, the cpu registers can hold any mode - check alignment
+ On the pdp, the cpu registers can hold any mode other than float
+ (because otherwise we may end up being asked to move from CPU to FPU
+ register, which isn't a valid operation on the PDP11).
+ For CPU registers, check alignment.
- FPU can only hold DF - simplifies life!
+ FPU accepts SF and DF but actually holds a DF - simplifies life!
*/
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(((REGNO) <= PC_REGNUM)? \
((GET_MODE_BITSIZE(MODE) <= 16) \
- || (GET_MODE_BITSIZE(MODE) >= 32 && !((REGNO) & 1))) \
- :(MODE) == DFmode)
+ || (GET_MODE_BITSIZE(MODE) >= 32 && \
+ !((REGNO) & 1) && !FLOAT_MODE_P (MODE))) \
+ :FLOAT_MODE_P (MODE))
/* Value is 1 if it is a good idea to tie two pseudo registers
@@ -322,19 +326,10 @@
#define IRA_COVER_CLASSES { GENERAL_REGS, FPU_REGS, LIM_REG_CLASSES }
-/* Given an rtx X being reloaded into a reg required to be
- in class CLASS, return the class of reg to actually use.
- In general this is just CLASS; but on some machines
- in some cases it is preferable to use a more restrictive class.
+/* Hook for testing if memory is needed for moving between registers. */
+#define SECONDARY_MEMORY_NEEDED(class1, class2, m) \
+ pdp11_secondary_memory_needed (class1, class2, m)
-loading is easier into LOAD_FPU_REGS than FPU_REGS! */
-
-#define PREFERRED_RELOAD_CLASS(X,CLASS) \
-(((CLASS) != FPU_REGS)?(CLASS):LOAD_FPU_REGS)
-
-#define SECONDARY_RELOAD_CLASS(CLASS,MODE,x) \
-(((CLASS) == NO_LOAD_FPU_REGS && !(REG_P(x) && LOAD_FPU_REG_P(REGNO(x))))?LOAD_FPU_REGS:NO_REGS)
-
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
@@ -343,6 +338,8 @@
1 \
)
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+ pdp11_cannot_change_mode_class (FROM, TO, CLASS)
/* Stack layout; function entry, exit and calling. */
@@ -386,7 +383,7 @@
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
#define BASE_RETURN_VALUE_REG(MODE) \
- ((MODE) == DFmode ? 8 : 0)
+ (FLOAT_MODE_P (MODE) ? AC0_REGNUM : RETVAL_REGNUM)
/* 1 if N is a possible register number for function argument passing.
- not used on pdp */
@@ -674,10 +671,6 @@
/* #define NO_FUNCTION_CSE */
-/* cost of moving one register class to another */
-#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
- pdp11_register_move_cost (CLASS1, CLASS2)
-
/* Tell emit-rtl.c how to initialize special values on a per-function base. */
extern struct rtx_def *cc0_reg_rtx;