Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
5b8ae21f
Commit
5b8ae21f
authored
May 08, 1998
by
Michael Meissner
Committed by
Michael Meissner
May 08, 1998
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Hunk of m32r changes
From-SVN: r19636
parent
cf879efa
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
722 additions
and
472 deletions
+722
-472
gcc/ChangeLog
+48
-0
gcc/config/m32r/m32r.c
+222
-113
gcc/config/m32r/m32r.h
+93
-48
gcc/config/m32r/m32r.md
+359
-311
No files found.
gcc/ChangeLog
View file @
5b8ae21f
...
...
@@ -3,6 +3,54 @@ Fri May 8 18:23:08 1998 Michael Meissner <meissner@cygnus.com>
* final.c (final_scan_insn): Call fatal_insn instead of abort if
we could not split an insn when required to.
* m32r.md ({add,sub}di3): Add define_splits and appropriate low
level insns.
(peepholes): Disable peepholes that call dead_or_set_p.
(movsi): Rewrite to handle addresses better after last change.
Add define_split to split load of addresses in large/medium modes.
(prologue): Call m32r_expand_prologue.
(movsi_{push,pop}): Generators for push/pop.
(movsi): Support PRE_{INC,DEC}, POST_INC.
(mov{di,df}): Rewrite. Always split the insns.
(movsf): Add define_split to get register load in correct mode.
(cmp_ne_small_const_insn): Use 'N' instead of 'S' constraint.
(attributes): Rewrite attributes so that type indicates both the
type and the length of the insn directly.
(all insns): Change to use new type attributes.
(debug): New attribute to convey whether -mdebug was used.
(opt_space): New attribute to convey whether -Os was used.
(function units): Loads are 3 cycles, not 2. Better classify all
insns into short/long.
(load/store/extend insns): Add separate case for load/store
indirect operations without an offset.
(divsi3): Division is a long operation, not short.
* m32r.h (LEGITIMATE_LO_SUM_ADDRESS_P): Do not allow LO_SUM for
modes > 1 word.
(GO_IF_MODE_DEPENDENT_ADDRESS): LO_SUM is now mode dependent.
(CONST_OK_FOR_LETTER_P): Make 'N' handle reverse 8 bit compares.
(EXTRA_CONSTRAINT): Remove 'S' special support. Add 'U' for
operands with PRE_{INC,DEC}, POST_INC.
(FUNCTION_PROFILER): Call abort instead of doing nothing.
(GO_IF_LEGITIMATE_ADDRESS): Allow PRE_{INC,DEC}, POST_INC of
SImode variables.
(gen_split_move_double): Declare.
(EXTRA_CONSTRAINT): Add 'T' for memory reference with no offset.
* m32r.c (gen_split_move_double): Fix typo. Also, don't call
emit_move_insn, build up SET's directly.
(toplevel): Include system.h, not stdio.h.
(move_double_src_operand): Allow any DF or DI mode constant.
(gen_split_move_double): Split moves of DI or DF values into the
appropriate moves, loads, or stores. Don't handle use of auto
inc/dec if using dead index. Do handle overlapping moves, etc.
(m32r_frame_info): Remove prologue_size field.
(m32r_compute_frame_size): Don't calculate prologue size.
(m32r_output_function_prologue): Change to pretty much a NOP.
(m32r_expand_prologue): Expand prologue as a series of INSNs.
(m32r_print_operand): Add support for PRE_{INC,DEC}, POST_INC.
(m32r_print_operand_address): Ditto.
Fri May 8 14:13:21 1998 H.J. Lu (hjl@gnu.org)
* reload1.c (emit_reload_insns): When performing expensive
...
...
gcc/config/m32r/m32r.c
View file @
5b8ae21f
...
...
@@ -19,7 +19,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include
<stdio.h>
#include
"system.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
...
...
@@ -729,10 +729,7 @@ move_double_src_operand (op, int_mode)
{
case
CONST_INT
:
case
CONST_DOUBLE
:
if
(
mode
==
DFmode
)
return
easy_df_const
(
op
);
else
return
easy_di_const
(
op
);
return
1
;
case
REG
:
return
register_operand
(
op
,
mode
);
case
SUBREG
:
...
...
@@ -1115,6 +1112,123 @@ gen_compare (int_code, x, y, need_compare)
return
gen_rtx
(
branch_code
,
VOIDmode
,
cc_reg
,
CONST0_RTX
(
mode
));
}
/* Split a 2 word move (DI or DF) into component parts. */
rtx
gen_split_move_double
(
operands
)
rtx
operands
[];
{
enum
machine_mode
mode
=
GET_MODE
(
operands
[
0
]);
rtx
dest
=
operands
[
0
];
rtx
src
=
operands
[
1
];
rtx
val
;
start_sequence
();
if
(
GET_CODE
(
dest
)
==
REG
||
GET_CODE
(
dest
)
==
SUBREG
)
{
/* reg = reg */
if
(
GET_CODE
(
src
)
==
REG
||
GET_CODE
(
src
)
==
SUBREG
)
{
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
operand 1, we must copy in the opposite order. */
int
reverse
=
(
REGNO
(
operands
[
0
])
==
REGNO
(
operands
[
1
])
+
1
);
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
operand_subword
(
dest
,
reverse
,
TRUE
,
mode
),
operand_subword
(
src
,
reverse
,
TRUE
,
mode
)));
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
operand_subword
(
dest
,
!
reverse
,
TRUE
,
mode
),
operand_subword
(
src
,
!
reverse
,
TRUE
,
mode
)));
}
/* reg = constant */
else
if
(
GET_CODE
(
src
)
==
CONST_INT
||
GET_CODE
(
src
)
==
CONST_DOUBLE
)
{
rtx
words
[
2
];
split_double
(
src
,
&
words
[
0
],
&
words
[
1
]);
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
operand_subword
(
dest
,
0
,
TRUE
,
mode
),
words
[
0
]));
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
operand_subword
(
dest
,
1
,
TRUE
,
mode
),
words
[
1
]));
}
/* reg = mem */
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
/* If the high-address word is used in the address, we must load it
last. Otherwise, load it first. */
rtx
addr
=
XEXP
(
src
,
0
);
int
reverse
=
(
refers_to_regno_p
(
REGNO
(
dest
),
REGNO
(
dest
)
+
1
,
addr
,
0
)
!=
0
);
/* We used to optimize loads from single registers as
ld r1,r3+; ld r2,r3
if r3 were not used subsequently. However, the REG_NOTES aren't
propigated correctly by the reload phase, and it can cause bad
code to be generated. We could still try:
ld r1,r3+; ld r2,r3; addi r3,-4
which saves 2 bytes and doesn't force longword alignment. */
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
operand_subword
(
dest
,
reverse
,
TRUE
,
mode
),
change_address
(
src
,
SImode
,
plus_constant
(
addr
,
reverse
*
UNITS_PER_WORD
))));
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
operand_subword
(
dest
,
!
reverse
,
TRUE
,
mode
),
change_address
(
src
,
SImode
,
plus_constant
(
addr
,
(
!
reverse
)
*
UNITS_PER_WORD
))));
}
else
abort
();
}
/* mem = reg */
/* We used to optimize loads from single registers as
st r1,r3; st r2,+r3
if r3 were not used subsequently. However, the REG_NOTES aren't
propigated correctly by the reload phase, and it can cause bad
code to be generated. We could still try:
st r1,r3; st r2,+r3; addi r3,-4
which saves 2 bytes and doesn't force longword alignment. */
else
if
(
GET_CODE
(
dest
)
==
MEM
&&
(
GET_CODE
(
src
)
==
REG
||
GET_CODE
(
src
)
==
SUBREG
))
{
rtx
addr
=
XEXP
(
dest
,
0
);
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
change_address
(
dest
,
SImode
,
addr
),
operand_subword
(
src
,
0
,
TRUE
,
mode
)));
emit_insn
(
gen_rtx_SET
(
VOIDmode
,
change_address
(
dest
,
SImode
,
plus_constant
(
addr
,
UNITS_PER_WORD
)),
operand_subword
(
src
,
1
,
TRUE
,
mode
)));
}
else
abort
();
val
=
gen_sequence
();
end_sequence
();
return
val
;
}
/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */
int
...
...
@@ -1298,7 +1412,6 @@ struct m32r_frame_info
unsigned
int
args_size
;
/* # bytes that outgoing arguments take up */
unsigned
int
reg_size
;
/* # bytes needed to store regs */
unsigned
int
var_size
;
/* # bytes that variables take up */
unsigned
int
prolog_size
;
/* # bytes that the prologue takes up */
unsigned
int
gmask
;
/* mask of saved gp registers */
unsigned
int
save_fp
;
/* nonzero if fp must be saved */
unsigned
int
save_lr
;
/* nonzero if lr (return addr) must be saved */
...
...
@@ -1322,7 +1435,7 @@ static struct m32r_frame_info zero_frame_info;
&& (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p)))
#define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])
#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM])
#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM]
|| profile_flag
)
#define SHORT_INSN_SIZE 2
/* size of small instructions */
#define LONG_INSN_SIZE 4
/* size of long instructions */
...
...
@@ -1338,7 +1451,7 @@ m32r_compute_frame_size (size)
{
int
regno
;
unsigned
int
total_size
,
var_size
,
args_size
,
pretend_size
,
extra_size
;
unsigned
int
reg_size
,
prolog_size
,
frame_size
;
unsigned
int
reg_size
,
frame_size
;
unsigned
int
gmask
;
enum
m32r_function_type
fn_type
;
int
interrupt_p
;
...
...
@@ -1349,7 +1462,6 @@ m32r_compute_frame_size (size)
extra_size
=
FIRST_PARM_OFFSET
(
0
);
total_size
=
extra_size
+
pretend_size
+
args_size
+
var_size
;
reg_size
=
0
;
prolog_size
=
0
;
gmask
=
0
;
/* See if this is an interrupt handler. Call used registers must be saved
...
...
@@ -1379,33 +1491,8 @@ m32r_compute_frame_size (size)
handler will do the right thing if this changes total_size. */
total_size
=
M32R_STACK_ALIGN
(
total_size
);
/* Calculate prologue size. Obviously any changes to
m32r_output_function_prologue must be mirrored here. */
if
(
pretend_size
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* addi sp,-pretend_size */
prolog_size
+=
SHORT_INSN_SIZE
*
(
reg_size
/
UNITS_PER_WORD
);
/* pushes */
frame_size
=
total_size
-
(
pretend_size
+
reg_size
);
if
(
frame_size
==
0
)
;
/* nothing to do */
else
if
(
frame_size
<=
128
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* addi sp,-<frame> */
else
{
if
((
prolog_size
%
LONG_INSN_SIZE
)
!=
0
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* nop */
if
(
frame_size
<=
32768
)
prolog_size
+=
LONG_INSN_SIZE
;
/* add3 sp,sp,-<frame> */
else
prolog_size
+=
(
LONG_INSN_SIZE
/* ld24 tmp,<frame>/sub sp,tmp */
+
SHORT_INSN_SIZE
);
}
if
(
frame_pointer_needed
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* mv fp,sp */
/* Save computed information. */
current_frame_info
.
total_size
=
total_size
;
current_frame_info
.
extra_size
=
extra_size
;
...
...
@@ -1413,7 +1500,6 @@ m32r_compute_frame_size (size)
current_frame_info
.
var_size
=
var_size
;
current_frame_info
.
args_size
=
args_size
;
current_frame_info
.
reg_size
=
reg_size
;
current_frame_info
.
prolog_size
=
prolog_size
;
current_frame_info
.
gmask
=
gmask
;
current_frame_info
.
initialized
=
reload_completed
;
...
...
@@ -1431,74 +1517,37 @@ m32r_first_insn_address ()
if
(
!
current_frame_info
.
initialized
)
m32r_compute_frame_size
(
get_frame_size
());
return
current_frame_info
.
prolog_size
;
return
0
;
}
/* Set up the stack and frame pointer (if desired) for the function.
Note, if this is changed, you need to mirror the changes in
m32r_compute_frame_size which calculates the prolog size. */
/* Expand the m32r prologue as a series of insns. */
void
m32r_output_function_prologue
(
file
,
size
)
FILE
*
file
;
int
size
;
m32r_expand_prologue
()
{
int
regno
;
int
total_size
,
frame_size
;
char
*
sp_str
=
reg_names
[
STACK_POINTER_REGNUM
];
char
*
fp_str
=
reg_names
[
FRAME_POINTER_REGNUM
];
int
frame_size
;
unsigned
int
gmask
=
current_frame_info
.
gmask
;
enum
m32r_function_type
fn_type
=
m32r_compute_function_type
(
current_function_decl
);
/* If this is an interrupt handler, mark it as such. */
if
(
M32R_INTERRUPT_P
(
fn_type
))
{
fprintf
(
file
,
"
\t
%s interrupt handler
\n
"
,
ASM_COMMENT_START
);
}
total_size
=
(
!
current_frame_info
.
initialized
?
m32r_compute_frame_size
(
size
)
:
current_frame_info
.
total_size
);
if
(
!
current_frame_info
.
initialized
)
m32r_compute_frame_size
(
get_frame_size
());
/* This is only for the human reader. */
fprintf
(
file
,
"
\t
%s BEGIN PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d, prolog= %d
\n
"
,
ASM_COMMENT_START
,
current_frame_info
.
var_size
,
current_frame_info
.
reg_size
/
4
,
current_frame_info
.
args_size
,
current_frame_info
.
extra_size
,
current_frame_info
.
prolog_size
);
gmask
=
current_frame_info
.
gmask
;
/* These cases shouldn't happen. Catch them now. */
if
(
total_size
==
0
&&
gmask
)
if
(
current_frame_info
.
total_size
==
0
&&
gmask
)
abort
();
#if 1
/* Allocate space for register arguments if this is a variadic function. */
if
(
current_frame_info
.
pretend_size
!=
0
)
fprintf
(
file
,
"
\t
addi %s,%s%d
\n
"
,
sp_str
,
IMMEDIATE_PREFIX
,
-
current_frame_info
.
pretend_size
);
#else
/* If there are unnamed args in registers, save them. */
if
(
current_function_stdarg
||
current_function_varargs
)
{
int
i
;
fprintf
(
file
,
"
\t
addi %s,%s%d
\n
"
,
sp_str
,
IMMEDIATE_PREFIX
,
-
M32R_MAX_PARM_REGS
*
UNITS_PER_WORD
);
for
(
i
=
0
;
i
<
M32R_MAX_PARM_REGS
;
++
i
)
fprintf
(
file
,
"
\t
st %s,@(sp,%d)
\n
"
,
reg_names
[
i
],
i
*
UNITS_PER_WORD
);
}
#endif
emit_insn
(
gen_addsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
GEN_INT
(
-
current_frame_info
.
pretend_size
)));
/* Save any registers we need to and set up fp. */
if
(
current_frame_info
.
save_fp
)
fprintf
(
file
,
"
\t
push %s
\n
"
,
fp_str
);
emit_insn
(
gen_movsi_push
(
stack_pointer_rtx
,
frame_pointer_rtx
)
);
gmask
&=
~
(
FRAME_POINTER_MASK
|
RETURN_ADDR_MASK
);
...
...
@@ -1507,33 +1556,68 @@ m32r_output_function_prologue (file, size)
for
(
regno
=
0
;
regno
<=
M32R_MAX_INT_REGS
;
++
regno
)
{
if
((
gmask
&
(
1
<<
regno
))
!=
0
)
fprintf
(
file
,
"
\t
push %s
\n
"
,
reg_names
[
regno
]);
emit_insn
(
gen_movsi_push
(
stack_pointer_rtx
,
gen_rtx_REG
(
Pmode
,
regno
)));
}
if
(
current_frame_info
.
save_lr
)
fprintf
(
file
,
"
\t
push %s
\n
"
,
reg_names
[
RETURN_ADDR_REGNUM
]);
emit_insn
(
gen_movsi_push
(
stack_pointer_rtx
,
gen_rtx_REG
(
Pmode
,
RETURN_ADDR_REGNUM
)));
/* Allocate the stack frame. */
frame_size
=
total_size
-
(
current_frame_info
.
pretend_size
+
current_frame_info
.
reg_size
);
frame_size
=
(
current_frame_info
.
total_size
-
(
current_frame_info
.
pretend_size
+
current_frame_info
.
reg_size
));
if
(
frame_size
==
0
)
;
/* nothing to do */
else
if
(
frame_size
<=
128
)
fprintf
(
file
,
"
\t
addi %s,%s%d
\n
"
,
sp_str
,
IMMEDIATE_PREFIX
,
-
frame_size
);
else
if
(
frame_size
<=
32768
)
fprintf
(
file
,
"
\t
add3 %s,%s,%s%d
\n
"
,
sp_str
,
sp_str
,
IMMEDIATE_PREFIX
,
-
frame_size
);
emit_insn
(
gen_addsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
GEN_INT
(
-
frame_size
))
);
else
fprintf
(
file
,
"
\t
ld24 %s,%s%d
\n\t
sub %s,%s
\n
"
,
reg_names
[
PROLOGUE_TMP_REGNUM
],
IMMEDIATE_PREFIX
,
frame_size
,
sp_str
,
reg_names
[
PROLOGUE_TMP_REGNUM
]);
{
rtx
tmp
=
gen_rtx_REG
(
Pmode
,
PROLOGUE_TMP_REGNUM
);
emit_insn
(
gen_movsi
(
tmp
,
GEN_INT
(
frame_size
)));
emit_insn
(
gen_subsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
tmp
));
}
if
(
frame_pointer_needed
)
fprintf
(
file
,
"
\t
mv %s,%s
\n
"
,
fp_str
,
sp_str
);
emit_insn
(
gen_movsi
(
frame_pointer_rtx
,
stack_pointer_rtx
));
if
(
profile_flag
||
profile_block_flag
)
emit_insn
(
gen_blockage
());
}
/* Set up the stack and frame pointer (if desired) for the function.
Note, if this is changed, you need to mirror the changes in
m32r_compute_frame_size which calculates the prolog size. */
void
m32r_output_function_prologue
(
file
,
size
)
FILE
*
file
;
int
size
;
{
enum
m32r_function_type
fn_type
=
m32r_compute_function_type
(
current_function_decl
);
/* If this is an interrupt handler, mark it as such. */
if
(
M32R_INTERRUPT_P
(
fn_type
))
{
fprintf
(
file
,
"
\t
%s interrupt handler
\n
"
,
ASM_COMMENT_START
);
}
if
(
!
current_frame_info
.
initialized
)
m32r_compute_frame_size
(
size
);
fprintf
(
file
,
"
\t
%s END PROLOGUE
\n
"
,
ASM_COMMENT_START
);
/* This is only for the human reader. */
fprintf
(
file
,
"
\t
%s PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d
\n
"
,
ASM_COMMENT_START
,
current_frame_info
.
var_size
,
current_frame_info
.
reg_size
/
4
,
current_frame_info
.
args_size
,
current_frame_info
.
extra_size
);
}
/* Do any necessary cleanup after a function to restore stack, frame,
...
...
@@ -1695,6 +1779,8 @@ m32r_print_operand (file, x, code)
rtx
x
;
int
code
;
{
rtx
addr
;
switch
(
code
)
{
case
'R'
:
...
...
@@ -1866,16 +1952,34 @@ m32r_print_operand (file, x, code)
break
;
case
MEM
:
fprintf
(
file
,
"@("
);
if
(
GET_CODE
(
XEXP
(
x
,
0
))
==
PRE_INC
)
output_address
(
plus_constant
(
XEXP
(
XEXP
(
x
,
0
),
0
),
GET_MODE_SIZE
(
GET_MODE
(
x
))));
else
if
(
GET_CODE
(
XEXP
(
x
,
0
))
==
PRE_DEC
)
output_address
(
plus_constant
(
XEXP
(
XEXP
(
x
,
0
),
0
),
-
GET_MODE_SIZE
(
GET_MODE
(
x
))));
addr
=
XEXP
(
x
,
0
);
if
(
GET_CODE
(
addr
)
==
PRE_INC
)
{
if
(
GET_CODE
(
XEXP
(
addr
,
0
))
!=
REG
)
abort
();
fprintf
(
file
,
"@+%s"
,
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))]);
}
else
if
(
GET_CODE
(
addr
)
==
PRE_DEC
)
{
if
(
GET_CODE
(
XEXP
(
addr
,
0
))
!=
REG
)
abort
();
fprintf
(
file
,
"@-%s"
,
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))]);
}
else
if
(
GET_CODE
(
addr
)
==
POST_INC
)
{
if
(
GET_CODE
(
XEXP
(
addr
,
0
))
!=
REG
)
abort
();
fprintf
(
file
,
"@%s+"
,
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))]);
}
else
output_address
(
XEXP
(
x
,
0
));
fputc
(
')'
,
file
);
{
fputs
(
"@("
,
file
);
output_address
(
XEXP
(
x
,
0
));
fputc
(
')'
,
file
);
}
break
;
case
CONST_DOUBLE
:
...
...
@@ -1975,11 +2079,16 @@ m32r_print_operand_address (file, addr)
fputs
(
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))],
file
);
break
;
case
PRE_INC
:
case
PRE_DEC
:
/* We shouldn't get here as we've lost the mode of the memory object
(which says how much to inc/dec by). */
abort
();
case
PRE_INC
:
/* Assume SImode */
fprintf
(
file
,
"+%s"
,
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))]);
break
;
case
PRE_DEC
:
/* Assume SImode */
fprintf
(
file
,
"-%s"
,
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))]);
break
;
case
POST_INC
:
/* Assume SImode */
fprintf
(
file
,
"%s+"
,
reg_names
[
REGNO
(
XEXP
(
addr
,
0
))]);
break
;
default
:
...
...
gcc/config/m32r/m32r.h
View file @
5b8ae21f
...
...
@@ -606,16 +606,17 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
#define INT32_P(X) ((X) >= (-(HOST_WIDE_INT) 0x7fffffff - 1) \
&& (X) <= (unsigned HOST_WIDE_INT) 0xffffffff)
#define UINT5_P(X) ((unsigned) (X) < 32)
#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128)
#define CONST_OK_FOR_LETTER_P(VALUE, C)
\
((C) == 'I' ? INT8_P (VALUE) \
: (C) == 'J' ? INT16_P (VALUE) \
: (C) == 'K' ? UINT16_P (VALUE) \
: (C) == 'L' ? UPPER16_P (VALUE) \
: (C) == 'M' ? UINT24_P (VALUE) \
: (C) == 'N' ? IN
T32_P (VALUE)
\
: (C) == 'O' ? UINT5_P (VALUE) \
: (C) == 'P' ? CMP_INT16_P (VALUE) \
#define CONST_OK_FOR_LETTER_P(VALUE, C)
\
((C) == 'I' ? INT8_P (VALUE)
\
: (C) == 'J' ? INT16_P (VALUE)
\
: (C) == 'K' ? UINT16_P (VALUE)
\
: (C) == 'L' ? UPPER16_P (VALUE)
\
: (C) == 'M' ? UINT24_P (VALUE)
\
: (C) == 'N' ? IN
VERTED_SIGNED_8BIT (VALUE)
\
: (C) == 'O' ? UINT5_P (VALUE)
\
: (C) == 'P' ? CMP_INT16_P (VALUE)
\
: 0)
/* Similar, but for floating constants, and defining letters G and H.
...
...
@@ -623,8 +624,8 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
For the m32r, handle a few constants inline.
??? We needn't treat DI and DF modes differently, but for now we do. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'G' ? easy_di_const (VALUE)
\
: (C) == 'H' ? easy_df_const (VALUE)
\
((C) == 'G' ? easy_di_const (VALUE)
\
: (C) == 'H' ? easy_df_const (VALUE)
\
: 0)
/* A C expression that defines the optional machine-dependent constraint
...
...
@@ -635,19 +636,25 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
be 0 regardless of VALUE. */
/* Q is for symbolic addresses loadable with ld24.
R is for symbolic addresses when ld24 can't be used.
S is for an 8 bit signed integer in the range +128 to -127 */
#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128)
#define EXTRA_CONSTRAINT(VALUE, C) \
((C) == 'Q' \
? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
|| addr24_operand (VALUE, VOIDmode)) \
: (C) == 'R' \
? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
|| addr32_operand (VALUE, VOIDmode)) \
: (C) == 'S' \
? ((GET_CODE (VALUE) == CONST_INT) && INVERTED_SIGNED_8BIT (INTVAL (VALUE))) \
S is unused.
T is for indirect of a pointer.
U is for pushes and pops of the stack pointer. */
#define EXTRA_CONSTRAINT(VALUE, C) \
((C) == 'Q' \
? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
|| addr24_operand (VALUE, VOIDmode)) \
: (C) == 'R' \
? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
|| addr32_operand (VALUE, VOIDmode)) \
: (C) == 'S' \
? 0 \
: (C) == 'T' \
? (GET_CODE (VALUE) == MEM \
&& memreg_operand (VALUE, GET_MODE (VALUE))) \
: (C) == 'U' \
? (GET_CODE (VALUE) == MEM \
&& PUSH_POP_P (GET_MODE (VALUE), XEXP (VALUE, 0))) \
: 0)
/* Stack layout and stack pointer usage. */
...
...
@@ -1069,7 +1076,7 @@ m32r_output_function_epilogue (FILE, SIZE)
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO)
#define FUNCTION_PROFILER(FILE, LABELNO)
abort ()
/* Trampolines. */
...
...
@@ -1184,24 +1191,37 @@ do { \
(GET_CODE (X) == CONST_INT && INT16_P (INTVAL (X)))
/* local to this file */
#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X)
\
(GET_CODE (X) == PLUS \
&& RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X)
\
(GET_CODE (X) == PLUS
\
&& RTX_OK_FOR_BASE_P (XEXP (X, 0))
\
&& RTX_OK_FOR_OFFSET_P (XEXP (X, 1)))
/* local to this file */
#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X) \
(GET_CODE (X) == LO_SUM \
&& RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
/* For LO_SUM addresses, do not allow them if the MODE is > 1 word,
since more than one instruction will be required. */
#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X) \
(GET_CODE (X) == LO_SUM \
&& (MODE != BLKmode && GET_MODE_SIZE (MODE) <= UNITS_PER_WORD) \
&& RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
&& CONSTANT_P (XEXP (X, 1)))
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ if (RTX_OK_FOR_BASE_P (X)) \
goto ADDR; \
if (LEGITIMATE_OFFSET_ADDRESS_P ((MODE), (X))) \
goto ADDR; \
if (LEGITIMATE_LO_SUM_ADDRESS_P ((MODE), (X))) \
goto ADDR; \
/* local to this file */
/* Memory address that is a push/pop of the stack pointer. */
#define PUSH_POP_P(MODE, X) \
((MODE) == SImode \
&& (GET_CODE (X) == POST_INC \
|| GET_CODE (X) == PRE_INC \
|| GET_CODE (X) == PRE_DEC))
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
{ if (RTX_OK_FOR_BASE_P (X)) \
goto ADDR; \
if (LEGITIMATE_OFFSET_ADDRESS_P ((MODE), (X))) \
goto ADDR; \
if (LEGITIMATE_LO_SUM_ADDRESS_P ((MODE), (X))) \
goto ADDR; \
if (PUSH_POP_P ((MODE), (X))) \
goto ADDR; \
}
/* Try machine-dependent ways of modifying an illegitimate address
...
...
@@ -1223,14 +1243,13 @@ do { \
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for. */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
do { \
if (GET_CODE (ADDR) == PRE_DEC) \
goto LABEL; \
if (GET_CODE (ADDR) == PRE_INC) \
goto LABEL; \
if (GET_CODE (ADDR) == POST_INC) \
goto LABEL; \
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
do { \
if (GET_CODE (ADDR) == PRE_DEC \
|| GET_CODE (ADDR) == PRE_INC \
|| GET_CODE (ADDR) == POST_INC \
|| GET_CODE (ADDR) == LO_SUM) \
goto LABEL; \
} while (0)
/* Condition code usage. */
...
...
@@ -1286,7 +1305,7 @@ do { \
/* Compute the cost of moving data between registers and memory. */
/* Memory is 3 times as expensive as registers.
??? Is that the right way to look at it? */
#define MEMORY_MOVE_COST(MODE,CLASS,IN) \
#define MEMORY_MOVE_COST(MODE,CLASS,IN
_P
) \
(GET_MODE_SIZE (MODE) <= UNITS_PER_WORD ? 6 : 12)
/* The cost of a branch insn. */
...
...
@@ -1355,7 +1374,10 @@ do { \
#define HAIFA_P 0
#endif
/* Indicate how many instructions can be issued at the same time. */
/* Indicate how many instructions can be issued at the same time.
This is 1/2 of a lie. The m32r can issue only 1 long insn at
once, but 2. However doing so allows the scheduler to group
the two short insns together. */
#define ISSUE_RATE 2
/* When the `length' insn attribute is used, this macro specifies the
...
...
@@ -1635,6 +1657,27 @@ do { \
fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \
} while (0)
/* CYGNUS LOCAL -- m32rx/meissner */
/* For the m32r if -Os, don't force line number label to begin
at the beginning of the word. */
#undef ASM_OUTPUT_SOURCE_LINE
#define ASM_OUTPUT_SOURCE_LINE(file, line) \
do \
{ \
static int sym_lineno = 1; \
fprintf (file, ".stabn 68,0,%d,.LM%d-", \
line, sym_lineno); \
assemble_name (file, \
XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));\
fprintf (file, \
(optimize_size) ? "\n\t.debugsym .LM%d\n" : "\n.LM%d:\n", \
sym_lineno); \
sym_lineno += 1; \
} \
while (0)
/* END CYGNUS LOCAL -- m32rx/meissner */
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
LABELNO is an integer which is different for each call. */
...
...
@@ -1998,6 +2041,7 @@ extern int small_insn_p PROTO((Rtx, int));
extern
int
large_insn_p
PROTO
((
Rtx
,
int
));
extern
int
m32r_select_cc_mode
PROTO
((
int
,
Rtx
,
Rtx
));
extern
Rtx
gen_compare
PROTO
((
int
,
Rtx
,
Rtx
,
int
));
extern
Rtx
gen_split_move_double
PROTO
((
Rtx
*
));
extern
int
function_arg_partial_nregs
PROTO
((
CUMULATIVE_ARGS
*
,
int
,
Tree
,
int
));
extern
void
m32r_setup_incoming_varargs
PROTO
((
CUMULATIVE_ARGS
*
,
...
...
@@ -2008,6 +2052,7 @@ extern enum m32r_function_type m32r_compute_function_type
PROTO
((
Tree
));
extern
unsigned
m32r_compute_frame_size
PROTO
((
int
));
extern
int
m32r_first_insn_address
PROTO
((
void
));
extern
void
m32r_expand_prologue
PROTO
((
void
));
extern
void
m32r_output_function_prologue
STDIO_PROTO
((
FILE
*
,
int
));
extern
void
m32r_output_function_epilogue
STDIO_PROTO
((
FILE
*
,
int
));
extern
void
m32r_finalize_pic
PROTO
((
void
));
...
...
gcc/config/m32r/m32r.md
View file @
5b8ae21f
...
...
@@ -24,33 +24,20 @@
;; 0 - blockage
;; 1 - flush_icache
;; 2 - load_sda_base
;; 3 - setting carry in addx/subx instructions.
;; Insn type. Used to default other attribute values.
;; move4 = 4 byte move
(define_attr "type"
"
move,move4,load,store,unary,binary,compare,shift,mul,div
,uncond_branch,branch,call,multi,misc"
"
int2,int4,load2,load4,load8,store2,store4,store8,shift2,shift4,mul2,div4
,uncond_branch,branch,call,multi,misc"
(const_string "misc"))
;; Length in bytes.
(define_attr "length" ""
(cond
[
(eq_attr "type" "
move,unary,shift,mul,div
")
(cond
[
(eq_attr "type" "
int2,load2,store2,shift2,mul2
")
(const_int 2)
(eq_attr "type" "binary")
(if_then_else (match_operand 2 "register_operand" "")
(const_int 2) (const_int 4))
(eq_attr "type" "compare")
(if_then_else (match_operand 1 "register_operand" "")
(const_int 2) (const_int 4))
(eq_attr "type" "load")
(if_then_else (match_operand 1 "memreg_operand" "")
(const_int 2) (const_int 4))
(eq_attr "type" "store")
(if_then_else (match_operand 0 "memreg_operand" "")
(const_int 2) (const_int 4))
(eq_attr "type" "int4,load4,store4,shift4,div4")
(const_int 4)
(eq_attr "type" "multi")
(const_int 8)
...
...
@@ -69,10 +56,16 @@
;; Whether an instruction is 16-bit or 32-bit
(define_attr "insn_size" "short,long"
(if_then_else (eq_attr "
length" "
2")
(if_then_else (eq_attr "
type" "int2,load2,store2,shift2,mul
2")
(const_string "short")
(const_string "long")))
(define_attr "debug" "no,yes"
(const (symbol_ref "(TARGET_DEBUG != 0)")))
(define_attr "opt_size" "no,yes"
(const (symbol_ref "(optimize_size != 0)")))
(define_attr "m32r" "no,yes"
(const (symbol_ref "(TARGET_M32R != 0)")))
...
...
@@ -196,39 +189,52 @@
;; (define_function_unit {name} {multiplicity} {simulataneity} {test}
;; {ready-delay} {issue-delay} [{conflict-list}])
;; References to loaded registers should wait a cycle.
;; Memory with load-delay of 1 (i.e. 2 cycle load).
(define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)
;; Hack to get GCC to better pack the instructions.
;; We pretend there is a separate long function unit that conflicts with
;; both the left and right 16 bit insn slots.
(define_function_unit "left" 1 1
(eq_attr "length" "2")
(define_function_unit "short" 2 2
(and (eq_attr "m32r" "yes")
(and (eq_attr "insn_size" "short")
(eq_attr "type" "!load2")))
1 0
[(
not (eq_attr "length" "2")
)])
[(
eq_attr "insn_size" "long"
)])
(define_function_unit "right" 1 1
(eq_attr "length" "2")
1 0
[(not (eq_attr "length" "2"))])
(define_function_unit "short" 2 2 ;; load delay of 1 clock for mem execution + 1 clock for WB
(and (eq_attr "m32r" "yes")
(eq_attr "type" "load2"))
3 0
[(eq_attr "insn_size" "long")])
(define_function_unit "long" 1 1
(not (eq_attr "length" "2"))
(and (eq_attr "m32r" "yes")
(and (eq_attr "insn_size" "long")
(eq_attr "type" "!load4,load8")))
1 0
[(eq_attr "length" "2")])
[(eq_attr "insn_size" "short")])
(define_function_unit "long" 1 1 ;; load delay of 1 clock for mem execution + 1 clock for WB
(and (eq_attr "m32r" "yes")
(and (eq_attr "insn_size" "long")
(eq_attr "type" "load4,load8")))
3 0
[(eq_attr "insn_size" "short")])
;; Instruction grouping
;; Expand prologue as RTL
;; ??? Unfinished.
;(define_expand "prologue"
; [(const_int 1)]
; ""
; "
;{
;}")
(define_expand "prologue"
[(const_int 1)]
""
"
{
m32r_expand_prologue ();
DONE;
}")
;; Move instructions.
;;
...
...
@@ -251,16 +257,19 @@
}")
(define_insn "*movqi_insn"
[(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,r,m")
(match_operand:QI 1 "move_src_operand" "r,I,JQR,
m
,r"))]
[(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,r,
r,T,
m")
(match_operand:QI 1 "move_src_operand" "r,I,JQR,
T,m,r
,r"))]
"register_operand (operands[0], QImode) || register_operand (operands[1], QImode)"
"@
mv %0,%1
ldi %0,%#%1
ldi %0,%#%1
ldub %0,%1
ldub %0,%1
stb %1,%0
stb %1,%0"
[(set_attr "type" "move,move,move4,load,store")])
[(set_attr "type" "int2,int2,int4,load2,load4,store2,store4")
(set_attr "length" "2,2,4,2,4,2,4")])
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
...
...
@@ -275,8 +284,8 @@
}")
(define_insn "*movhi_insn"
[(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,r,r,m")
(match_operand:HI 1 "move_src_operand" "r,I,JQR,K,
m
,r"))]
[(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,r,r,
r,T,
m")
(match_operand:HI 1 "move_src_operand" "r,I,JQR,K,
T,m,r
,r"))]
"register_operand (operands[0], HImode) || register_operand (operands[1], HImode)"
"@
mv %0,%1
...
...
@@ -284,8 +293,23 @@
ldi %0,%#%1
ld24 %0,%#%1
lduh %0,%1
lduh %0,%1
sth %1,%0
sth %1,%0"
[(set_attr "type" "move,move,move4,move4,load,store")])
[(set_attr "type" "int2,int2,int4,int4,load2,load4,store2,store4")
(set_attr "length" "2,2,4,4,2,4,2,4")])
(define_expand "movsi_push"
[(set (mem:SI (pre_dec:SI (match_operand:SI 0 "register_operand" "")))
(match_operand:SI 1 "register_operand" ""))]
""
"")
(define_expand "movsi_pop"
[(set (match_operand:SI 0 "register_operand" "")
(mem:SI (post_inc:SI (match_operand:SI 1 "register_operand" ""))))]
""
"")
(define_expand "movsi"
[(set (match_operand:SI 0 "general_operand" "")
...
...
@@ -314,21 +338,60 @@
}
}")
(define_insn "*movsi_insn"
[(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,r,r,r,r,m")
;; ??? Do we need a const_double constraint here for large unsigned values?
(match_operand:SI 1 "move_src_operand" "r,I,J,MQ,L,N,m,r"))]
(define_insn "*movsi_insn"
[(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,r,r,r,r,r,r,T,U,m")
(match_operand:SI 1 "move_src_operand" "r,I,J,MQ,L,n,T,U,m,r,r,r"))]
"register_operand (operands[0], SImode) || register_operand (operands[1], SImode)"
"@
mv %0,%1
ldi %0,%#%1 ; %X1
ldi %0,%#%1 ; %X1
ld24 %0,%#%1 ; %X1
seth %0,%#%T1
seth %0,%#%T1\;or3 %0,%0,%#%B1
ld %0,%1
st %1,%0"
[(set_attr "type" "move,move,move4,move4,move4,multi,load,store")])
"*
{
if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == SUBREG)
{
switch (GET_CODE (operands[1]))
{
HOST_WIDE_INT value;
default:
break;
case REG:
case SUBREG:
return \"mv %0,%1\";
case MEM:
return \"ld %0,%1\";
case CONST_INT:
value = INTVAL (operands[1]);
if (INT16_P (value))
return \"ldi %0,%#%1\\t; %X1\";
if (UINT24_P (value))
return \"ld24 %0,%#%1\\t; %X1\";
if (UPPER16_P (value))
return \"seth %0,%#%T1\\t; %X1\";
return \"#\";
case CONST:
case SYMBOL_REF:
case LABEL_REF:
if (TARGET_ADDR24)
return \"ld24 %0,%#%1\";
return \"#\";
}
}
else if (GET_CODE (operands[0]) == MEM
&& (GET_CODE (operands[1]) == REG || GET_CODE (operands[1]) == SUBREG))
return \"st %1,%0\";
fatal_insn (\"bad movsi insn\", insn);
}"
[(set_attr "type" "int2,int2,int4,int4,int4,multi,load2,load2,load4,store2,store2,store4")
(set_attr "length" "2,2,4,4,4,8,2,2,4,2,2,4")])
; Try to use a four byte / two byte pair for constants not loadable with
; ldi, ld24, seth.
...
...
@@ -376,6 +439,17 @@
operands[3] = GEN_INT ((val) & 0xffff);
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "seth_add3_operand" "i"))]
"TARGET_ADDR32"
[(set (match_dup 0)
(high:SI (match_dup 1)))
(set (match_dup 0)
(lo_sum:SI (match_dup 0)
(match_dup 1)))]
"")
;; Small data area support.
;; The address of _SDA_BASE_ is loaded into a register and all objects in
;; the small data area are indexed off that. This is done for each reference
...
...
@@ -413,7 +487,8 @@
(unspec [(const_int 0)] 2))]
""
"ld24 %0,#_SDA_BASE_"
[(set_attr "type" "move4")])
[(set_attr "type" "int4")
(set_attr "length" "4")])
;; 32 bit address support.
...
...
@@ -438,7 +513,8 @@
(high:SI (match_operand 1 "symbolic_operand" "")))]
""
"seth %0,%#shigh(%1)"
[(set_attr "type" "move4")])
[(set_attr "type" "int4")
(set_attr "length" "4")])
(define_insn "lo_sum_si"
[(set (match_operand:SI 0 "register_operand" "=r")
...
...
@@ -446,7 +522,8 @@
(match_operand:SI 2 "immediate_operand" "in")))]
""
"add3 %0,%1,%#%B2"
[(set_attr "length" "4")])
[(set_attr "type" "int4")
(set_attr "length" "4")])
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
...
...
@@ -458,85 +535,22 @@
if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (DImode, operands[1]);
if (CONSTANT_P (operands[1])
&& ! easy_di_const (operands[1]))
{
rtx mem = force_const_mem (DImode, operands[1]);
rtx reg = ((reload_in_progress || reload_completed)
? copy_to_suggested_reg (XEXP (mem, 0),
gen_rtx (REG, Pmode, REGNO (operands[0])),
Pmode)
: force_reg (Pmode, XEXP (mem, 0)));
operands[1] = change_address (mem, DImode, reg);
}
}")
(define_insn "*movdi_insn"
[(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,m")
(match_operand:DI 1 "move_double_src_operand" "r,nG,m,r"))]
[(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,
r,
m")
(match_operand:DI 1 "move_double_src_operand" "r,nG,
F,
m,r"))]
"register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"
"*
{
switch (which_alternative)
{
case 0 :
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
operand 1, we must copy in the opposite order. */
if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
return \"mv %R0,%R1\;mv %0,%1\";
else
return \"mv %0,%1\;mv %R0,%R1\";
case 1 :
return \"#\";
case 2 :
/* If the low-address word is used in the address, we must load it
last. Otherwise, load it first. Note that we cannot have
auto-increment in that case since the address register is known to be
dead. */
if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
operands [1], 0))
{
return \"ld %R0,%R1\;ld %0,%1\";
}
else
{
/* Try to use auto-inc addressing if we can. */
if (GET_CODE (XEXP (operands[1], 0)) == REG
&& dead_or_set_p (insn, XEXP (operands[1], 0)))
{
operands[1] = XEXP (operands[1], 0);
return \"ld %0,@%1+\;ld %R0,@%1\";
}
return \"ld %0,%1\;ld %R0,%R1\";
}
case 3 :
/* Try to use auto-inc addressing if we can. */
if (GET_CODE (XEXP (operands[0], 0)) == REG
&& dead_or_set_p (insn, XEXP (operands[0], 0)))
{
operands[0] = XEXP (operands[0], 0);
return \"st %1,@%0\;st %R1,@+%0\";
}
return \"st %1,%0\;st %R1,%R0\";
}
}"
[(set_attr "type" "multi,multi,multi,multi")
(set_attr "length" "4,4,6,6")])
"#"
[(set_attr "type" "multi,multi,multi,load8,store8")
(set_attr "length" "4,4,16,6,6")])
(define_split
[(set (match_operand:DI 0 "
register
_operand" "")
(match_operand:DI 1 "
const_double
_operand" ""))]
[(set (match_operand:DI 0 "
move_dest
_operand" "")
(match_operand:DI 1 "
move_double_src
_operand" ""))]
"reload_completed"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"
{
operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
split_double (operands[1], operands + 4, operands + 5);
}")
[(match_dup 2)]
"operands[2] = gen_split_move_double (operands);")
;; Floating point move insns.
...
...
@@ -553,37 +567,36 @@
}")
(define_insn "*movsf_insn"
[(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,m")
(match_operand:SF 1 "move_src_operand" "r,F,
m
,r"))]
[(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,
r,T,
m")
(match_operand:SF 1 "move_src_operand" "r,F,
T,m,r
,r"))]
"register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)"
"*
{
switch (which_alternative)
{
case 0 :
return \"mv %0,%1\";
case 1 :
{
REAL_VALUE_TYPE r;
long l;
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, l);
operands[1] = GEN_INT (l);
if (l == 0)
return \"ldi %0,%#0\";
if ((l & 0xffff) == 0)
return \"seth %0,%#%T1\";
else
return \"seth %0,%#%T1\;or3 %0,%0,%#%B1\";
}
case 2 :
return \"ld %0,%1\";
case 3 :
return \"st %1,%0\";
}
}"
"@
mv %0,%1
#
ld %0,%1
ld %0,%1
st %1,%0
st %1,%0"
;; ??? Length of alternative 1 is either 2, 4 or 8.
[(set_attr "type" "move,multi,load,store")])
[(set_attr "type" "int2,multi,load2,load4,store2,store4")
(set_attr "length" "2,8,2,4,2,4")])
(define_split
[(set (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "const_double_operand" ""))]
"reload_completed"
[(set (match_dup 2) (match_dup 3))]
"
{
long l;
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
operands[2] = operand_subword (operands[0], 0, 0, SFmode);
operands[3] = GEN_INT (l);
}")
(define_expand "movdf"
[(set (match_operand:DF 0 "general_operand" "")
...
...
@@ -595,118 +608,57 @@
if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (DFmode, operands[1]);
if (GET_CODE (operands[1]) == CONST_DOUBLE
&& ! easy_df_const (operands[1]))
{
rtx mem = force_const_mem (DFmode, operands[1]);
rtx reg = ((reload_in_progress || reload_completed)
? copy_to_suggested_reg (XEXP (mem, 0),
gen_rtx (REG, Pmode, REGNO (operands[0])),
Pmode)
: force_reg (Pmode, XEXP (mem, 0)));
operands[1] = change_address (mem, DFmode, reg);
}
}")
(define_insn "*movdf_insn"
[(set (match_operand:DF 0 "move_dest_operand" "=r,r,r,m")
(match_operand:DF 1 "move_double_src_operand" "r,
H
,m,r"))]
(match_operand:DF 1 "move_double_src_operand" "r,
F
,m,r"))]
"register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)"
"*
{
switch (which_alternative)
{
case 0 :
/* We normally copy the low-numbered register first. However, if
the first register operand 0 is the same as the second register of
operand 1, we must copy in the opposite order. */
if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
return \"mv %R0,%R1\;mv %0,%1\";
else
return \"mv %0,%1\;mv %R0,%R1\";
case 1 :
{
REAL_VALUE_TYPE r;
long l[2];
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_DOUBLE (r, l);
operands[1] = GEN_INT (l[0]);
if (l[0] == 0 && l[1] == 0)
return \"ldi %0,%#0\;ldi %R0,%#0\";
else if (l[1] != 0)
abort ();
else if ((l[0] & 0xffff) == 0)
return \"seth %0,%#%T1\;ldi %R0,%#0\";
else
abort ();
}
case 2 :
/* If the low-address word is used in the address, we must load it
last. Otherwise, load it first. Note that we cannot have
auto-increment in that case since the address register is known to be
dead. */
if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
operands [1], 0))
{
return \"ld %R0,%R1\;ld %0,%1\";
}
else
{
/* Try to use auto-inc addressing if we can. */
if (GET_CODE (XEXP (operands[1], 0)) == REG
&& dead_or_set_p (insn, XEXP (operands[1], 0)))
{
operands[1] = XEXP (operands[1], 0);
return \"ld %0,@%1+\;ld %R0,@%1\";
}
return \"ld %0,%1\;ld %R0,%R1\";
}
case 3 :
/* Try to use auto-inc addressing if we can. */
if (GET_CODE (XEXP (operands[0], 0)) == REG
&& dead_or_set_p (insn, XEXP (operands[0], 0)))
{
operands[0] = XEXP (operands[0], 0);
return \"st %1,@%0\;st %R1,@+%0\";
}
return \"st %1,%0\;st %R1,%R0\";
}
}"
[(set_attr "type" "multi,multi,multi,multi")
(set_attr "length" "4,6,6,6")])
"#"
[(set_attr "type" "multi,multi,load8,store8")
(set_attr "length" "4,16,6,6")])
(define_split
[(set (match_operand:DF 0 "move_dest_operand" "")
(match_operand:DF 1 "move_double_src_operand" ""))]
"reload_completed"
[(match_dup 2)]
"operands[2] = gen_split_move_double (operands);")
;; Zero extension instructions.
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r,r")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
[(set (match_operand:HI 0 "register_operand" "=r,r
,r
")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,
T,
m")))]
""
"@
and3 %0,%1,%#255
ldub %0,%1
ldub %0,%1"
[(set_attr "type" "
unary,load
")
(set_attr "length" "4,
*
")])
[(set_attr "type" "
int4,load2,load4
")
(set_attr "length" "4,
2,4
")])
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
[(set (match_operand:SI 0 "register_operand" "=r,r
,r
")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,
T,
m")))]
""
"@
and3 %0,%1,%#255
ldub %0,%1
ldub %0,%1"
[(set_attr "type" "
unary,load
")
(set_attr "length" "4,
*
")])
[(set_attr "type" "
int4,load2,load4
")
(set_attr "length" "4,
2,4
")])
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
[(set (match_operand:SI 0 "register_operand" "=r,r
,r
")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,
T,
m")))]
""
"@
and3 %0,%1,%#65535
lduh %0,%1
lduh %0,%1"
[(set_attr "type" "
unary,load
")
(set_attr "length" "4,
*
")])
[(set_attr "type" "
int4,load2,load4
")
(set_attr "length" "4,
2,4
")])
;; Sign extension instructions.
;; ??? See v850.md.
...
...
@@ -747,11 +699,12 @@
}")
(define_insn "*sign_extendqihi2_insn"
[(set (match_operand:HI 0 "register_operand" "=r")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
[(set (match_operand:HI 0 "register_operand" "=r
,r
")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "
T,
m")))]
""
"ldb %0,%1"
[(set_attr "type" "load")])
[(set_attr "type" "load2,load4")
(set_attr "length" "2,4")])
(define_expand "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
...
...
@@ -777,11 +730,12 @@
}")
(define_insn "*sign_extendqisi2_insn"
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
[(set (match_operand:SI 0 "register_operand" "=r
,r
")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "
T,
m")))]
""
"ldb %0,%1"
[(set_attr "type" "load")])
[(set_attr "type" "load2,load4")
(set_attr "length" "2,4")])
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
...
...
@@ -807,11 +761,12 @@
}")
(define_insn "*sign_extendhisi2_insn"
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
[(set (match_operand:SI 0 "register_operand" "=r
,r
")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "
T,
m")))]
""
"ldh %0,%1"
[(set_attr "type" "load")])
[(set_attr "type" "load2,load4")
(set_attr "length" "2,4")])
;; Arithmetic instructions.
...
...
@@ -828,7 +783,7 @@
add %0,%2
addi %0,%#%2
add3 %0,%1,%#%2"
[(set_attr "type" "
binary
")
[(set_attr "type" "
int2,int2,int4
")
(set_attr "length" "2,2,4")])
;(define_split
...
...
@@ -849,21 +804,69 @@
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:CC 17))]
""
"*
{
/* ??? The cmp clears the condition bit. Can we speed up somehow? */
return \"cmp %L0,%L0\;addx %L0,%L2\;addx %H0,%H2\";
}"
[(set_attr "type" "binary")
"#"
[(set_attr "type" "multi")
(set_attr "length" "6")])
;; ??? The cmp clears the condition bit. Can we speed up somehow?
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))
(clobber (match_operand 3 "" ""))]
"reload_completed"
[(parallel [(set (match_dup 3)
(const_int 0))
(use (match_dup 4))])
(parallel [(set (match_dup 4)
(plus:SI (match_dup 4)
(plus:SI (match_dup 5)
(match_dup 3))))
(set (match_dup 3)
(unspec [(const_int 0)] 3))])
(parallel [(set (match_dup 6)
(plus:SI (match_dup 6)
(plus:SI (match_dup 7)
(match_dup 3))))
(set (match_dup 3)
(unspec [(const_int 0)] 3))])]
"
{
operands[4] = operand_subword (operands[0], (WORDS_BIG_ENDIAN != 0), 0, DImode);
operands[5] = operand_subword (operands[2], (WORDS_BIG_ENDIAN != 0), 0, DImode);
operands[6] = operand_subword (operands[0], (WORDS_BIG_ENDIAN == 0), 0, DImode);
operands[7] = operand_subword (operands[2], (WORDS_BIG_ENDIAN == 0), 0, DImode);
}")
(define_insn "*clear_c"
[(set (reg:CC 17)
(const_int 0))
(use (match_operand:SI 0 "register_operand" "r"))]
""
"cmp %0,%0"
[(set_attr "type" "int2")
(set_attr "length" "2")])
(define_insn "*add_carry"
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:SI 1 "register_operand" "%0")
(plus:SI (match_operand:SI 2 "register_operand" "r")
(reg:CC 17))))
(set (reg:CC 17)
(unspec [(const_int 0)] 3))]
""
"addx %0,%2"
[(set_attr "type" "int2")
(set_attr "length" "2")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "register_operand" "r")))]
""
"sub %0,%2"
[(set_attr "type" "binary")])
[(set_attr "type" "int2")
(set_attr "length" "2")])
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
...
...
@@ -871,13 +874,51 @@
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:CC 17))]
""
"*
{
/* ??? The cmp clears the condition bit. Can we speed up somehow? */
return \"cmp %L0,%L0\;subx %L0,%L2\;subx %H0,%H2\";
}"
[(set_attr "type" "binary")
"#"
[(set_attr "type" "multi")
(set_attr "length" "6")])
;; ??? The cmp clears the condition bit. Can we speed up somehow?
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))
(clobber (match_operand 3 "" ""))]
"reload_completed"
[(parallel [(set (match_dup 3)
(const_int 0))
(use (match_dup 4))])
(parallel [(set (match_dup 4)
(minus:SI (match_dup 4)
(minus:SI (match_dup 5)
(match_dup 3))))
(set (match_dup 3)
(unspec [(const_int 0)] 3))])
(parallel [(set (match_dup 6)
(minus:SI (match_dup 6)
(minus:SI (match_dup 7)
(match_dup 3))))
(set (match_dup 3)
(unspec [(const_int 0)] 3))])]
"
{
operands[4] = operand_subword (operands[0], (WORDS_BIG_ENDIAN != 0), 0, DImode);
operands[5] = operand_subword (operands[2], (WORDS_BIG_ENDIAN != 0), 0, DImode);
operands[6] = operand_subword (operands[0], (WORDS_BIG_ENDIAN == 0), 0, DImode);
operands[7] = operand_subword (operands[2], (WORDS_BIG_ENDIAN == 0), 0, DImode);
}")
(define_insn "*sub_carry"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "%0")
(minus:SI (match_operand:SI 2 "register_operand" "r")
(reg:CC 17))))
(set (reg:CC 17)
(unspec [(const_int 0)] 3))]
""
"subx %0,%2"
[(set_attr "type" "int2")
(set_attr "length" "2")])
; Multiply/Divide instructions.
...
...
@@ -887,7 +928,7 @@
(sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
""
"mullo %1,%2\;mvfacmi %0"
[(set_attr "type" "mul")
[(set_attr "type" "mul
ti
")
(set_attr "length" "4")])
(define_insn "mulsi3"
...
...
@@ -896,7 +937,8 @@
(match_operand:SI 2 "register_operand" "r")))]
""
"mul %0,%2"
[(set_attr "type" "mul")])
[(set_attr "type" "mul2")
(set_attr "length" "2")])
(define_insn "divsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
...
...
@@ -904,7 +946,8 @@
(match_operand:SI 2 "register_operand" "r")))]
""
"div %0,%2"
[(set_attr "type" "div")])
[(set_attr "type" "div4")
(set_attr "length" "4")])
(define_insn "udivsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
...
...
@@ -912,7 +955,8 @@
(match_operand:SI 2 "register_operand" "r")))]
""
"divu %0,%2"
[(set_attr "type" "div")])
[(set_attr "type" "div4")
(set_attr "length" "4")])
(define_insn "modsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
...
...
@@ -920,7 +964,8 @@
(match_operand:SI 2 "register_operand" "r")))]
""
"rem %0,%2"
[(set_attr "type" "div")])
[(set_attr "type" "div4")
(set_attr "length" "4")])
(define_insn "umodsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
...
...
@@ -928,7 +973,8 @@
(match_operand:SI 2 "register_operand" "r")))]
""
"remu %0,%2"
[(set_attr "type" "div")])
[(set_attr "type" "div4")
(set_attr "length" "4")])
;; Boolean instructions.
;;
...
...
@@ -942,8 +988,9 @@
""
"@
and %0,%2
and3 %0,%1,%#%2 ; %X2"
[(set_attr "type" "binary")])
and3 %0,%1,%#%2\\t; %X2"
[(set_attr "type" "int2,int4")
(set_attr "length" "2,4")])
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
...
...
@@ -952,8 +999,9 @@
""
"@
or %0,%2
or3 %0,%1,%#%2 ; %X2"
[(set_attr "type" "binary")])
or3 %0,%1,%#%2\\t; %X2"
[(set_attr "type" "int2,int4")
(set_attr "length" "2,4")])
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
...
...
@@ -962,22 +1010,25 @@
""
"@
xor %0,%2
xor3 %0,%1,%#%2 ; %X2"
[(set_attr "type" "binary")])
xor3 %0,%1,%#%2\\t; %X2"
[(set_attr "type" "int2,int4")
(set_attr "length" "2,4")])
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "register_operand" "r")))]
""
"neg %0,%1"
[(set_attr "type" "unary")])
[(set_attr "type" "int2")
(set_attr "length" "2")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "r")))]
""
"not %0,%1"
[(set_attr "type" "unary")])
[(set_attr "type" "int2")
(set_attr "length" "2")])
;; Shift instructions.
...
...
@@ -990,7 +1041,7 @@
sll %0,%2
slli %0,%#%2
sll3 %0,%1,%#%2"
[(set_attr "type" "shift")
[(set_attr "type" "shift
2,shift2,shift4
")
(set_attr "length" "2,2,4")])
(define_insn "ashrsi3"
...
...
@@ -1002,7 +1053,7 @@
sra %0,%2
srai %0,%#%2
sra3 %0,%1,%#%2"
[(set_attr "type" "shift")
[(set_attr "type" "shift
2,shift2,shift4
")
(set_attr "length" "2,2,4")])
(define_insn "lshrsi3"
...
...
@@ -1014,7 +1065,7 @@
srl %0,%2
srli %0,%#%2
srl3 %0,%1,%#%2"
[(set_attr "type" "shift")
[(set_attr "type" "shift
2,shift2,shift4
")
(set_attr "length" "2,2,4")])
;; Compare instructions.
...
...
@@ -1067,7 +1118,7 @@
return \"add3 %2,%0,%#%N1\;cmpui %2,#1\";
}
}"
[(set_attr "type" "
compare,compare
")
[(set_attr "type" "
multi,multi
")
(set_attr "length" "8,8")])
(define_insn "cmp_ltsi_insn"
...
...
@@ -1078,23 +1129,19 @@
"@
cmp %0,%1
cmpi %0,%#%1"
[(set_attr "type" "
compare,compare
")
(set_attr "length" "
4,6
")])
[(set_attr "type" "
int2,int4
")
(set_attr "length" "
2,4
")])
(define_insn "cmp_ltusi_insn"
[(set (reg:CC 17)
(ltu:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_uint16_operand" "r,K")))]
""
"*
{
if (which_alternative == 0)
return \"cmpu %0,%1\";
else
return \"cmpui %0,%#%1\";
}"
[(set_attr "type" "compare")
(set_attr "length" "4,6")])
"@
cmpu %0,%1
cmpui %0,%#%1"
[(set_attr "type" "int2,int4")
(set_attr "length" "2,4")])
;; reg == small constant comparisons are best handled by putting the result
;; of the comparison in a tmp reg and then using beqz/bnez.
...
...
@@ -1104,12 +1151,12 @@
(define_insn "cmp_ne_small_const_insn"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ne:SI (match_operand:SI 1 "register_operand" "0,r")
(match_operand:SI 2 "cmp_int16_operand" "
S
,P")))]
(match_operand:SI 2 "cmp_int16_operand" "
N
,P")))]
""
"@
addi %0,%#%N2
add3 %0,%1,%#%N2"
[(set_attr "type" "
compare
")
[(set_attr "type" "
int2,int4
")
(set_attr "length" "2,4")])
;; These control RTL generation for conditional jump insns.
...
...
@@ -1582,7 +1629,7 @@
[
(const_int 0)
]
""
"nop"
[
(set_attr "type" "
misc
")
[
(set_attr "type" "
int2
")
(set_attr "length" "2")])
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
...
...
@@ -1599,7 +1646,8 @@
[
(unspec_volatile [(match_operand 0 "memory_operand" "m")
]
0)]
""
"
*
return
\"
nop ; flush-icache
\"
;"
[
(set_attr "type" "misc")
]
)
[
(set_attr "type" "int2")
(set_attr "length" "2")])
;; Conditional move instructions
;; Based on those done for the d10v
...
...
@@ -1638,7 +1686,7 @@
)]
"zero_and_one (operands
[
2
]
, operands
[
3
]
)"
"
*
return emit_cond_move (operands, insn);"
[
(set_attr "type"
"move
")
[
(set_attr "type"
"multi
")
(set_attr "length" "8")
]
)
...
...
@@ -1657,9 +1705,9 @@
[
(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r")
(const_int 4)))
(match_operand:SI 1 "register_operand" "r"))]
"dead_or_set_p (insn, operands
[
0
]
)"
"
0 &&
dead_or_set_p (insn, operands
[
0
]
)"
"st %1,@+%0"
[
(set_attr "type" "store")
[
(set_attr "type" "store
2
")
(set_attr "length" "2")])
;; This case is triggered by compiling this code:
...
...
@@ -1698,9 +1746,9 @@
(match_dup 0)
)
]
"dead_or_set_p (insn, operands
[
0
]
)"
"
0 &&
dead_or_set_p (insn, operands
[
0
]
)"
"st %1,@(%3,%2)"
[
(set_attr "type" "store")
[
(set_attr "type" "store
4
")
(set_attr "length" "4")
]
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment