Commit b4324a14 by Paul Koning Committed by Paul Koning

Convert pdp11 back end to CCmode.

	* common/config/pdp11/pdp11-common.c (pdp11_handle_option): Handle
	mutually exclusive options.
	* config/pdp11/constraints.md (h): New constraint.
	(O): Update definition to match shift code generation.
	(D): New constraint.
	* config/pdp11/pdp11-modes.def (CCNZ): Define mode.
	(CCFP): Remove.
	* config/pdp11/pdp11-protos.h (int_no_side_effect_operand): New
	function.
	(output_jump): Change arguments.
	(pdp11_fixed_cc_regs): New function.
	(pdp11_cc_mode): Ditto.
	(pdp11_expand_shift): Ditto.
	(pdp11_assemble_shift): Ditto.
	(pdp11_small_shift): Ditto.
	(pdp11_branch_cost): Remove.
	* config/pdp11/pdp11.c (pdp11_assemble_integer): Remove comments
	from output.
	(pdp11_register_move_cost): Update for CC registers.
	(pdp11_rtx_costs): Add case for LSHIFTRT.
	(pdp11_output_jump): Add CCNZ mode conditional branches.
	(notice_update_cc_on_set): Remove.
	(pdp11_cc_mode): New function.
	(simple_memory_operand): Correct pre/post decrement case.
	(no_side_effect_operand): New function.
	(pdp11_regno_reg_class): Add CC_REGS class.
	(pdp11_fixed_cc_regs): New function.
	(pdp11_small_shift): New function.
	(pdp11_expand_shift): New function to expand shift insns.
	(pdp11_assemble_shift): New function to output shifts.
	(pdp11_branch_cost): Remove.
	(pdp11_modes_tieable_p): Make QI/HI modes tieable.
	* config/pdp11/pdp11.h (SIZE_TYPE): Ensure 16-bit type.
	(WCHAR_TYPE): Ditto.
	(PTRDIFF_TYPE): Ditto.
	(ADJUST_INSN_LENGTH): New macro.
	(FIXED_REGISTERS): Add CC registers.
	(CALL_USED_REGISTERS): Ditto.
	(reg_class): Ditto.
	(REG_CLASS_NAMES): Ditto.
	(REG_CLASS_CONTENTS): Ditto.
	(SELECT_CC_MODE): Use new function.
	(TARGET_FLAGS_REGNUM): New macro.
	(TARGET_FIXED_CONDITION_CODE_REGS): Ditto.
	(cc0_reg_rtx): Remove.
	(CC_STATUS_MDEP): Remove.
	(CC_STATUS_MDEFP_INIT): Remove.
	(CC_IN_FPU): Remove.
	(NOTICE_UPDATE_CC): Remove.
	(REGISTER_NAMES): Add CC registers.
	(BRANCH_COST): Change to constant 1.
	* config/pdp11/pdp11.md: Rewrite for CCmode condition code
	handling.
	* config/pdp11/pdp11.opt (mbcopy): Remove.
	(mbcopy-builtin): Remove.
	(mbranch-cheap): Remove.
	(mbranch-expensive): Remove.
	* config/pdp11/predicates.md (expand_shift_operand): Update to
	match shift code generation.
	(ccnz_operator): New predicate.
	* doc/invoke.texi (PDP-11 Options): Remove deleted options
	-mbcopy, -mbcopy-builtin, -mbranch-cheap, -mbranch-expensive.
	Remove non-existent option -mabshi, -mno-abshi.  Document mutually
	exclusive options.
	* doc/md.texi (PDP-11): Document new D and h constraints.  Update
	description of O constraint.

From-SVN: r262198
parent 356d5363
2018-06-27 Paul Koning <ni1d@arrl.net>
* common/config/pdp11/pdp11-common.c (pdp11_handle_option): Handle
mutually exclusive options.
* config/pdp11/constraints.md (h): New constraint.
(O): Update definition to match shift code generation.
(D): New constraint.
* config/pdp11/pdp11-modes.def (CCNZ): Define mode.
(CCFP): Remove.
* config/pdp11/pdp11-protos.h (int_no_side_effect_operand): New
function.
(output_jump): Change arguments.
(pdp11_fixed_cc_regs): New function.
(pdp11_cc_mode): Ditto.
(pdp11_expand_shift): Ditto.
(pdp11_assemble_shift): Ditto.
(pdp11_small_shift): Ditto.
(pdp11_branch_cost): Remove.
* config/pdp11/pdp11.c (pdp11_assemble_integer): Remove comments
from output.
(pdp11_register_move_cost): Update for CC registers.
(pdp11_rtx_costs): Add case for LSHIFTRT.
(pdp11_output_jump): Add CCNZ mode conditional branches.
(notice_update_cc_on_set): Remove.
(pdp11_cc_mode): New function.
(simple_memory_operand): Correct pre/post decrement case.
(no_side_effect_operand): New function.
(pdp11_regno_reg_class): Add CC_REGS class.
(pdp11_fixed_cc_regs): New function.
(pdp11_small_shift): New function.
(pdp11_expand_shift): New function to expand shift insns.
(pdp11_assemble_shift): New function to output shifts.
(pdp11_branch_cost): Remove.
(pdp11_modes_tieable_p): Make QI/HI modes tieable.
* config/pdp11/pdp11.h (SIZE_TYPE): Ensure 16-bit type.
(WCHAR_TYPE): Ditto.
(PTRDIFF_TYPE): Ditto.
(ADJUST_INSN_LENGTH): New macro.
(FIXED_REGISTERS): Add CC registers.
(CALL_USED_REGISTERS): Ditto.
(reg_class): Ditto.
(REG_CLASS_NAMES): Ditto.
(REG_CLASS_CONTENTS): Ditto.
(SELECT_CC_MODE): Use new function.
(TARGET_FLAGS_REGNUM): New macro.
(TARGET_FIXED_CONDITION_CODE_REGS): Ditto.
(cc0_reg_rtx): Remove.
(CC_STATUS_MDEP): Remove.
(CC_STATUS_MDEFP_INIT): Remove.
(CC_IN_FPU): Remove.
(NOTICE_UPDATE_CC): Remove.
(REGISTER_NAMES): Add CC registers.
(BRANCH_COST): Change to constant 1.
* config/pdp11/pdp11.md: Rewrite for CCmode condition code
handling.
* config/pdp11/pdp11.opt (mbcopy): Remove.
(mbcopy-builtin): Remove.
(mbranch-cheap): Remove.
(mbranch-expensive): Remove.
* config/pdp11/predicates.md (expand_shift_operand): Update to
match shift code generation.
(ccnz_operator): New predicate.
* doc/invoke.texi (PDP-11 Options): Remove deleted options
-mbcopy, -mbcopy-builtin, -mbranch-cheap, -mbranch-expensive.
Remove non-existent option -mabshi, -mno-abshi. Document mutually
exclusive options.
* doc/md.texi (PDP-11): Document new D and h constraints. Update
description of O constraint.
2018-06-27 Jeff Law <law@redhat.com> 2018-06-27 Jeff Law <law@redhat.com>
Austin Law <austinklaw@gmail.com> Austin Law <austinklaw@gmail.com>
......
...@@ -39,7 +39,25 @@ pdp11_handle_option (struct gcc_options *opts, ...@@ -39,7 +39,25 @@ pdp11_handle_option (struct gcc_options *opts,
switch (code) switch (code)
{ {
case OPT_m10: case OPT_m10:
opts->x_target_flags &= ~(MASK_40 | MASK_45); opts->x_target_flags &= ~(MASK_40 | MASK_45 | MASK_FPU | MASK_AC0 | MASK_SPLIT);
return true;
case OPT_m40:
opts->x_target_flags &= ~(MASK_45 | MASK_FPU | MASK_AC0 | MASK_SPLIT);
return true;
case OPT_mfpu:
opts->x_target_flags &= ~MASK_40;
opts->x_target_flags |= MASK_45;
return true;
case OPT_msoft_float:
opts->x_target_flags &= ~MASK_AC0;
return true;
case OPT_msplit:
opts->x_target_flags &= ~MASK_40;
opts->x_target_flags |= MASK_45;
return true; return true;
default: default:
......
...@@ -18,11 +18,14 @@ ...@@ -18,11 +18,14 @@
;; along with GCC; see the file COPYING3. If not see ;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>. ;; <http://www.gnu.org/licenses/>.
(define_register_constraint "a" "LOAD_FPU_REGS"
"FPU register that can be directly loaded from memory")
(define_register_constraint "f" "FPU_REGS" (define_register_constraint "f" "FPU_REGS"
"Any FPU register") "Any FPU register")
(define_register_constraint "a" "LOAD_FPU_REGS" (define_register_constraint "h" "NO_LOAD_FPU_REGS"
"FPU register that can be directly loaded from memory") "FPU register that cannot be directly loaded from memory")
(define_register_constraint "d" "MUL_REGS" (define_register_constraint "d" "MUL_REGS"
"General register that can be used for 16-bit multiply (odd numbered)") "General register that can be used for 16-bit multiply (odd numbered)")
...@@ -60,7 +63,7 @@ ...@@ -60,7 +63,7 @@
(define_constraint "O" (define_constraint "O"
"Integer constant for which several individual shifts are better than one big one" "Integer constant for which several individual shifts are better than one big one"
(and (match_code "const_int") (and (match_code "const_int")
(match_test "abs (ival) > 1 && abs (ival) <= 4"))) (match_test "pdp11_small_shift (ival)")))
(define_constraint "G" (define_constraint "G"
"Defines a real zero constant." "Defines a real zero constant."
...@@ -79,3 +82,9 @@ ...@@ -79,3 +82,9 @@
(match_test "memory_address_p (GET_MODE (op), XEXP (op, 0)) (match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
&& simple_memory_operand (op, GET_MODE (op))"))) && simple_memory_operand (op, GET_MODE (op))")))
(define_constraint "D"
"Memory reference that is encoded within the opcode, and not push or pop"
(and (match_code "mem")
(match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
&& no_side_effect_operand (op, GET_MODE (op))")))
...@@ -19,8 +19,26 @@ along with GCC; see the file COPYING3. If not see ...@@ -19,8 +19,26 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
/* Add any extra modes needed to represent the condition code. /* Add any extra modes needed to represent the condition code.
CCFPmode is used for FPU, but should we use a separate reg? */
CC_MODE (CCFP); The default CCmode is the CPU condition codes, as set by compare;
all conditional branches are valid with this.
CCNZmode is the CPU condition code as a side effect of arithmetic
or logic operations where N and Z reflect sign and zero status of
the result, but the V bit is not meaningful. Unsigned conditional
branches don't apply then (no such thing when comparing with zero)
and signed branches that use V need to clear V first if they are to
be used. CCNZ mode appears in side effects (implicit compare with
zero) if V is not forced to 0 by the instruction. In such cases, V
often reflects signed overflow of the operation, which means a
signed branch will get the sign backwards. This applies both to
some float and integer operations.
These modes are used both in the FPU and the CPU, since they have
the same meaning, and also because the FPU condition codes are
copied to the CPU before being used in conditional branches. */
CC_MODE (CCNZ);
RESET_FLOAT_FORMAT (SF, pdp11_f_format); RESET_FLOAT_FORMAT (SF, pdp11_f_format);
RESET_FLOAT_FORMAT (DF, pdp11_d_format); RESET_FLOAT_FORMAT (DF, pdp11_d_format);
...@@ -21,13 +21,13 @@ along with GCC; see the file COPYING3. If not see ...@@ -21,13 +21,13 @@ along with GCC; see the file COPYING3. If not see
/* declarations */ /* declarations */
#ifdef RTX_CODE #ifdef RTX_CODE
extern int simple_memory_operand (rtx, machine_mode); extern int simple_memory_operand (rtx, machine_mode);
extern int no_side_effect_operand (rtx, machine_mode);
extern int legitimate_const_double_p (rtx); extern int legitimate_const_double_p (rtx);
extern void notice_update_cc_on_set (rtx, rtx); extern void notice_update_cc_on_set (rtx, rtx);
extern void output_addr_const_pdp11 (FILE *, rtx); extern void output_addr_const_pdp11 (FILE *, rtx);
extern const char *output_move_multiple (rtx *); extern const char *output_move_multiple (rtx *);
extern const char *output_block_move (rtx *); extern const char *output_block_move (rtx *);
extern const char *output_jump (enum rtx_code, int, int); extern const char *output_jump (rtx *, int, int);
extern void print_operand_address (FILE *, rtx); extern void print_operand_address (FILE *, rtx);
typedef enum { no_action, dec_before, inc_after } pdp11_action; typedef enum { no_action, dec_before, inc_after } pdp11_action;
typedef enum { little, either, big } pdp11_partorder; typedef enum { little, either, big } pdp11_partorder;
...@@ -36,6 +36,12 @@ extern bool pdp11_expand_operands (rtx *, rtx [][2], int, ...@@ -36,6 +36,12 @@ extern bool pdp11_expand_operands (rtx *, rtx [][2], int,
extern int pdp11_sp_frame_offset (void); extern int pdp11_sp_frame_offset (void);
extern int pdp11_initial_elimination_offset (int, int); extern int pdp11_initial_elimination_offset (int, int);
extern enum reg_class pdp11_regno_reg_class (int); extern enum reg_class pdp11_regno_reg_class (int);
extern bool pdp11_fixed_cc_regs (unsigned int *, unsigned int *);
extern machine_mode pdp11_cc_mode (enum rtx_code, rtx, rtx);
extern bool pdp11_expand_shift (rtx *, rtx (*) (rtx, rtx, rtx),
rtx (*) (rtx, rtx, rtx));
extern const char * pdp11_assemble_shift (rtx *, machine_mode, int);
extern bool pdp11_small_shift (int);
#endif /* RTX_CODE */ #endif /* RTX_CODE */
...@@ -43,5 +49,4 @@ extern void output_ascii (FILE *, const char *, int); ...@@ -43,5 +49,4 @@ extern void output_ascii (FILE *, const char *, int);
extern void pdp11_asm_output_var (FILE *, const char *, int, int, bool); extern void pdp11_asm_output_var (FILE *, const char *, int, int, bool);
extern void pdp11_expand_prologue (void); extern void pdp11_expand_prologue (void);
extern void pdp11_expand_epilogue (void); extern void pdp11_expand_epilogue (void);
extern int pdp11_branch_cost (void);
extern poly_int64 pdp11_push_rounding (poly_int64); extern poly_int64 pdp11_push_rounding (poly_int64);
...@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "expr.h" #include "expr.h"
#include "builtins.h" #include "builtins.h"
#include "dbxout.h" #include "dbxout.h"
#include "expmed.h"
/* This file should be included last. */ /* This file should be included last. */
#include "target-def.h" #include "target-def.h"
...@@ -146,9 +147,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, ...@@ -146,9 +147,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
(*vax_d_format.decode) (fmt, r, tbuf); (*vax_d_format.decode) (fmt, r, tbuf);
} }
/* This is where the condition code register lives. */
/* rtx cc0_reg_rtx; - no longer needed? */
static const char *singlemove_string (rtx *); static const char *singlemove_string (rtx *);
static bool pdp11_assemble_integer (rtx, unsigned int, int); static bool pdp11_assemble_integer (rtx, unsigned int, int);
static bool pdp11_rtx_costs (rtx, machine_mode, int, int, int *, bool); static bool pdp11_rtx_costs (rtx, machine_mode, int, int, int *, bool);
...@@ -872,48 +870,40 @@ pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p) ...@@ -872,48 +870,40 @@ pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
case 1: case 1:
fprintf (asm_out_file, "\t.byte\t"); fprintf (asm_out_file, "\t.byte\t");
output_addr_const_pdp11 (asm_out_file, GEN_INT (INTVAL (x) & 0xff)); output_addr_const_pdp11 (asm_out_file, GEN_INT (INTVAL (x) & 0xff));
; fputs ("\n", asm_out_file);
fprintf (asm_out_file, " /* char */\n");
return true; return true;
case 2: case 2:
fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t"); fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
output_addr_const_pdp11 (asm_out_file, x); output_addr_const_pdp11 (asm_out_file, x);
fprintf (asm_out_file, " /* short */\n"); fputs ("\n", asm_out_file);
return true; return true;
} }
return default_assemble_integer (x, size, aligned_p); return default_assemble_integer (x, size, aligned_p);
} }
/* register move costs, indexed by regs */ /* Register to register moves are cheap if both are general registers.
The same is true for FPU, but there we return cost of 3 rather than
static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 2 to make reload look at the constraints. The raeson is that
{ load/store double require extra care since load touches condition
/* NO MUL GEN LFPU NLFPU FPU ALL */ codes and store doesn't, which is (partly anyway) described by
constraints. */
/* NO */ { 0, 0, 0, 0, 0, 0, 0},
/* 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 10 -- or not ? */
static int static int
pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
reg_class_t c1, reg_class_t c2) reg_class_t c1, reg_class_t c2)
{ {
return move_costs[(int)c1][(int)c2]; if (((c1 == MUL_REGS || c1 == GENERAL_REGS) &&
(c2 == MUL_REGS || c2 == GENERAL_REGS)))
return 2;
else if ((c1 >= LOAD_FPU_REGS && c1 <= FPU_REGS && c2 == LOAD_FPU_REGS) ||
(c2 >= LOAD_FPU_REGS && c2 <= FPU_REGS && c1 == LOAD_FPU_REGS))
return 3;
else
return 22;
} }
static bool static bool
pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED, pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
int opno ATTRIBUTE_UNUSED, int *total, int opno ATTRIBUTE_UNUSED, int *total,
...@@ -988,7 +978,6 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED, ...@@ -988,7 +978,6 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
return false; return false;
case ASHIFT: case ASHIFT:
case LSHIFTRT:
case ASHIFTRT: case ASHIFTRT:
if (optimize_size) if (optimize_size)
*total = COSTS_N_INSNS (1); *total = COSTS_N_INSNS (1);
...@@ -1020,30 +1009,67 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED, ...@@ -1020,30 +1009,67 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
} }
return false; return false;
case LSHIFTRT:
if (optimize_size)
*total = COSTS_N_INSNS (2);
else if (mode == QImode)
{
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
*total = COSTS_N_INSNS (12); /* worst case */
else
*total = COSTS_N_INSNS (1 + INTVAL (XEXP (x, 1)));
}
else if (mode == HImode)
{
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
if (abs (INTVAL (XEXP (x, 1))) == 1)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (3.5 + 0.5 * INTVAL (XEXP (x, 1)));
}
else
*total = COSTS_N_INSNS (12); /* worst case */
}
else if (mode == SImode)
{
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
*total = COSTS_N_INSNS (3.5 + 0.5 * INTVAL (XEXP (x, 1)));
else /* worst case */
*total = COSTS_N_INSNS (20);
}
return false;
default: default:
return false; return false;
} }
} }
const char * const char *
output_jump (enum rtx_code code, int inv, int length) output_jump (rtx *operands, int ccnz, int length)
{ {
static int x = 0; rtx tmpop[1];
static char buf[100];
static char buf[1000];
const char *pos, *neg; const char *pos, *neg;
enum rtx_code code = GET_CODE (operands[0]);
if (cc_prev_status.flags & CC_NO_OVERFLOW) if (ccnz)
{ {
/* These are the branches valid for CCNZmode, i.e., a comparison
with zero where the V bit is not set to zero. These cases
occur when CC or FCC are set as a side effect of some data
manipulation, such as the ADD instruction. */
switch (code) switch (code)
{ {
case GTU: code = GT; break; case EQ: pos = "beq", neg = "bne"; break;
case LTU: code = LT; break; case NE: pos = "bne", neg = "beq"; break;
case GEU: code = GE; break; case LT: pos = "bmi", neg = "bpl"; break;
case LEU: code = LE; break; case GE: pos = "bpl", neg = "bmi"; break;
default: ; default: gcc_unreachable ();
} }
} }
else
{
switch (code) switch (code)
{ {
case EQ: pos = "beq", neg = "bne"; break; case EQ: pos = "beq", neg = "bne"; break;
...@@ -1058,76 +1084,59 @@ output_jump (enum rtx_code code, int inv, int length) ...@@ -1058,76 +1084,59 @@ output_jump (enum rtx_code code, int inv, int length)
case LEU: pos = "blos", neg = "bhi"; break; case LEU: pos = "blos", neg = "bhi"; break;
default: gcc_unreachable (); default: gcc_unreachable ();
} }
}
#if 0
/* currently we don't need this, because the tstdf and cmpdf
copy the condition code immediately, and other float operations are not
yet recognized as changing the FCC - if so, then the length-cost of all
jump insns increases by one, because we have to potentially copy the
FCC! */
if (cc_status.flags & CC_IN_FPU)
output_asm_insn("cfcc", NULL);
#endif
switch (length) switch (length)
{ {
case 2: case 2:
sprintf (buf, "%s %%l1", pos);
sprintf(buf, "%s %%l1", inv ? neg : pos);
return buf; return buf;
case 6: case 6:
tmpop[0] = gen_label_rtx ();
sprintf(buf, "%s JMP_%d\n\tjmp %%l1\nJMP_%d:", inv ? pos : neg, x, x); sprintf (buf, "%s %%l0", neg);
output_asm_insn (buf, tmpop);
x++; output_asm_insn ("jmp %l1", operands);
output_asm_label (tmpop[0]);
return buf; fputs (":\n", asm_out_file);
return "";
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
} }
void /* Select the CC mode to be used for the side effect compare with
notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED) zero, given the compare operation code in op and the compare
operands in x in and y. */
machine_mode
pdp11_cc_mode (enum rtx_code op, rtx x, rtx y)
{ {
if (GET_CODE (SET_DEST (exp)) == CC0) if (FLOAT_MODE_P (GET_MODE (x)))
{
cc_status.flags = 0;
cc_status.value1 = SET_DEST (exp);
cc_status.value2 = SET_SRC (exp);
}
else if (GET_CODE (SET_SRC (exp)) == CALL)
{ {
CC_STATUS_INIT; switch (GET_CODE (x))
}
else if (SET_DEST(exp) == pc_rtx)
{ {
/* jump */ case ABS:
case NEG:
case REG:
case MEM:
return CCmode;
default:
return CCNZmode;
} }
else if (GET_MODE (SET_DEST(exp)) == HImode
|| GET_MODE (SET_DEST(exp)) == QImode)
{
cc_status.flags = GET_CODE (SET_SRC(exp)) == MINUS ? 0 : CC_NO_OVERFLOW;
cc_status.value1 = SET_SRC (exp);
cc_status.value2 = SET_DEST (exp);
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
&& cc_status.value2
&& GET_CODE (cc_status.value2) == MEM)
cc_status.value2 = 0;
} }
else else
{ {
CC_STATUS_INIT; switch (GET_CODE (x))
{
case XOR:
case AND:
case IOR:
case MULT:
case NOT:
case REG:
case MEM:
return CCmode;
default:
return CCNZmode;
}
} }
} }
...@@ -1141,11 +1150,63 @@ simple_memory_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED) ...@@ -1141,11 +1150,63 @@ simple_memory_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
if (GET_CODE (op) != MEM) if (GET_CODE (op) != MEM)
return FALSE; return FALSE;
#if 0 /* Decode the address now. */
/* dword operations really put out 2 instructions, so eliminate them. */
if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) indirection:
addr = XEXP (op, 0);
switch (GET_CODE (addr))
{
case REG:
/* (R0) - no extra cost */
return 1;
case PRE_DEC:
case POST_INC:
case PRE_MODIFY:
case POST_MODIFY:
/* -(R0), (R0)+ - cheap! */
return 1;
case MEM:
/* cheap - is encoded in addressing mode info!
-- except for @(R0), which has to be @0(R0) !!! */
if (GET_CODE (XEXP (addr, 0)) == REG)
return 0;
op=addr;
goto indirection;
case CONST_INT:
case LABEL_REF:
case CONST:
case SYMBOL_REF:
/* @#address - extra cost */
return 0;
case PLUS:
/* X(R0) - extra cost */
return 0;
default:
break;
}
return FALSE;
}
/* Similar to simple_memory_operand but doesn't match push/pop. */
int
no_side_effect_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
{
rtx addr;
/* Eliminate non-memory operations */
if (GET_CODE (op) != MEM)
return FALSE; return FALSE;
#endif
/* Decode the address now. */ /* Decode the address now. */
...@@ -1161,7 +1222,8 @@ simple_memory_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED) ...@@ -1161,7 +1222,8 @@ simple_memory_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
case PRE_DEC: case PRE_DEC:
case POST_INC: case POST_INC:
/* -(R0), (R0)+ - cheap! */ case PRE_MODIFY:
case POST_MODIFY:
return 0; return 0;
case MEM: case MEM:
...@@ -1446,7 +1508,7 @@ pdp11_preferred_output_reload_class (rtx x, reg_class_t rclass) ...@@ -1446,7 +1508,7 @@ pdp11_preferred_output_reload_class (rtx x, reg_class_t rclass)
FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an
intermediate register (AC0-AC3: LOAD_FPU_REGS). Everything else intermediate register (AC0-AC3: LOAD_FPU_REGS). Everything else
can be loade/stored directly. */ can be loaded/stored directly. */
static reg_class_t static reg_class_t
pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED, pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
rtx x, rtx x,
...@@ -1464,8 +1526,7 @@ pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED, ...@@ -1464,8 +1526,7 @@ pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
/* Implement TARGET_SECONDARY_MEMORY_NEEDED. /* Implement TARGET_SECONDARY_MEMORY_NEEDED.
The answer is yes if we're going between general register and FPU The answer is yes if we're going between general register and FPU
registers. The mode doesn't matter in making this check. registers. The mode doesn't matter in making this check. */
*/
static bool static bool
pdp11_secondary_memory_needed (machine_mode, reg_class_t c1, reg_class_t c2) pdp11_secondary_memory_needed (machine_mode, reg_class_t c1, reg_class_t c2)
{ {
...@@ -1594,6 +1655,8 @@ pdp11_regno_reg_class (int regno) ...@@ -1594,6 +1655,8 @@ pdp11_regno_reg_class (int regno)
{ {
if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM) if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
return GENERAL_REGS; return GENERAL_REGS;
else if (regno == CC_REGNUM || regno == FCC_REGNUM)
return CC_REGS;
else if (regno > AC3_REGNUM) else if (regno > AC3_REGNUM)
return NO_LOAD_FPU_REGS; return NO_LOAD_FPU_REGS;
else if (regno >= AC0_REGNUM) else if (regno >= AC0_REGNUM)
...@@ -1604,6 +1667,14 @@ pdp11_regno_reg_class (int regno) ...@@ -1604,6 +1667,14 @@ pdp11_regno_reg_class (int regno)
return GENERAL_REGS; return GENERAL_REGS;
} }
/* Return the regnums of the CC registers. */
bool
pdp11_fixed_cc_regs (unsigned int *p1, unsigned int *p2)
{
*p1 = CC_REGNUM;
*p2 = FCC_REGNUM;
return true;
}
int int
pdp11_sp_frame_offset (void) pdp11_sp_frame_offset (void)
...@@ -1804,6 +1875,151 @@ pdp11_function_value_regno_p (const unsigned int regno) ...@@ -1804,6 +1875,151 @@ pdp11_function_value_regno_p (const unsigned int regno)
return (regno == RETVAL_REGNUM) || (TARGET_AC0 && (regno == AC0_REGNUM)); return (regno == RETVAL_REGNUM) || (TARGET_AC0 && (regno == AC0_REGNUM));
} }
/* Used for O constraint, matches if shift count is "small". */
bool
pdp11_small_shift (int n)
{
return (unsigned) n < 4;
}
/* Expand a shift insn. Returns true if the expansion was done,
false if it needs to be handled by the caller. */
bool
pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
rtx (*shift_base) (rtx, rtx, rtx))
{
rtx dest, n, r, test;
rtx_code_label *lb, *lb2;
if (CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2])))
emit_insn ((*shift_sc) (operands[0], operands[1], operands[2]));
else if (TARGET_40_PLUS)
return false;
else
{
lb = gen_label_rtx ();
r = gen_reg_rtx (HImode);
emit_move_insn (operands[0], operands[1]);
emit_move_insn (r, operands[2]);
if (!CONSTANT_P (operands[2]))
{
test = gen_rtx_LE (HImode, r, const0_rtx);
emit_jump_insn (gen_cbranchhi4 (test, r, const0_rtx, lb));
}
/* It would be nice to expand the loop here, but that's not
possible because shifts may be generated by the loop unroll
optimizer and it doesn't appreciate flow changes happening
while it's doing things. */
emit_insn ((*shift_base) (operands[0], operands[1], r));
if (!CONSTANT_P (operands[2]))
{
emit_label (lb);
/* Allow REG_NOTES to be set on last insn (labels don't have enough
fields, and can't be used for REG_NOTES anyway). */
emit_use (stack_pointer_rtx);
}
}
return true;
}
/* Emit the instructions needed to produce a shift by a small constant
amount (unrolled), or a shift made from a loop for the base machine
case. */
const char *
pdp11_assemble_shift (rtx *operands, machine_mode m, int code)
{
int i, n;
rtx exops[4][2];
rtx lb[1];
pdp11_action action[2];
const bool small = CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2]));
gcc_assert (small || !TARGET_40_PLUS);
if (m == E_SImode)
pdp11_expand_operands (operands, exops, 1, action, either);
if (!small)
{
/* Loop case, generate the top of loop label. */
lb[0] = gen_label_rtx ();
output_asm_label (lb[0]);
fputs (":\n", asm_out_file);
n = 1;
}
else
n = INTVAL (operands[2]);
if (code == LSHIFTRT)
{
output_asm_insn ("clc", NULL);
switch (m)
{
case E_QImode:
output_asm_insn ("rorb %0", operands);
break;
case E_HImode:
output_asm_insn ("ror %0", operands);
break;
case E_SImode:
output_asm_insn ("ror %0", exops[0]);
output_asm_insn ("ror %0", exops[1]);
break;
default:
gcc_unreachable ();
}
n--;
}
for (i = 0; i < n; i++)
{
switch (code)
{
case LSHIFTRT:
case ASHIFTRT:
switch (m)
{
case E_QImode:
output_asm_insn ("asrb %0", operands);
break;
case E_HImode:
output_asm_insn ("asr %0", operands);
break;
case E_SImode:
output_asm_insn ("asr %0", exops[0]);
output_asm_insn ("ror %0", exops[1]);
break;
default:
gcc_unreachable ();
}
break;
case ASHIFT:
switch (m)
{
case E_QImode:
output_asm_insn ("aslb %0", operands);
break;
case E_HImode:
output_asm_insn ("asl %0", operands);
break;
case E_SImode:
output_asm_insn ("asl %0", exops[1]);
output_asm_insn ("rol %0", exops[0]);
break;
default:
gcc_unreachable ();
}
break;
}
}
if (!small)
{
/* Loop case, emit the count-down and branch if not done. */
output_asm_insn ("dec %2", operands);
output_asm_insn ("bne %l0", lb);
}
return "";
}
/* Worker function for TARGET_TRAMPOLINE_INIT. /* Worker function for TARGET_TRAMPOLINE_INIT.
trampoline - how should i do it in separate i+d ? trampoline - how should i do it in separate i+d ?
...@@ -1814,7 +2030,6 @@ pdp11_function_value_regno_p (const unsigned int regno) ...@@ -1814,7 +2030,6 @@ pdp11_function_value_regno_p (const unsigned int regno)
MOV #STATIC, $4 01270Y 0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM MOV #STATIC, $4 01270Y 0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM
JMP @#FUNCTION 000137 0x0000 <- FUNCTION JMP @#FUNCTION 000137 0x0000 <- FUNCTION
*/ */
static void static void
pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
{ {
...@@ -1934,12 +2149,6 @@ pdp11_scalar_mode_supported_p (scalar_mode mode) ...@@ -1934,12 +2149,6 @@ pdp11_scalar_mode_supported_p (scalar_mode mode)
return default_scalar_mode_supported_p (mode); return default_scalar_mode_supported_p (mode);
} }
int
pdp11_branch_cost ()
{
return (TARGET_BRANCH_CHEAP ? 0 : 1);
}
/* Implement TARGET_HARD_REGNO_NREGS. */ /* Implement TARGET_HARD_REGNO_NREGS. */
static unsigned int static unsigned int
...@@ -1972,9 +2181,9 @@ pdp11_hard_regno_mode_ok (unsigned int regno, machine_mode mode) ...@@ -1972,9 +2181,9 @@ pdp11_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
/* Implement TARGET_MODES_TIEABLE_P. */ /* Implement TARGET_MODES_TIEABLE_P. */
static bool static bool
pdp11_modes_tieable_p (machine_mode, machine_mode) pdp11_modes_tieable_p (machine_mode mode1, machine_mode mode2)
{ {
return false; return mode1 == HImode && mode2 == QImode;
} }
/* Implement PUSH_ROUNDING. On the pdp11, the stack is on an even /* Implement PUSH_ROUNDING. On the pdp11, the stack is on an even
......
...@@ -65,11 +65,11 @@ along with GCC; see the file COPYING3. If not see ...@@ -65,11 +65,11 @@ along with GCC; see the file COPYING3. If not see
#define LONG_DOUBLE_TYPE_SIZE 64 #define LONG_DOUBLE_TYPE_SIZE 64
/* machine types from ansi */ /* machine types from ansi */
#define SIZE_TYPE "unsigned int" /* definition of size_t */ #define SIZE_TYPE "short unsigned int" /* definition of size_t */
#define WCHAR_TYPE "int" /* or long int???? */ #define WCHAR_TYPE "short int" /* or long int???? */
#define WCHAR_TYPE_SIZE 16 #define WCHAR_TYPE_SIZE 16
#define PTRDIFF_TYPE "int" #define PTRDIFF_TYPE "short int"
/* target machine storage layout */ /* target machine storage layout */
...@@ -99,8 +99,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -99,8 +99,7 @@ along with GCC; see the file COPYING3. If not see
extern const struct real_format pdp11_f_format; extern const struct real_format pdp11_f_format;
extern const struct real_format pdp11_d_format; extern const struct real_format pdp11_d_format;
/* Maximum sized of reasonable data type /* Maximum sized of reasonable data type -- DImode ...*/
DImode or Dfmode ...*/
#define MAX_FIXED_MODE_SIZE 64 #define MAX_FIXED_MODE_SIZE 64
/* Allocation boundary (in *bits*) for storing pointers in memory. */ /* Allocation boundary (in *bits*) for storing pointers in memory. */
...@@ -125,6 +124,22 @@ extern const struct real_format pdp11_d_format; ...@@ -125,6 +124,22 @@ extern const struct real_format pdp11_d_format;
when given unaligned data. */ when given unaligned data. */
#define STRICT_ALIGNMENT 1 #define STRICT_ALIGNMENT 1
/* Adjust the length of shifts by small constant amounts. The base
value (in "length" on input) is the length of a shift by one, not
including the CLC in logical shifts. */
#define ADJUST_INSN_LENGTH(insn, length) \
if ((GET_CODE (insn) == ASHIFT || \
GET_CODE (insn) == ASHIFTRT || \
GET_CODE (insn) == LSHIFTRT) && \
GET_CODE (XEXP (insn, 2)) == CONST_INT && \
pdp11_small_shift (XINT (insn, 2))) \
{ \
if (GET_CODE (insn) == LSHIFTRT) \
length = (length * XINT (insn, 2)) + 2; \
else \
length *= XINT (insn, 2); \
}
/* Standard register usage. */ /* Standard register usage. */
/* Number of actual hardware registers. /* Number of actual hardware registers.
...@@ -147,7 +162,8 @@ extern const struct real_format pdp11_d_format; ...@@ -147,7 +162,8 @@ extern const struct real_format pdp11_d_format;
#define FIXED_REGISTERS \ #define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 1, 1, \ {0, 0, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1 } 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
...@@ -161,7 +177,8 @@ extern const struct real_format pdp11_d_format; ...@@ -161,7 +177,8 @@ extern const struct real_format pdp11_d_format;
/* don't know about fp */ /* don't know about fp */
#define CALL_USED_REGISTERS \ #define CALL_USED_REGISTERS \
{1, 1, 0, 0, 0, 0, 1, 1, \ {1, 1, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1 } 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
/* Specify the registers used for certain standard purposes. /* Specify the registers used for certain standard purposes.
...@@ -203,27 +220,47 @@ NO_LOAD_FPU_REGS is ac4 and ac5, currently - difficult to load them ...@@ -203,27 +220,47 @@ NO_LOAD_FPU_REGS is ac4 and ac5, currently - difficult to load them
FPU_REGS is all fpu regs FPU_REGS is all fpu regs
*/ */
enum reg_class { NO_REGS, MUL_REGS, GENERAL_REGS, LOAD_FPU_REGS, NO_LOAD_FPU_REGS, FPU_REGS, ALL_REGS, LIM_REG_CLASSES }; enum reg_class
{ NO_REGS,
MUL_REGS,
GENERAL_REGS,
LOAD_FPU_REGS,
NO_LOAD_FPU_REGS,
FPU_REGS,
CC_REGS,
ALL_REGS,
LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES #define N_REG_CLASSES ((int) LIM_REG_CLASSES)
/* have to allow this till cmpsi/tstsi are fixed in a better way !! */ /* have to allow this till cmpsi/tstsi are fixed in a better way !! */
#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
/* Since GENERAL_REGS is the same class as ALL_REGS,
don't give it a different class number; just make it an alias. */
/* #define GENERAL_REGS ALL_REGS */
/* Give names of register classes as strings for dump file. */ /* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES {"NO_REGS", "MUL_REGS", "GENERAL_REGS", "LOAD_FPU_REGS", "NO_LOAD_FPU_REGS", "FPU_REGS", "ALL_REGS" } #define REG_CLASS_NAMES \
{ "NO_REGS", \
"MUL_REGS", \
"GENERAL_REGS", \
"LOAD_FPU_REGS", \
"NO_LOAD_FPU_REGS", \
"FPU_REGS", \
"CC_REGS", \
"ALL_REGS" }
/* Define which registers fit in which classes. /* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */ of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0xc0ff}, {0x0f00}, {0x3000}, {0x3f00}, {0xffff}} #define REG_CLASS_CONTENTS \
{ {0x00000}, /* NO_REGS */ \
{0x000aa}, /* MUL_REGS */ \
{0x0c0ff}, /* GENERAL_REGS */ \
{0x00f00}, /* LOAD_FPU_REGS */ \
{0x03000}, /* NO_LOAD_FPU_REGS */ \
{0x03f00}, /* FPU_REGS */ \
{0x30000}, /* CC_REGS */ \
{0x3ffff}} /* ALL_REGS */
/* The same information, inverted: /* The same information, inverted:
Return the class number of the smallest class containing Return the class number of the smallest class containing
...@@ -331,7 +368,7 @@ extern int may_call_alloca; ...@@ -331,7 +368,7 @@ extern int may_call_alloca;
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ {{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO))) ((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
...@@ -424,11 +461,18 @@ extern int may_call_alloca; ...@@ -424,11 +461,18 @@ extern int may_call_alloca;
#define DBX_CONTIN_LENGTH 0 #define DBX_CONTIN_LENGTH 0
/* Give a comparison code (EQ, NE etc) and the first operand of a COMPARE, /* Give a comparison code (EQ, NE etc) and the first operand of a COMPARE,
return the mode to be used for the comparison. For floating-point, CCFPmode return the mode to be used for the comparison. */
should be used. */
#define SELECT_CC_MODE(OP,X,Y) pdp11_cc_mode (OP, X, Y)
/* Enable compare elimination pass.
FIXME: how can this be enabled for two registers? */
#undef TARGET_FLAGS_REGNUM
#define TARGET_FLAGS_REGNUM CC_REGNUM
#define SELECT_CC_MODE(OP,X,Y) \ /* Specify the CC registers. TODO: is this for "type 1" CC handling only? */
(GET_MODE_CLASS(GET_MODE(X)) == MODE_FLOAT? CCFPmode : CCmode) #undef TARGET_FIXED_CONDITION_CODE_REGS
#define TARGET_FIXED_CONDITION_CODE_REGS pdp11_fixed_cc_regs
/* Specify the machine mode that pointers have. /* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction After generation of rtl, the compiler makes no further distinction
...@@ -447,54 +491,6 @@ extern int may_call_alloca; ...@@ -447,54 +491,6 @@ extern int may_call_alloca;
/* #define NO_FUNCTION_CSE */ /* #define NO_FUNCTION_CSE */
/* Tell emit-rtl.c how to initialize special values on a per-function base. */
extern rtx cc0_reg_rtx;
#define CC_STATUS_MDEP rtx
#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0)
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
#define CC_IN_FPU 04000
/* Do UPDATE_CC if EXP is a set, used in
NOTICE_UPDATE_CC
floats only do compare correctly, else nullify ...
get cc0 out soon ...
*/
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
#define NOTICE_UPDATE_CC(EXP, INSN) \
{ if (GET_CODE (EXP) == SET) \
{ \
notice_update_cc_on_set(EXP, INSN); \
} \
else if (GET_CODE (EXP) == PARALLEL \
&& GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \
{ \
notice_update_cc_on_set(XVECEXP (EXP, 0, 0), INSN); \
} \
else if (GET_CODE (EXP) == CALL) \
{ /* all bets are off */ CC_STATUS_INIT; } \
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \
&& cc_status.value2 \
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \
{ \
printf ("here!\n"); \
cc_status.value2 = 0; \
} \
}
/* Control the assembler format that we output. */ /* Control the assembler format that we output. */
/* Output to assembler file text saying following lines /* Output to assembler file text saying following lines
...@@ -520,7 +516,8 @@ extern rtx cc0_reg_rtx; ...@@ -520,7 +516,8 @@ extern rtx cc0_reg_rtx;
#define REGISTER_NAMES \ #define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \ {"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \
"ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap" } "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap", \
"cc", "fcc" }
/* Globalizing directive for a label. */ /* Globalizing directive for a label. */
#define GLOBAL_ASM_OP "\t.globl " #define GLOBAL_ASM_OP "\t.globl "
...@@ -603,10 +600,7 @@ extern rtx cc0_reg_rtx; ...@@ -603,10 +600,7 @@ extern rtx cc0_reg_rtx;
#define TRAMPOLINE_SIZE 8 #define TRAMPOLINE_SIZE 8
#define TRAMPOLINE_ALIGNMENT 16 #define TRAMPOLINE_ALIGNMENT 16
/* there is no point in avoiding branches on a pdp, #define BRANCH_COST(speed_p, predictable_p) 1
since branches are really cheap - I just want to find out
how much difference the BRANCH_COST macro makes in code */
#define BRANCH_COST(speed_p, predictable_p) pdp11_branch_cost ()
#define COMPARE_FLAG_MODE HImode #define COMPARE_FLAG_MODE HImode
......
...@@ -44,27 +44,79 @@ ...@@ -44,27 +44,79 @@
;; arguments. ;; arguments.
(FRAME_POINTER_REGNUM 14) (FRAME_POINTER_REGNUM 14)
(ARG_POINTER_REGNUM 15) (ARG_POINTER_REGNUM 15)
(FIRST_PSEUDO_REGISTER 16) ;; Condition code registers
(CC_REGNUM 16)
(FCC_REGNUM 17)
;; End of hard registers
(FIRST_PSEUDO_REGISTER 18)
;; Branch offset limits, as byte offsets from instruction address ;; Branch offset limits, as byte offsets from instruction address
(MIN_BRANCH -254) (MIN_BRANCH -254)
(MAX_BRANCH 256) (MAX_BRANCH 256)
(MIN_SOB -126) (MIN_SOB -126)
(MAX_SOB 0)]) (MAX_SOB 0)])
;; DF is 64 bit
;; SF is 32 bit
;; SI is 32 bit
;; HI is 16 bit ;; HI is 16 bit
;; QI is 8 bit ;; QI is 8 bit
;; Integer modes supported on the PDP11, with a mapping from machine mode ;; Integer modes supported on the PDP11, with a mapping from machine mode
;; to mnemonic suffix. SImode and DImode always are special cases. ;; to mnemonic suffix. SImode and DImode are usually special cases.
(define_mode_iterator PDPint [QI HI]) (define_mode_iterator PDPint [QI HI])
(define_mode_attr isfx [(QI "b") (HI "")]) (define_mode_attr isfx [(QI "b") (HI "")])
(define_mode_attr mname [(QI "QImode") (HI "HImode") (SI "SImode") (DI "DImode")])
(define_mode_attr e_mname [(QI "E_QImode") (HI "E_HImode") (SI "E_SImode") (DI "E_DImode")])
(define_mode_attr hmode [(QI "hi") (HI "hi") (SI "si") (DI "di")])
;; These are analogous for use in splitters and expanders.
(define_mode_iterator HSint [HI SI])
(define_mode_iterator QHSint [QI HI SI])
(define_mode_iterator QHSDint [QI HI SI DI])
(define_code_iterator SHF [ashift ashiftrt lshiftrt])
;; Substitution to turn a CC clobber into a CC setter. We have four of
;; these: for CCmode vs. CCNZmode, and for CC_REGNUM vs. FCC_REGNUM.
(define_subst "cc_cc"
[(set (match_operand 0 "") (match_operand 1 ""))
(clobber (reg CC_REGNUM))]
""
[(set (reg:CC CC_REGNUM)
(compare:CC (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. (define_subst "cc_ccnz"
[(set (match_operand 0 "") (match_operand 1 ""))
(clobber (reg CC_REGNUM))]
""
[(set (reg:CCNZ CC_REGNUM)
(compare:CCNZ (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])
(define_subst "fcc_cc"
[(set (match_operand 0 "") (match_operand 1 ""))
(clobber (reg FCC_REGNUM))]
""
[(set (reg:CC FCC_REGNUM)
(compare:CC (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])
;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code (define_subst "fcc_ccnz"
;;- updates for most instructions. [(set (match_operand 0 "") (match_operand 1 ""))
(clobber (reg FCC_REGNUM))]
""
[(set (reg:CCNZ FCC_REGNUM)
(compare:CCNZ (match_dup 1) (const_int 0)))
(set (match_dup 0) (match_dup 1))])
(define_subst_attr "cc_cc" "cc_cc" "_nocc" "_cc")
(define_subst_attr "fcc_cc" "fcc_cc" "_nocc" "_cc")
(define_subst_attr "cc_ccnz" "cc_ccnz" "_nocc" "_cc")
(define_subst_attr "fcc_ccnz" "fcc_ccnz" "_nocc" "_cc")
;;- Operand classes for the register allocator: ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;; Compare instructions. ;; Compare instructions.
...@@ -82,16 +134,6 @@ ...@@ -82,16 +134,6 @@
;; and ucmp_optab for mode SImode, because we don't have that!!! ;; and ucmp_optab for mode SImode, because we don't have that!!!
;; - yet since no libfunc is there, we abort () ;; - yet since no libfunc is there, we abort ()
;; The only thing that remains to be done then is output
;; the floats in a way the assembler can handle it (and
;; if you're really into it, use a PDP11 float emulation
;; library to do floating point constant folding - but
;; I guess you'll get reasonable results even when not
;; doing this)
;; the last thing to do is fix the UPDATE_CC macro to check
;; for floating point condition codes, and set cc_status
;; properly, also setting the CC_IN_FCCR flag.
;; define attributes ;; define attributes
;; currently type is only fpu or arith or unknown, maybe branch later ? ;; currently type is only fpu or arith or unknown, maybe branch later ?
;; default is arith ;; default is arith
...@@ -163,23 +205,30 @@ ...@@ -163,23 +205,30 @@
;; compare ;; compare
(define_insn "*cmpdf" (define_insn "*cmpdf"
[(set (cc0) [(set (reg:CC FCC_REGNUM)
(compare (match_operand:DF 0 "general_operand" "fR,fR,Q,QF") (compare:CC (match_operand:DF 0 "general_operand" "fR,fR,Q,QF")
(match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))] (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))]
"TARGET_FPU" "TARGET_FPU && reload_completed"
"* "*
{ {
cc_status.flags = CC_IN_FPU;
if (which_alternative == 0 || which_alternative == 2) if (which_alternative == 0 || which_alternative == 2)
return \"{tstd|tstf} %0\;cfcc\"; return \"{tstd|tstf} %0\";
else else
return \"{cmpd|cmpf} %0, %1\;cfcc\"; return \"{cmpd|cmpf} %0, %1\";
}" }"
[(set_attr "length" "4,4,6,6")]) [(set_attr "length" "2,2,4,4")
(set_attr "type" "fp")])
(define_insn "*cmp<mode>"
[(set (cc0) ;; Copy floating point processor condition code register to main CPU
(compare (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi") ;; condition code register.
(define_insn "*cfcc"
[(set (reg CC_REGNUM) (reg FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"cfcc")
(define_insn "cmp<mode>"
[(set (reg:CC CC_REGNUM)
(compare:CC (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi")
(match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))] (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))]
"" ""
"@ "@
...@@ -191,8 +240,7 @@ ...@@ -191,8 +240,7 @@
cmp<PDPint:isfx> %0,%1" cmp<PDPint:isfx> %0,%1"
[(set_attr "length" "2,2,4,4,4,6")]) [(set_attr "length" "2,2,4,4,4,6")])
;; sob instruction - we need an assembler which can make this instruction ;; sob instruction - FIXME: this doesn't do anything, need to use doloop_end.
;; valid under _all_ circumstances!
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
...@@ -208,22 +256,17 @@ ...@@ -208,22 +256,17 @@
"TARGET_40_PLUS" "TARGET_40_PLUS"
"* "*
{ {
static int labelcount = 0;
static char buf[1000];
if (get_attr_length (insn) == 2) if (get_attr_length (insn) == 2)
return \"sob %0, %l1\"; return \"sob %0, %l1\";
/* emulate sob */ /* emulate sob */
operands[2] = gen_label_rtx ();
output_asm_insn (\"dec %0\", operands); output_asm_insn (\"dec %0\", operands);
output_asm_insn (\"beq %l2\", operands);
sprintf (buf, \"bge LONG_SOB%d\", labelcount);
output_asm_insn (buf, NULL);
output_asm_insn (\"jmp %l1\", operands); output_asm_insn (\"jmp %l1\", operands);
sprintf (buf, \"LONG_SOB%d:\", labelcount++); output_asm_label (operands[2]);
output_asm_insn (buf, NULL); fputs (\":\\n\", asm_out_file);
return \"\"; return \"\";
}" }"
...@@ -238,46 +281,73 @@ ...@@ -238,46 +281,73 @@
;; These control RTL generation for conditional jump insns ;; These control RTL generation for conditional jump insns
;; and match them for register allocation. ;; and match them for register allocation.
;; Post reload these get expanded into insns that actually
(define_expand "cbranchdf4" ;; manipulate the condition code registers. We can't do that before
[(set (cc0) ;; because instructions generated by reload clobber condition codes (new
(compare (match_operand:DF 1 "general_operand") ;; CC design, type #2).
(match_operand:DF 2 "register_or_const0_operand"))) (define_insn_and_split "cbranchdf4"
(set (pc) [(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator" (if_then_else (match_operator 0 "ordered_comparison_operator"
[(cc0) (const_int 0)]) [(match_operand:DF 1 "general_operand" "fg")
(match_operand:DF 2 "general_operand" "a")])
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (pc)))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(set (reg:CC FCC_REGNUM)
(compare:CC (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (match_op_dup 0
[(reg:CC FCC_REGNUM) (const_int 0)])
(label_ref (match_dup 3))
(pc)))]
"") "")
(define_expand "cbranch<mode>4" (define_insn_and_split "cbranch<mode>4"
[(set (cc0) [(set (pc)
(compare (match_operand:PDPint 1 "general_operand")
(match_operand:PDPint 2 "general_operand")))
(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator" (if_then_else (match_operator 0 "ordered_comparison_operator"
[(cc0) (const_int 0)]) [(match_operand:PDPint 1 "general_operand" "g")
(match_operand:PDPint 2 "general_operand" "g")])
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (pc)))]
"" ""
"#"
"reload_completed"
[(set (reg:CC CC_REGNUM)
(compare:CC (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (match_op_dup 0
[(reg:CC CC_REGNUM) (const_int 0)])
(label_ref (match_dup 3))
(pc)))]
"") "")
;; problem with too short jump distance! we need an assembler which can ;; This splitter turns a branch on float condition into a branch on
;; make this valid for all jump distances! ;; CPU condition, by adding a CFCC.
;; e.g. gas! (define_split
[(set (pc)
;; these must be changed to check for CC_IN_FCCR if float is to be (if_then_else (match_operator 0 "ordered_comparison_operator"
;; enabled [(reg:CC FCC_REGNUM) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_FPU && reload_completed"
[(set (reg:CC CC_REGNUM) (reg:CC FCC_REGNUM))
(set (pc)
(if_then_else (match_op_dup 0
[(reg:CC CC_REGNUM) (const_int 0)])
(label_ref (match_dup 1))
(pc)))]
"")
(define_insn "*branch" (define_insn "cond_branch"
[(set (pc) [(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator" (if_then_else (match_operator 0 "ordered_comparison_operator"
[(cc0) (const_int 0)]) [(reg:CC CC_REGNUM) (const_int 0)])
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"" "reload_completed"
"* return output_jump(GET_CODE (operands[0]), 0, get_attr_length(insn));" "* return output_jump (operands, 0, get_attr_length (insn));"
[(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1) [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1)
(pc)) (pc))
(const_int MIN_BRANCH)) (const_int MIN_BRANCH))
...@@ -287,17 +357,14 @@ ...@@ -287,17 +357,14 @@
(const_int 6) (const_int 6)
(const_int 2)))]) (const_int 2)))])
(define_insn "*branch"
;; These match inverted jump insns for register allocation.
(define_insn "*branch_inverted"
[(set (pc) [(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator" (if_then_else (match_operator 0 "ccnz_operator"
[(cc0) (const_int 0)]) [(reg:CCNZ CC_REGNUM) (const_int 0)])
(pc) (label_ref (match_operand 1 "" ""))
(label_ref (match_operand 1 "" ""))))] (pc)))]
"" "reload_completed"
"* return output_jump(GET_CODE (operands[0]), 1, get_attr_length(insn));" "* return output_jump (operands, 1, get_attr_length (insn));"
[(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1) [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1)
(pc)) (pc))
(const_int MIN_BRANCH)) (const_int MIN_BRANCH))
...@@ -307,12 +374,21 @@ ...@@ -307,12 +374,21 @@
(const_int 6) (const_int 6)
(const_int 2)))]) (const_int 2)))])
;; Move instructions ;; Move instructions
(define_insn "movdi" (define_insn "movdi"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g") [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g")
(match_operand:DI 1 "general_operand" "rN,g"))] (match_operand:DI 1 "general_operand" "rN,g"))]
"" ""
"")
(define_insn "*movdi_nocc"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g")
(match_operand:DI 1 "general_operand" "rN,g"))
(clobber (reg:CC CC_REGNUM))]
""
"* return output_move_multiple (operands);" "* return output_move_multiple (operands);"
[(set_attr "length" "16,32")]) [(set_attr "length" "16,32")])
...@@ -320,6 +396,13 @@ ...@@ -320,6 +396,13 @@
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g") [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g")
(match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))] (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))]
"" ""
"")
(define_insn "*movsi_nocc"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g")
(match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))
(clobber (reg:CC CC_REGNUM))]
""
"* return output_move_multiple (operands);" "* return output_move_multiple (operands);"
[(set_attr "length" "4,6,8,16")]) [(set_attr "length" "4,6,8,16")])
...@@ -327,6 +410,25 @@ ...@@ -327,6 +410,25 @@
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))] (match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))]
"" ""
"")
;; This splits all the integer moves: DI and SI modes as well as
;; the simple machine operations.
(define_split
[(set (match_operand:QHSDint 0 "nonimmediate_operand" "")
(match_operand:QHSDint 1 "general_operand" ""))]
"reload_completed"
[(parallel [(set (match_dup 0)
(match_dup 1))
(clobber (reg:CC CC_REGNUM))])]
"")
;; MOV clears V
(define_insn "*mov<mode>_<cc_cc>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
if (operands[1] == const0_rtx) if (operands[1] == const0_rtx)
...@@ -336,31 +438,87 @@ ...@@ -336,31 +438,87 @@
}" }"
[(set_attr "length" "2,4,4,6")]) [(set_attr "length" "2,4,4,6")])
(define_insn "movdf" ;; movdf has unusually complicated condition code handling, because
[(set (match_operand:DF 0 "float_nonimm_operand" "=a,fR,a,Q,g") ;; load (into float register) updates the FCC, while store (from
(match_operand:DF 1 "float_operand" "fR,a,FQ,a,g"))] ;; float register) leaves it untouched.
;;
;; 1. Loads are: ac4, ac5, or non-register into load-register
;; 2. Stores are: load-register to non-register, ac4, or ac5
;; 3. Moves from ac0-ac3 to another ac0-ac3 can be handled
;; either as loads or as stores.
(define_expand "movdf"
[(set (match_operand:DF 0 "float_nonimm_operand" "")
(match_operand:DF 1 "float_operand" ""))]
"TARGET_FPU" "TARGET_FPU"
"* if (which_alternative ==0 || which_alternative == 2) "")
return \"ldd %1, %0\";
else if (which_alternative == 1 || which_alternative == 3)
return \"std %1, %0\";
else
return output_move_multiple (operands); "
;; last one is worst-case
[(set_attr "length" "2,2,4,4,24")])
(define_insn "movsf" ;; Splitter for all these cases. Store is the first two
[(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,g") ;; alternatives, which are not split. Note that case 3
(match_operand:SF 1 "float_operand" "fR,a,FQ,a,g"))] ;; is treated as a store, i.e., not split.
(define_insn_and_split "movdf_split"
[(set (match_operand:DF 0 "float_nonimm_operand" "=fR,FQ,a,a,a")
(match_operand:DF 1 "float_operand" "a,a,hR,FQ,G"))]
"TARGET_FPU" "TARGET_FPU"
"* if (which_alternative ==0 || which_alternative == 2) "*
return \"{ldcfd|movof} %1, %0\"; gcc_assert (which_alternative < 2);
else if (which_alternative == 1 || which_alternative == 3) return \"std %1, %0\";
return \"{stcdf|movfo} %1, %0\"; "
else "&& reload_completed"
return output_move_multiple (operands); " [(parallel [(set (match_dup 0)
;; last one is worst-case (match_dup 1))
[(set_attr "length" "2,2,4,4,12")]) (clobber (reg:CC FCC_REGNUM))])]
"{
if (GET_CODE (operands[1]) == REG &&
REGNO_REG_CLASS (REGNO (operands[1])) == LOAD_FPU_REGS)
FAIL;
}"
[(set_attr "length" "2,4,0,0,0")])
;; Loads (case 1).
(define_insn "*ldd<fcc_cc>"
[(set (match_operand:DF 0 "float_nonimm_operand" "=a,a,a")
(match_operand:DF 1 "float_operand" "hR,FQ,G"))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"@
ldd %1, %0
ldd %1, %0
clrd %0"
[(set_attr "length" "2,4,2")])
;; SFmode is easier because that uses convert load/store, which
;; always change condition codes.
;; Note that these insns are cheating a bit. We actually have
;; DFmode operands in the FPU registers, which is why the
;; ldcfd and stcdf instructions appear. But GCC likes to think
;; of these as SFmode loads and does the conversion once in the
;; register, at least in many cases. So we pretend to do this,
;; but then extend and truncate register-to-register are NOP and
;; generate no code.
(define_insn_and_split "movsf"
[(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q")
(match_operand:SF 1 "float_operand" "fRG,a,FQ,a"))]
"TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(match_dup 1))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "*movsf<fcc_ccnz>"
[(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,a")
(match_operand:SF 1 "float_operand" "fR,a,FQ,a,G"))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"@
{ldcfd|movof} %1, %0
{stcdf|movfo} %1, %0
{ldcfd|movof} %1, %0
{stcdf|movfo} %1, %0
clrf %0"
[(set_attr "length" "2,2,4,4,2")])
;; maybe fiddle a bit with move_ratio, then ;; maybe fiddle a bit with move_ratio, then
;; let constraints only accept a register ... ;; let constraints only accept a register ...
...@@ -374,7 +532,7 @@ ...@@ -374,7 +532,7 @@
(clobber (match_dup 4)) (clobber (match_dup 4))
(clobber (match_dup 5)) (clobber (match_dup 5))
(clobber (match_dup 2))])] (clobber (match_dup 2))])]
"(TARGET_BCOPY_BUILTIN)" ""
" "
{ {
operands[0] operands[0]
...@@ -389,7 +547,7 @@ ...@@ -389,7 +547,7 @@
}") }")
(define_insn "movmemhi1" (define_insn "*movmemhi1"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "r,r")) [(set (mem:BLK (match_operand:HI 0 "register_operand" "r,r"))
(mem:BLK (match_operand:HI 1 "register_operand" "r,r"))) (mem:BLK (match_operand:HI 1 "register_operand" "r,r")))
(use (match_operand:HI 2 "general_operand" "n,r")) (use (match_operand:HI 2 "general_operand" "n,r"))
...@@ -398,7 +556,7 @@ ...@@ -398,7 +556,7 @@
(clobber (match_dup 0)) (clobber (match_dup 0))
(clobber (match_dup 1)) (clobber (match_dup 1))
(clobber (match_dup 2))] (clobber (match_dup 2))]
"(TARGET_BCOPY_BUILTIN)" ""
"* return output_block_move (operands);" "* return output_block_move (operands);"
;;; just a guess ;;; just a guess
[(set_attr "length" "80")]) [(set_attr "length" "80")])
...@@ -407,29 +565,56 @@ ...@@ -407,29 +565,56 @@
;;- truncation instructions ;;- truncation instructions
(define_insn "truncdfsf2" ;; We sometimes end up doing a register to register truncate,
;; which isn't right because we actually load registers always
;; with a DFmode value. But even with PROMOTE the compiler
;; doesn't always get that (so we don't use it). That means
;; a register to register truncate is a NOP.
(define_insn_and_split "truncdfsf2"
[(set (match_operand:SF 0 "float_nonimm_operand" "=f,R,Q") [(set (match_operand:SF 0 "float_nonimm_operand" "=f,R,Q")
(float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))] (float_truncate:SF (match_operand:DF 1 "register_operand" "0,a,a")))]
"TARGET_FPU" "TARGET_FPU"
"* if (which_alternative ==0)
{ {
return \"\"; gcc_assert (which_alternative == 0);
return "";
} }
else if (which_alternative == 1) "&& reload_completed"
return \"{stcdf|movfo} %1, %0\"; [(parallel [(set (match_dup 0) (float_truncate:SF (match_dup 1)))
else (clobber (reg:CC FCC_REGNUM))])]
return \"{stcdf|movfo} %1, %0\"; "{
" if (GET_CODE (operands[0]) == REG &&
[(set_attr "length" "0,2,4")]) GET_CODE (operands[1]) == REG &&
REGNO (operands[0]) == REGNO (operands[1]))
FAIL;
}"
[(set_attr "length" "0,0,0")])
(define_insn "*truncdfsf2_<fcc_cc>"
[(set (match_operand:SF 0 "float_nonimm_operand" "=R,Q")
(float_truncate:SF (match_operand:DF 1 "register_operand" "a,a")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{stcdf|movfo} %1, %0"
[(set_attr "length" "2,4")])
;;- zero extension instructions ;;- zero extension instructions
(define_insn "zero_extendqihi2" (define_insn_and_split "zero_extendqihi2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))] (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (zero_extend:HI (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*zero_extendqihi2<cc_cc>"
[(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))
(clobber (reg:CC CC_REGNUM))])]
"reload_completed"
"bic $0177400, %0" "bic $0177400, %0"
[(set_attr "length" "4,6")]) [(set_attr "length" "4,6")])
...@@ -448,56 +633,73 @@ ...@@ -448,56 +633,73 @@
;;- sign extension instructions ;;- sign extension instructions
(define_insn "extendsfdf2" ;; We sometimes end up doing a register to register extend,
;; which isn't right because we actually load registers always
;; with a DFmode value. But even with PROMOTE the compiler
;; doesn't always get that (so we don't use it). That means
;; a register to register truncate is a NOP.
(define_insn_and_split "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f,a,a") [(set (match_operand:DF 0 "register_operand" "=f,a,a")
(float_extend:DF (match_operand:SF 1 "float_operand" "f,R,Q")))] (float_extend:DF (match_operand:SF 1 "float_operand" "0,R,Q")))]
"TARGET_FPU" "TARGET_FPU"
"@ {
/* nothing */ gcc_assert (which_alternative == 0);
{ldcfd|movof} %1, %0 return "";
{ldcfd|movof} %1, %0" }
[(set_attr "length" "0,2,4")]) "&& reload_completed"
[(parallel [(set (match_dup 0) (float_extend:DF (match_dup 1)))
(clobber (reg:CC FCC_REGNUM))])]
"{
if (GET_CODE (operands[0]) == REG &&
GET_CODE (operands[1]) == REG &&
REGNO (operands[0]) == REGNO (operands[1]))
FAIL;
}"
[(set_attr "length" "0,0,0")])
;; does movb sign extend in register-to-register move? (define_insn "*extendsfdf2_<fcc_cc>"
(define_insn "extendqihi2" [(set (match_operand:DF 0 "register_operand" "=a,a")
(float_extend:DF (match_operand:SF 1 "float_operand" "R,Q")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{ldcfd|movof} %1, %0"
[(set_attr "length" "2,4")])
;; movb sign extends if destination is a register
(define_insn_and_split "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r,r") [(set (match_operand:HI 0 "register_operand" "=r,r")
(sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))] (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
"")
;; MOVB clears V
(define_insn "*extendqihi2<cc_cc>"
[(set (match_operand:HI 0 "register_operand" "=r,r")
(sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"movb %1, %0" "movb %1, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_insn "extendqisi2" (define_insn_and_split "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r") [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r")
(sign_extend:SI (match_operand:QI 1 "general_operand" "rR,Q")))] (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"* "#"
{ "&& reload_completed"
rtx latehalf[2]; [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
/* make register pair available */
latehalf[0] = operands[0];
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+ 1);
output_asm_insn(\"movb %1, %0\", operands);
output_asm_insn(\"sxt %0\", latehalf);
return \"\";
}"
[(set_attr "length" "4,6")])
;; maybe we have to use define_expand to say that we have the instruction,
;; unconditionally, and then match dependent on CPU type:
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(sign_extend:SI (match_operand:HI 1 "general_operand" "g")))]
""
"") "")
(define_insn "" ; "extendhisi2" (define_insn "*extendhisi2_nocc"
[(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r") [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r")
(sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))] (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))
"TARGET_40_PLUS" (clobber (reg:CC CC_REGNUM))]
"TARGET_40_PLUS && reload_completed"
"* "*
{ {
rtx latehalf[2]; rtx latehalf[2];
...@@ -542,48 +744,29 @@ ...@@ -542,48 +744,29 @@
}" }"
[(set_attr "length" "10,6,6")]) [(set_attr "length" "10,6,6")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "general_operand" "0")))]
"(! TARGET_40_PLUS)"
"*
{
static int count = 0;
char buf[100];
rtx lateoperands[2];
lateoperands[0] = operands[0];
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
output_asm_insn(\"tst %0\", operands);
sprintf(buf, \"bge extendhisi%d\", count);
output_asm_insn(buf, NULL);
output_asm_insn(\"mov -1, %0\", lateoperands);
sprintf(buf, \"bne extendhisi%d\", count+1);
output_asm_insn(buf, NULL);
sprintf(buf, \"\\nextendhisi%d:\", count);
output_asm_insn(buf, NULL);
output_asm_insn(\"clr %0\", lateoperands);
sprintf(buf, \"\\nextendhisi%d:\", count+1);
output_asm_insn(buf, NULL);
count += 2;
return \"\";
}"
[(set_attr "length" "12")])
;; make float to int and vice versa ;; make float to int and vice versa
;; using the cc_status.flag field we could probably cut down
;; on seti and setl
;; assume that we are normally in double and integer mode - ;; assume that we are normally in double and integer mode -
;; what do pdp library routines do to fpu mode ? ;; what do pdp library routines do to fpu mode ?
(define_insn "floatsidf2" ;; Note: the hardware treats register source as
;; a 16-bit (high order only) source, which isn't
;; what we want. But we do need to support register
;; dest because gcc asks for it.
(define_insn_and_split "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=a,a,a") [(set (match_operand:DF 0 "register_operand" "=a,a,a")
(float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))] (float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (float:DF (match_dup 1)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "*floatsidf2<fcc_cc>"
[(set (match_operand:DF 0 "register_operand" "=a,a,a")
(float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"* if (which_alternative ==0) "* if (which_alternative ==0)
{ {
rtx latehalf[2]; rtx latehalf[2];
...@@ -598,25 +781,53 @@ ...@@ -598,25 +781,53 @@
output_asm_insn(\"seti\", operands); output_asm_insn(\"seti\", operands);
return \"\"; return \"\";
} }
else if (which_alternative == 1)
return \"setl\;{ldcld|movif} %1, %0\;seti\";
else else
return \"setl\;{ldcld|movif} %1, %0\;seti\"; return \"setl\;{ldcld|movif} %1, %0\;seti\";
" "
[(set_attr "length" "10,6,8")]) [(set_attr "length" "10,6,8")])
(define_insn "floathidf2" (define_insn_and_split "floathidf2"
[(set (match_operand:DF 0 "register_operand" "=a,a") [(set (match_operand:DF 0 "register_operand" "=a,a")
(float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))] (float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (float:DF (match_dup 1)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "*floathidf2<fcc_cc>"
[(set (match_operand:DF 0 "register_operand" "=a,a")
(float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{ldcid|movif} %1, %0" "{ldcid|movif} %1, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;; cut float to int ;; cut float to int
(define_insn "fix_truncdfsi2"
;; Note: the hardware treats register destination as
;; a 16-bit (high order only) destination, which isn't
;; what we want. But we do need to support register
;; dest because gcc asks for it.
(define_insn_and_split "fix_truncdfsi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q") [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q")
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))] (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (fix:SI (fix:DF (match_dup 1))))
(clobber (reg:CC CC_REGNUM))
(clobber (reg:CC FCC_REGNUM))])]
"")
;; Note: this clobbers both sets of condition codes!
(define_insn "*fix_truncdfsi2_nocc"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q")
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))
(clobber (reg:CC CC_REGNUM))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"* if (which_alternative ==0) "* if (which_alternative ==0)
{ {
output_asm_insn(\"setl\", operands); output_asm_insn(\"setl\", operands);
...@@ -627,17 +838,29 @@ ...@@ -627,17 +838,29 @@
output_asm_insn(\"mov (sp)+, %0\", operands); output_asm_insn(\"mov (sp)+, %0\", operands);
return \"\"; return \"\";
} }
else if (which_alternative == 1)
return \"setl\;{stcdl|movfi} %1, %0\;seti\";
else else
return \"setl\;{stcdl|movfi} %1, %0\;seti\"; return \"setl\;{stcdl|movfi} %1, %0\;seti\";
" "
[(set_attr "length" "10,6,8")]) [(set_attr "length" "10,6,8")])
(define_insn "fix_truncdfhi2" (define_insn_and_split "fix_truncdfhi2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))] (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (fix:HI (fix:DF (match_dup 1))))
(clobber (reg:CC CC_REGNUM))
(clobber (reg:CC FCC_REGNUM))])]
"")
;; Note: this clobbers both sets of condition codes!
(define_insn "*fix_truncdfhi2_nocc"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))
(clobber (reg:CC CC_REGNUM))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{stcdi|movfi} %1, %0" "{stcdi|movfi} %1, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
...@@ -645,19 +868,45 @@ ...@@ -645,19 +868,45 @@
;;- arithmetic instructions ;;- arithmetic instructions
;;- add instructions ;;- add instructions
(define_insn "adddf3" (define_insn_and_split "adddf3"
[(set (match_operand:DF 0 "register_operand" "=a,a") [(set (match_operand:DF 0 "register_operand" "=a,a")
(plus:DF (match_operand:DF 1 "register_operand" "%0,0") (plus:DF (match_operand:DF 1 "register_operand" "%0,0")
(match_operand:DF 2 "general_operand" "fR,QF")))] (match_operand:DF 2 "general_operand" "fR,QF")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(plus:DF (match_dup 1) (match_dup 2)))
(clobber (reg:CC FCC_REGNUM))])]
"")
;; Float add sets V if overflow from add
(define_insn "*adddf3<fcc_ccnz>"
[(set (match_operand:DF 0 "register_operand" "=a,a")
(plus:DF (match_operand:DF 1 "register_operand" "%0,0")
(match_operand:DF 2 "general_operand" "fR,QF")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{addd|addf} %2, %0" "{addd|addf} %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_insn "adddi3" (define_insn_and_split "adddi3"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
(plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0") (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0")
(match_operand:DI 2 "general_operand" "r,on,r,on")))] (match_operand:DI 2 "general_operand" "r,on,r,on")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*adddi3_nocc"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
(plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0")
(match_operand:DI 2 "general_operand" "r,on,r,on")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
rtx inops[2]; rtx inops[2];
...@@ -701,11 +950,23 @@ ...@@ -701,11 +950,23 @@
;; high word is added at the end, so the adding of the high parts ;; high word is added at the end, so the adding of the high parts
;; will always used the original high part and not a high part ;; will always used the original high part and not a high part
;; modified by carry (which would amount to double carry). ;; modified by carry (which would amount to double carry).
(define_insn "addsi3" (define_insn_and_split "addsi3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o") [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
(plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0") (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0")
(match_operand:SI 2 "general_operand" "r,on,r,on")))] (match_operand:SI 2 "general_operand" "r,on,r,on")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*addsi3_nocc"
[(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
(plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0")
(match_operand:SI 2 "general_operand" "r,on,r,on")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
rtx inops[2]; rtx inops[2];
...@@ -727,11 +988,25 @@ ...@@ -727,11 +988,25 @@
}" }"
[(set_attr "length" "6,10,12,16")]) [(set_attr "length" "6,10,12,16")])
(define_insn "addhi3" (define_insn_and_split "addhi3"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0") (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0")
(match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))] (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0)
(plus:HI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
;; Add sets V if overflow from the add
(define_insn "*addhi3<cc_ccnz>"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0")
(match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
if (GET_CODE (operands[2]) == CONST_INT) if (GET_CODE (operands[2]) == CONST_INT)
...@@ -752,19 +1027,44 @@ ...@@ -752,19 +1027,44 @@
;; args, since they are canonical plus:xx now! ;; args, since they are canonical plus:xx now!
;; also for minus:DF ?? ;; also for minus:DF ??
(define_insn "subdf3" (define_insn_and_split "subdf3"
[(set (match_operand:DF 0 "register_operand" "=a,a") [(set (match_operand:DF 0 "register_operand" "=a,a")
(minus:DF (match_operand:DF 1 "register_operand" "0,0") (minus:DF (match_operand:DF 1 "register_operand" "0,0")
(match_operand:DF 2 "general_operand" "fR,Q")))] (match_operand:DF 2 "general_operand" "fR,Q")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(minus:DF (match_dup 1) (match_dup 2)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "*subdf3<fcc_ccnz>"
[(set (match_operand:DF 0 "register_operand" "=a,a")
(minus:DF (match_operand:DF 1 "register_operand" "0,0")
(match_operand:DF 2 "general_operand" "fR,QF")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{subd|subf} %2, %0" "{subd|subf} %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_insn "subdi3" (define_insn_and_split "subdi3"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
(minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0") (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0")
(match_operand:DI 2 "general_operand" "r,on,r,on")))] (match_operand:DI 2 "general_operand" "r,on,r,on")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*subdi3_nocc"
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
(minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0")
(match_operand:DI 2 "general_operand" "r,on,r,on")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
rtx inops[2]; rtx inops[2];
...@@ -799,11 +1099,23 @@ ...@@ -799,11 +1099,23 @@
}" }"
[(set_attr "length" "20,28,40,48")]) [(set_attr "length" "20,28,40,48")])
(define_insn "subsi3" (define_insn_and_split "subsi3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o") [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
(minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
(match_operand:SI 2 "general_operand" "r,on,r,on")))] (match_operand:SI 2 "general_operand" "r,on,r,on")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*subsi3_nocc"
[(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
(minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
(match_operand:SI 2 "general_operand" "r,on,r,on")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
rtx inops[2]; rtx inops[2];
...@@ -825,14 +1137,37 @@ ...@@ -825,14 +1137,37 @@
}" }"
[(set_attr "length" "6,10,12,16")]) [(set_attr "length" "6,10,12,16")])
(define_insn "subhi3" (define_insn_and_split "subhi3"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
(match_operand:HI 2 "general_operand" "rR,Qi,rR,Qi")))] (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0)
(minus:HI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
;; Note: the manual says that (minus m (const_int n)) is converted
;; to (plus m (const_int -n)) but that does not appear to be
;; the case when it's wrapped in a PARALLEL. So instead we handle
;; that case here, which is easy enough.
(define_insn "*subhi3<cc_ccnz>"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
(match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"* "*
{ {
gcc_assert (GET_CODE (operands[2]) != CONST_INT); if (GET_CODE (operands[2]) == CONST_INT)
{
if (INTVAL(operands[2]) == 1)
return \"dec %0\";
else if (INTVAL(operands[2]) == -1)
return \"inc %0\";
}
return \"sub %2, %0\"; return \"sub %2, %0\";
}" }"
...@@ -867,317 +1202,288 @@ ...@@ -867,317 +1202,288 @@
operands[1] = expand_unop (<MODE>mode, one_cmpl_optab, op1, 0, 1); operands[1] = expand_unop (<MODE>mode, one_cmpl_optab, op1, 0, 1);
}") }")
(define_insn "*bic<mode>" (define_insn_and_split "*bic<mode>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(and:PDPint (and:PDPint
(not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi")) (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi"))
(match_operand:PDPint 2 "general_operand" "0,0,0,0")))] (match_operand:PDPint 2 "general_operand" "0,0,0,0")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0)
(and:PDPint (not:PDPint (match_dup 1)) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*bic<mode><cc_cc>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(and:PDPint
(not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi"))
(match_operand:PDPint 2 "general_operand" "0,0,0,0")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"bic<PDPint:isfx> %1, %0" "bic<PDPint:isfx> %1, %0"
[(set_attr "length" "2,4,4,6")]) [(set_attr "length" "2,4,4,6")])
;;- Bit set (inclusive or) instructions ;;- Bit set (inclusive or) instructions
(define_insn "ior<mode>3" (define_insn_and_split "ior<mode>3"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0") (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0")
(match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))] (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0)
(ior:PDPint (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "ior<mode>3<cc_cc>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
(ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0")
(match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"bis<PDPint:isfx> %2, %0" "bis<PDPint:isfx> %2, %0"
[(set_attr "length" "2,4,4,6")]) [(set_attr "length" "2,4,4,6")])
;;- xor instructions ;;- xor instructions
(define_insn "xorhi3" (define_insn_and_split "xorhi3"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(xor:HI (match_operand:HI 1 "general_operand" "%0,0") (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
(match_operand:HI 2 "register_operand" "r,r")))] (match_operand:HI 2 "register_operand" "r,r")))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(xor:HI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*xorhi3<cc_cc>"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(xor:HI (match_operand:HI 1 "general_operand" "%0,0")
(match_operand:HI 2 "register_operand" "r,r")))
(clobber (reg:CC CC_REGNUM))]
"TARGET_40_PLUS && reload_completed"
"xor %2, %0" "xor %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;;- one complement instructions ;;- one complement instructions
(define_insn "one_cmpl<mode>2" (define_insn_and_split "one_cmpl<mode>2"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
(not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))] (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0)
(not:PDPint (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "*one_cmpl<mode>2<cc_cc>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
(not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
"com<PDPint:isfx> %0" "com<PDPint:isfx> %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;;- arithmetic shift instructions ;;- arithmetic shift instructions
(define_insn "ashlsi3" ;;
[(set (match_operand:SI 0 "register_operand" "=r,r") ;; There is a fair amount of complexity here because with -m10
(ashift:SI (match_operand:SI 1 "register_operand" "0,0") ;; (pdp-11/10, /20) we only have shift by one bit. Iterators are
(match_operand:HI 2 "general_operand" "rR,Qi")))] ;; used to reduce the amount of very similar code.
"TARGET_40_PLUS" ;;
"ashc %2,%0" ;; First the insns used for small constant shifts.
[(set_attr "length" "2,4")]) ;
;; The "length" attribute values are modified by the ADJUST_INSN_LENGTH
;; Arithmetic right shift on the pdp works by negating the shift count. ;; macro for the small constant shift case (first two alternatives).
(define_expand "ashrsi3" ;; For those, the value coded in the length attribute is the cost of just
[(set (match_operand:SI 0 "register_operand" "=r") ;; the shift for a single shift.
(ashift:SI (match_operand:SI 1 "register_operand" "0") (define_insn "<code><mode>_sc"
(match_operand:HI 2 "general_operand" "g")))] [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q")
(SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0")
(match_operand:HI 2 "expand_shift_operand" "O,O")))]
"" ""
" "* return pdp11_assemble_shift (operands, <QHSint:mname>, <CODE>);"
{ [(set_attr "length" "2,4")])
operands[2] = negate_rtx (HImode, operands[2]);
}")
;; define asl aslb asr asrb - ashc missing!
;; asl ;; Next, shifts that are done as a loop on base (11/10 class) machines.
(define_insn "" ;; This applies to shift counts too large to unroll, or variable shift
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") ;; counts. The check for count <= 0 is done before we get here.
(ashift:HI (match_operand:HI 1 "general_operand" "0,0") (define_insn "<code><mode>_base"
(const_int 1)))] [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q")
(SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0")
(match_operand:HI 2 "register_operand" "r,r")))
(clobber (match_dup 2))]
"" ""
"asl %0" "* return pdp11_assemble_shift (operands, <QHSint:mname>, <CODE>);"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;; and another possibility for asr is << -1 ;; Next the insns that use the extended instructions ash and ashc.
;; might cause problems since -1 can also be encoded as 65535! ;; Note that these are just left shifts, and HI/SI only. (Right shifts
;; not in gcc2 ??? ;; are done by shifting by a negative amount.)
(define_insn "aslhi_op"
;; asr [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r")
(define_insn ""
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
(ashift:HI (match_operand:HI 1 "general_operand" "0,0") (ashift:HI (match_operand:HI 1 "general_operand" "0,0")
(const_int -1)))] (match_operand:HI 2 "general_operand" "rR,Q")))]
"" "TARGET_40_PLUS"
"asr %0" "ash %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;; lsr (define_insn "aslsi_op"
(define_insn "lsrhi1" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r")
[(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") (ashift:SI (match_operand:SI 1 "general_operand" "0,0")
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0,0") (match_operand:HI 2 "general_operand" "rR,Q")))]
(const_int 1)))] "TARGET_40_PLUS"
"" "ashc %2, %0"
"clc\;ror %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_insn "lsrsi1" ;; Now the expanders that produce the insns defined above.
[(set (match_operand:SI 0 "register_operand" "=r") (define_expand "ashl<mode>3"
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0") [(match_operand:QHSint 0 "nonimmediate_operand" "")
(const_int 1)))] (match_operand:QHSint 1 "general_operand" "")
""
{
rtx lateoperands[2];
lateoperands[0] = operands[0];
operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
lateoperands[1] = operands[1];
operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
output_asm_insn (\"clc\", operands);
output_asm_insn (\"ror %0\", lateoperands);
output_asm_insn (\"ror %0\", operands);
return \"\";
}
[(set_attr "length" "10")])
(define_expand "lshrsi3"
[(match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "register_operand" "0")
(match_operand:HI 2 "general_operand" "")] (match_operand:HI 2 "general_operand" "")]
"" ""
" "
{ {
rtx r; rtx r;
if (!TARGET_40_PLUS && if (!pdp11_expand_shift (operands, gen_ashift<mode>_sc, gen_ashift<mode>_base))
(GET_CODE (operands[2]) != CONST_INT ||
(unsigned) INTVAL (operands[2]) > 3))
FAIL;
emit_insn (gen_lsrsi1 (operands[0], operands[1]));
if (GET_CODE (operands[2]) != CONST_INT)
{ {
r = gen_reg_rtx (HImode); if (<QHSint:e_mname> == E_QImode)
emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1)));
emit_insn (gen_ashrsi3 (operands[0], operands[0], r));
}
else if ((unsigned) INTVAL (operands[2]) != 1)
{ {
emit_insn (gen_ashlsi3 (operands[0], operands[0], r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1]));
GEN_INT (1 - INTVAL (operands[2])))); emit_insn (gen_aslhi_op (r, r, operands[2]));
emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
} }
DONE;
}
"
)
;; shift is by arbitrary count is expensive,
;; shift by one cheap - so let's do that, if
;; space doesn't matter
(define_insn ""
[(set (match_operand:HI 0 "nonimmediate_operand" "=r")
(ashift:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:HI 2 "expand_shift_operand" "O")))]
"! optimize_size"
"*
{
register int i;
for (i = 1; i <= abs(INTVAL(operands[2])); i++)
if (INTVAL(operands[2]) < 0)
output_asm_insn(\"asr %0\", operands);
else else
output_asm_insn(\"asl %0\", operands);
return \"\";
}"
;; longest is 4
[(set (attr "length") (const_int 8))])
;; aslb
(define_insn ""
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,o")
(ashift:QI (match_operand:QI 1 "general_operand" "0,0")
(match_operand:HI 2 "const_int_operand" "n,n")))]
""
"*
{ /* allowing predec or post_inc is possible, but hairy! */
int i, cnt;
cnt = INTVAL(operands[2]) & 0x0007;
for (i=0 ; i < cnt ; i++)
output_asm_insn(\"aslb %0\", operands);
return \"\";
}"
;; set attribute length ( match_dup 2 & 7 ) *(1 or 2) !!!
[(set_attr_alternative "length"
[(const_int 14)
(const_int 28)])])
;;; asr
;(define_insn ""
; [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
; (ashiftrt:HI (match_operand:HI 1 "general_operand" "0,0")
; (const_int 1)))]
; ""
; "asr %0"
; [(set_attr "length" "2,4")])
;; asrb
(define_insn ""
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,o")
(ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0")
(match_operand:HI 2 "const_int_operand" "n,n")))]
""
"*
{ /* allowing predec or post_inc is possible, but hairy! */
int i, cnt;
cnt = INTVAL(operands[2]) & 0x0007;
for (i=0 ; i < cnt ; i++)
output_asm_insn(\"asrb %0\", operands);
return \"\";
}"
[(set_attr_alternative "length"
[(const_int 14)
(const_int 28)])])
;; the following is invalid - too complex!!! - just say 14 !!!
; [(set (attr "length") (plus (and (match_dup 2)
; (const_int 14))
; (and (match_dup 2)
; (const_int 14))))])
;; can we get +-1 in the next pattern? should
;; have been caught by previous patterns!
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r")
(ashift:HI (match_operand:HI 1 "register_operand" "0,0")
(match_operand:HI 2 "general_operand" "rR,Qi")))]
"TARGET_40_PLUS"
"*
{
if (GET_CODE(operands[2]) == CONST_INT)
{ {
if (INTVAL(operands[2]) == 1) emit_insn (gen_asl<QHSint:hmode>_op (operands[0], operands[1], operands[2]));
return \"asl %0\";
else if (INTVAL(operands[2]) == -1)
return \"asr %0\";
} }
}
DONE;
}")
return \"ash %2,%0\"; (define_expand "ashr<mode>3"
}" [(match_operand:QHSint 0 "nonimmediate_operand" "")
[(set_attr "length" "2,4")]) (match_operand:QHSint 1 "general_operand" "")
(match_operand:HI 2 "general_operand" "")]
;; Arithmetic right shift on the pdp works by negating the shift count.
(define_expand "ashrhi3"
[(set (match_operand:HI 0 "register_operand" "=r")
(ashift:HI (match_operand:HI 1 "register_operand" "0")
(match_operand:HI 2 "general_operand" "g")))]
"" ""
" "
{ {
rtx r;
if (!pdp11_expand_shift (operands, gen_ashiftrt<mode>_sc, gen_ashiftrt<mode>_base))
{
operands[2] = negate_rtx (HImode, operands[2]); operands[2] = negate_rtx (HImode, operands[2]);
if (<QHSint:e_mname> == E_QImode)
{
r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1]));
emit_insn (gen_aslhi_op (r, r, operands[2]));
emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
}
else
{
emit_insn (gen_asl<QHSint:hmode>_op (operands[0], operands[1], operands[2]));
}
}
DONE;
}") }")
(define_expand "lshrhi3" (define_expand "lshr<mode>3"
[(match_operand:HI 0 "register_operand" "") [(match_operand:QHSint 0 "nonimmediate_operand" "")
(match_operand:HI 1 "register_operand" "") (match_operand:QHSint 1 "general_operand" "")
(match_operand:HI 2 "general_operand" "")] (match_operand:HI 2 "general_operand" "")]
"" ""
" "
{ {
rtx r; rtx r, n;
if (!TARGET_40_PLUS && if (!pdp11_expand_shift (operands, gen_lshiftrt<mode>_sc, gen_lshiftrt<mode>_base))
(GET_CODE (operands[2]) != CONST_INT || {
(unsigned) INTVAL (operands[2]) > 3)) if (<QHSint:e_mname> == E_QImode)
FAIL;
emit_insn (gen_lsrhi1 (operands[0], operands[1]));
if (GET_CODE (operands[2]) != CONST_INT)
{ {
r = gen_reg_rtx (HImode); r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1]));
emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1))); emit_insn (gen_aslhi_op (r, r, operands[2]));
emit_insn (gen_ashrhi3 (operands[0], operands[0], r)); emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
} }
else if ((unsigned) INTVAL (operands[2]) != 1) else
{
r = gen_reg_rtx (<QHSint:mname>);
emit_insn (gen_lshiftrt<mode>_sc (r, operands[1], const1_rtx));
if (GET_CODE (operands[2]) != CONST_INT)
{ {
emit_insn (gen_ashlhi3 (operands[0], operands[0], n = gen_reg_rtx (HImode);
emit_insn (gen_addhi3 (n, operands [2], GEN_INT (-1)));
emit_insn (gen_ashr<mode>3 (operands[0], r, n));
}
else
emit_insn (gen_asl<QHSint:hmode>_op (operands[0], r,
GEN_INT (1 - INTVAL (operands[2])))); GEN_INT (1 - INTVAL (operands[2]))));
} }
}
DONE; DONE;
} }")
"
)
;; absolute ;; absolute
(define_insn "absdf2" (define_insn_and_split "absdf2"
[(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
(abs:DF (match_operand:DF 1 "general_operand" "0,0")))] (abs:DF (match_operand:DF 1 "general_operand" "0,0")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (abs:DF (match_dup 1)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "absdf2<fcc_cc>"
[(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
(abs:DF (match_operand:DF 1 "general_operand" "0,0")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{absd|absf} %0" "{absd|absf} %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;; negate insns ;; negate insns
(define_insn "negdf2" (define_insn_and_split "negdf2"
[(set (match_operand:DF 0 "float_nonimm_operand" "=fR,Q") [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
(neg:DF (match_operand:DF 1 "register_operand" "0,0")))] (neg:DF (match_operand:DF 1 "general_operand" "0,0")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (neg:DF (match_dup 1)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "negdf2<fcc_cc>"
[(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
(neg:DF (match_operand:DF 1 "general_operand" "0,0")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{negd|negf} %0" "{negd|negf} %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_insn "negdi2" (define_insn_and_split "negdi2"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
(neg:DI (match_operand:DI 1 "general_operand" "0,0")))] (neg:DI (match_operand:DI 1 "general_operand" "0,0")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (neg:DI (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
"")
;; TODO: this can be neg/adc/neg/adc... I believe. Check. Saves one word.
(define_insn "negdi2_nocc"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
(neg:DI (match_operand:DI 1 "general_operand" "0,0")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
{ {
rtx exops[4][2]; rtx exops[4][2];
...@@ -1196,10 +1502,22 @@ ...@@ -1196,10 +1502,22 @@
} }
[(set_attr "length" "18,34")]) [(set_attr "length" "18,34")])
(define_insn "negsi2" (define_insn_and_split "negsi2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,o") [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o")
(neg:SI (match_operand:SI 1 "general_operand" "0,0")))] (neg:SI (match_operand:SI 1 "general_operand" "0,0")))]
"" ""
"#"
"reload_completed"
[(parallel [(set (match_dup 0) (neg:SI (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
"")
;; TODO: this can be neg/adc/neg/adc... I believe. Check. Saves one word.
(define_insn "negsi2_nocc"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,o")
(neg:SI (match_operand:SI 1 "general_operand" "0,0")))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
{ {
rtx exops[2][2]; rtx exops[2][2];
...@@ -1212,13 +1530,24 @@ ...@@ -1212,13 +1530,24 @@
return \"\"; return \"\";
} }
[(set_attr "length" "12,20")]) [(set_attr "length" "10,18")])
(define_insn "neg<mode>2" (define_insn_and_split "neg<mode>2"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
(neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))] (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
"" ""
"neg<isfx> %0" "#"
"reload_completed"
[(parallel [(set (match_dup 0) (neg:PDPint (match_dup 1)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "neg<mode>2<cc_ccnz>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
(neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))
(clobber (reg:CC CC_REGNUM))]
""
"neg<PDPint:isfx> %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
...@@ -1242,14 +1571,6 @@ ...@@ -1242,14 +1571,6 @@
(const_int 4) (const_int 4)
(const_int 2)))]) (const_int 2)))])
(define_insn ""
[(set (pc)
(label_ref (match_operand 0 "" "")))
(clobber (const_int 1))]
""
"jmp %l0"
[(set_attr "length" "4")])
(define_insn "tablejump" (define_insn "tablejump"
[(set (pc) (match_operand:HI 0 "general_operand" "r,R,Q")) [(set (pc) (match_operand:HI 0 "general_operand" "r,R,Q"))
(use (label_ref (match_operand 1 "" "")))] (use (label_ref (match_operand 1 "" "")))]
...@@ -1260,22 +1581,20 @@ ...@@ -1260,22 +1581,20 @@
jmp %@%0" jmp %@%0"
[(set_attr "length" "2,2,4")]) [(set_attr "length" "2,2,4")])
;; indirect jump - let's be conservative! ;; indirect jump. TODO: this needs a constraint that allows memory
;; allow only register_operand, even though we could also ;; references but not indirection, since we add a level of indirection
;; allow labels etc. ;; in the generated code.
(define_insn "indirect_jump" (define_insn "indirect_jump"
[(set (pc) (match_operand:HI 0 "register_operand" "r"))] [(set (pc) (match_operand:HI 0 "general_operand" "r"))]
"" ""
"jmp (%0)") "jmp @%0"
[(set_attr "length" "2")])
;;- jump to subroutine ;;- jump to subroutine
(define_insn "call" (define_insn "call"
[(call (match_operand:HI 0 "general_operand" "rR,Q") [(call (match_operand:HI 0 "general_operand" "rR,Q")
(match_operand:HI 1 "general_operand" "g,g")) (match_operand:HI 1 "general_operand" "g,g"))]
;; (use (reg:HI 0)) what was that ???
]
;;- Don't use operand 1 for most machines. ;;- Don't use operand 1 for most machines.
"" ""
"jsr pc, %0" "jsr pc, %0"
...@@ -1285,14 +1604,38 @@ ...@@ -1285,14 +1604,38 @@
(define_insn "call_value" (define_insn "call_value"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
(call (match_operand:HI 1 "general_operand" "rR,Q") (call (match_operand:HI 1 "general_operand" "rR,Q")
(match_operand:HI 2 "general_operand" "g,g"))) (match_operand:HI 2 "general_operand" "g,g")))]
;; (use (reg:HI 0)) - what was that ????
]
;;- Don't use operand 2 for most machines. ;;- Don't use operand 2 for most machines.
"" ""
"jsr pc, %1" "jsr pc, %1"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
{
int i;
emit_call_insn (gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
rtx set = XVECEXP (operands[2], 0, i);
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
/* The optimizer does not know that the call sets the function value
registers we stored in the result block. We avoid problems by
claiming that all hard registers are used and clobbered at this
point. */
emit_insn (gen_blockage ());
DONE;
})
;;- nop instruction ;;- nop instruction
(define_insn "nop" (define_insn "nop"
[(const_int 0)] [(const_int 0)]
...@@ -1302,124 +1645,134 @@ ...@@ -1302,124 +1645,134 @@
;;- multiply ;;- multiply
(define_insn "muldf3" (define_insn_and_split "muldf3"
[(set (match_operand:DF 0 "register_operand" "=a,a") [(set (match_operand:DF 0 "register_operand" "=a,a")
(mult:DF (match_operand:DF 1 "register_operand" "%0,0") (mult:DF (match_operand:DF 1 "register_operand" "%0,0")
(match_operand:DF 2 "float_operand" "fR,QF")))] (match_operand:DF 2 "float_operand" "fR,QF")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (mult:DF (match_dup 1) (match_dup 2)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "muldf3<fcc_ccnz>"
[(set (match_operand:DF 0 "register_operand" "=a,a")
(mult:DF (match_operand:DF 1 "register_operand" "%0,0")
(match_operand:DF 2 "float_operand" "fR,QF")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{muld|mulf} %2, %0" "{muld|mulf} %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;; 16 bit result multiply: ;; 16 bit result multiply. This uses odd numbered registers.
;; currently we multiply only into odd registers, so we don't use two
;; registers - but this is a bit inefficient at times. If we define
;; a register class for each register, then we can specify properly
;; which register need which scratch register ....
(define_insn "mulhi3" (define_insn_and_split "mulhi3"
[(set (match_operand:HI 0 "register_operand" "=d,d") ; multiply regs [(set (match_operand:HI 0 "register_operand" "=d,d") ; multiply regs
(mult:HI (match_operand:HI 1 "register_operand" "%0,0") (mult:HI (match_operand:HI 1 "register_operand" "%0,0")
(match_operand:HI 2 "float_operand" "rR,Qi")))] (match_operand:HI 2 "general_operand" "rR,Qi")))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (mult:HI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "mulhi3<cc_cc>"
[(set (match_operand:HI 0 "register_operand" "=d,d")
(mult:HI (match_operand:HI 1 "register_operand" "%0,0")
(match_operand:HI 2 "general_operand" "rR,Qi")))
(clobber (reg:CC CC_REGNUM))]
"TARGET_40_PLUS && reload_completed"
"mul %2, %0" "mul %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;; 32 bit result ;; 32 bit result from 16 bit operands
(define_expand "mulhisi3" (define_insn_and_split "mulhisi3"
[(set (match_dup 3) [(set (match_operand:SI 0 "register_operand" "=r,r")
(match_operand:HI 1 "nonimmediate_operand" "g,g")) (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0"))
(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered! (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi"))))]
(mult:SI (truncate:HI
(match_dup 0))
(match_operand:HI 2 "general_operand" "rR,Qi")))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"operands[3] = gen_lowpart(HImode, operands[1]);") "#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(mult:SI (sign_extend:SI (match_dup 1))
(sign_extend:SI (match_dup 2))))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_insn "" (define_insn "mulhisi3<cc_cc>"
[(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered! [(set (match_operand:SI 0 "register_operand" "=r,r")
(mult:SI (truncate:HI (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0"))
(match_operand:SI 1 "register_operand" "%0,0")) (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi"))))
(match_operand:HI 2 "general_operand" "rR,Qi")))] (clobber (reg:CC CC_REGNUM))]
"TARGET_40_PLUS" "TARGET_40_PLUS && reload_completed"
"mul %2, %0" "mul %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
;(define_insn "mulhisi3"
; [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
; (mult:SI (truncate:HI
; (match_operand:SI 1 "register_operand" "%0,0"))
; (match_operand:HI 2 "general_operand" "rR,Qi")))]
; "TARGET_40_PLUS"
; "mul %2, %0"
; [(set_attr "length" "2,4")])
;;- divide ;;- divide
(define_insn "divdf3" (define_insn_and_split "divdf3"
[(set (match_operand:DF 0 "register_operand" "=a,a") [(set (match_operand:DF 0 "register_operand" "=a,a")
(div:DF (match_operand:DF 1 "register_operand" "0,0") (div:DF (match_operand:DF 1 "register_operand" "0,0")
(match_operand:DF 2 "general_operand" "fR,QF")))] (match_operand:DF 2 "general_operand" "fR,QF")))]
"TARGET_FPU" "TARGET_FPU"
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0) (div:DF (match_dup 1) (match_dup 2)))
(clobber (reg:CC FCC_REGNUM))])]
"")
(define_insn "divdf3<fcc_ccnz>"
[(set (match_operand:DF 0 "register_operand" "=a,a")
(div:DF (match_operand:DF 1 "register_operand" "0,0")
(match_operand:DF 2 "general_operand" "fR,QF")))
(clobber (reg:CC FCC_REGNUM))]
"TARGET_FPU && reload_completed"
"{divd|divf} %2, %0" "{divd|divf} %2, %0"
[(set_attr "length" "2,4")]) [(set_attr "length" "2,4")])
(define_expand "divmodhi4"
(define_expand "divhi3" [(parallel
[(set (subreg:HI (match_dup 1) 0) [(set (subreg:HI (match_dup 1) 0)
(div:HI (match_operand:SI 1 "register_operand" "0") (div:HI (match_operand:SI 1 "register_operand" "0")
(match_operand:HI 2 "general_operand" "g"))) (match_operand:HI 2 "general_operand" "g")))
(set (subreg:HI (match_dup 1) 2)
(mod:HI (match_dup 1) (match_dup 2)))])
(set (match_operand:HI 0 "register_operand" "=r") (set (match_operand:HI 0 "register_operand" "=r")
(subreg:HI (match_dup 1) 0))] (subreg:HI (match_dup 1) 0))
(set (match_operand:HI 3 "register_operand" "=r")
(subreg:HI (match_dup 1) 2))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"") "")
(define_insn "" (define_insn_and_split "*divmodhi4"
[(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0) [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0)
(div:HI (match_operand:SI 1 "general_operand" "0") (div:HI (match_operand:SI 1 "register_operand" "0,0")
(match_operand:HI 2 "general_operand" "g")))] (match_operand:HI 2 "general_operand" "rR,Qi")))
"TARGET_40_PLUS" (set (subreg:HI (match_dup 1) 2)
"div %2,%0" (mod:HI (match_dup 1) (match_dup 2)))]
[(set_attr "length" "4")])
(define_expand "modhi3"
[(set (subreg:HI (match_dup 1) 2)
(mod:HI (match_operand:SI 1 "register_operand" "0")
(match_operand:HI 2 "general_operand" "g")))
(set (match_operand:HI 0 "register_operand" "=r")
(subreg:HI (match_dup 1) 2))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"#"
"&& reload_completed"
[(parallel [(set (subreg:HI (match_dup 0) 0)
(div:HI (match_dup 1) (match_dup 2)))
(set (subreg:HI (match_dup 1) 2)
(mod:HI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
"") "")
(define_insn "" ;; Note that there is no corresponding CC setter pattern.
[(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 2) ;; The reason is that it won't be generated, because
(mod:HI (match_operand:SI 1 "general_operand" "0") ;; compare-elim.c only does the transformation on input
(match_operand:HI 2 "general_operand" "g")))] ;; insns that have a two-element PARALLEL, as opposed to
;; the three-element one we have here.
(define_insn "divmodhi4_nocc"
[(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0)
(div:HI (match_operand:SI 1 "register_operand" "0,0")
(match_operand:HI 2 "general_operand" "rR,Qi")))
(set (subreg:HI (match_dup 1) 2)
(mod:HI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))]
"TARGET_40_PLUS" "TARGET_40_PLUS"
"div %2,%0" "div %2,%0"
[(set_attr "length" "4")]) [(set_attr "length" "2,4")])
;(define_expand "divmodhi4"
; [(parallel [(set (subreg:HI (match_dup 1) 0)
; (div:HI (match_operand:SI 1 "register_operand" "0")
; (match_operand:HI 2 "general_operand" "g")))
; (set (subreg:HI (match_dup 1) 2)
; (mod:HI (match_dup 1)
; (match_dup 2)))])
; (set (match_operand:HI 3 "register_operand" "=r")
; (subreg:HI (match_dup 1) 2))
; (set (match_operand:HI 0 "register_operand" "=r")
; (subreg:HI (match_dup 1) 0))]
; "TARGET_40_PLUS"
; "")
;
;(define_insn ""
; [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0)
; (div:HI (match_operand:SI 1 "general_operand" "0")
; (match_operand:HI 2 "general_operand" "g")))
; (set (subreg:HI (match_dup 0) 2)
; (mod:HI (match_dup 1)
; (match_dup 2)))]
; "TARGET_40_PLUS"
; "div %2, %0")
;
;; is rotate doing the right thing to be included here ????
...@@ -34,22 +34,6 @@ mac0 ...@@ -34,22 +34,6 @@ mac0
Target Report Mask(AC0) Target Report Mask(AC0)
Return floating-point results in ac0 (fr0 in Unix assembler syntax). Return floating-point results in ac0 (fr0 in Unix assembler syntax).
mbcopy
Target RejectNegative Report Mask(BCOPY)
Do not use inline patterns for copying memory.
mbcopy-builtin
Target RejectNegative Report InverseMask(BCOPY, BCOPY_BUILTIN)
Use inline patterns for copying memory.
mbranch-cheap
Target RejectNegative Report InverseMask(BRANCH_EXPENSIVE, BRANCH_CHEAP)
Do not pretend that branches are expensive.
mbranch-expensive
Target RejectNegative Report Mask(BRANCH_EXPENSIVE)
Pretend that branches are expensive.
mdec-asm mdec-asm
Target RejectNegative Report InverseMask(UNIX_ASM) Target RejectNegative Report InverseMask(UNIX_ASM)
Use the DEC assembler syntax. Use the DEC assembler syntax.
......
...@@ -23,17 +23,12 @@ ...@@ -23,17 +23,12 @@
(ior (match_operand 0 "register_operand") (ior (match_operand 0 "register_operand")
(match_test "op == CONST0_RTX (GET_MODE (op))"))) (match_test "op == CONST0_RTX (GET_MODE (op))")))
;; Accept integer arguments in the range -4..-2 and 2..4, which are the ;; Accept integer arguments in the range 1..3, which are the
;; shift counts for which we unroll a shift. This matches the rule for ;; shift counts for which we unroll a shift. This matches the rule for
;; the "O" constraint. ;; the "O" constraint.
(define_predicate "expand_shift_operand" (define_predicate "expand_shift_operand"
(match_code "const_int") (and (match_code "const_int")
{ (match_test "(unsigned) INTVAL (op) < 4")))
int sh;
sh = INTVAL (op);
return (abs (sh) > 1 && abs (sh) <= 4);
})
;; Accept anything general_operand accepts, except that registers must ;; Accept anything general_operand accepts, except that registers must
;; be FPU registers. ;; be FPU registers.
...@@ -52,3 +47,7 @@ ...@@ -52,3 +47,7 @@
(match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS") (match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS")
(match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS")) (match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS"))
(match_operand 0 "nonimmediate_operand"))) (match_operand 0 "nonimmediate_operand")))
;; Accept any comparison valid for CCNZmode
(define_predicate "ccnz_operator"
(match_code "eq,ne,ge,lt"))
...@@ -969,11 +969,9 @@ Objective-C and Objective-C++ Dialects}. ...@@ -969,11 +969,9 @@ Objective-C and Objective-C++ Dialects}.
@emph{PDP-11 Options} @emph{PDP-11 Options}
@gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol @gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol
-mbcopy -mbcopy-builtin -mint32 -mno-int16 @gol -mint32 -mno-int16 -mint16 -mno-int32 @gol
-mint16 -mno-int32 -mfloat32 -mno-float64 @gol -mfloat32 -mno-float64 -mfloat64 -mno-float32 @gol
-mfloat64 -mno-float32 -mabshi -mno-abshi @gol -msplit -munix-asm -mdec-asm}
-mbranch-expensive -mbranch-cheap @gol
-munix-asm -mdec-asm}
@emph{picoChip Options} @emph{picoChip Options}
@gccoptlist{-mae=@var{ae_type} -mvliw-lookahead=@var{N} @gol @gccoptlist{-mae=@var{ae_type} -mvliw-lookahead=@var{N} @gol
...@@ -22018,7 +22016,7 @@ These options are defined for the PDP-11: ...@@ -22018,7 +22016,7 @@ These options are defined for the PDP-11:
@item -mfpu @item -mfpu
@opindex mfpu @opindex mfpu
Use hardware FPP floating point. This is the default. (FIS floating Use hardware FPP floating point. This is the default. (FIS floating
point on the PDP-11/40 is not supported.) point on the PDP-11/40 is not supported.) Implies -m45.
@item -msoft-float @item -msoft-float
@opindex msoft-float @opindex msoft-float
...@@ -22034,7 +22032,7 @@ Return floating-point results in memory. This is the default. ...@@ -22034,7 +22032,7 @@ Return floating-point results in memory. This is the default.
@item -m40 @item -m40
@opindex m40 @opindex m40
Generate code for a PDP-11/40. Generate code for a PDP-11/40. Implies -msoft-float -mno-split.
@item -m45 @item -m45
@opindex m45 @opindex m45
...@@ -22042,16 +22040,7 @@ Generate code for a PDP-11/45. This is the default. ...@@ -22042,16 +22040,7 @@ Generate code for a PDP-11/45. This is the default.
@item -m10 @item -m10
@opindex m10 @opindex m10
Generate code for a PDP-11/10. Generate code for a PDP-11/10. Implies -msoft-float -mno-split.
@item -mbcopy-builtin
@opindex mbcopy-builtin
Use inline @code{movmemhi} patterns for copying memory. This is the
default.
@item -mbcopy
@opindex mbcopy
Do not use inline @code{movmemhi} patterns for copying memory.
@item -mint16 @item -mint16
@itemx -mno-int32 @itemx -mno-int32
...@@ -22077,32 +22066,17 @@ Use 64-bit @code{float}. This is the default. ...@@ -22077,32 +22066,17 @@ Use 64-bit @code{float}. This is the default.
@opindex mno-float64 @opindex mno-float64
Use 32-bit @code{float}. Use 32-bit @code{float}.
@item -mabshi @item -msplit
@opindex mabshi @opindex msplit
Use @code{abshi2} pattern. This is the default. Target has split instruction and data space. Implies -m45.
@item -mno-abshi
@opindex mno-abshi
Do not use @code{abshi2} pattern.
@item -mbranch-expensive
@opindex mbranch-expensive
Pretend that branches are expensive. This is for experimenting with
code generation only.
@item -mbranch-cheap
@opindex mbranch-cheap
Do not pretend that branches are expensive. This is the default.
@item -munix-asm @item -munix-asm
@opindex munix-asm @opindex munix-asm
Use Unix assembler syntax. This is the default when configured for Use Unix assembler syntax.
@samp{pdp11-*-bsd}.
@item -mdec-asm @item -mdec-asm
@opindex mdec-asm @opindex mdec-asm
Use DEC assembler syntax. This is the default when configured for any Use DEC assembler syntax. This is the default.
PDP-11 target other than @samp{pdp11-*-bsd}.
@end table @end table
@node picoChip Options @node picoChip Options
...@@ -2966,12 +2966,20 @@ memory with a single instruction. ...@@ -2966,12 +2966,20 @@ memory with a single instruction.
Odd numbered general registers (R1, R3, R5). These are used for Odd numbered general registers (R1, R3, R5). These are used for
16-bit multiply operations. 16-bit multiply operations.
@item D
A memory reference that is encoded within the opcode, but not
auto-increment or auto-decrement.
@item f @item f
Any of the floating point registers (AC0 through AC5). Any of the floating point registers (AC0 through AC5).
@item G @item G
Floating point constant 0. Floating point constant 0.
@item h
Floating point registers AC4 and AC5. These cannot be loaded from/to
memory with a single instruction.
@item I @item I
An integer constant that fits in 16 bits. An integer constant that fits in 16 bits.
...@@ -2992,7 +3000,7 @@ The integer constant @minus{}1. ...@@ -2992,7 +3000,7 @@ The integer constant @minus{}1.
The integer constant 0. The integer constant 0.
@item O @item O
Integer constants @minus{}4 through @minus{}1 and 1 through 4; shifts by these Integer constants 0 through 3; shifts by these
amounts are handled as multiple single-bit shifts rather than a single amounts are handled as multiple single-bit shifts rather than a single
variable-length shift. variable-length shift.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment