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
0d7e008e
Commit
0d7e008e
authored
Feb 05, 1994
by
Steve Chamberlain
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
*** empty log message ***
From-SVN: r6486
parent
2c65021a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
2821 additions
and
1466 deletions
+2821
-1466
gcc/config/sh/sh.c
+1436
-822
gcc/config/sh/sh.h
+336
-158
gcc/config/sh/sh.md
+1049
-486
No files found.
gcc/config/sh/sh.c
View file @
0d7e008e
/* Output routines for GCC for Hitachi Super-H
/* Output routines for GCC for Hitachi Super-H
Copyright (C) 1993 Free Software Foundation, Inc.
Copyright (C) 1993
, 1994
Free Software Foundation, Inc.
This file is part of GNU CC.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
the Free Software Foundation; either version 2, or (at your option)
any later version.
any later version.
GNU CC is distributed in the hope that it will be useful,
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Contributed by Steve Chamberlain (sac@cygnus.com) */
/* Contributed by Steve Chamberlain (sac@cygnus.com) */
...
@@ -32,27 +32,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
...
@@ -32,27 +32,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "insn-flags.h"
#include "insn-flags.h"
#include "tree.h"
#include "tree.h"
#include "output.h"
#include "output.h"
#include "insn-attr.h"
#include "insn-attr.h"
#include "flags.h"
#include "flags.h"
#include "obstack.h"
#include "obstack.h"
#include "expr.h"
#include "expr.h"
static
rtx
add_constant
();
static
int
add_constant
()
;
int
pragma_interrupt
;
int
dump_constants
()
;
int
pragma_trapa
;
int
current_function_anonymous_args
;
int
current_function_anonymous_args
;
extern
int
current_function_pretend_args_size
;
extern
int
current_function_pretend_args_size
;
extern
char
*
version_string
;
extern
char
*
version_string
;
extern
int
flag_traditional
;
extern
int
flag_traditional
;
static
rtx
shiftsyms
[
32
];
struct
rtx_def
*
table_lab
;
enum
attr_cpu
sh_cpu
;
/* target cpu */
enum
attr_cpu
sh_cpu
;
/* target cpu */
/* Global variables for machine-dependent things. */
/* Global variables for machine-dependent things. */
/* Saved operands from the last compare to use when we generate an scc
/* Saved operands from the last compare to use when we generate an scc
or bcc insn. */
or bcc insn. */
rtx
sh_compare_op0
;
rtx
sh_compare_op0
;
rtx
sh_compare_op1
;
rtx
sh_compare_op1
;
...
@@ -62,12 +65,12 @@ rtx sh_compare_op1;
...
@@ -62,12 +65,12 @@ rtx sh_compare_op1;
int
regno_reg_class
[
FIRST_PSEUDO_REGISTER
]
=
int
regno_reg_class
[
FIRST_PSEUDO_REGISTER
]
=
{
{
R0_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
R0_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
GENERAL_REGS
,
PR_REGS
,
T_REGS
,
NO_REGS
,
MAC_REGS
,
GENERAL_REGS
,
PR_REGS
,
T_REGS
,
NO_REGS
,
MAC_REGS
,
MAC_REGS
,
MAC_REGS
,
};
};
/* Provide reg_class from a letter such as appears in the machine
/* Provide reg_class from a letter such as appears in the machine
...
@@ -84,24 +87,45 @@ enum reg_class reg_class_from_letter[] =
...
@@ -84,24 +87,45 @@ enum reg_class reg_class_from_letter[] =
/* y */
NO_REGS
,
/* z */
R0_REGS
/* y */
NO_REGS
,
/* z */
R0_REGS
};
};
/* Value is 1 if register/mode pair is acceptable on SH. Even
registers can hold DIs and DF values. The rest can only hold
SI's efficiently */
#define REG_ODD \
( (1 << (int) QImode) | (1 << (int) HImode) | (1 << (int) SImode) \
| (1 << (int) QFmode) | (1 << (int) HFmode) | (1 << (int) SFmode) \
| (1 << (int) CQImode) | (1 << (int) CHImode))
#define REG_EVEN \
(REG_ODD | (1 << (int) DImode) | (1 << (int) DFmode) \
| (1 << (int) CSImode) | (1 << (int) SCmode))
#define SI_ONLY (1<<(int)SImode)
int
hard_regno_mode_ok
[]
=
{
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG_EVEN
,
REG_ODD
,
REG
,
0
,
SI_ONLY
,
SI_ONLY
,
SI_ONLY
,
SI_ONLY
};
/* Local label counter, used for constants in the pool and inside
/* Local label counter, used for constants in the pool and inside
pattern branches. */
pattern branches. */
static
int
lf
=
100
;
static
int
lf
=
100
;
/* Used to work out sizes of instructions */
static
int
first_pc
;
/* Number of bytes pushed for anonymous args, used to pass information
static
int
pc
;
between expand_prologue and expand_epilogue. */
#define MAYBE_DUMP_LEVEL 900
static
int
extra_push
;
#define MUST_DUMP_LEVEL 1000
static
int
dumpnext
;
void
void
push
(
rn
)
push
(
rn
)
int
rn
;
{
{
emit_insn
(
gen_push
(
gen_rtx
(
REG
,
SImode
,
rn
)));
emit_insn
(
gen_push
(
gen_rtx
(
REG
,
SImode
,
rn
)));
}
}
...
@@ -116,8 +140,7 @@ pop (rn)
...
@@ -116,8 +140,7 @@ pop (rn)
/* Adjust the stack and return the number of bytes taken to do it */
/* Adjust the stack and return the number of bytes taken to do it */
static
void
static
void
output_stack_adjust
(
direction
,
size
)
output_stack_adjust
(
size
)
int
direction
;
int
size
;
int
size
;
{
{
if
(
size
)
if
(
size
)
...
@@ -125,24 +148,18 @@ output_stack_adjust (direction, size)
...
@@ -125,24 +148,18 @@ output_stack_adjust (direction, size)
rtx
val
=
GEN_INT
(
size
);
rtx
val
=
GEN_INT
(
size
);
rtx
insn
;
rtx
insn
;
if
(
size
>
120
)
if
(
!
CONST_OK_FOR_I
(
size
)
)
{
{
rtx
nval
=
gen_rtx
(
REG
,
SImode
,
1
3
);
rtx
nval
=
gen_rtx
(
REG
,
SImode
,
3
);
emit_insn
(
gen_movsi
(
nval
,
val
));
emit_insn
(
gen_movsi
(
nval
,
val
));
val
=
nval
;
val
=
nval
;
}
}
if
(
direction
>
0
)
insn
=
gen_addsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
val
);
insn
=
gen_addsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
val
);
else
insn
=
gen_subsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
val
);
emit_insn
(
insn
);
emit_insn
(
insn
);
}
}
}
}
/* Generate code to push the regs specified in the mask, and return
/* Generate code to push the regs specified in the mask, and return
the number of bytes the insns take. */
the number of bytes the insns take. */
...
@@ -151,7 +168,6 @@ push_regs (mask)
...
@@ -151,7 +168,6 @@ push_regs (mask)
int
mask
;
int
mask
;
{
{
int
i
;
int
i
;
int
size
=
0
;
for
(
i
=
0
;
i
<
FIRST_PSEUDO_REGISTER
;
i
++
)
for
(
i
=
0
;
i
<
FIRST_PSEUDO_REGISTER
;
i
++
)
{
{
...
@@ -163,13 +179,11 @@ push_regs (mask)
...
@@ -163,13 +179,11 @@ push_regs (mask)
}
}
/*
/* Print an instruction which would have gone into a delay slot after
Print an instruction which would have gone into a delay slot
an instructiuon, but couldn't because the instruction expanded into a
after an instructiuon, but couldn't because the instruction expanded
sequence where putting the slot insn at the end wouldn't work. */
into a sequence where putting the slot insn at the end wouldn't work.
*/
void
static
void
print_slot
(
insn
)
print_slot
(
insn
)
rtx
insn
;
rtx
insn
;
{
{
...
@@ -178,35 +192,65 @@ print_slot (insn)
...
@@ -178,35 +192,65 @@ print_slot (insn)
INSN_DELETED_P
(
XVECEXP
(
insn
,
0
,
1
))
=
1
;
INSN_DELETED_P
(
XVECEXP
(
insn
,
0
,
1
))
=
1
;
}
}
/* Number of bytes pushed for anonymous args */
static
int
extra_push
;
/* Work out the registers which need to be saved, both as a mask and a
/* Work out the registers which need to be saved, both as a mask and a
count
*/
count
.
int
If doing a pragma interrupt function, then push all regs used by the function,
calc_live_regs
(
count
)
and if we call another function (we can tell by looking at PR), make sure that all the
int
*
count
;
regs it clobbers are safe too.
*/
static
int
calc_live_regs
(
count_ptr
)
int
*
count_ptr
;
{
{
int
reg
;
int
reg
;
int
live_regs_mask
=
0
;
int
live_regs_mask
=
0
;
*
count
=
0
;
int
count
=
0
;
for
(
reg
=
0
;
reg
<
FIRST_PSEUDO_REGISTER
;
reg
++
)
for
(
reg
=
0
;
reg
<
FIRST_PSEUDO_REGISTER
;
reg
++
)
{
{
if
(
regs_ever_live
[
reg
]
&&
!
call_used_regs
[
reg
])
if
(
reg
==
ARG_POINTER_REGNUM
)
continue
;
if
(
reg
==
T_REG
)
continue
;
if
(
reg
==
GBR_REG
)
continue
;
if
(
pragma_interrupt
&&
!
pragma_trapa
)
{
/* Need to save all the regs ever live */
if
((
regs_ever_live
[
reg
]
||
(
call_used_regs
[
reg
]
&&
regs_ever_live
[
PR_REG
]))
&&
reg
!=
15
)
{
live_regs_mask
|=
1
<<
reg
;
count
++
;
}
}
else
if
(
TARGET_SMALLCALL
)
{
/* Don't need to push anthing, but count the regs which have
been pushed by the wrapper */
if
(
call_used_regs
[
reg
])
count
++
;
}
else
{
{
(
*
count
)
++
;
/* Only push those regs which are used and need to be saved */
live_regs_mask
|=
(
1
<<
reg
);
if
(
regs_ever_live
[
reg
]
&&
!
call_used_regs
[
reg
])
{
count
++
;
live_regs_mask
|=
(
1
<<
reg
);
}
}
}
}
}
*
count_ptr
=
count
;
return
live_regs_mask
;
return
live_regs_mask
;
}
}
static
int
static
int
need_slot
(
insn
)
need_slot
(
insn
)
rtx
insn
;
rtx
insn
;
...
@@ -287,7 +331,7 @@ print_operand_address (stream, x)
...
@@ -287,7 +331,7 @@ print_operand_address (stream, x)
a double word value
a double word value
'O' print a constant without the #
'O' print a constant without the #
'M' print a constant as its negative
'M' print a constant as its negative
'
I' put something into the constant pool and print its label
*/
'
N' print insides of a @++ or @-- o
*/
void
void
print_operand
(
stream
,
x
,
code
)
print_operand
(
stream
,
x
,
code
)
...
@@ -297,8 +341,6 @@ print_operand (stream, x, code)
...
@@ -297,8 +341,6 @@ print_operand (stream, x, code)
{
{
switch
(
code
)
switch
(
code
)
{
{
case
'.'
:
case
'.'
:
if
(
need_slot
(
final_sequence
))
if
(
need_slot
(
final_sequence
))
fprintf
(
stream
,
".s"
);
fprintf
(
stream
,
".s"
);
...
@@ -306,13 +348,9 @@ print_operand (stream, x, code)
...
@@ -306,13 +348,9 @@ print_operand (stream, x, code)
case
'*'
:
case
'*'
:
fprintf
(
stream
,
"LF%d"
,
lf
);
fprintf
(
stream
,
"LF%d"
,
lf
);
break
;
break
;
case
'!'
:
dump_constants
(
0
);
break
;
case
'^'
:
case
'^'
:
lf
++
;
lf
++
;
break
;
break
;
case
'#'
:
case
'#'
:
/* Output a nop if there's nothing in the delay slot */
/* Output a nop if there's nothing in the delay slot */
if
(
dbr_sequence_length
()
==
0
)
if
(
dbr_sequence_length
()
==
0
)
...
@@ -321,31 +359,26 @@ print_operand (stream, x, code)
...
@@ -321,31 +359,26 @@ print_operand (stream, x, code)
}
}
break
;
break
;
case
'O'
:
case
'O'
:
fprintf
(
asm_out_file
,
"%d"
,
INTVAL
(
x
));
output_addr_const
(
stream
,
x
);
break
;
case
'I'
:
fprintf
(
asm_out_file
,
"LK%d"
,
add_constant
(
x
,
SImode
));
break
;
break
;
case
'M'
:
case
'M'
:
fprintf
(
asm_out_file
,
"#%d"
,
-
INTVAL
(
x
));
fprintf
(
asm_out_file
,
"#%d"
,
-
INTVAL
(
x
));
break
;
break
;
case
'N'
:
fputs
(
reg_names
[
REGNO
(
XEXP
(
XEXP
(
x
,
0
),
0
))],
(
stream
));
break
;
case
'R'
:
case
'R'
:
/* Next location along in memory or register*/
/* Next location along in memory or register
*/
switch
(
GET_CODE
(
x
))
switch
(
GET_CODE
(
x
))
{
{
case
REG
:
case
REG
:
fputs
(
reg_names
[
REGNO
(
x
)
+
1
],
(
stream
));
fputs
(
reg_names
[
REGNO
(
x
)
+
1
],
(
stream
));
break
;
break
;
case
MEM
:
case
MEM
:
print_operand_address
(
stream
,
print_operand_address
(
stream
,
XEXP
(
adj_offsettable_operand
(
x
,
4
),
0
));
XEXP
(
adj_offsettable_operand
(
x
,
4
),
0
),
0
);
break
;
break
;
}
}
break
;
break
;
default
:
default
:
switch
(
GET_CODE
(
x
))
switch
(
GET_CODE
(
x
))
{
{
...
@@ -359,43 +392,241 @@ print_operand (stream, x, code)
...
@@ -359,43 +392,241 @@ print_operand (stream, x, code)
fputc
(
'#'
,
stream
);
fputc
(
'#'
,
stream
);
output_addr_const
(
stream
,
x
);
output_addr_const
(
stream
,
x
);
break
;
break
;
}
}
break
;
break
;
}
}
}
}
sextb
(
x
)
{
x
&=
0xff
;
if
(
x
>
127
)
{
x
=
-
256
+
x
;
}
return
x
;
}
/* Define the offset between two registers, one to be eliminated, and
the other its replacement, at the start of a routine. */
int
/* Take a move with integer constant source in OPERANDS, see if it can be generated by
initial_elimination_offset
(
from
,
to
)
devious shifting. If so, generate the instruction sequence and return 1, otherwise
return 0.
OPERANDS[0] Destination register
OPERANDS[1] Source constant
00000000 00000000 00000000 0NNNNNNNN simple load
00000000 00000000 00000000 NNNNNNNN0 load and shift by 1
00000000 00000000 0000000N NNNNNNN00 load and shift by 2
00000000 00000000 0NNNNNNN 000000000 load and shift by 8
00000000 0NNNNNNN 00000000 000000000 load and shift by 16
N0000000 00000000 00000000 00NNNNNNN load and rotate right
11111111 11111111 11111111 1NNNNNNNN simple load
11111111 11111111 11111111 NNNNNNNN0 load and shift by 1
11111111 11111111 1111111N NNNNNNN00 load and shift by 2
11111111 11111111 1NNNNNNN 000000000 load and shift by 8
11111111 1NNNNNNN 00000000 000000000 load and shift by 16
N1111111 11111111 11111111 11NNNNNNN load and rotate right
00000000 00000000 00000000 1NNNNNNNN load and zero extend byte
00000000 00000000 11111111 1NNNNNNNN load and zero extend word
*/
static
int
synth_constant
(
operands
,
mode
)
rtx
operands
[];
enum
machine_mode
mode
;
{
{
int
regs_saved
;
rtx
dst
;
int
d
=
calc_live_regs
(
&
regs_saved
);
int
i
=
INTVAL
(
operands
[
1
])
&
0xffffffff
;
int
total_saved_regs_space
=
(
regs_saved
)
*
4
;
int
total_auto_space
=
get_frame_size
();
if
(
CONST_OK_FOR_I
(
i
))
return
0
;
dst
=
mode
==
SImode
?
operands
[
0
]
:
gen_reg_rtx
(
SImode
);
if
(
from
==
ARG_POINTER_REGNUM
&&
to
==
FRAME_POINTER_REGNUM
)
/* 00000000 00000000 11111111 1NNNNNNNN load and zero extend word */
if
((
i
&
0xffffff80
)
==
0x0000ff80
)
{
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
)));
emit_insn
(
gen_and_ffff
(
dst
,
dst
));
}
/* 00000000 00000000 00000000 1NNNNNNNN load and zero extend byte */
else
if
((
i
&
0xffffff80
)
==
0x00000080
)
{
{
return
total_saved_regs_space
;
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
)));
emit_insn
(
gen_and_ff
(
dst
,
dst
));
}
}
/* 00000000 00000000 00000000 NNNNNNNN0 load and shift by 1
11111111 11111111 11111111 NNNNNNNN0 load and shift by 1 */
else
if
((
i
&
0xffffff01
)
==
0
||
(
i
&
0xffffff01
)
==
0xffffff00
)
{
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
>>
1
)));
emit_insn
(
gen_ashlsi3_n
(
dst
,
dst
,
GEN_INT
(
1
)));
}
/* 00000000 00000000 0000000N NNNNNNN00 load and shift by 2
11111111 11111111 1111111N NNNNNNN00 load and shift by 2*/
else
if
((
i
&
0xfffffe03
)
==
0
||
(
i
&
0xfffffe03
)
==
0xfffffe00
)
{
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
>>
2
)));
emit_insn
(
gen_ashlsi3_n
(
dst
,
dst
,
GEN_INT
(
2
)));
}
/* 00000000 00000000 0NNNNNNN 000000000 load and shift by 8
11111111 11111111 1NNNNNNN 000000000 load and shift by 8 */
if
(
from
==
ARG_POINTER_REGNUM
&&
to
==
STACK_POINTER_REGNUM
)
else
if
((
i
&
0xffff80ff
)
==
0
||
(
i
&
0xffff80ff
)
==
0xffff8000
)
{
{
return
total_saved_regs_space
+
total_auto_space
;
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
>>
8
)));
emit_insn
(
gen_ashlsi3_n
(
dst
,
dst
,
GEN_INT
(
8
)));
}
/* 00000000 0NNNNNNN 00000000 000000000 load and shift by 16
11111111 1NNNNNNN 00000000 000000000 load and shift by 16 */
else
if
((
i
&
0xff80ffff
)
==
0
||
(
i
&
0xff80ffff
)
==
0xff80ffff
)
{
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
>>
16
)));
emit_insn
(
gen_ashlsi3_n
(
dst
,
dst
,
GEN_INT
(
16
)));
}
}
/* 00000000 00000000 0NNNNNNN 0NNNNNNNN load shift 8 and add */
else
if
((
i
&
0xffff8080
)
==
0
&&
TARGET_CLEN3
)
{
emit_move_insn
(
dst
,
GEN_INT
(
sextb
(
i
>>
8
)));
emit_insn
(
gen_ashlsi3_n
(
dst
,
dst
,
GEN_INT
(
8
)));
emit_insn
(
gen_addsi3
(
dst
,
dst
,
GEN_INT
(
i
&
0x7f
)));
}
else
return
0
;
if
(
from
==
FRAME_POINTER_REGNUM
&&
to
==
STACK_POINTER_REGNUM
)
if
(
mode
!=
SImode
)
{
{
return
total_auto_space
;
emit_insn
(
gen_rtx
(
SET
,
VOIDmode
,
operands
[
0
],
gen_rtx
(
SUBREG
,
mode
,
dst
,
0
)));
}
}
return
1
;
}
}
/* Emit code to perform a block move. Choose the best method.
OPERANDS[0] is the destination.
OPERANDS[1] is the source.
OPERANDS[2] is the size.
OPERANDS[3] is the alignment safe to use. */
int
expand_block_move
(
operands
)
rtx
*
operands
;
{
int
align
=
INTVAL
(
operands
[
3
]);
int
constp
=
(
GET_CODE
(
operands
[
2
])
==
CONST_INT
);
int
bytes
=
(
constp
?
INTVAL
(
operands
[
2
])
:
0
);
enum
machine_mode
mode
;
/* IF odd then fail */
if
(
!
constp
||
bytes
<=
0
)
return
0
;
switch
(
align
)
{
case
1
:
mode
=
QImode
;
break
;
case
2
:
mode
=
HImode
;
break
;
default
:
mode
=
SImode
;
align
=
4
;
}
if
(
mode
==
SImode
&&
constp
&&
bytes
<
64
&&
(
bytes
%
4
==
0
))
{
char
entry
[
30
];
tree
entry_name
;
rtx
func_addr_rtx
;
rtx
r4
=
gen_rtx
(
REG
,
SImode
,
4
);
rtx
r5
=
gen_rtx
(
REG
,
SImode
,
5
);
sprintf
(
entry
,
"__movstr%s%d"
,
GET_MODE_NAME
(
mode
),
bytes
);
entry_name
=
get_identifier
(
entry
);
func_addr_rtx
=
copy_to_mode_reg
(
Pmode
,
gen_rtx
(
SYMBOL_REF
,
Pmode
,
IDENTIFIER_POINTER
(
entry_name
)));
emit_insn
(
gen_move_insn
(
r4
,
XEXP
(
operands
[
0
],
0
)));
emit_insn
(
gen_move_insn
(
r5
,
XEXP
(
operands
[
1
],
0
)));
emit_insn
(
gen_block_move_real
(
func_addr_rtx
));
return
1
;
}
if
(
mode
==
SImode
&&
constp
&&
(
bytes
%
4
==
0
))
{
char
entry
[
30
];
tree
entry_name
;
rtx
func_addr_rtx
;
int
groups
;
rtx
r4
=
gen_rtx
(
REG
,
SImode
,
4
);
rtx
r5
=
gen_rtx
(
REG
,
SImode
,
5
);
rtx
r6
=
gen_rtx
(
REG
,
SImode
,
6
);
entry_name
=
get_identifier
(
"__movstr"
);
func_addr_rtx
=
copy_to_mode_reg
(
Pmode
,
gen_rtx
(
SYMBOL_REF
,
Pmode
,
IDENTIFIER_POINTER
(
entry_name
)));
emit_insn
(
gen_move_insn
(
r4
,
XEXP
(
operands
[
0
],
0
)));
emit_insn
(
gen_move_insn
(
r5
,
XEXP
(
operands
[
1
],
0
)));
/* r6 controls the size of the move, 16 is decremented from it
for each 64 bytes moved, then the -ve bit is used as an index into a
list of move instructions like this:
{
do {
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
..etc.. 16 in all
*dst++ = *src++;
*dst++ = *src++;
size -= 16;
} while (size > 0);
switch (size)
{
case -15:
*dst++ = *src++;
case -14:
*dst++ = *src++;
.. etc.. ;
case -2:
*dst++ = *src++;
case -1:
*dst++ = *src++;
case 0:
;
}
}
eg, a 72 byte move would be set up with size(r6) = 14, for one
iteration through the big while loop, and a switch of -2 for the last part */
{
int
final_switch
=
16
-
((
bytes
/
4
)
%
16
);
int
while_loop
=
((
bytes
/
4
)
/
16
-
1
)
*
16
;
emit_insn
(
gen_move_insn
(
r6
,
GEN_INT
(
while_loop
+
final_switch
)));
emit_insn
(
gen_block_lump_real
(
func_addr_rtx
));
return
1
;
}
}
return
0
;
}
/* Prepare operands for a move define_expand; specifically, one of the
/* Prepare operands for a move define_expand; specifically, one of the
operands must be in a register. Take this chance to remove
operands must be in a register. Take this chance to remove
addressing modes which can't be coped with very well. */
addressing modes which can't be coped with very well. */
...
@@ -405,38 +636,130 @@ prepare_move_operands (operands, mode)
...
@@ -405,38 +636,130 @@ prepare_move_operands (operands, mode)
rtx
operands
[];
rtx
operands
[];
enum
machine_mode
mode
;
enum
machine_mode
mode
;
{
{
/* One of the operands has to be a register */
if
(
!
(
reload_in_progress
||
reload_completed
)
if
((
!
register_operand
(
operands
[
0
],
mode
)
&&
((
!
register_operand
(
operands
[
0
],
mode
)
&&
!
register_operand
(
operands
[
1
],
mode
))
&&
!
register_operand
(
operands
[
1
],
mode
))
||
GET_CODE
(
operands
[
1
])
==
PLUS
)
||
GET_CODE
(
operands
[
1
])
==
PLUS
)
)
{
{
/* copy the source to a register */
/* copy the source to a register */
operands
[
1
]
=
copy_to_mode_reg
(
mode
,
operands
[
1
]);
operands
[
1
]
=
copy_to_mode_reg
(
mode
,
operands
[
1
]);
}
}
if
((
mode
==
DImode
||
mode
==
SImode
||
mode
==
HImode
||
mode
==
QImode
)
/* If we've got a negative index, break it down */
&&
GET_CODE
(
operands
[
1
])
==
CONST_INT
)
if
(
GET_CODE
(
operands
[
0
])
==
MEM
&&
!
reload_in_progress
)
{
{
return
synth_constant
(
operands
,
mode
);
}
if
(
mode
==
DFmode
||
mode
==
DImode
)
{
rtx
src
=
operands
[
1
];
rtx
dst
=
operands
[
0
];
rtx
insns
;
rtx
inside
=
XEXP
(
operands
[
0
],
0
);
if
(
src
==
dst
)
if
(
GET_CODE
(
inside
)
==
PLUS
)
{
{
rtx
inside1
=
XEXP
(
inside
,
1
);
emit_insn
(
gen_rtx
(
SET
,
VOIDmode
,
dst
,
src
));
if
(
GET_CODE
(
inside1
)
==
CONST_INT
return
1
;
&&
INTVAL
(
inside1
)
<
0
)
}
{
/* Catch this now and break it into bits, it will only cause
problems later */
rtx
sub
=
copy_to_mode_reg
(
SImode
,
inside
);
if
(
GET_CODE
(
src
)
==
REG
&&
XEXP
(
operands
[
0
],
0
)
=
sub
;
REGNO
(
src
)
>=
FIRST_PSEUDO_REGISTER
)
}
return
0
;
if
(
GET_CODE
(
dst
)
==
REG
&&
REGNO
(
dst
)
>=
FIRST_PSEUDO_REGISTER
)
return
0
;
if
(
push_operand
(
dst
,
mode
))
return
0
;
if
(
GET_CODE
(
src
)
==
CONST_DOUBLE
)
src
=
force_const_mem
(
DFmode
,
src
);
if
(
reload_in_progress
)
{
if
(
!
(
offsettable_memref_p
(
src
)
||
register_operand
(
src
,
mode
)))
return
0
;
if
(
!
(
offsettable_memref_p
(
dst
)
||
register_operand
(
dst
,
mode
)))
return
0
;
}
start_sequence
();
if
(
GET_CODE
(
operands
[
0
])
!=
REG
||
!
refers_to_regno_p
(
REGNO
(
operands
[
0
]),
REGNO
(
operands
[
0
])
+
1
,
operands
[
1
],
0
))
{
emit_move_insn
(
operand_subword
(
dst
,
0
,
1
,
mode
),
operand_subword_force
(
src
,
0
,
mode
));
emit_move_insn
(
operand_subword
(
dst
,
1
,
1
,
mode
),
operand_subword_force
(
src
,
1
,
mode
));
}
else
{
emit_move_insn
(
operand_subword
(
dst
,
1
,
1
,
mode
),
operand_subword_force
(
src
,
1
,
mode
));
emit_move_insn
(
operand_subword
(
dst
,
0
,
1
,
mode
),
operand_subword_force
(
src
,
0
,
mode
));
}
}
insns
=
get_insns
();
end_sequence
();
emit_no_conflict_block
(
insns
,
dst
,
src
,
0
,
src
);
return
1
;
}
}
return
0
;
return
0
;
}
}
/* Work out the subword parts to split up a double move
into two SI moves - take care to do it in the right order
*/
int
prepare_split_double_ops
(
operands
,
mode
)
rtx
operands
[];
enum
machine_mode
mode
;
{
if
(
GET_CODE
(
operands
[
1
])
==
REG
&&
REGNO
(
operands
[
1
])
>
FIRST_PSEUDO_REGISTER
)
return
0
;
if
(
GET_CODE
(
operands
[
0
])
==
REG
&&
REGNO
(
operands
[
0
])
>
FIRST_PSEUDO_REGISTER
)
return
0
;
/* If we split move insns from memory, it confuses scheduling
later on. */
if
(
GET_CODE
(
operands
[
1
])
==
MEM
)
return
0
;
if
(
GET_CODE
(
operands
[
0
])
==
MEM
)
return
0
;
if
(
GET_CODE
(
operands
[
0
])
!=
REG
||
!
refers_to_regno_p
(
REGNO
(
operands
[
0
]),
REGNO
(
operands
[
0
])
+
1
,
operands
[
1
],
0
))
{
operands
[
2
]
=
operand_subword
(
operands
[
0
],
0
,
0
,
mode
);
operands
[
3
]
=
operand_subword
(
operands
[
1
],
0
,
0
,
mode
);
operands
[
4
]
=
operand_subword
(
operands
[
0
],
1
,
0
,
mode
);
operands
[
5
]
=
operand_subword
(
operands
[
1
],
1
,
0
,
mode
);
}
else
{
operands
[
2
]
=
operand_subword
(
operands
[
0
],
1
,
0
,
mode
);
operands
[
3
]
=
operand_subword
(
operands
[
1
],
1
,
0
,
mode
);
operands
[
4
]
=
operand_subword
(
operands
[
0
],
0
,
0
,
mode
);
operands
[
5
]
=
operand_subword
(
operands
[
1
],
0
,
0
,
mode
);
}
if
(
operands
[
2
]
==
0
||
operands
[
3
]
==
0
||
operands
[
4
]
==
0
||
operands
[
5
]
==
0
)
return
0
;
emit_move_insn
(
operands
[
2
],
operands
[
3
]);
emit_move_insn
(
operands
[
4
],
operands
[
5
]);
return
1
;
}
/* Prepare the operands for an scc instruction; make sure that the
/* Prepare the operands for an scc instruction; make sure that the
compare has been done. */
compare has been done. */
...
@@ -446,17 +769,44 @@ prepare_scc_operands (code)
...
@@ -446,17 +769,44 @@ prepare_scc_operands (code)
if
(
GET_CODE
(
sh_compare_op0
)
!=
REG
if
(
GET_CODE
(
sh_compare_op0
)
!=
REG
||
REGNO
(
sh_compare_op0
)
!=
T_REG
)
||
REGNO
(
sh_compare_op0
)
!=
T_REG
)
{
{
int
newcode
=
code
;
/* First need a compare insn */
/* First need a compare insn */
emit_insn
(
gen_rtx
(
SET
,
SImode
,
switch
(
code
)
{
case
NE
:
newcode
=
EQ
;
break
;
case
LT
:
newcode
=
GT
;
break
;
case
LE
:
newcode
=
GE
;
break
;
case
LTU
:
newcode
=
GTU
;
break
;
case
LEU
:
newcode
=
GEU
;
break
;
}
if
(
newcode
!=
code
)
{
rtx
tmp
=
sh_compare_op0
;
sh_compare_op0
=
sh_compare_op1
;
sh_compare_op1
=
tmp
;
code
=
newcode
;
}
sh_compare_op0
=
force_reg
(
SImode
,
sh_compare_op0
);
emit_insn
(
gen_rtx
(
SET
,
VOIDmode
,
gen_rtx
(
REG
,
SImode
,
T_REG
),
gen_rtx
(
REG
,
SImode
,
T_REG
),
gen_rtx
(
code
,
SImode
,
sh_compare_op0
,
gen_rtx
(
code
,
SImode
,
sh_compare_op0
,
sh_compare_op1
)));
sh_compare_op1
)));
}
}
return
gen_rtx
(
REG
,
SImode
,
T_REG
);
return
gen_rtx
(
REG
,
SImode
,
T_REG
);
}
}
/* Functions to output assembly */
/* Functions to output assembly
code.
*/
/* Return a sequence of instructions to perform DI or DF move.
/* Return a sequence of instructions to perform DI or DF move.
...
@@ -464,15 +814,24 @@ prepare_scc_operands (code)
...
@@ -464,15 +814,24 @@ prepare_scc_operands (code)
to take care when we see overlapping source and dest registers.
to take care when we see overlapping source and dest registers.
*/
*/
char
*
char
*
output_movedouble
(
operands
,
mode
)
output_movedouble
(
insn
,
operands
,
mode
)
rtx
insn
;
rtx
operands
[];
rtx
operands
[];
enum
machine_mode
mode
;
enum
machine_mode
mode
;
{
{
rtx
dst
=
operands
[
0
];
rtx
dst
=
operands
[
0
];
rtx
src
=
operands
[
1
];
rtx
src
=
operands
[
1
];
int
lowfirst
;
fprintf
(
asm_out_file
,
"! move double
\n
"
);
fprintf
(
asm_out_file
,
"! pc %04x
\n
"
,
insn_addresses
[
INSN_UID
(
insn
)]);
if
(
GET_CODE
(
dst
)
==
MEM
&&
GET_CODE
(
XEXP
(
dst
,
0
))
==
POST_INC
)
{
operands
[
0
]
=
XEXP
(
XEXP
(
dst
,
0
),
0
);
return
"mov.l %R1,@(4,%0)
\n\t
mov.l %1,@%0
\n\t
add #8,%0"
;
}
if
(
register_operand
(
dst
,
mode
)
if
(
register_operand
(
dst
,
mode
)
&&
register_operand
(
src
,
mode
))
&&
register_operand
(
src
,
mode
))
{
{
...
@@ -480,24 +839,31 @@ output_movedouble (operands, mode)
...
@@ -480,24 +839,31 @@ output_movedouble (operands, mode)
return
"sts mach,%0
\n\t
sts macl,%R0"
;
return
"sts mach,%0
\n\t
sts macl,%R0"
;
/*
/*
when mov.d r1,r2 do r2->r3 then r1->r2
when mov.d r1,r2 do r2->r3 then r1->r2
when mov.d r1,r0 do r1->r0 then r2->r1
when mov.d r1,r0 do r1->r0 then r2->r1
*/
*/
if
(
REGNO
(
src
)
+
1
==
REGNO
(
dst
))
if
(
REGNO
(
src
)
+
1
==
REGNO
(
dst
))
return
"mov %
1,%0
\n\t
mov %R1,%R0 ! cr
"
;
return
"mov %
R1,%R0
\n\t
mov %1,%0 ! cra
"
;
else
else
return
"mov %R1,%R0
\n\t
mov %1,%0 "
;
return
"mov %1,%0
\n\t
mov %R1,%R0 ! crb"
;
}
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
{
if
(
INTVAL
(
src
)
<
0
)
HOST_WIDE_INT
val
=
INTVAL
(
src
);
return
"mov #-1,%0
\n\t
mov %1,%R0"
;
int
rn
=
REGNO
(
operands
[
0
]);
if
(
val
<
0
)
{
fprintf
(
asm_out_file
,
"
\t
mov #-1,r%d
\n
"
,
rn
);
}
else
else
return
"mov #0,%0
\n\t
mov %1,%R0"
;
{
}
fprintf
(
asm_out_file
,
"
\t
mov #0,r%d
\n
"
,
rn
);
}
fprintf
(
asm_out_file
,
"
\t
mov #%d,r%d
\n
"
,
val
,
rn
+
1
);
return
""
;
}
else
if
(
GET_CODE
(
src
)
==
MEM
)
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
{
int
ptrreg1
=
-
1
;
int
ptrreg1
=
-
1
;
...
@@ -518,10 +884,13 @@ output_movedouble (operands, mode)
...
@@ -518,10 +884,13 @@ output_movedouble (operands, mode)
if
(
GET_CODE
(
rhs
)
==
REG
)
if
(
GET_CODE
(
rhs
)
==
REG
)
ptrreg2
=
REGNO
(
rhs
);
ptrreg2
=
REGNO
(
rhs
);
}
}
else
if
(
GET_CODE
(
inside
)
==
LABEL_REF
)
{
return
"mov.l %1,%0
\n\t
mov.l %1+4,%R0"
;
}
else
else
abort
();
abort
();
if
((
ptrreg1
>=
0
&&
ptrreg2
>=
0
)
if
((
ptrreg1
>=
0
&&
ptrreg2
>=
0
)
&&
(
dreg
==
ptrreg1
&&
(
dreg
==
ptrreg1
||
dreg
==
ptrreg2
||
dreg
==
ptrreg2
...
@@ -582,7 +951,24 @@ output_shift (string, reg, k, code)
...
@@ -582,7 +951,24 @@ output_shift (string, reg, k, code)
{
{
int
s
=
INTVAL
(
k
);
int
s
=
INTVAL
(
k
);
if
(
s
<
0
)
{
s
=
-
s
;
switch
(
code
)
{
case
LSHIFTRT
:
case
ASHIFTRT
:
code
=
LSHIFT
;
break
;
case
ASHIFT
:
code
=
ASHIFTRT
;
break
;
case
LSHIFT
:
code
=
LSHIFTRT
;
default
:
abort
();
}
}
if
(
code
==
ASHIFT
&&
s
==
31
)
if
(
code
==
ASHIFT
&&
s
==
31
)
{
{
/* Shift left by 31 moving into the t bit, clearing and rotating the other way */
/* Shift left by 31 moving into the t bit, clearing and rotating the other way */
...
@@ -632,13 +1018,80 @@ output_shift (string, reg, k, code)
...
@@ -632,13 +1018,80 @@ output_shift (string, reg, k, code)
return
""
;
return
""
;
}
}
void
function_epilogue
(
stream
,
size
)
FILE
*
stream
;
int
size
;
{
fprintf
(
stream
,
"
\t
rts
\n
"
);
fprintf
(
stream
,
"
\t
or r0,r0
\n
"
);
}
/* Return the text of the branch instruction which matches its length
/* Return the text of the branch instruction which matches its length
attribute.
attribute.
This gets tricky if we have an insn in the delay slot of a branch
This gets tricky if we have an insn in the delay slot of a branch
and the branch needs more than 1 insn to complete.*/
and the branch needs more than 1 insn to complete. */
int
pending_const_table
;
/* We can't tell if we need a register as a scratch for the jump
until after branch shortening, and then it's too late to allocate a
register the 'proper' way. These instruction sequences are rare
anyway, so to avoid always using a reg up from our limited set, we'll
grab one when we need one on output. */
char
*
output_far_jump
(
insn
,
op
)
rtx
insn
;
rtx
op
;
{
rtx
thislab
=
gen_label_rtx
();
/* See if we can grab a reg from the prev insn */
rtx
gotone
=
0
;
rtx
prev
=
PREV_INSN
(
insn
);
rtx
link
;
if
(
dbr_sequence_length
())
{
/* Something to go in what would have been the delay
slot if this had been a short branch. Make sure the
reg we use to generate the branch target address
doesn't conflict */
int
i
;
rtx
vec
[
2
];
vec
[
0
]
=
thislab
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
vec
[
1
]
=
gen_rtx
(
REG
,
SImode
,
i
);
if
(
!
reg_referenced_p
(
vec
[
1
],
PATTERN
(
XVECEXP
(
final_sequence
,
0
,
1
))))
break
;
}
output_asm_insn
(
"mov.l %1,@-r15"
,
vec
);
output_asm_insn
(
"mov.l %O0,%1"
,
vec
);
print_slot
(
final_sequence
);
output_asm_insn
(
"jmp @%1 ! 32 xcond"
,
vec
);
output_asm_insn
(
"mov.l @r15+,%1"
,
vec
);
}
else
{
output_asm_insn
(
"mov.l r13,@-r15"
,
0
);
output_asm_insn
(
"mov.l %O0,r13"
,
&
thislab
);
output_asm_insn
(
"jmp @r13 ! 32 zcond"
,
0
);
output_asm_insn
(
"mov.l @r15+,r13"
,
0
);
}
ASM_OUTPUT_INTERNAL_LABEL
(
asm_out_file
,
"L"
,
CODE_LABEL_NUMBER
(
thislab
));
output_asm_insn
(
".align 2"
,
0
);
output_asm_insn
(
".long %O0"
,
&
op
);
return
""
;
}
char
*
char
*
output_branch
(
logic
,
insn
)
output_branch
(
logic
,
insn
)
...
@@ -649,6 +1102,7 @@ output_branch (logic, insn)
...
@@ -649,6 +1102,7 @@ output_branch (logic, insn)
int
label
=
lf
++
;
int
label
=
lf
++
;
int
rn
=
-
1
;
int
rn
=
-
1
;
int
need_save
;
int
need_save
;
fprintf
(
asm_out_file
,
"! pc %04x
\n
"
,
insn_addresses
[
INSN_UID
(
insn
)]);
switch
(
get_attr_length
(
insn
))
switch
(
get_attr_length
(
insn
))
{
{
...
@@ -679,16 +1133,13 @@ output_branch (logic, insn)
...
@@ -679,16 +1133,13 @@ output_branch (logic, insn)
output_asm_insn
(
"bra %l0 ! 12 bit cond "
,
recog_operand
);
output_asm_insn
(
"bra %l0 ! 12 bit cond "
,
recog_operand
);
fprintf
(
asm_out_file
,
"
\t
or r0,r0
\n
"
);
fprintf
(
asm_out_file
,
"
\t
or r0,r0
\n
"
);
label
=
dump_constants
(
label
);
fprintf
(
asm_out_file
,
"LF%d:
\n
"
,
label
);
fprintf
(
asm_out_file
,
"LF%d:
\n
"
,
label
);
}
}
return
""
;
return
""
;
case
8
:
case
16
:
/* Branches a long way away */
/* Branches a long way away */
{
{
rtx
oldop
=
recog_operand
[
0
];
rtx
oldop
=
recog_operand
[
0
];
if
(
need_slot
(
final_sequence
))
if
(
need_slot
(
final_sequence
))
...
@@ -702,20 +1153,7 @@ output_branch (logic, insn)
...
@@ -702,20 +1153,7 @@ output_branch (logic, insn)
fprintf
(
asm_out_file
,
"
\t
b%c
\t
LF%d
\n
"
,
logic
?
'f'
:
't'
,
label
);
fprintf
(
asm_out_file
,
"
\t
b%c
\t
LF%d
\n
"
,
logic
?
'f'
:
't'
,
label
);
}
}
recog_operand
[
0
]
=
oldop
;
output_far_jump
(
insn
,
oldop
);
/* We use r13 as a scratch */
need_save
=
0
;
rn
=
13
;
if
(
need_save
)
fprintf
(
asm_out_file
,
"
\t
push r%d
\n
"
,
rn
);
fprintf
(
asm_out_file
,
"
\t
mov.l LK%d,r%d
\n
"
,
add_constant
(
oldop
,
SImode
),
rn
);
fprintf
(
asm_out_file
,
"
\t
jmp @r%d ! 32 cond
\n
"
,
rn
);
if
(
need_save
)
fprintf
(
asm_out_file
,
"
\t
pop r%d
\n
"
,
rn
);
else
fprintf
(
asm_out_file
,
"
\t
or r0,r0
\n
"
);
fprintf
(
asm_out_file
,
"LF%d:
\n
"
,
label
);
fprintf
(
asm_out_file
,
"LF%d:
\n
"
,
label
);
return
""
;
return
""
;
}
}
...
@@ -724,231 +1162,70 @@ output_branch (logic, insn)
...
@@ -724,231 +1162,70 @@ output_branch (logic, insn)
}
}
/* Predicates used by the templates */
/* The SH cannot load a large constant into a register, constants have to
come from a pc relative load. The reference of a pc relative load
/* Non zero if op is an immediate ok for a byte index */
instruction must be less than 1k infront of the instruction. This
means that we often have to dump a constant inside a function, and
generate code to branch around it.
int
It is important to minimize this, since the branches will slow things
byte_index_operand
(
op
,
mode
)
down and make things bigger.
rtx
op
;
enum
machine_mode
mode
;
{
return
(
GET_CODE
(
op
)
==
CONST_INT
&&
INTVAL
(
op
)
>=
0
&&
INTVAL
(
op
)
<=
15
);
}
/* Non zero if OP is a pop operand */
Worst case code looks like:
int
mov.l L1,rn
pop_operand
(
op
,
mode
)
bra L2
rtx
op
;
nop
enum
machine_mode
mode
;
align
{
L1: .long value
if
(
GET_CODE
(
op
)
!=
MEM
)
L2:
return
0
;
..
if
(
GET_MODE
(
op
)
!=
mode
)
return
0
;
op
=
XEXP
(
op
,
0
);
if
(
GET_CODE
(
op
)
!=
POST_INC
)
return
0
;
return
XEXP
(
op
,
0
)
==
stack_pointer_rtx
;
}
/* Non zero if OP is an immediate which can be made from two insns. */
int
painful_immediate_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
GET_CODE
(
op
)
==
CONST_INT
)
{
int
i
=
INTVAL
(
op
);
if
(
i
>
127
&&
i
<
255
)
return
1
;
/* two adds */
}
return
0
;
}
/* Non zero if OP can be source of a simple move operation. */
int
general_movsrc_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
GET_CODE
(
op
)
==
REG
||
GET_CODE
(
op
)
==
SUBREG
||
(
GET_CODE
(
op
)
==
CONST_INT
&&
CONST_OK_FOR_I
(
INTVAL
(
op
)))
||
GET_CODE
(
op
)
==
MEM
)
return
general_operand
(
op
,
mode
);
return
0
;
}
/* Nonzero if OP is a normal arithmetic register. */
int
arith_reg_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
register_operand
(
op
,
mode
))
{
if
(
GET_CODE
(
op
)
==
REG
)
return
REGNO
(
op
)
!=
T_REG
;
return
1
;
}
return
0
;
}
/* Nonzero if OP is a valid source operand for an arithmetic insn. */
int
arith_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
register_operand
(
op
,
mode
))
return
1
;
if
(
GET_CODE
(
op
)
==
CONST_INT
)
{
if
(
CONST_OK_FOR_I
(
INTVAL
(
op
)))
return
1
;
}
return
0
;
}
/* Nonzero if OP is a valid source operand for a logical operation */
int
logical_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
register_operand
(
op
,
mode
))
return
1
;
if
(
GET_CODE
(
op
)
==
CONST_INT
)
{
if
(
CONST_OK_FOR_L
(
INTVAL
(
op
)))
return
1
;
}
return
0
;
}
/* Nonzero if p is a valid shift operand for lshr and ashl */
int
mov.l L3,rn
ok_shift_value
(
p
)
bra L4
rtx
p
;
nop
{
align
if
(
GET_CODE
(
p
)
==
CONST_INT
)
L3: .long value
{
L4:
switch
(
INTVAL
(
p
))
..
{
case
1
:
case
2
:
case
8
:
case
16
:
return
1
;
default
:
if
(
TARGET_FASTCODE
)
return
INTVAL
(
p
)
>=
0
;
}
}
return
0
;
}
/* Nonzero if the arg is an immediate which has to be loaded from
We fix this by performing a scan before scheduling, which notices which
memory */
instructions need to have their operands fetched from the constant table
and builds the table.
int
hard_immediate_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
immediate_operand
(
op
,
mode
))
{
if
(
GET_CODE
(
op
)
==
CONST_INT
&&
INTVAL
(
op
)
>=
-
128
&&
INTVAL
(
op
)
<
127
)
return
0
;
return
1
;
}
return
0
;
}
/* The SH cannot load a large constant into a register, constants have to
come from a pc relative load. The reference of a pc relative load
instruction must be less than 1k infront of the instruction. This
means that we often have to dump a constant inside a function, and
generate code to branch around it.
It is important to minimize this, since the branches will slow things
The algorithm is:
down and make things bigger.
Worst case code looks like:
scan, find an instruction which needs a pcrel move. Look forward, find the
last barrier which is within MAX_COUNT bytes of the requirement.
mov.l L1,rn
If there isn't one, make one. Process all the instructions between
bra L2
the find and the barrier.
nop
align
L1: .long value
L2:
..
mov.l L3,rn
bra L4
nop
align
L3: .long value
L4:
..
During shorten_branches we notice the instructions which can have a
constant table in them, if we see two that are close enough
together, we move the constants from the first table to the second
table and continue. This process can happen again and again, and
in the best case, moves the constant table outside of the function.
In the above example, we can tell that L3 is within 1k of L1, so
In the above example, we can tell that L3 is within 1k of L1, so
the first move can be shrunk from the 3 insn+constant sequence into
the first move can be shrunk from the 3 insn+constant sequence into
just 1 insn, and the constant moved to L3 to make:
just 1 insn, and the constant moved to L3 to make:
mov.l
L1,rn
mov.l
L1,rn
..
..
mov.l
L3,rn
mov.l
L3,rn
bra
L4
bra
L4
nop
nop
align
align
L3:.long value
L3:.long value
L4:.long value
L4:.long value
Then the second move becomes the target for the shortening process.
Then the second move becomes the target for the shortening process.
We keep a simple list of all the constants accumulated in the
*/
current pool so there are no duplicates in a single table, but
they are not factored into the size estimates.
*/
typedef
struct
typedef
struct
{
{
rtx
value
;
rtx
value
;
/* Value in table */
int
number
;
rtx
label
;
/* Label of value */
enum
machine_mode
mode
;
enum
machine_mode
mode
;
/* Mode of value */
}
pool_node
;
}
pool_node
;
/* The maximum number of constants that can fit into one pool, since
/* The maximum number of constants that can fit into one pool, since
the pc relative range is 0...1020 bytes and constants are at least 4
the pc relative range is 0...1020 bytes and constants are at least 4
...
@@ -958,28 +1235,19 @@ typedef struct
...
@@ -958,28 +1235,19 @@ typedef struct
static
pool_node
pool_vector
[
MAX_POOL_SIZE
];
static
pool_node
pool_vector
[
MAX_POOL_SIZE
];
static
int
pool_size
;
static
int
pool_size
;
/* Add a constant to the pool and return its label. */
/* Add a constant to the pool and return its label number. */
static
rtx
static
int
add_constant
(
x
,
mode
)
add_constant
(
x
,
mode
)
rtx
x
;
rtx
x
;
enum
machine_mode
mode
;
enum
machine_mode
mode
;
{
{
int
i
;
int
i
;
rtx
lab
;
/* Start the countdown on the first constant */
if
(
!
pool_size
)
{
first_pc
=
pc
;
}
/* First see if we've already got it */
/* First see if we've already got it */
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
{
{
if
(
x
->
code
==
pool_vector
[
i
].
value
->
code
if
(
x
->
code
==
pool_vector
[
i
].
value
->
code
&&
mode
==
pool_vector
[
i
].
mode
)
&&
mode
==
pool_vector
[
i
].
mode
)
{
{
...
@@ -989,546 +1257,657 @@ add_constant (x, mode)
...
@@ -989,546 +1257,657 @@ add_constant (x, mode)
continue
;
continue
;
}
}
}
}
if
(
rtx_equal_p
(
x
,
pool_vector
[
i
].
value
))
if
(
rtx_equal_p
(
x
,
pool_vector
[
i
].
value
))
return
pool_vector
[
i
].
number
;
return
pool_vector
[
i
].
label
;
}
}
/* Need a new one */
pool_vector
[
pool_size
].
value
=
x
;
pool_vector
[
pool_size
].
value
=
x
;
lab
=
gen_label_rtx
();
pool_vector
[
pool_size
].
mode
=
mode
;
pool_vector
[
pool_size
].
mode
=
mode
;
pool_vector
[
pool_size
].
number
=
lf
;
pool_vector
[
pool_size
].
label
=
lab
;
pool_size
++
;
pool_size
++
;
return
lab
;
return
lf
++
;
}
}
/*
Nonzero if the insn could take a constant table.
*/
/*
Dump out interesting debug info
*/
static
int
rtx
has_constant_table
(
insn
)
final_prescan_insn
(
insn
,
opvec
,
noperands
)
rtx
insn
;
rtx
insn
;
rtx
*
opvec
;
int
noperands
;
{
{
rtx
body
;
if
(
target_flags
&
ISIZE_BIT
)
if
(
GET_CODE
(
insn
)
==
NOTE
||
GET_CODE
(
insn
)
==
BARRIER
||
GET_CODE
(
insn
)
==
CODE_LABEL
)
return
0
;
body
=
PATTERN
(
insn
);
if
(
GET_CODE
(
body
)
==
SEQUENCE
)
return
0
;
if
(
GET_CODE
(
body
)
==
ADDR_VEC
)
return
0
;
if
(
GET_CODE
(
body
)
==
USE
)
return
0
;
if
(
GET_CODE
(
body
)
==
CLOBBER
)
return
0
;
if
(
get_attr_constneed
(
insn
)
==
CONSTNEED_YES
)
return
1
;
if
(
GET_CODE
(
body
)
==
UNSPEC_VOLATILE
)
{
{
return
INTVAL
(
XVECEXP
(
body
,
0
,
0
))
==
1
;
extern
int
*
insn_addresses
;
fprintf
(
asm_out_file
,
"
\n
! at %04x
\n
"
,
insn_addresses
[
INSN_UID
(
insn
)]);
}
}
return
0
;
}
}
/* Adjust the length of an instruction.
We'll look at the previous instruction which holds a constant
table and see if we can move the table to here instead. */
int
target_insn_uid
;
int
target_insn_smallest_size
;
int
target_pc
;
/* Stuff taken from m88k.c */
int
target_insn_range
;
int
current_pc
;
int
pool_bytes
;
int
last_uid
;
/* Output to FILE the start of the assembler file. */
int
last_pc
;
void
struct
option
adjust_insn_length
(
insn
,
insn_lengths
)
rtx
insn
;
short
*
insn_lengths
;
{
{
int
uid
=
INSN_UID
(
insn
);
char
*
string
;
rtx
body
=
PATTERN
(
insn
);
int
*
variable
;
int
on_value
;
current_pc
+=
insn_lengths
[
uid
];
};
if
(
GET_CODE
(
body
)
==
SEQUENCE
)
static
int
output_option
(
file
,
sep
,
type
,
name
,
indent
,
pos
,
max
)
FILE
*
file
;
char
*
sep
;
char
*
type
;
char
*
name
;
char
*
indent
;
int
pos
;
int
max
;
{
if
(
strlen
(
sep
)
+
strlen
(
type
)
+
strlen
(
name
)
+
pos
>
max
)
{
{
int
i
;
fprintf
(
file
,
indent
);
return
fprintf
(
file
,
"%s%s"
,
type
,
name
);
for
(
i
=
0
;
i
<
XVECLEN
(
body
,
0
);
i
++
)
{
adjust_insn_length
(
XVECEXP
(
body
,
0
,
i
),
insn_lengths
);
}
}
}
else
return
pos
+
fprintf
(
file
,
"%s%s%s"
,
sep
,
type
,
name
);
{
}
if
(
has_constant_table
(
insn
))
{
if
(
current_pc
>=
target_insn_range
)
{
/* This instruction is further away from the referencing
instruction than it can reach, so we'll stop accumulating
from that one and start fresh. */
target_pc
=
current_pc
;
target_insn_range
=
current_pc
+
MAYBE_DUMP_LEVEL
;
}
else
{
/* This instruction is within the reach of the target,
remove the constant table from the target by adjusting
downwards, and increase the size of this one to
compensate. */
/* Add the stuff from this insn to what will go in the
static
struct
growing table. */
{
char
*
name
;
int
value
;
}
pool_bytes
+=
get_attr_constantsize
(
insn
)
;
m_options
[]
=
TARGET_SWITCHES
;
/* The target shinks to its smallest natural size */
static
void
insn_lengths
[
target_insn_uid
]
=
target_insn_smallest_size
;
output_options
(
file
,
f_options
,
f_len
,
W_options
,
W_len
,
pos
,
max
,
sep
,
indent
,
term
)
FILE
*
file
;
struct
option
*
f_options
;
struct
option
*
W_options
;
int
f_len
,
W_len
;
int
pos
;
int
max
;
char
*
sep
;
char
*
indent
;
char
*
term
;
{
register
int
j
;
/* The current insn grows to be its larger size plust the
table size. */
insn_lengths
[
uid
]
=
get_attr_largestsize
(
insn
)
+
pool_bytes
;
if
(
optimize
)
pos
=
output_option
(
file
,
sep
,
"-O"
,
""
,
indent
,
pos
,
max
);
if
(
write_symbols
!=
NO_DEBUG
)
pos
=
output_option
(
file
,
sep
,
"-g"
,
""
,
indent
,
pos
,
max
);
if
(
flag_traditional
)
pos
=
output_option
(
file
,
sep
,
"-traditional"
,
""
,
indent
,
pos
,
max
);
if
(
profile_flag
)
pos
=
output_option
(
file
,
sep
,
"-p"
,
""
,
indent
,
pos
,
max
);
if
(
profile_block_flag
)
pos
=
output_option
(
file
,
sep
,
"-a"
,
""
,
indent
,
pos
,
max
);
}
for
(
j
=
0
;
j
<
f_len
;
j
++
)
/* Current insn becomes the target. */
if
(
*
f_options
[
j
].
variable
==
f_options
[
j
].
on_value
)
target_insn_uid
=
uid
;
pos
=
output_option
(
file
,
sep
,
"-f"
,
f_options
[
j
].
string
,
target_insn_smallest_size
=
get_attr_smallestsize
(
insn
);
indent
,
pos
,
max
);
}
for
(
j
=
0
;
j
<
W_len
;
j
++
)
}
if
(
*
W_options
[
j
].
variable
==
W_options
[
j
].
on_value
)
}
pos
=
output_option
(
file
,
sep
,
"-W"
,
W_options
[
j
].
string
,
indent
,
pos
,
max
);
for
(
j
=
0
;
j
<
sizeof
m_options
/
sizeof
m_options
[
0
];
j
++
)
if
(
m_options
[
j
].
name
[
0
]
!=
'\0'
&&
m_options
[
j
].
value
>
0
&&
((
m_options
[
j
].
value
&
target_flags
)
==
m_options
[
j
].
value
))
pos
=
output_option
(
file
,
sep
,
"-m"
,
m_options
[
j
].
name
,
indent
,
pos
,
max
);
/* Dump out the pending constant pool.
fprintf
(
file
,
term
);
If label provided then insert an branch in the middle of the table
fprintf
(
file
,
"! %d %d
\n
"
,
max_count_si
,
max_count_hi
);
*/
}
int
void
dump_constants
(
label
)
output_file_start
(
file
,
f_options
,
f_len
,
W_options
,
W_len
)
FILE
*
file
;
struct
option
*
f_options
;
struct
option
*
W_options
;
int
f_len
,
W_len
;
{
{
int
i
;
register
int
pos
;
int
rlabel
=
label
;
int
size
=
0
;
if
(
pool_size
)
{
fprintf
(
asm_out_file
,
"
\n\t
! constants - waited %d
\n
"
,
pc
-
first_pc
);
fprintf
(
asm_out_file
,
"
\t
.align
\t
2
\n
"
);
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
{
pool_node
*
p
=
pool_vector
+
i
;
fprintf
(
asm_out_file
,
"LK%d:"
,
p
->
number
);
size
+=
GET_MODE_SIZE
(
p
->
mode
);
switch
(
GET_MODE_CLASS
(
p
->
mode
))
{
case
MODE_INT
:
case
MODE_PARTIAL_INT
:
assemble_integer
(
p
->
value
,
GET_MODE_SIZE
(
p
->
mode
),
1
);
break
;
case
MODE_FLOAT
:
{
union
real_extract
u
;
bcopy
(
&
CONST_DOUBLE_LOW
(
p
->
value
),
&
u
,
sizeof
u
);
assemble_real
(
u
.
d
,
p
->
mode
);
}
}
/* After 200 bytes of table, stick in another branch */
if
(
label
&&
size
>
200
)
{
rlabel
=
lf
++
;
fprintf
(
asm_out_file
,
"LF%d:
\t
bra LF%d
\n
"
,
label
,
rlabel
);
fprintf
(
asm_out_file
,
"
\t
or r0,r0
\n
"
);
label
=
0
;
}
}
output_file_directive
(
file
,
main_input_filename
);
}
pool_size
=
0
;
/* Switch to the data section so that the coffsem symbol and the
current_pc
=
0
;
gcc2_compiled. symbol aren't in the text section. */
pc
=
0
;
data_section
();
pool_bytes
=
0
;
target_insn_range
=
0
;
return
rlabel
;
pos
=
fprintf
(
file
,
"
\n
! Hitachi SH cc1 (%s) arguments:"
,
version_string
);
output_options
(
file
,
f_options
,
f_len
,
W_options
,
W_len
,
pos
,
75
,
" "
,
"
\n
! "
,
"
\n\n
"
);
}
}
/*
Emit the text to load a value from a constant table.
*/
/*
Return the cost of a shift
*/
char
*
int
output_movepcrel
(
insn
,
operands
,
mode
)
shiftcosts
(
RTX
)
rtx
insn
;
rtx
RTX
;
rtx
operands
[];
enum
machine_mode
mode
;
{
{
int
len
=
GET_MODE_SIZE
(
mode
);
/* If shift by a non constant, then this will be expensive. */
int
rn
=
REGNO
(
operands
[
0
]);
if
(
GET_CODE
(
XEXP
(
RTX
,
1
))
!=
CONST_INT
)
return
20
;
fprintf
(
asm_out_file
,
"
\t
mov.l LK%d,r%d
\n
"
,
add_constant
(
operands
[
1
],
mode
),
rn
);
if
(
GET_MODE_SIZE
(
mode
)
>
4
)
{
fprintf
(
asm_out_file
,
"
\t
mov.l LK%d+4,r%d
\n
"
,
add_constant
(
operands
[
1
],
mode
),
rn
+
1
);
}
/* otherwise, it will be very cheap if by one of the constants
we can cope with. */
if
(
CONST_OK_FOR_K
(
INTVAL
(
XEXP
(
RTX
,
1
))))
return
1
;
/* This may have been the last move in the function, so nothing
/* otherwise it will be several insns, but we pretend that it will be more than
took its constant table, we may be able to move it past the end
just the components, so that combine doesn't glue together a load of shifts into
of the function (after the rts) if we are careful */
one shift which has to be emitted as a bunch anyway - breaking scheduling */
return
100
;
}
if
(
target_insn_uid
==
INSN_UID
(
insn
)
int
&&
current_pc
<
target_insn_range
)
andcosts
(
RTX
)
return
""
;
rtx
RTX
;
{
int
i
;
if
(
GET_CODE
(
XEXP
(
RTX
,
1
))
!=
CONST_INT
)
return
2
;
i
=
INTVAL
(
XEXP
(
RTX
,
1
));
/* And can use the extend insns cheaply */
if
(
i
==
0xff
||
i
==
0xffff
)
return
2
;
/* Any small constant is reasonably cheap - but requires r0 */
if
(
CONST_OK_FOR_I
(
i
))
return
3
;
return
5
;
}
/* Return the cost of a multiply */
int
multcosts
(
RTX
)
rtx
RTX
;
{
if
(
TARGET_SH2
)
return
2
;
/* If we we're aiming at small code, then just count the number of
insns in a multiply call sequence, otherwise, count all the insnsn
inside the call. */
if
(
TARGET_SMALLCODE
)
return
3
;
return
30
;
}
/* Code to expand a shift */
/* If this instruction is as small as it can be, there can be no
void
constant table attached to it. */
gen_ashift
(
type
,
n
,
reg
)
if
(
get_attr_length
(
insn
)
!=
get_attr_smallestsize
(
insn
))
int
type
;
int
n
;
rtx
reg
;
{
switch
(
type
)
{
{
/* This needs a constant table */
case
ASHIFTRT
:
fprintf
(
asm_out_file
,
"
\t
!constant table start
\n
"
);
emit_insn
(
gen_ashrsi3_k
(
reg
,
reg
,
GEN_INT
(
n
)));
fprintf
(
asm_out_file
,
"
\t
bra LF%d
\n
"
,
lf
);
break
;
fprintf
(
asm_out_file
,
"
\t
or r0,r0 ! wasted slot
\n
"
);
case
LSHIFTRT
:
dump_constants
(
0
);
emit_insn
(
gen_lshrsi3_k
(
reg
,
reg
,
GEN_INT
(
n
)));
fprintf
(
asm_out_file
,
"LF%d:
\n
"
,
lf
++
);
break
;
fprintf
(
asm_out_file
,
"
\t
!constant table end
\n
"
);
case
ASHIFT
:
if
(
n
==
1
)
emit_insn
(
gen_addsi3
(
reg
,
reg
,
reg
));
else
emit_insn
(
gen_ashlsi3_k
(
reg
,
reg
,
GEN_INT
(
n
)));
break
;
}
}
return
""
;
}
}
/* Dump out interesting debug info */
rtx
int
final_prescan_insn
(
insn
,
opvec
,
noperands
)
gen_shifty_op
(
code
,
operands
)
rtx
insn
;
int
code
;
rtx
*
opvec
;
rtx
*
operands
;
int
noperands
;
{
{
register
rtx
body
=
PATTERN
(
insn
);
rtx
wrk
=
gen_reg_rtx
(
SImode
);
rtx
t
;
if
(
target_flags
&
ISIZE_BIT
)
char
*
func
;
if
(
GET_CODE
(
operands
[
2
])
==
CONST_INT
)
{
{
extern
int
*
insn_addresses
;
int
value
=
INTVAL
(
operands
[
2
]);
top
:
fprintf
(
asm_out_file
,
"
\n
!%04x*
\n
"
,
switch
(
code
)
insn_addresses
[
INSN_UID
(
insn
)]
+
0x10
);
{
case
ASHIFTRT
:
if
(
value
<
0
)
{
code
=
ASHIFT
;
value
=
-
value
;
goto
top
;
}
fprintf
(
asm_out_file
,
"
\n
!%04x %d %04x len=%d
\n
"
,
/* Expand a short sequence inline, longer call a magic routine */
pc
,
pool_size
,
first_pc
,
get_attr_length
(
insn
));
if
(
value
<
4
)
{
emit_move_insn
(
wrk
,
operands
[
1
]);
while
(
value
--
)
{
gen_ashift
(
ASHIFTRT
,
1
,
wrk
);
}
emit_move_insn
(
operands
[
0
],
wrk
);
return
1
;
}
t
=
gen_reg_rtx
(
Pmode
);
/* Load the value into an arg reg and call a helper */
emit_move_insn
(
gen_rtx
(
REG
,
SImode
,
4
),
operands
[
1
]);
if
(
!
shiftsyms
[
value
])
{
func
=
xmalloc
(
18
);
sprintf
(
func
,
"__ashiftrt_r4_%d"
,
value
);
shiftsyms
[
value
]
=
gen_rtx
(
SYMBOL_REF
,
Pmode
,
func
);
}
emit_move_insn
(
t
,
shiftsyms
[
value
]);
emit_insn
(
gen_ashrsi3_n
(
GEN_INT
(
value
),
t
));
emit_move_insn
(
operands
[
0
],
gen_rtx
(
REG
,
SImode
,
4
));
return
1
;
if
(
TARGET_DUMP_RTL
)
case
ASHIFT
:
print_rtl
(
asm_out_file
,
body
);
if
(
value
<
0
)
{
code
=
LSHIFTRT
;
value
=
-
value
;
goto
top
;
}
/* Fall through */
case
LSHIFTRT
:
if
(
value
<
0
)
{
code
=
ASHIFT
;
value
=
-
value
;
goto
top
;
}
}
emit_move_insn
(
wrk
,
operands
[
1
]);
while
(
value
)
{
if
(
value
>=
16
)
{
gen_ashift
(
code
,
16
,
wrk
);
value
-=
16
;
}
else
if
(
value
>=
8
)
{
gen_ashift
(
code
,
8
,
wrk
);
value
-=
8
;
}
else
if
(
value
>=
2
)
{
gen_ashift
(
code
,
2
,
wrk
);
value
-=
2
;
}
else
{
gen_ashift
(
code
,
1
,
wrk
);
value
--
;
}
}
emit_move_insn
(
operands
[
0
],
wrk
);
return
1
;
pc
+=
get_attr_length
(
insn
);
}
if
(
pool_size
&&
pc
-
first_pc
>
MUST_DUMP_LEVEL
)
{
/* For some reason we have not dumped out a constant table, and
we have emitted a lot of code. This can happen if the think
which wants the table is a long conditional branch (which has no
room for a constant table), and there has not been a move
constant anywhere. */
int
label
=
lf
++
;
fprintf
(
asm_out_file
,
"
\t
!forced constant table
\n
"
);
fprintf
(
asm_out_file
,
"
\t
bra LF%d
\n
"
,
label
);
fprintf
(
asm_out_file
,
"
\t
or r0,r0 ! wasted slot
\n
"
);
label
=
dump_constants
(
label
);
fprintf
(
asm_out_file
,
"LF%d:
\n
"
,
label
);
fprintf
(
asm_out_file
,
"
\t
!constant table end
\n
"
);
}
}
return
0
;
}
}
/* Dump out any constants accumulated in the final pass -
which will only be labels */
char
*
output_jump_label_table
()
{
int
i
;
if
(
pool_size
)
{
fprintf
(
asm_out_file
,
"
\t
.align 2
\n
"
);
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
{
pool_node
*
p
=
pool_vector
+
i
;
ASM_OUTPUT_INTERNAL_LABEL
(
asm_out_file
,
"L"
,
CODE_LABEL_NUMBER
(
p
->
label
));
output_asm_insn
(
".long %O0"
,
&
p
->
value
);
}
pool_size
=
0
;
}
/* Block move stuff stolen from m88k*/
return
""
;
}
/* Emit code to perform a block move. Choose the best method.
/* Output the literal table */
OPERANDS[0] is the destination.
OPERANDS[1] is the source.
OPERANDS[2] is the size.
OPERANDS[3] is the alignment safe to use. */
/* Emit code to perform a block move with an offset sequence of ld/st
instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are
known constants. DEST and SRC are registers. OFFSET is the known
starting point for the output pattern. */
static
enum
machine_mode
mode_from_align
[]
=
{
VOIDmode
,
QImode
,
HImode
,
VOIDmode
,
SImode
,
VOIDmode
,
VOIDmode
,
VOIDmode
,
DImode
};
static
void
static
void
dump_table
(
scan
)
block_move_sequence
(
dest
,
dest_mem
,
src
,
src_mem
,
size
,
align
,
offset
)
rtx
scan
;
rtx
dest
,
dest_mem
;
rtx
src
,
src_mem
;
int
size
;
int
align
;
int
offset
;
{
{
rtx
temp
[
2
];
int
i
;
enum
machine_mode
mode
[
2
];
int
pass
;
int
amount
[
2
];
int
need_align
=
1
;
int
active
[
2
];
int
phase
=
0
;
int
next
;
int
offset_ld
=
offset
;
int
offset_st
=
offset
;
active
[
0
]
=
active
[
1
]
=
FALSE
;
/* Establish parameters for the first load and for the second load if
it is known to be the same mode as the first. */
amount
[
0
]
=
amount
[
1
]
=
align
;
mode
[
0
]
=
mode_from_align
[
align
];
/* Do two passes, first time dump out the HI sized constants */
temp
[
0
]
=
gen_reg_rtx
(
mode
[
0
]);
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
if
(
size
>=
2
*
align
)
{
{
mode
[
1
]
=
mode
[
0
];
pool_node
*
p
=
pool_vector
+
i
;
temp
[
1
]
=
gen_reg_rtx
(
mode
[
1
]);
if
(
p
->
mode
==
HImode
)
{
if
(
need_align
)
{
scan
=
emit_insn_after
(
gen_align_2
(),
scan
);
need_align
=
0
;
}
scan
=
emit_label_after
(
p
->
label
,
scan
);
scan
=
emit_insn_after
(
gen_consttable_2
(
p
->
value
),
scan
);
}
}
}
need_align
=
1
;
do
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
{
{
rtx
srcp
,
dstp
;
pool_node
*
p
=
pool_vector
+
i
;
next
=
phase
;
phase
=
!
phase
;
if
(
size
>
0
)
switch
(
p
->
mode
)
{
{
/* Change modes as the sequence tails off. */
case
HImode
:
if
(
size
<
amount
[
next
])
break
;
case
SImode
:
if
(
need_align
)
{
{
amount
[
next
]
=
(
size
>=
4
?
4
:
(
size
>=
2
?
2
:
1
));
need_align
=
0
;
mode
[
next
]
=
mode_from_align
[
amount
[
next
]];
scan
=
emit_insn_after
(
gen_align_4
(),
scan
);
temp
[
next
]
=
gen_reg_rtx
(
mode
[
next
]);
}
}
size
-=
amount
[
next
];
scan
=
emit_label_after
(
p
->
label
,
scan
);
srcp
=
gen_rtx
(
MEM
,
scan
=
emit_insn_after
(
gen_consttable_4
(
p
->
value
),
scan
);
MEM_IN_STRUCT_P
(
src_mem
)
?
mode
[
next
]
:
BLKmode
,
break
;
gen_rtx
(
PLUS
,
Pmode
,
src
,
case
DImode
:
gen_rtx
(
CONST_INT
,
SImode
,
offset_ld
)));
if
(
need_align
)
RTX_UNCHANGING_P
(
srcp
)
=
RTX_UNCHANGING_P
(
src_mem
);
{
MEM_VOLATILE_P
(
srcp
)
=
MEM_VOLATILE_P
(
src_mem
);
need_align
=
0
;
MEM_IN_STRUCT_P
(
srcp
)
=
1
;
scan
=
emit_insn_after
(
gen_align_4
(),
scan
);
emit_insn
(
gen_rtx
(
SET
,
VOIDmode
,
temp
[
next
],
srcp
));
}
offset_ld
+=
amount
[
next
];
scan
=
emit_label_after
(
p
->
label
,
scan
);
active
[
next
]
=
TRUE
;
scan
=
emit_insn_after
(
gen_consttable_8
(
p
->
value
),
scan
);
}
break
;
default
:
if
(
active
[
phase
])
abort
();
{
break
;
active
[
phase
]
=
FALSE
;
dstp
=
gen_rtx
(
MEM
,
MEM_IN_STRUCT_P
(
dest_mem
)
?
mode
[
phase
]
:
BLKmode
,
gen_rtx
(
PLUS
,
Pmode
,
dest
,
gen_rtx
(
CONST_INT
,
SImode
,
offset_st
)));
RTX_UNCHANGING_P
(
dstp
)
=
RTX_UNCHANGING_P
(
dest_mem
);
MEM_VOLATILE_P
(
dstp
)
=
MEM_VOLATILE_P
(
dest_mem
);
MEM_IN_STRUCT_P
(
dstp
)
=
1
;
emit_insn
(
gen_rtx
(
SET
,
VOIDmode
,
dstp
,
temp
[
phase
]));
offset_st
+=
amount
[
phase
];
}
}
}
}
while
(
active
[
next
]);
}
void
expand_block_move
(
dest_mem
,
src_mem
,
operands
)
rtx
dest_mem
;
rtx
src_mem
;
rtx
*
operands
;
{
int
align
=
INTVAL
(
operands
[
3
]);
int
constp
=
(
GET_CODE
(
operands
[
2
])
==
CONST_INT
);
int
bytes
=
(
constp
?
INTVAL
(
operands
[
2
])
:
0
);
#if 0
scan
=
emit_insn_after
(
gen_consttable_end
(),
scan
);
if (constp && bytes <= 0)
scan
=
emit_barrier_after
(
scan
);
return;
pool_size
=
0
;
}
if (align > 4)
align = 4;
if (constp && bytes <= 3 * align)
block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
bytes, align, 0);
#if 0
/* Non zero if the src operand needs to be fixed up */
else if (constp && bytes <= best_from_align[target][align])
static
block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
int
bytes, align);
fixit
(
src
,
mode
)
rtx
src
;
enum
machine_mode
mode
;
{
if
(
mode
==
QImode
)
return
0
;
/* QIs never need to be fixed */
if
(
GET_CODE
(
src
)
==
CONST
)
return
1
;
else if (constp && align == 4 && TARGET_88100)
if
(
GET_CODE
(
src
)
==
SYMBOL_REF
)
block_move_loop (operands[0], dest_mem, operands[1], src_mem,
bytes, align);
#endif
else
#endif
{
{
emit_library_call
(
gen_rtx
(
SYMBOL_REF
,
Pmode
,
"memcpy"
),
0
,
return
1
;
VOIDmode
,
3
,
}
operands
[
0
],
Pmode
,
if
(
GET_CODE
(
src
)
==
CONST_INT
)
operands
[
1
],
Pmode
,
{
operands
[
2
],
SImode
);
/* All QI insns are ok */
if
(
mode
==
QImode
)
return
1
;
/* The rest may need to be fixed */
return
!
CONST_OK_FOR_I
(
INTVAL
(
src
));
}
}
return
0
;
}
}
/* Return Non-zero if constant would be an ok source for a
override_options
()
mov.w instead of a mov.l */
int
hi_const
(
src
)
rtx
src
;
{
{
sh_cpu
=
CPU_SH0
;
return
(
GET_CODE
(
src
)
==
CONST_INT
if
(
TARGET_SH1
)
&&
INTVAL
(
src
)
>=
-
32768
sh_cpu
=
CPU_SH1
;
&&
INTVAL
(
src
)
<=
32767
);
if
(
TARGET_SH2
)
sh_cpu
=
CPU_SH2
;
if
(
TARGET_SH3
)
sh_cpu
=
CPU_SH3
;
}
}
/* Stuff taken from m88k.c */
/* Output to FILE the start of the assembler file. */
/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one.
If an HI move is found, then make sure that MAX_COUNT_HI isn't broken from that one. */
struct
option
static
rtx
find_barrier
(
from
)
rtx
from
;
{
{
char
*
string
;
int
count_si
=
0
;
int
*
variable
;
int
count_hi
=
0
;
int
on_value
;
int
found_hi
=
0
;
};
int
found_si
=
0
;
rtx
found_barrier
=
0
;
while
(
from
&&
count_si
<
max_count_si
&&
count_hi
<
max_count_hi
)
{
int
inc
;
if
(
GET_CODE
(
from
)
==
BARRIER
)
{
found_barrier
=
from
;
}
/* Count the length of this insn - we assume that all the pcrelloads
will work out to be only 2 bytes long */
static
int
if
(
GET_CODE
(
from
)
==
INSN
&&
output_option
(
file
,
sep
,
type
,
name
,
indent
,
pos
,
max
)
GET_CODE
(
PATTERN
(
from
))
==
SET
)
FILE
*
file
;
{
char
*
sep
;
rtx
src
=
SET_SRC
(
PATTERN
(
from
));
char
*
type
;
if
(
hi_const
(
src
))
char
*
name
;
found_hi
=
1
;
char
*
indent
;
else
int
pos
;
found_si
=
1
;
int
max
;
inc
=
2
;
{
}
if
(
strlen
(
sep
)
+
strlen
(
type
)
+
strlen
(
name
)
+
pos
>
max
)
else
{
inc
=
get_attr_length
(
from
);
}
if
(
found_si
)
count_si
+=
inc
;
if
(
found_hi
)
count_hi
+=
inc
;
from
=
NEXT_INSN
(
from
);
}
if
(
!
found_barrier
)
{
{
fprintf
(
file
,
indent
);
/* Insert a jump around the barrier here */
return
fprintf
(
file
,
"%s%s"
,
type
,
name
);
rtx
label
=
gen_label_rtx
();
/* Walk back to be just before any jump */
while
(
GET_CODE
(
from
)
==
JUMP_INSN
||
GET_CODE
(
from
)
==
NOTE
)
{
from
=
PREV_INSN
(
from
);
}
from
=
emit_jump_insn_after
(
gen_jump
(
label
),
from
);
JUMP_LABEL
(
from
)
=
label
;
found_barrier
=
emit_barrier_after
(
from
);
emit_label_after
(
label
,
found_barrier
);
return
found_barrier
;
}
}
return
pos
+
fprintf
(
file
,
"%s%s%s"
,
sep
,
type
,
name
)
;
return
found_barrier
;
}
}
static
struct
/* Non zero if the insn is a move instruction which needs to be fixed. */
{
char
*
name
;
int
value
;
}
m_options
[]
=
TARGET_SWITCHES
;
static
void
static
output_options
(
file
,
f_options
,
f_len
,
W_options
,
W_len
,
int
pos
,
max
,
sep
,
indent
,
term
)
broken_move
(
insn
)
FILE
*
file
;
rtx
insn
;
struct
option
*
f_options
;
struct
option
*
W_options
;
int
f_len
,
W_len
;
int
pos
;
int
max
;
char
*
sep
;
char
*
indent
;
char
*
term
;
{
{
register
int
j
;
if
(
!
INSN_DELETED_P
(
insn
)
&&
GET_CODE
(
insn
)
==
INSN
&&
GET_CODE
(
PATTERN
(
insn
))
==
SET
)
if
(
optimize
)
{
pos
=
output_option
(
file
,
sep
,
"-O"
,
""
,
indent
,
pos
,
max
);
rtx
pat
=
PATTERN
(
insn
);
if
(
write_symbols
!=
NO_DEBUG
)
rtx
src
=
SET_SRC
(
pat
);
pos
=
output_option
(
file
,
sep
,
"-g"
,
""
,
indent
,
pos
,
max
);
rtx
dst
=
SET_DEST
(
pat
);
if
(
flag_traditional
)
enum
machine_mode
mode
=
GET_MODE
(
dst
);
pos
=
output_option
(
file
,
sep
,
"-traditional"
,
""
,
indent
,
pos
,
max
);
if
(
dst
==
pc_rtx
)
if
(
profile_flag
)
return
0
;
pos
=
output_option
(
file
,
sep
,
"-p"
,
""
,
indent
,
pos
,
max
);
return
fixit
(
src
,
mode
);
if
(
profile_block_flag
)
}
pos
=
output_option
(
file
,
sep
,
"-a"
,
""
,
indent
,
pos
,
max
);
return
0
;
}
for
(
j
=
0
;
j
<
f_len
;
j
++
)
if
(
*
f_options
[
j
].
variable
==
f_options
[
j
].
on_value
)
pos
=
output_option
(
file
,
sep
,
"-f"
,
f_options
[
j
].
string
,
indent
,
pos
,
max
);
for
(
j
=
0
;
j
<
W_len
;
j
++
)
/* Exported to toplev.c
if
(
*
W_options
[
j
].
variable
==
W_options
[
j
].
on_value
)
pos
=
output_option
(
file
,
sep
,
"-W"
,
W_options
[
j
].
string
,
indent
,
pos
,
max
);
for
(
j
=
0
;
j
<
sizeof
m_options
/
sizeof
m_options
[
0
];
j
++
)
Scan the function looking for move instructions which have to be changed to
if
(
m_options
[
j
].
name
[
0
]
!=
'\0'
pcrel loads and insert the literal tables. */
&&
m_options
[
j
].
value
>
0
&&
((
m_options
[
j
].
value
&
target_flags
)
==
m_options
[
j
].
value
))
pos
=
output_option
(
file
,
sep
,
"-m"
,
m_options
[
j
].
name
,
indent
,
pos
,
max
);
void
machine_dependent_reorg
(
first
)
rtx
first
;
{
rtx
insn
;
int
limit
;
for
(
insn
=
first
;
insn
;
insn
=
NEXT_INSN
(
insn
))
{
if
(
broken_move
(
insn
))
{
/* This is a broken move instruction, scan ahead looking for
a barrier to stick the constant table behind */
rtx
scan
;
rtx
barrier
=
find_barrier
(
insn
);
fprintf
(
file
,
term
);
/* Now find all the moves between the points and modify them */
for
(
scan
=
insn
;
scan
!=
barrier
;
scan
=
NEXT_INSN
(
scan
))
{
if
(
broken_move
(
scan
))
{
rtx
pat
=
PATTERN
(
scan
);
rtx
src
=
SET_SRC
(
pat
);
rtx
dst
=
SET_DEST
(
pat
);
enum
machine_mode
mode
=
GET_MODE
(
dst
);
rtx
lab
;
rtx
newinsn
;
rtx
newsrc
;
/* This is a broken move instruction, add it to the pool */
if
(
mode
==
SImode
&&
hi_const
(
src
))
{
/* This is an HI source, clobber the dest to get the mode right too */
mode
=
HImode
;
dst
=
gen_rtx
(
REG
,
HImode
,
REGNO
(
dst
));
}
lab
=
add_constant
(
src
,
mode
);
newsrc
=
gen_rtx
(
MEM
,
mode
,
gen_rtx
(
LABEL_REF
,
VOIDmode
,
lab
));
/* Build a jump insn wrapper around the move instead
of an ordinary insn, because we want to have room for
the target label rtx in fld[7], which an ordinary
insn doesn't have. */
newinsn
=
emit_jump_insn_after
(
gen_rtx
(
SET
,
VOIDmode
,
dst
,
newsrc
),
scan
);
JUMP_LABEL
(
newinsn
)
=
lab
;
/* But it's still an ordinary insn */
PUT_CODE
(
newinsn
,
INSN
);
/* Kill old insn */
delete_insn
(
scan
);
scan
=
newinsn
;
}
}
dump_table
(
barrier
);
}
}
}
}
void
/* Called from the md file, set up the operands of a compare instruction */
output_file_start
(
file
,
f_options
,
f_len
,
W_options
,
W_len
)
FILE
*
file
;
int
struct
option
*
f_options
;
from_compare
(
operands
,
code
)
struct
option
*
W_option
s
;
rtx
*
operand
s
;
int
f_len
,
W_len
;
int
code
;
{
{
register
int
pos
;
operands
[
1
]
=
sh_compare_op0
;
operands
[
2
]
=
force_reg
(
SImode
,
sh_compare_op1
);
operands
[
1
]
=
force_reg
(
SImode
,
operands
[
1
]);
}
output_file_directive
(
file
,
main_input_filename
);
/* Non-zero if x is EQ or NE */
/* Switch to the data section so that the coffsem symbol and the
int
gcc2_compiled. symbol aren't in the text section. */
equality_operator
(
x
,
mode
)
data_section
();
rtx
x
;
enum
machine_mode
mode
;
{
enum
rtx_code
code
=
GET_CODE
(
x
);
return
(
code
==
EQ
||
code
==
NE
);
}
pos
=
fprintf
(
file
,
"
\n
! Hitachi SH cc1 (%s) arguments:"
,
version_string
);
/* Framefull frame looks like:
output_options
(
file
,
f_options
,
f_len
,
W_options
,
W_len
,
pos
,
75
,
" "
,
"
\n
! "
,
"
\n\n
"
);
arg-5
}
arg-4
[ if current_function_anonymous_args
arg-3
arg-2
arg-1
arg-0 ]
saved-fp
saved-r10
saved-r11
saved-r12
saved-pr
local-n
..
local-1
local-0 <- fp points here
If TARGET_SMALLCALL, then the preserved registers are pushed by a
wrapper before the routine is entered, so the regs are always pushed
and there are two pr's on the stack - the caller and the wrapper.
*/
/* Code to generate prologue and epilogue sequences */
/* Code to generate prologue and epilogue sequences */
void
void
sh_expand_prologue
()
sh_expand_prologue
()
{
{
...
@@ -1537,7 +1916,9 @@ sh_expand_prologue ()
...
@@ -1537,7 +1916,9 @@ sh_expand_prologue ()
live_regs_mask
=
calc_live_regs
(
&
d
);
live_regs_mask
=
calc_live_regs
(
&
d
);
output_stack_adjust
(
-
1
,
current_function_pretend_args_size
);
/* We have pretend args if we had an object sent partially in registers
and partially on the stack - eg a large structure */
output_stack_adjust
(
-
current_function_pretend_args_size
);
if
(
current_function_anonymous_args
)
if
(
current_function_anonymous_args
)
{
{
...
@@ -1549,22 +1930,16 @@ sh_expand_prologue ()
...
@@ -1549,22 +1930,16 @@ sh_expand_prologue ()
if
(
i
>
NPARM_REGS
-
current_function_args_info
)
if
(
i
>
NPARM_REGS
-
current_function_args_info
)
break
;
break
;
push
(
rn
);
push
(
rn
);
extra_push
+=
4
;
extra_push
+=
4
;
}
}
}
}
push_regs
(
live_regs_mask
);
output_stack_adjust
(
-
get_frame_size
());
if
(
frame_pointer_needed
)
if
(
frame_pointer_needed
)
{
{
push_regs
(
live_regs_mask
);
emit_insn
(
gen_movsi
(
frame_pointer_rtx
,
stack_pointer_rtx
));
emit_insn
(
gen_movsi
(
frame_pointer_rtx
,
stack_pointer_rtx
));
}
}
else
{
push_regs
(
live_regs_mask
);
}
output_stack_adjust
(
-
1
,
get_frame_size
());
}
}
void
void
...
@@ -1580,13 +1955,10 @@ sh_expand_epilogue ()
...
@@ -1580,13 +1955,10 @@ sh_expand_epilogue ()
{
{
emit_insn
(
gen_movsi
(
stack_pointer_rtx
,
frame_pointer_rtx
));
emit_insn
(
gen_movsi
(
stack_pointer_rtx
,
frame_pointer_rtx
));
}
}
else
output_stack_adjust
(
get_frame_size
());
{
output_stack_adjust
(
1
,
get_frame_size
());
}
/* Pop all the registers */
/* Pop all the registers */
for
(
i
=
0
;
i
<
FIRST_PSEUDO_REGISTER
;
i
++
)
for
(
i
=
0
;
i
<
FIRST_PSEUDO_REGISTER
;
i
++
)
{
{
int
j
=
(
FIRST_PSEUDO_REGISTER
-
1
)
-
i
;
int
j
=
(
FIRST_PSEUDO_REGISTER
-
1
)
-
i
;
...
@@ -1595,43 +1967,285 @@ sh_expand_epilogue ()
...
@@ -1595,43 +1967,285 @@ sh_expand_epilogue ()
pop
(
j
);
pop
(
j
);
}
}
}
}
output_stack_adjust
(
1
,
extra_push
+
current_function_pretend_args_size
);
extra_push
=
0
;
output_stack_adjust
(
extra_push
+
current_function_pretend_args_size
)
;
extra_push
=
0
;
current_function_pretend_args_size
=
0
;
current_function_anonymous_args
=
0
;
current_function_anonymous_args
=
0
;
for
(
i
=
0
;
i
<
32
;
i
++
)
shiftsyms
[
i
]
=
0
;
}
}
/* Define the offset between two registers, one to be eliminated, and
the other its replacement, at the start of a routine. */
int
initial_elimination_offset
(
from
,
to
)
{
int
regs_saved
;
int
regs_saved_mask
=
calc_live_regs
(
&
regs_saved
);
int
total_saved_regs_space
;
int
total_auto_space
=
get_frame_size
();
total_saved_regs_space
=
(
regs_saved
)
*
4
;
/* Return the cost of a shift */
if
(
from
==
ARG_POINTER_REGNUM
&&
to
==
FRAME_POINTER_REGNUM
)
{
return
total_saved_regs_space
+
total_auto_space
;
}
if
(
from
==
ARG_POINTER_REGNUM
&&
to
==
STACK_POINTER_REGNUM
)
{
return
total_saved_regs_space
+
total_auto_space
;
}
if
(
from
==
FRAME_POINTER_REGNUM
&&
to
==
STACK_POINTER_REGNUM
)
{
/* Initial gap between fp and sp is 0 */
return
0
;
}
abort
();
}
/* Handle machine specific pragmas to be semi-compatible with Hitachi
compiler */
int
int
shiftcosts
(
RTX
)
handle_pragma
(
file
)
rtx
RTX
;
FILE
*
file
;
{
{
/* If shift by a non constant, then this will be expensive. */
int
c
;
if
(
GET_CODE
(
XEXP
(
RTX
,
1
))
!=
CONST_INT
)
char
pbuf
[
200
];
return
2
0
;
int
psize
=
0
;
/* otherwise, it will be very cheap if by one of the constants
c
=
getc
(
file
);
we can cope with. */
while
(
c
==
' '
||
c
==
'\t'
)
if
(
CONST_OK_FOR_K
(
INTVAL
(
XEXP
(
RTX
,
1
))))
c
=
getc
(
file
);
if
(
c
==
'\n'
||
c
==
EOF
)
return
c
;
while
(
psize
<
sizeof
(
pbuf
)
-
1
&&
c
!=
'\n'
)
{
pbuf
[
psize
++
]
=
c
;
if
(
psize
==
9
&&
strncmp
(
pbuf
,
"interrupt"
,
9
)
==
0
)
{
pragma_interrupt
=
1
;
return
;
}
if
(
psize
==
5
&&
strncmp
(
pbuf
,
"trapa"
,
5
)
==
0
)
{
pragma_interrupt
=
pragma_trapa
=
1
;
return
;
}
c
=
getc
(
file
);
}
return
c
;
}
/* insn expand helpers */
/* Emit insns to perform a call. If TARGET_SMALLCALL, then load the
target address into r1 and call __saveargs, otherwise
perform the standard call sequence */
void
expand_acall
(
isa_retval
,
operands
)
int
isa_retval
;
rtx
*
operands
;
{
rtx
call
;
rtx
ret
=
operands
[
0
];
rtx
call_target
=
operands
[
isa_retval
+
0
];
rtx
numargs
=
operands
[
isa_retval
+
1
];
if
(
GET_CODE
(
call_target
)
==
MEM
)
{
call_target
=
force_reg
(
Pmode
,
XEXP
(
call_target
,
0
));
}
if
(
TARGET_SMALLCALL
)
{
rtx
tmp
=
gen_reg_rtx
(
SImode
);
rtx
r1
=
gen_rtx
(
REG
,
SImode
,
1
);
emit_move_insn
(
tmp
,
gen_rtx
(
SYMBOL_REF
,
SImode
,
"__saveargs"
));
emit_move_insn
(
r1
,
call_target
);
emit_insn
(
gen_rtx
(
USE
,
VOIDmode
,
r1
));
call_target
=
tmp
;
}
call
=
gen_rtx
(
CALL
,
VOIDmode
,
gen_rtx
(
MEM
,
SImode
,
call_target
),
numargs
);
if
(
isa_retval
)
{
call
=
gen_rtx
(
SET
,
VOIDmode
,
ret
,
call
);
}
emit_call_insn
(
gen_rtx
(
PARALLEL
,
VOIDmode
,
gen_rtvec
(
2
,
call
,
gen_rtx
(
CLOBBER
,
VOIDmode
,
gen_rtx
(
REG
,
SImode
,
17
)))));
}
/* Predicates used by the templates */
/* Returns 1 if OP can be source of a simple move operation.
Same as general_operand, but a LABEL_REF is valid, PRE_DEC is
invalid as are subregs of system registers. */
int
general_movsrc_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
/* Any MEM(label_ref) is ok, that's a pcrel load */
if
(
GET_CODE
(
op
)
==
MEM
&&
GET_CODE
(
XEXP
(
op
,
0
))
==
LABEL_REF
)
return
1
;
return
1
;
/* otherwise it will be several insns. */
/* No predec allowed */
return
4
;
if
(
GET_CODE
(
op
)
==
MEM
&&
GET_CODE
(
XEXP
(
op
,
0
))
==
PRE_DEC
)
return
0
;
if
((
mode
==
QImode
||
mode
==
HImode
)
&&
(
GET_CODE
(
op
)
==
SUBREG
&&
GET_CODE
(
XEXP
(
op
,
0
))
==
REG
&&
system_reg_operand
(
XEXP
(
op
,
0
),
mode
)))
return
0
;
if
(
GET_CODE
(
op
)
==
CONST_INT
)
{
int
i
=
INTVAL
(
op
);
return
CONST_OK_FOR_I
(
i
);
}
return
general_operand
(
op
,
mode
);
}
}
/* Return the cost of a multiply */
/* Returns 1 if OP can be a destination of a move.
Same as general_operand, but no preinc allowed. */
int
int
multcosts
(
RTX
)
general_movdst_operand
(
op
,
mode
)
rtx
RTX
;
rtx
op
;
enum
machine_mode
mode
;
{
{
/* If we we're aiming at small code, then just count the number of
if
(
GET_CODE
(
op
)
==
MEM
insns in a multiply call sequence, otherwise, count all the insnsn
&&
GET_CODE
(
XEXP
(
op
,
0
))
==
PRE_INC
)
inside the call. */
return
0
;
if
(
TARGET_SMALLCODE
)
return
general_operand
(
op
,
mode
);
return
3
;
}
return
30
;
/* Returns 1 if OP is an immediate ok for a byte index. */
int
byte_index_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
return
(
GET_CODE
(
op
)
==
CONST_INT
&&
INTVAL
(
op
)
>=
0
&&
INTVAL
(
op
)
<=
15
);
}
/* Returns 1 if OP is a pop operand. */
int
pop_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
GET_CODE
(
op
)
!=
MEM
)
return
0
;
if
(
GET_MODE
(
op
)
!=
mode
)
return
0
;
op
=
XEXP
(
op
,
0
);
if
(
GET_CODE
(
op
)
!=
POST_INC
)
return
0
;
return
XEXP
(
op
,
0
)
==
stack_pointer_rtx
;
}
/* Returns 1 if OP is a normal arithmetic register. */
int
arith_reg_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
register_operand
(
op
,
mode
))
{
if
(
GET_CODE
(
op
)
==
REG
)
return
(
REGNO
(
op
)
!=
T_REG
&&
REGNO
(
op
)
!=
PR_REG
);
return
1
;
}
return
0
;
}
/* Returns 1 if OP is MACL, MACH or PR. */
int
system_reg_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
GET_CODE
(
op
)
==
REG
)
{
switch
(
REGNO
(
op
))
{
case
PR_REG
:
case
MACL_REG
:
case
MACH_REG
:
return
1
;
}
}
return
0
;
}
/* Returns 1 if OP is a valid source operand for an arithmetic insn. */
int
arith_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
arith_reg_operand
(
op
,
mode
))
return
1
;
if
(
GET_CODE
(
op
)
==
CONST_INT
)
{
if
(
CONST_OK_FOR_I
(
INTVAL
(
op
)))
return
1
;
}
return
0
;
}
/* Returns 1 if OP is a valid source operand for a logical operation. */
int
logical_operand
(
op
,
mode
)
rtx
op
;
enum
machine_mode
mode
;
{
if
(
arith_reg_operand
(
op
,
mode
))
return
1
;
if
(
GET_CODE
(
op
)
==
CONST_INT
)
{
if
(
CONST_OK_FOR_L
(
INTVAL
(
op
)))
return
1
;
}
return
0
;
}
}
gcc/config/sh/sh.h
View file @
0d7e008e
/* Definitions of target machine for GNU compiler, for Hitachi Super-H.
/* Definitions of target machine for GNU compiler, for Hitachi Super-H.
Copyright (C) 1993 Free Software Foundation, Inc.
Copyright (C) 1993
, 1994
Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com)
Contributed by Steve Chamberlain (sac@cygnus.com)
...
@@ -36,24 +36,48 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
...
@@ -36,24 +36,48 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Show we can debug even without a frame pointer. */
/* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP
#define CAN_DEBUG_WITHOUT_FP
#define CONDITIONAL_REGISTER_USAGE \
/* Experimental calling convention with fewer saved registers */
\
if (TARGET_NOSAVE) \
{ \
call_used_regs[8] = 1; \
call_used_regs[9] = 1; \
call_used_regs[10] = 1; \
call_used_regs[11] = 1; \
} \
/* Hitachi saves and restores mac registers on call */
\
if (TARGET_HITACHI) \
{ \
call_used_regs[MACH_REG] = 0; \
call_used_regs[MACL_REG] = 0; \
}
/* Run-time compilation parameters selecting different hardware subsets. */
/* Run-time compilation parameters selecting different hardware subsets. */
extern
int
target_flags
;
extern
int
target_flags
;
#define ISIZE_BIT 1
#define ISIZE_BIT (1<<1)
#define FAST_BIT 2
#define FAST_BIT (1<<2)
#define MAC_BIT (1<<3)
#define MAC_BIT 8
#define RTL_BIT (1<<4)
#define RTL_BIT 16
#define DT_BIT (1<<5)
#define DT_BIT 32
#define DALIGN_BIT (1<<6)
#define DALIGN_BIT 64
#define SH0_BIT (1<<7)
#define SH0_BIT 128
#define SH1_BIT (1<<8)
#define SH1_BIT 256
#define SH2_BIT (1<<9)
#define SH2_BIT 512
#define SH3_BIT (1<<10)
#define SH3_BIT 1024
#define C_BIT (1<<11)
#define C_BIT 2048
#define R_BIT (1<<12)
#define R_BIT (1<<12)
#define SPACE_BIT (1<<13)
#define SPACE_BIT (1<<13)
#define BIGTABLE_BIT (1<<14)
#define TRYR0_BIT (1<<15)
#define NOSAVE_BIT (1<<16)
#define SMALLCALL_BIT (1<<17)
#define CONSTLEN_2_BIT (1<<20)
#define CONSTLEN_3_BIT (1<<21)
#define HITACHI_BIT (1<<22)
/* Nonzero if we should generate code using type 0 insns */
/* Nonzero if we should generate code using type 0 insns */
#define TARGET_SH0 (target_flags & SH0_BIT)
#define TARGET_SH0 (target_flags & SH0_BIT)
...
@@ -88,28 +112,81 @@ extern int target_flags;
...
@@ -88,28 +112,81 @@ extern int target_flags;
/* Nonzero to align doubles on 64 bit boundaries */
/* Nonzero to align doubles on 64 bit boundaries */
#define TARGET_ALIGN_DOUBLE (target_flags & DALIGN_BIT)
#define TARGET_ALIGN_DOUBLE (target_flags & DALIGN_BIT)
/* Nonzero to use long jump tables */
#define TARGET_BIGTABLE (target_flags & BIGTABLE_BIT)
/* Nonzero if
C
ombine dumping wanted */
/* Nonzero if
c
ombine dumping wanted */
#define TARGET_CDUMP (target_flags & C_BIT)
#define TARGET_CDUMP (target_flags & C_BIT)
#define TARGET_SWITCHES \
/* Nonzero if trying to use reg+disp for QIs and HIs. This
{ {"isize", ( ISIZE_BIT) },\
doesn't work yet.*/
{"space", ( SPACE_BIT) },\
#define TARGET_TRYR0 (target_flags & TRYR0_BIT)
{"0", ( SH0_BIT) },\
{"1", ( SH1_BIT) },\
/* Nonzero if using no save calling convention */
{"2", ( SH2_BIT) },\
#define TARGET_NOSAVE (target_flags & NOSAVE_BIT)
{"3", ( SH3_BIT) },\
{"ac", ( MAC_BIT) },\
/* Nonzero if using no save calling convention */
{"dalign", ( DALIGN_BIT) },\
#define TARGET_SMALLCALL (target_flags & SMALLCALL_BIT)
{"c", ( C_BIT) },\
{"r", ( RTL_BIT) },\
/* Select max size of computed constant code sequences to be 3 insns */
{"R", ( R_BIT) },\
#define TARGET_CLEN3 (target_flags & CONSTLEN_3_BIT)
{"", TARGET_DEFAULT} \
/* Nonzero if using Hitachi's calling convention */
#define TARGET_HITACHI (target_flags & HITACHI_BIT)
#define TARGET_SWITCHES \
{ {"isize", ( ISIZE_BIT) }, \
{"space", ( SPACE_BIT) }, \
{"0", ( SH0_BIT) }, \
{"1", ( SH1_BIT) }, \
{"2", ( SH2_BIT) }, \
{"3", ( SH3_BIT) }, \
{"ac", ( MAC_BIT) }, \
{"dalign", ( DALIGN_BIT) }, \
{"c", ( C_BIT) }, \
{"r", ( RTL_BIT) }, \
{"bigtable", ( BIGTABLE_BIT)}, \
{"try-r0", ( TRYR0_BIT)}, \
{"R", ( R_BIT) }, \
{"nosave", ( NOSAVE_BIT) }, \
{"clen3", ( CONSTLEN_3_BIT) }, \
{"smallcall", ( SMALLCALL_BIT) }, \
{"hitachi", ( HITACHI_BIT) }, \
{"", TARGET_DEFAULT} \
}
}
#define TARGET_DEFAULT FAST_BIT
#define TARGET_DEFAULT (FAST_BIT)
#define OVERRIDE_OPTIONS override_options();
/* Macro to define table for command options with values. */
#define TARGET_OPTIONS \
{ { "maxsi-", &max_si}, \
{ "maxhi-", &max_hi} }
#define OVERRIDE_OPTIONS \
do { \
sh_cpu = CPU_SH0; \
if (TARGET_SH1) \
sh_cpu = CPU_SH1; \
if (TARGET_SH2) \
sh_cpu = CPU_SH2; \
if (TARGET_SH3) \
sh_cpu = CPU_SH3; \
\
/* We *MUST* always define optimize since we *HAVE* to run \
shorten branches to get correct code. */
\
\
optimize = 1; \
flag_delayed_branch = 1; \
\
if (max_si) \
max_count_si = atoi (max_si); \
else \
max_count_si = 1010; \
if (max_hi) \
max_count_hi = atoi (max_hi); \
else \
max_count_hi = 505; \
} while (0)
/* Target machine storage Layout. */
/* Target machine storage Layout. */
...
@@ -171,7 +248,7 @@ extern int target_flags;
...
@@ -171,7 +248,7 @@ extern int target_flags;
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
((TREE_CODE (EXP) == STRING_CST \
((TREE_CODE (EXP) == STRING_CST \
&& (ALIGN) < FASTEST_ALIGNMENT) \
&& (ALIGN) < FASTEST_ALIGNMENT) \
? FASTEST_ALIGNMENT : (ALIGN))
? FASTEST_ALIGNMENT : (ALIGN))
/* Make arrays of chars word-aligned for the same reasons. */
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
#define DATA_ALIGNMENT(TYPE, ALIGN) \
...
@@ -186,13 +263,13 @@ extern int target_flags;
...
@@ -186,13 +263,13 @@ extern int target_flags;
/* Standard register usage. */
/* Standard register usage. */
/* Register allocation for
our first guess
/* Register allocation for
the Hitachi calling convention:
r0-r3 scratch
r0 arg return
r
4-r7 args in and out
r
1..r3 scratch
r
8-r12 call saved
r
4-r7 args in
r
13 assembler temp
r
8..r13 call saved
r14 frame pointer
r14 frame pointer
/call saved
r15 stack pointer
r15 stack pointer
ap arg pointer (doesn't really exist, always eliminated)
ap arg pointer (doesn't really exist, always eliminated)
pr subroutine return address
pr subroutine return address
...
@@ -207,23 +284,33 @@ extern int target_flags;
...
@@ -207,23 +284,33 @@ extern int target_flags;
All registers that the compiler knows about must be given numbers,
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers.
even those that are not normally considered general registers.
SH has 16 integer registers and 4 control registers + the arg
*/
pointer */
#define FIRST_PSEUDO_REGISTER 22
#define AP_REG 16
#define PR_REG 17
#define PR_REG 17
#define T_REG 18
#define T_REG 18
#define GBR_REG 19
#define GBR_REG 19
#define MACH_REG 20
#define MACH_REG 20
#define MACL_REG 21
#define MACL_REG 21
#define FIRST_PSEUDO_REGISTER 22
/* 1 for registers that have pervasive standard uses
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator. */
and are not available for the register allocator. */
/* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 ap pr t gbr mh ml */
/* r0 r1 r2 r3
#define FIXED_REGISTERS \
r4 r5 r6 r7
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1}
r8 r9 r10 r11
r12 r13 r14 r15
ap pr t gbr
mh ml */
#define FIXED_REGISTERS \
{ 0, 0, 0, 0, \
0, 0, 0, 0, \
0, 0, 0, 0, \
0, 0, 0, 1, \
1, 1, 1, 1, \
1, 1}
/* 1 for registers not available across function calls.
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
These must include the FIXED_REGISTERS and also any
...
@@ -232,9 +319,20 @@ extern int target_flags;
...
@@ -232,9 +319,20 @@ extern int target_flags;
and the register where structure-value addresses are passed.
and the register where structure-value addresses are passed.
Aside from that, you can include as many other registers as you like. */
Aside from that, you can include as many other registers as you like. */
/* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 ap pr t gbr mh ml */
/* r0 r1 r2 r3
#define CALL_USED_REGISTERS \
r4 r5 r6 r7
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1}
r8 r9 r10 r11
r12 r13 r14 r15
ap pr t gbr
mh ml */
#define CALL_USED_REGISTERS \
{ 1, 1, 1, 1, \
1, 1, 1, 1, \
0, 0, 0, 0, \
0, 0, 0, 1, \
1, 0, 1, 1, \
1, 1}
/* Return number of consecutive hard regs needed starting at reg REGNO
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
to hold something of mode MODE.
...
@@ -242,14 +340,16 @@ extern int target_flags;
...
@@ -242,14 +340,16 @@ extern int target_flags;
but can be less for certain modes in special long registers.
but can be less for certain modes in special long registers.
On the SH regs are UNITS_PER_WORD bits wide; */
On the SH regs are UNITS_PER_WORD bits wide; */
#define HARD_REGNO_NREGS(REGNO, MODE) \
#define HARD_REGNO_NREGS(REGNO, MODE) \
(((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
(((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
We may keep double values in even registers */
We may keep double values in even registers */
extern
int
hard_regno_mode_ok
[];
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(
(TARGET_ALIGN_DOUBLE && GET_MODE_SIZE(MODE) > 4) ? (((REGNO)&1)==0) : 1
)
(
hard_regno_mode_ok[REGNO] & (1<<(int)MODE)
)
/* Value is 1 if it is a good idea to tie two pseudo registers
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
when one has mode MODE1 and one has mode MODE2.
...
@@ -275,8 +375,7 @@ extern int target_flags;
...
@@ -275,8 +375,7 @@ extern int target_flags;
Zero means the frame pointer need not be set up (and parms may be accessed
Zero means the frame pointer need not be set up (and parms may be accessed
via the stack pointer) in functions that seem suitable. */
via the stack pointer) in functions that seem suitable. */
#define FRAME_POINTER_REQUIRED 0
#define FRAME_POINTER_REQUIRED (get_frame_size() > 1000)
/* Definitions for register eliminations.
/* Definitions for register eliminations.
...
@@ -290,11 +389,17 @@ extern int target_flags;
...
@@ -290,11 +389,17 @@ extern int target_flags;
followed by "to". Eliminations of the same "from" register are listed
followed by "to". Eliminations of the same "from" register are listed
in order of preference. */
in order of preference. */
/* This is an array of structures. Each structure initializes one pair
of eliminable registers. The "from" register number is given first,
followed by "to". Eliminations of the same "from" register are listed
in order of preference. */
#define ELIMINABLE_REGS \
#define ELIMINABLE_REGS \
{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},}
{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},}
/* Given FROM and TO register numbers, say whether this elimination
/* Given FROM and TO register numbers, say whether this elimination
is allowed. */
is allowed. */
#define CAN_ELIMINATE(FROM, TO) \
#define CAN_ELIMINATE(FROM, TO) \
...
@@ -314,9 +419,21 @@ extern int target_flags;
...
@@ -314,9 +419,21 @@ extern int target_flags;
/* The register in which a struct value address is passed */
/* The register in which a struct value address is passed */
#define STRUCT_VALUE_REGNUM 3
#define STRUCT_VALUE_REGNUM 2
/* If the structure value address is not passed in a register, define
`STRUCT_VALUE' as an expression returning an RTX for the place
where the address is passed. If it returns 0, the address is
passed as an "invisible" first argument. */
/*#define STRUCT_VALUE ((rtx)0)*/
/* Don't default to pcc-struct-return, because we have already specified
exactly how to return structures in the RETURN_IN_MEMORY macro. */
#define DEFAULT_PCC_STRUCT_RETURN 0
/* Define the classes of registers for register constraints in the
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
machine description. Also define ranges of constants.
...
@@ -347,10 +464,10 @@ enum reg_class
...
@@ -347,10 +464,10 @@ enum reg_class
{
{
NO_REGS
,
NO_REGS
,
R0_REGS
,
R0_REGS
,
GENERAL_REGS
,
PR_REGS
,
PR_REGS
,
T_REGS
,
T_REGS
,
MAC_REGS
,
MAC_REGS
,
GENERAL_REGS
,
ALL_REGS
,
ALL_REGS
,
LIM_REG_CLASSES
LIM_REG_CLASSES
};
};
...
@@ -362,10 +479,10 @@ enum reg_class
...
@@ -362,10 +479,10 @@ enum reg_class
{ \
{ \
"NO_REGS", \
"NO_REGS", \
"R0_REGS", \
"R0_REGS", \
"GENERAL_REGS", \
"PR_REGS", \
"PR_REGS", \
"T_REGS", \
"T_REGS", \
"MAC_REGS", \
"MAC_REGS", \
"GENERAL_REGS", \
"ALL_REGS", \
"ALL_REGS", \
}
}
...
@@ -377,10 +494,10 @@ enum reg_class
...
@@ -377,10 +494,10 @@ enum reg_class
{ \
{ \
0x000000,
/* NO_REGS */
\
0x000000,
/* NO_REGS */
\
0x000001,
/* R0_REGS */
\
0x000001,
/* R0_REGS */
\
0x01FFFF,
/* GENERAL_REGS */
\
0x020000,
/* PR_REGS */
\
0x020000,
/* PR_REGS */
\
0x040000,
/* T_REGS */
\
0x040000,
/* T_REGS */
\
0x300000,
/* MAC_REGS */
\
0x300000,
/* MAC_REGS */
\
0x01FFFF,
/* GENERAL_REGS */
\
0x37FFFF
/* ALL_REGS */
\
0x37FFFF
/* ALL_REGS */
\
}
}
...
@@ -392,9 +509,15 @@ enum reg_class
...
@@ -392,9 +509,15 @@ enum reg_class
extern
int
regno_reg_class
[];
extern
int
regno_reg_class
[];
#define REGNO_REG_CLASS(REGNO) regno_reg_class[REGNO]
#define REGNO_REG_CLASS(REGNO) regno_reg_class[REGNO]
/* When defined, the compiler allows registers explicitly used in the
rtl to be used as spill registers but prevents the compiler from
extending the lifetime of these registers. */
#define SMALL_REGISTER_CLASSES
/* The order in which register should be allocated. */
/* The order in which register should be allocated. */
#define REG_ALLOC_ORDER \
#define REG_ALLOC_ORDER \
{ 1,2,3,7,
4,5,6,0,8,9,10,11,12,13,14,15,16,17,18,19,20,21
}
{ 1,2,3,7,
6,5,4,0,8,9,10,11,12,13,14,15,16,17,18,19,20,21
}
/* The class value for index registers, and the one for base regs. */
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS R0_REGS
#define INDEX_REG_CLASS R0_REGS
...
@@ -415,20 +538,22 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -415,20 +538,22 @@ extern enum reg_class reg_class_from_letter[];
Return 1 if VALUE is in the range specified by C.
Return 1 if VALUE is in the range specified by C.
I: arithmetic operand -127..128, as used in add, sub, etc
I: arithmetic operand -127..128, as used in add, sub, etc
L: logical operand 0..255, as used in and, or, etc.
L: logical operand 0..255, as used in and, or, etc.
J: something ok as a move source - so it must be easy to make
M: constant 1
M: constant 1
N: constant 0
K: shift operand 1,2,8 or 16 */
K: shift operand 1,2,8 or 16 */
#define CONST_OK_FOR_I(VALUE) (((int)(VALUE))>= -128 && ((int)(VALUE)) <= 127)
#define CONST_OK_FOR_I(VALUE) (((int)(VALUE))>= -128 && ((int)(VALUE)) <= 127)
#define CONST_OK_FOR_L(VALUE) (((int)(VALUE))>= 0 && ((int)(VALUE)) <= 255)
#define CONST_OK_FOR_L(VALUE) (((int)(VALUE))>= 0 && ((int)(VALUE)) <= 255)
#define CONST_OK_FOR_M(VALUE) ((VALUE)==1)
#define CONST_OK_FOR_M(VALUE) ((VALUE)==1)
#define CONST_OK_FOR_N(VALUE) ((VALUE)==0)
#define CONST_OK_FOR_K(VALUE) ((VALUE)==1||(VALUE)==2||(VALUE)==8||(VALUE)==16)
#define CONST_OK_FOR_K(VALUE) ((VALUE)==1||(VALUE)==2||(VALUE)==8||(VALUE)==16)
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? CONST_OK_FOR_I (VALUE) \
((C) == 'I' ? CONST_OK_FOR_I (VALUE) \
: (C) == 'K' ? CONST_OK_FOR_K (VALUE) \
: (C) == 'L' ? CONST_OK_FOR_L (VALUE) \
: (C) == 'L' ? CONST_OK_FOR_L (VALUE) \
: (C) == 'M' ? CONST_OK_FOR_M (VALUE) \
: (C) == 'M' ? CONST_OK_FOR_M (VALUE) \
: (C) == 'K' ? CONST_OK_FOR_K (VALUE) \
: 0)
: 0)
/* Similar, but for floating constants, and defining letters G and H.
/* Similar, but for floating constants, and defining letters G and H.
...
@@ -444,13 +569,12 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -444,13 +569,12 @@ extern enum reg_class reg_class_from_letter[];
In general this is just CLASS; but on some machines
In general this is just CLASS; but on some machines
in some cases it is preferable to use a more restrictive class. */
in some cases it is preferable to use a more restrictive class. */
#define PREFERRED_RELOAD_CLASS(X, CLASS)
CLASS
#define PREFERRED_RELOAD_CLASS(X, CLASS) CLASS
/* Return the register class of a scratch register needed to copy IN into
/* Return the register class of a scratch register needed to copy IN into
or out of a register in CLASS in MODE. If it can be done directly,
or out of a register in CLASS in MODE. If it can be done directly,
NO_REGS is returned. */
NO_REGS is returned. */
#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) NO_REGS
/* Return the maximum number of consecutive registers
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS.
needed to represent mode MODE in a register of class CLASS.
...
@@ -459,6 +583,7 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -459,6 +583,7 @@ extern enum reg_class reg_class_from_letter[];
#define CLASS_MAX_NREGS(CLASS, MODE) \
#define CLASS_MAX_NREGS(CLASS, MODE) \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* Stack layout; function entry, exit and calling. */
/* Stack layout; function entry, exit and calling. */
...
@@ -466,22 +591,21 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -466,22 +591,21 @@ extern enum reg_class reg_class_from_letter[];
These two macros are used only in other macro definitions below. */
These two macros are used only in other macro definitions below. */
#define NPARM_REGS 4
#define NPARM_REGS 4
#define FIRST_PARM_REG 4
#define FIRST_PARM_REG 4
#define FIRST_RET_REG
4
#define FIRST_RET_REG
0
/* Define this if pushing a word on the stack
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
#define STACK_GROWS_DOWNWARD
/* Define this if the nominal address of the stack frame
/* Define this macro if the addresses of local variable slots are at
is at the high-address end of the local variables;
negative offsets from the frame pointer.
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD
/* Offset within stack frame to start allocating local variables at.
The SH only has positive indexes, so grow the frame up
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
*/
first local allocated. Otherwise, it is the offset to the BEGINNING
/* #define FRAME_GROWS_DOWNWARD */
of the first local allocated. */
/* Offset from the frame pointer to the first local variable slot to
be allocated. */
#define STARTING_FRAME_OFFSET 0
#define STARTING_FRAME_OFFSET 0
/* If we generate an insn to push BYTES bytes,
/* If we generate an insn to push BYTES bytes,
...
@@ -505,8 +629,11 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -505,8 +629,11 @@ extern enum reg_class reg_class_from_letter[];
VALTYPE is the data type of the value (as a tree).
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
otherwise, FUNC is 0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx (REG, TYPE_MODE (VALTYPE), FIRST_RET_REG)
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx (REG, \
TYPE_MODE (VALTYPE) == BLKmode ? SImode : TYPE_MODE (VALTYPE), \
FIRST_RET_REG)
/* Define how to find the value returned by a library function
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
assuming the value has mode MODE. */
...
@@ -514,7 +641,7 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -514,7 +641,7 @@ extern enum reg_class reg_class_from_letter[];
gen_rtx (REG, MODE, FIRST_RET_REG)
gen_rtx (REG, MODE, FIRST_RET_REG)
/* 1 if N is a possible register number for a function value.
/* 1 if N is a possible register number for a function value.
On the SH, only r
4
can return results. */
On the SH, only r
0
can return results. */
#define FUNCTION_VALUE_REGNO_P(REGNO) \
#define FUNCTION_VALUE_REGNO_P(REGNO) \
((REGNO) == FIRST_RET_REG)
((REGNO) == FIRST_RET_REG)
...
@@ -593,6 +720,7 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -593,6 +720,7 @@ extern enum reg_class reg_class_from_letter[];
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
(NAMED && ROUND_REG ((CUM), (MODE)) < NPARM_REGS \
(NAMED && ROUND_REG ((CUM), (MODE)) < NPARM_REGS \
&& (MODE) != BLKmode \
&& ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \
&& ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \
&& ((TYPE)==0 || (MODE) != BLKmode \
&& ((TYPE)==0 || (MODE) != BLKmode \
|| (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0)) \
|| (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0)) \
...
@@ -603,20 +731,10 @@ extern enum reg_class reg_class_from_letter[];
...
@@ -603,20 +731,10 @@ extern enum reg_class reg_class_from_letter[];
/* For an arg passed partly in registers and partly in memory,
/* For an arg passed partly in registers and partly in memory,
this is the number of registers used.
this is the number of registers used.
For args passed entirely in registers or entirely in memory, zero.
For args passed entirely in registers or entirely in memory, zero.
Any arg that starts in the first NPARM_REGS regs but won't entirely
fit in them needs partial registers on the SH. */
We never split args */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
((ROUND_REG ((CUM), (MODE)) < NPARM_REGS \
&& ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \
&& ((TYPE)==0 || (MODE) != BLKmode \
|| (TYPE_ALIGN ((TYPE)) % PARM_BOUNDARY == 0)) \
&& (ROUND_REG ((CUM), (MODE)) \
+ ((MODE) == BLKmode \
? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
: ROUND_ADVANCE (GET_MODE_SIZE (MODE)))) - NPARM_REGS > 0) \
? (NPARM_REGS - ROUND_REG ((CUM), (MODE))) \
: 0)
extern
int
current_function_anonymous_args
;
extern
int
current_function_anonymous_args
;
...
@@ -647,8 +765,8 @@ extern int current_function_anonymous_args;
...
@@ -647,8 +765,8 @@ extern int current_function_anonymous_args;
/* Generate the assembly code for function exit
/* Generate the assembly code for function exit
Just dump out any accumulated constant table.*/
Just dump out any accumulated constant table.*/
#define FUNCTION_EPILOGUE(STREAM, SIZE)
\
#define FUNCTION_EPILOGUE(STREAM, SIZE)
function_epilogue (STREAM, SIZE)
dump_constants(0);
/* Output assembler code for a block containing the constant parts
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts.
of a trampoline, leaving space for the variable parts.
...
@@ -691,7 +809,6 @@ extern int current_function_anonymous_args;
...
@@ -691,7 +809,6 @@ extern int current_function_anonymous_args;
/* Addressing modes, and classification of registers for them. */
/* Addressing modes, and classification of registers for them. */
/*#define HAVE_POST_INCREMENT 1*/
/*#define HAVE_POST_INCREMENT 1*/
/*#define HAVE_PRE_INCREMENT 1*/
/*#define HAVE_PRE_INCREMENT 1*/
/*#define HAVE_POST_DECREMENT 1*/
/*#define HAVE_POST_DECREMENT 1*/
...
@@ -706,27 +823,27 @@ extern int current_function_anonymous_args;
...
@@ -706,27 +823,27 @@ extern int current_function_anonymous_args;
has been allocated, which happens in local-alloc.c.
has been allocated, which happens in local-alloc.c.
*/
*/
#define REGNO_OK_FOR_BASE_P(REGNO) \
#define REGNO_OK_FOR_BASE_P(REGNO) \
((REGNO) < PR_REG || (unsigned) reg_renumber[(REGNO)] < PR_REG)
((REGNO) < PR_REG || (unsigned) reg_renumber[(REGNO)] < PR_REG)
#define REGNO_OK_FOR_INDEX_P(REGNO) \
#define REGNO_OK_FOR_INDEX_P(REGNO) ((REGNO)==
0)
((REGNO) == 0 || (unsigned) reg_renumber[(REGNO)] ==
0)
/* Maximum number of registers that can appear in a valid memory
/* Maximum number of registers that can appear in a valid memory
address. */
address. */
#define MAX_REGS_PER_ADDRESS
4
#define MAX_REGS_PER_ADDRESS
2
/* Recognize any constant value that is a valid address. */
/* Recognize any constant value that is a valid address. */
#define CONSTANT_ADDRESS_P(X) \
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF)
(GET_CODE (X) == LABEL_REF)
/* Nonzero if the constant value X is a legitimate general operand.
/* Nonzero if the constant value X is a legitimate general operand. */
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.
On the SH, allow anything but a double */
#define LEGITIMATE_CONSTANT_P(X) \
(GET_CODE(X) != CONST_DOUBLE && GET_CODE(X) != LABEL_REF)
#define LEGITIMATE_CONSTANT_P(X) (GET_CODE(X) != CONST_DOUBLE)
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
and check its validity for a certain class.
...
@@ -735,23 +852,27 @@ extern int current_function_anonymous_args;
...
@@ -735,23 +852,27 @@ extern int current_function_anonymous_args;
them unless they have been allocated suitable hard regs.
them unless they have been allocated suitable hard regs.
The symbol REG_OK_STRICT causes the latter definition to be used. */
The symbol REG_OK_STRICT causes the latter definition to be used. */
#define MODE_DISP_OK_4(X,MODE) ((GET_MODE_SIZE(MODE)==4) && ((unsigned)INTVAL(X)<64))
#define MODE_DISP_OK_2(X,MODE) ((GET_MODE_SIZE(MODE)==2) && ((unsigned)INTVAL(X)<32) && TARGET_TRYR0)
#define MODE_DISP_OK_1(X,MODE) ((GET_MODE_SIZE(MODE)==1) && ((unsigned)INTVAL(X)<16) && TARGET_TRYR0)
#ifndef REG_OK_STRICT
#ifndef REG_OK_STRICT
/* Nonzero if X is a hard reg that can be used as a base reg
/* Nonzero if X is a hard reg that can be used as a base reg
or if it is a pseudo reg. */
or if it is a pseudo reg. */
#define REG_OK_FOR_BASE_P(X) \
#define REG_OK_FOR_BASE_P(X) \
(REGNO (X) <= 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
(REGNO (X) <= 16 || REGNO(X) >= FIRST_PSEUDO_REGISTER)
/* Nonzero if X is a hard reg that can be used as an index
/* Nonzero if X is a hard reg that can be used as an index
or if it is a pseudo reg. */
or if it is a pseudo reg. */
#define REG_OK_FOR_INDEX_P(X) \
#define REG_OK_FOR_INDEX_P(X) \
(REGNO (X) == 0 || REGNO
(X) >= FIRST_PSEUDO_REGISTER)
(REGNO (X) == 0 || REGNO
(X) >= FIRST_PSEUDO_REGISTER)
#define REG_OK_FOR_PRE_POST_P(X) \
#define REG_OK_FOR_PRE_POST_P(X) \
(REGNO (X) <= 16)
(REGNO (X) <= 16)
#else
#else
/* Nonzero if X is a hard reg that can be used as a base reg. */
/* Nonzero if X is a hard reg that can be used as a base reg. */
#define REG_OK_FOR_BASE_P(X) \
#define REG_OK_FOR_BASE_P(X) \
REGNO_OK_FOR_BASE_P (REGNO (X))
REGNO_OK_FOR_BASE_P (REGNO (X))
...
@@ -761,8 +882,29 @@ extern int current_function_anonymous_args;
...
@@ -761,8 +882,29 @@ extern int current_function_anonymous_args;
REGNO_OK_FOR_INDEX_P (REGNO (X))
REGNO_OK_FOR_INDEX_P (REGNO (X))
#define REG_OK_FOR_PRE_POST_P(X) \
#define REG_OK_FOR_PRE_POST_P(X) \
(REGNO (X) <= 16
|| (unsigned) reg_renumber[REGNO (X)] <=16
)
(REGNO (X) <= 16)
#endif
#endif
/* The Q is a pc relative load operand */
#define EXTRA_CONSTRAINT_Q(OP) \
(GET_CODE (OP) == MEM && GET_CODE (XEXP (OP,0)) == LABEL_REF)
/* The U is a label ref */
#define EXTRA_CONSTRAINT_U(OP) \
(GET_CODE (OP) == LABEL_REF)
#define IS_INDEX(OP) \
((GET_CODE(OP) == PLUS && \
(INDEX_REGISTER_RTX_P(XEXP(OP,0)) && BASE_REGISTER_RTX_P(XEXP(OP,1))) || \
(INDEX_REGISTER_RTX_P(XEXP(OP,1)) && BASE_REGISTER_RTX_P(XEXP(OP,0)))))
#define EXTRA_CONSTRAINT(OP, C) \
((C) == 'Q' ? EXTRA_CONSTRAINT_Q (OP) \
: (C) == 'U' ? EXTRA_CONSTRAINT_U (OP) \
: 0)
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
that is a valid memory address for an instruction.
...
@@ -796,18 +938,14 @@ extern int current_function_anonymous_args;
...
@@ -796,18 +938,14 @@ extern int current_function_anonymous_args;
A legitimate index for a QI or HI is 0, SI and above can be any
A legitimate index for a QI or HI is 0, SI and above can be any
number 0..63 */
number 0..63 */
#define GO_IF_LEGITIMATE_INDEX(MODE, REGNO, OP, LABEL) \
#define GO_IF_LEGITIMATE_INDEX(MODE, REGNO, OP, LABEL) \
do { \
do { \
if (GET_CODE (OP) == CONST_INT) \
if (GET_CODE (OP) == CONST_INT) \
{ \
{ \
if (0&&GET_MODE_SIZE (MODE) == 2 && ((unsigned)INTVAL(OP)) <=30)\
if (MODE_DISP_OK_4 (OP, MODE)) goto LABEL; \
goto LABEL; \
if (MODE_DISP_OK_2 (OP, MODE)) goto LABEL; \
if (0&&GET_MODE_SIZE (MODE) == 1 && ((unsigned)INTVAL(OP)) <=15)\
if (MODE_DISP_OK_1 (OP, MODE)) goto LABEL; \
goto LABEL; \
} \
if (GET_MODE_SIZE (MODE) >=4 \
&& ((unsigned)INTVAL(OP)) < 64) \
goto LABEL; \
} \
} while(0)
} while(0)
...
@@ -819,13 +957,13 @@ extern int current_function_anonymous_args;
...
@@ -819,13 +957,13 @@ extern int current_function_anonymous_args;
&& GET_CODE (XEXP (X, 0)) == REG \
&& GET_CODE (XEXP (X, 0)) == REG \
&& REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \
&& REG_OK_FOR_PRE_POST_P (XEXP (X, 0))) \
goto LABEL; \
goto LABEL; \
else if (GET_CODE (X) == PLUS
|| GET_CODE(X) == LO_SUM)
\
else if (GET_CODE (X) == PLUS
)
\
{ \
{ \
rtx xop0 = XEXP(X,0); \
rtx xop0 = XEXP(X,0); \
rtx xop1 = XEXP(X,1); \
rtx xop1 = XEXP(X,1); \
if (GET_MODE_SIZE(MODE)
>
= 4 && BASE_REGISTER_RTX_P (xop0)) \
if (GET_MODE_SIZE(MODE)
<
= 4 && BASE_REGISTER_RTX_P (xop0)) \
GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \
GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop0), xop1, LABEL); \
if (GET_MODE_SIZE(MODE)
>
= 4 && BASE_REGISTER_RTX_P (xop1)) \
if (GET_MODE_SIZE(MODE)
<
= 4 && BASE_REGISTER_RTX_P (xop1)) \
GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \
GO_IF_LEGITIMATE_INDEX (MODE, REGNO (xop1), xop0, LABEL); \
if (GET_MODE_SIZE(MODE)<=4) { \
if (GET_MODE_SIZE(MODE)<=4) { \
if(BASE_REGISTER_RTX_P(xop1) && \
if(BASE_REGISTER_RTX_P(xop1) && \
...
@@ -869,12 +1007,12 @@ extern int current_function_anonymous_args;
...
@@ -869,12 +1007,12 @@ extern int current_function_anonymous_args;
/* Specify the machine mode that this machine uses
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE
SImode
#define CASE_VECTOR_MODE
(TARGET_BIGTABLE ? SImode : HImode)
/* Define this if the tablejump instruction expects the table
/* Define this if the tablejump instruction expects the table
to contain offsets from the address of the table.
to contain offsets from the address of the table.
Do not define this if the table should contain absolute addresses. */
Do not define this if the table should contain absolute addresses. */
/* #define CASE_VECTOR_PC_RELATIVE */
#define CASE_VECTOR_PC_RELATIVE
/* Specify the tree operation to be used to convert reals to integers. */
/* Specify the tree operation to be used to convert reals to integers. */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
...
@@ -889,7 +1027,7 @@ extern int current_function_anonymous_args;
...
@@ -889,7 +1027,7 @@ extern int current_function_anonymous_args;
#define SIZE_TYPE "unsigned int"
#define SIZE_TYPE "unsigned int"
/* Don't cse the address of the function being compiled. */
/* Don't cse the address of the function being compiled. */
#define NO_RECURSIVE_FUNCTION_CSE 1
/*#define NO_RECURSIVE_FUNCTION_CSE 1*/
/* Max number of bytes we can move from memory to memory
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
in one reasonably fast instruction. */
...
@@ -940,15 +1078,12 @@ extern int current_function_anonymous_args;
...
@@ -940,15 +1078,12 @@ extern int current_function_anonymous_args;
#define Pmode SImode
#define Pmode SImode
#define FUNCTION_MODE Pmode
#define FUNCTION_MODE Pmode
/* The structure type of the machine dependent info field of insns
No uses for this yet. */
/* #define INSN_MACHINE_INFO struct machine_info */
/* The relative costs of various types of constants. Note that cse.c defines
/* The relative costs of various types of constants. Note that cse.c defines
REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */
REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */
#define CONST_COSTS(RTX, CODE, OUTER_CODE) \
#define CONST_COSTS(RTX, CODE, OUTER_CODE) \
case CONST_INT: \
case CONST_INT: \
if (INTVAL(RTX)==0) return 0; \
if (CONST_OK_FOR_I (INTVAL(RTX))) \
if (CONST_OK_FOR_I (INTVAL(RTX))) \
return 1; \
return 1; \
else \
else \
...
@@ -961,6 +1096,8 @@ extern int current_function_anonymous_args;
...
@@ -961,6 +1096,8 @@ extern int current_function_anonymous_args;
return 10;
return 10;
#define RTX_COSTS(X, CODE, OUTER_CODE) \
#define RTX_COSTS(X, CODE, OUTER_CODE) \
case AND: \
return COSTS_N_INSNS (andcosts (X)); \
case MULT: \
case MULT: \
return COSTS_N_INSNS (multcosts (X)); \
return COSTS_N_INSNS (multcosts (X)); \
case ASHIFT: \
case ASHIFT: \
...
@@ -976,6 +1113,34 @@ extern int current_function_anonymous_args;
...
@@ -976,6 +1113,34 @@ extern int current_function_anonymous_args;
case FIX: \
case FIX: \
return 100;
return 100;
/* The multiply and divide insns on the SH are actually function calls
with some special constraints on arguments and register usage.
These macros tell reorg that the references to arguments and
register clobbers for insns of type sfunc do not appear to happen
until after the millicode call. This allows reorg to put insns
which set the argument registers into the delay slot of the millicode
call -- thus they act more like traditional CALL_INSNs.
get_attr_type will try to recognize the given insn, so make sure to
filter out things it will not accept -- SEQUENCE, USE and CLOBBER insns
in particular. */
#define INSN_SETS_ARE_DELAYED(X) \
((GET_CODE (X) == INSN \
&& GET_CODE (PATTERN (X)) != SEQUENCE \
&& GET_CODE (PATTERN (X)) != USE \
&& GET_CODE (PATTERN (X)) != CLOBBER \
&& get_attr_type (X) == TYPE_SFUNC))
#define INSN_REFERENCES_ARE_DELAYED(X) \
((GET_CODE (X) == INSN \
&& GET_CODE (PATTERN (X)) != SEQUENCE \
&& GET_CODE (PATTERN (X)) != USE \
&& GET_CODE (PATTERN (X)) != CLOBBER \
&& get_attr_type (X) == TYPE_SFUNC))
/* Compute extra cost of moving data between one register class
/* Compute extra cost of moving data between one register class
and another.
and another.
...
@@ -984,7 +1149,7 @@ extern int current_function_anonymous_args;
...
@@ -984,7 +1149,7 @@ extern int current_function_anonymous_args;
*/
*/
#define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS) \
#define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS) \
((
DSTCLASS == T_REGS
) ? 10 : 1)
((
(DSTCLASS == T_REGS) || (DSTCLASS == PR_REG)
) ? 10 : 1)
/* Assembler output control */
/* Assembler output control */
...
@@ -994,23 +1159,23 @@ extern int current_function_anonymous_args;
...
@@ -994,23 +1159,23 @@ extern int current_function_anonymous_args;
W_options, sizeof W_options / sizeof W_options[0]);
W_options, sizeof W_options / sizeof W_options[0]);
#define ASM_FILE_END(STREAM) \
#define ASM_FILE_END(STREAM)
dump_constants(0);
#define ASM_APP_ON ""
#define ASM_APP_OFF ""
#define FILE_ASM_OP "\t.file\n"
#define ASM_APP_ON ""
#define IDENT_ASM_OP "\t.ident\n"
#define ASM_APP_OFF ""
#define FILE_ASM_OP "\t.file\n"
#define IDENT_ASM_OP "\t.ident\n"
/* How to change between sections. */
/* Switch to the text or data segment. */
#define TEXT_SECTION_ASM_OP "\t.text"
#define TEXT_SECTION_ASM_OP "\t.text"
#define DATA_SECTION_ASM_OP "\t.data"
#define DATA_SECTION_ASM_OP "\t.data"
#define CTORS_SECTION_ASM_OP "\t.section\t.ctors\n"
#define CTORS_SECTION_ASM_OP "\t.section\t.ctors\n"
#define DTORS_SECTION_ASM_OP "\t.section\t.dtors\n"
#define DTORS_SECTION_ASM_OP "\t.section\t.dtors\n"
#define INIT_SECTION_ASM_OP "\t.section\t.init\n"
#define EXTRA_SECTIONS in_ctors, in_dtors
#define EXTRA_SECTIONS in_ctors, in_dtors
#define EXTRA_SECTION_FUNCTIONS \
#define EXTRA_SECTION_FUNCTIONS \
void \
void \
ctors_section() \
ctors_section() \
...
@@ -1040,8 +1205,8 @@ dtors_section() \
...
@@ -1040,8 +1205,8 @@ dtors_section() \
#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
do { dtors_section(); fprintf(FILE,"\t.long\t_%s\n", NAME); } while (0)
do { dtors_section(); fprintf(FILE,"\t.long\t_%s\n", NAME); } while (0)
#undef DO_GLOBAL_CTORS_BODY
#undef DO_GLOBAL_CTORS_BODY
#define DO_GLOBAL_CTORS_BODY \
#define DO_GLOBAL_CTORS_BODY \
{ \
{ \
typedef (*pfunc)(); \
typedef (*pfunc)(); \
...
@@ -1068,14 +1233,12 @@ dtors_section() \
...
@@ -1068,14 +1233,12 @@ dtors_section() \
}
}
#define ASM_OUTPUT_REG_PUSH(file, v) \
#define ASM_OUTPUT_REG_PUSH(file, v) \
fprintf (file, "\tmov.l r%s,-@r15\n", v);
fprintf (file, "\tmov.l r%s,-@r15\n", v);
#define ASM_OUTPUT_REG_POP(file, v) \
#define ASM_OUTPUT_REG_POP(file, v) \
fprintf (file, "\tmov.l @r15+,r%s\n", v);
fprintf (file, "\tmov.l @r15+,r%s\n", v);
/* The assembler's names for the registers. RFP need not always be used as
/* The assembler's names for the registers. RFP need not always be used as
the Real framepointer; it can also be used as a normal general register.
the Real framepointer; it can also be used as a normal general register.
...
@@ -1133,18 +1296,25 @@ dtors_section() \
...
@@ -1133,18 +1296,25 @@ dtors_section() \
((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \
((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \
sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER)))
sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER)))
/* Jump tables must be 32 bit aligned
.
*/
/* Jump tables must be 32 bit aligned
, no matter the size of the element
*/
#define ASM_OUTPUT_CASE_LABEL(STREAM,PREFIX,NUM,TABLE) \
#define ASM_OUTPUT_CASE_LABEL(STREAM,PREFIX,NUM,TABLE) \
fprintf (STREAM, "\t.align 2\n%s%d:\n", PREFIX, NUM);
fprintf (STREAM, "\t.align 2\n%s%d:\n", PREFIX, NUM);
/* Output a relative address table. */
/* Output a relative address. Not needed since jump tables are absolute
#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,VALUE,REL) \
but we must define it anyway. */
if (TARGET_BIGTABLE) \
#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,VALUE,REL) \
fprintf (STREAM, "\t.long L%d-L%d\n", VALUE,REL); \
fputs ("- - - ASM_OUTPUT_ADDR_DIFF_ELT called!\n", STREAM)
else \
fprintf (STREAM, "\t.word L%d-L%d\n", VALUE,REL); \
/* Output an element of a dispatch table. */
/* Output an absolute table element */
#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \
fprintf (STREAM, "\t.long\tL%d\n", VALUE)
#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \
if (TARGET_BIGTABLE) \
fprintf (STREAM, "\t.long L%d\n", VALUE); \
else \
fprintf (STREAM, "\t.word L%d\n", VALUE); \
/* Output various types of constants. */
/* Output various types of constants. */
...
@@ -1165,7 +1335,6 @@ do { char dstr[30]; \
...
@@ -1165,7 +1335,6 @@ do { char dstr[30]; \
fprintf (FILE, "\t.float %s\n", dstr); \
fprintf (FILE, "\t.float %s\n", dstr); \
} while (0)
} while (0)
#define ASM_OUTPUT_INT(STREAM, EXP) \
#define ASM_OUTPUT_INT(STREAM, EXP) \
(fprintf (STREAM, "\t.long\t"), \
(fprintf (STREAM, "\t.long\t"), \
output_addr_const (STREAM, (EXP)), \
output_addr_const (STREAM, (EXP)), \
...
@@ -1237,16 +1406,13 @@ do { char dstr[30]; \
...
@@ -1237,16 +1406,13 @@ do { char dstr[30]; \
#define PRINT_OPERAND_ADDRESS(STREAM,X) print_operand_address (STREAM, X)
#define PRINT_OPERAND_ADDRESS(STREAM,X) print_operand_address (STREAM, X)
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
((CHAR)=='.' || (CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR)
==
'!')
((CHAR)=='.' || (CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR)
==
'!')
/* Define the information needed to generate branch insns. This is stored
from the compare operation. Note that we can't use "rtx" here since it
hasn't been defined! */
extern
struct
rtx_def
*
sh_compare_op0
;
extern
struct
rtx_def
*
sh_compare_op0
;
extern
struct
rtx_def
*
sh_compare_op1
;
extern
struct
rtx_def
*
sh_compare_op1
;
extern
struct
rtx_def
*
prepare_scc_operands
();
extern
struct
rtx_def
*
prepare_scc_operands
();
extern
struct
rtx_def
*
table_lab
;
extern
enum
attr_cpu
sh_cpu
;
/* target cpu */
extern
enum
attr_cpu
sh_cpu
;
/* target cpu */
...
@@ -1256,12 +1422,24 @@ extern char *output_branch();
...
@@ -1256,12 +1422,24 @@ extern char *output_branch();
extern
char
*
output_shift
();
extern
char
*
output_shift
();
extern
char
*
output_movedouble
();
extern
char
*
output_movedouble
();
extern
char
*
output_movepcrel
();
extern
char
*
output_movepcrel
();
extern
char
*
output_jump_label_table
();
extern
char
*
output_far_jump
();
#define MACHINE_DEPENDENT_REORG(X) machine_dependent_reorg(X)
#define ADJUST_INSN_LENGTH(insn, length) \
/* Generate calls to memcpy, memcmp and memset. */
adjust_insn_length (insn, insn_lengths)
#define TARGET_MEM_FUNCTIONS
#define HANDLE_PRAGMA(finput) handle_pragma (finput)
/* Set when processing a function with pragma interrupt turned on. */
extern
int
pragma_interrupt
;
#define MOVE_RATIO 16
char
*
max_si
;
char
*
max_hi
;
int
max_count_si
;
int
max_count_hi
;
gcc/config/sh/sh.md
View file @
0d7e008e
...
@@ -18,10 +18,37 @@
...
@@ -18,10 +18,37 @@
;; along with GNU CC; see the file COPYING. If not, write to
;; along with GNU CC; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;- See file "rtl.def" for documentation on define_insn, match_
*
, et. al.
;; Special constraints for SH machine description:
;;
;; t -- T
;; x -- mac
;; l -- pr
;; z -- r0
;;
;; Special formats used for outputting SH instructions:
;;
;; %. -- print a .s if insn needs delay slot
;; %
*
-- print a local label
;; %^ -- increment the local label number
;; %# -- output a nop if there is nothing to put in the delay slot
;; %R -- print the next register or memory location along, ie the lsw in
;; a double word value
;; %O -- print a constant without the #
;; %M -- print a constant as its negative
;;
;;
;; Special predicates:
;;
;; arith_operand -- operand is valid source for arithmetic op
;; arith_reg_operand -- operand is valid register for arithmetic op
;; byte_index_operand -- operand is ok as an index in a mov.b
;; general_movdst_operand -- operand is valid move destination
;; general_movsrc_operand -- operand is valid move source
;; logical_operand -- operand is valid source for logical op
;; pop_operand -- operand is a pop from the stack
;; system_reg_operand -- operand is MACL, MACH, or PR
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; Attributes
;; Attributes
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
...
@@ -30,66 +57,98 @@
...
@@ -30,66 +57,98 @@
(define_attr "cpu" "sh0,sh1,sh2,sh3"
(define_attr "cpu" "sh0,sh1,sh2,sh3"
(const (symbol_ref "sh_cpu")))
(const (symbol_ref "sh_cpu")))
;;
(define_attr "type" "cbranch,ctable,jump,arith,other,load,store,move,smpy,dmpy,return,pload"
;; cbranch conditional branch instructions
;; jump unconditional jumps
;; arith ordinary arithmetic
;; load from memory
;; store to memory
;; move register to register
;; smpy single precision integer multiply
;; dmpy double precision integer multiply
;; return rts
;; pload load of pr reg (can't be put into delay slot of rts)
;; pcloadsi pc relative load of SI value
;; pcloadhi pc relative load of HI value
;; rte return from exception
;; sfunc special function call with known used registers
(define_attr "type"
"cbranch,jump,arith,other,load,store,move,smpy,dmpy,return,pload,pcloadsi,pcloadhi,rte,sfunc"
(const_string "other"))
(const_string "other"))
; If a conditional branch destination is within -1
00..10
0 bytes away
; If a conditional branch destination is within -1
20..12
0 bytes away
; from the instruction it can be 2 bytes long. Something in the
; from the instruction it can be 2 bytes long. Something in the
; range -40
00..400
0 bytes can be 6 bytes long, all other conditional
; range -40
90..409
0 bytes can be 6 bytes long, all other conditional
; branches are 8 bytes long.
; branches are 8 bytes long.
; An unconditional jump which can reach forward or back 4k can be
; An unconditional jump which can reach forward or back 4k can be
; 6 bytes long (including the delay slot). If it is too big, it
; 6 bytes long (including the delay slot). If it is too big, it
; must be
8
bytes long.
; must be
10
bytes long.
; If a pcrel instruction is within 500 bytes of the constant, then the insn is
; 2 bytes long, otherwise 12 bytes
; All other instructions are two bytes long by default.
; All other instructions are two bytes long by default.
(define_attr "length" ""
(define_attr "length" ""
(cond
[
(eq_attr "type" "cbranch")
(cond
[
(eq_attr "type" "cbranch")
(if_then_else (and (ge (minus (pc) (match_dup 0))
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -100
))
(const_int -122
))
(le (minus (pc) (match_dup 0))
(le (minus (pc) (match_dup 0))
(const_int 100
)))
(const_int 122
)))
(const_int 2)
(const_int 2)
(if_then_else (and (ge (minus (pc) (match_dup 0))
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -400
0))
(const_int -409
0))
(le (minus (pc) (match_dup 0))
(le (minus (pc) (match_dup 0))
(const_int 400
0)))
(const_int 409
0)))
(const_int 6)
(const_int 6)
(const_int 8
)))
(const_int 16
)))
(eq_attr "type" "jump")
(eq_attr "type" "jump")
(if_then_else (and (ge (minus (pc) (match_dup 0))
(if_then_else (and (ge (minus (pc) (match_dup 0))
(const_int -4000))
(const_int -4090))
(le (minus (pc) (match_dup 0))
(le (minus (pc) (match_dup 0))
(const_int 4000)))
(const_int 4090)))
(const_int 4)
(const_int 4)
(const_int 6))
(const_int 10))
(eq_attr "type" "pcloadsi")
(if_then_else (gt (pc) (minus (match_dup 0) (const_int 1000)))
(const_int 2)
(const_int 12))
(eq_attr "type" "pcloadhi")
(if_then_else (gt (pc) (minus (match_dup 0) (const_int 500)))
(const_int 2)
(const_int 12))
] (const_int 2)))
] (const_int 2)))
;; (define_function_unit {name} {num-units} {n-users} {test}
;; (define_function_unit {name} {num-units} {n-users} {test}
;; {ready-delay} {issue-delay}
[
{conflict-list}
]
)
;; {ready-delay} {issue-delay}
[
{conflict-list}
]
)
(define_function_unit "memory" 1
1 (eq_attr "type" "load") 1
0)
(define_function_unit "memory" 1
0 (eq_attr "type" "load,pcloadsi,pcloadhi") 2
0)
(define_function_unit "mpy" 1
1
(eq_attr "type" "smpy") 3 0)
(define_function_unit "mpy" 1
0
(eq_attr "type" "smpy") 3 0)
(define_function_unit "mpy" 1
1
(eq_attr "type" "dmpy") 5 0)
(define_function_unit "mpy" 1
0
(eq_attr "type" "dmpy") 5 0)
(define_attr "needs_delay_slot" "yes,no"
(define_attr "needs_delay_slot" "yes,no"
(cond
[
(eq_attr "type" "jump") (const_string "yes")
(cond
[
(eq_attr "type" "jump")
(const_string "yes")
(eq_attr "type" "return") (const_string "yes")]
(eq_attr "type" "return") (const_string "yes")]
(const_string "no")))
(const_string "no")))
(define_delay
(define_delay
(eq_attr "needs_delay_slot" "yes")
(eq_attr "needs_delay_slot" "yes")
[
(eq_attr "in_delay_slot" "yes") (nil) (nil)
]
)
[
(eq_attr "in_delay_slot" "yes") (nil) (nil)
]
)
(define_delay
(eq_attr "type" "rte")
[
(and (eq_attr "in_delay_slot" "yes")
(eq_attr "hit_stack" "no")) (nil) (nil)])
(define_attr "hit_stack" "yes,no" (const_string "no"))
(define_attr "dump" "yes,no,must" (const_string "no"))
(define_delay
(define_attr "constneed" "yes,no" (const_string "no"))
(and (eq_attr "type" "cbranch")
(define_attr "smallestsize" "" (const_int 2))
(eq_attr "cpu" "sh2"))
(define_attr "largestsize" "" (const_int 8))
[
(eq_attr "in_delay_slot" "yes") (nil) (nil)
]
)
(define_attr "constantsize" "" (const_int 4))
(define_attr "in_delay_slot" "maybe,yes,no"
(define_attr "in_delay_slot" "maybe,yes,no"
(cond
[
(eq_attr "type" "cbranch") (const_string "no")
(cond
[
(eq_attr "type" "cbranch") (const_string "no")
...
@@ -100,7 +159,6 @@
...
@@ -100,7 +159,6 @@
(eq_attr "length" "4,6,8,10,12") (const_string "no")
(eq_attr "length" "4,6,8,10,12") (const_string "no")
] (const_string "yes")))
] (const_string "yes")))
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; SImode signed integer comparisons
;; SImode signed integer comparisons
...
@@ -112,49 +170,50 @@
...
@@ -112,49 +170,50 @@
(const_int 1)))]
(const_int 1)))]
""
""
"movt %0 !movt1")
"movt %0 !movt1")
(define_insn ""
(define_insn ""
[
(set (reg:SI 18) (gt (match_operand:SI 0 "arith_reg_operand" "r")
[
(set (reg:SI 18) (gt
:SI
(match_operand:SI 0 "arith_reg_operand" "r")
(const_int 0)))]
(const_int 0)))]
""
""
"cmp/pl %0")
"cmp/pl %0")
(define_insn ""
(define_insn ""
[
(set (reg:SI 18) (ge (match_operand:SI 0 "arith_reg_operand" "r")
[
(set (reg:SI 18) (ge
:SI
(match_operand:SI 0 "arith_reg_operand" "r")
(const_int 0)))]
(const_int 0)))]
""
""
"cmp/pz %0")
"cmp/pz %0")
(define_insn "cmpeq
si_t
"
(define_insn "cmpeq
_0
"
[
(set (reg:SI 18) (eq
(match_operand:SI 0 "arith_reg_operand" "r,z
")
[
(set (reg:SI 18) (eq
:SI (match_operand:SI 0 "arith_reg_operand" "r
")
(match_operand:SI 1 "arith_operand" "r,I"
)))]
(const_int 0
)))]
""
""
"
cmp/eq %1,%
0")
"
tst %0,%0 ! t
0")
(define_insn "cmpeqsi_t"
[
(set (reg:SI 18) (eq:SI (match_operand:SI 0 "arith_operand" "r,N,r,z")
(match_operand:SI 1 "arith_operand" "N,r,r,I")))]
""
"@
tst %0,%0 !t1
tst %1,%1 !t2
cmp/eq %1,%0
cmp/eq %1,%0")
(define_insn "cmpgtsi_t"
(define_insn "cmpgtsi_t"
[
(set (reg:SI 18) (gt
(match_operand:SI 0 "arith_reg_operand" "
r")
[
(set (reg:SI 18) (gt
:SI (match_operand:SI 0 "arith_reg_operand" "r,
r")
(match_operand:SI 1 "arith_reg_operand" "
r")))]
(match_operand:SI 1 "arith_operand" "N,
r")))]
""
""
"cmp/gt %1,%0")
"@
cmp/pl %0
cmp/gt %1,%0")
(define_insn "cmpgesi_t"
(define_insn "cmpgesi_t"
[
(set (reg:SI 18) (ge
(match_operand:SI 0 "arith_reg_operand" "
r")
[
(set (reg:SI 18) (ge
:SI (match_operand:SI 0 "arith_reg_operand" "r,
r")
(match_operand:SI 1 "arith_reg_operand" "
r")))]
(match_operand:SI 1 "arith_operand" "N,
r")))]
""
""
"cmp/ge %1,%0")
"@
cmp/pz %0
(define_insn "cmpltsi_t"
cmp/ge %1,%0")
[
(set (reg:SI 18) (lt (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
""
"cmp/gt %0,%1")
(define_insn "cmplesi_t"
[
(set (reg:SI 18) (le (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
""
"cmp/ge %0,%1")
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
...
@@ -162,38 +221,31 @@
...
@@ -162,38 +221,31 @@
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
(define_insn "cmpgeusi_t"
(define_insn "cmpgeusi_t"
[
(set (reg:SI 18) (geu
(match_operand:SI 0 "arith_reg_operand" "
r")
[
(set (reg:SI 18) (geu
:SI (match_operand:SI 0 "arith_reg_operand" "r,
r")
(match_operand:SI 1 "arith_reg_operand" "
r")))]
(match_operand:SI 1 "arith_operand" "N,
r")))]
""
""
"cmp/hs %1,%0")
"@
cmp/pz %1
cmp/hs %1,%0")
(define_insn "cmpgtusi_t"
(define_insn "cmpgtusi_t"
[
(set (reg:SI 18) (gtu (match_operand:SI 0 "arith_reg_operand" "r")
[
(set (reg:SI 18) (gtu:SI (match_operand:SI 0 "arith_operand" "r,r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
(match_operand:SI 1 "arith_operand" "N,r")))]
""
"cmp/hi %1,%0")
(define_insn "cmpleusi_t"
[
(set (reg:SI 18) (leu (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
""
"cmp/hs %0,%1")
(define_insn "cmpltusi_t"
[
(set (reg:SI 18) (ltu (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
""
""
"cmp/hi %0,%1")
"@
cmp/pl %1
cmp/hi %1,%0")
;; We save the compare operands in the cmpxx patterns and use them when
;; We save the compare operands in the cmpxx patterns and use them when
;; we generate the branch.
;; we generate the branch.
(define_expand "cmpsi"
(define_expand "cmpsi"
[
(set (reg:SI 18) (compare (match_operand:SI 0 "arith_
reg_
operand" "")
[
(set (reg:SI 18) (compare (match_operand:SI 0 "arith_operand" "")
(match_operand:SI 1 "arith_
reg_
operand" "")))]
(match_operand:SI 1 "arith_operand" "")))]
""
""
"
"
{ sh_compare_op0 = operands
[
0
]
;
{
sh_compare_op0 = operands
[
0
]
;
sh_compare_op1 = operands
[
1
]
;
sh_compare_op1 = operands
[
1
]
;
DONE;
DONE;
}")
}")
...
@@ -203,19 +255,36 @@
...
@@ -203,19 +255,36 @@
;; Addition instructions
;; Addition instructions
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
(define_insn "adddi3"
(define_insn "addc"
[
(set (match_operand:DI 0 "arith_reg_operand" "=&r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(plus:DI (match_operand:DI 1 "arith_reg_operand" "%0")
(plus:SI (reg:SI 18)
(match_operand:DI 2 "arith_reg_operand" "r")))
(plus:SI (match_operand:SI 1 "arith_reg_operand" "%0")
(match_operand:SI 2 "arith_reg_operand" "r"))))
(clobber (reg:SI 18))]
(clobber (reg:SI 18))]
""
""
"clrt
\;
addc %R2,%R0
\;
addc %2,%0"
"addc %2,%0")
[
(set_attr "length" "6")
(set_attr "in_delay_slot" "no")
(set_attr "type" "arith")])
;; this should be a define split.
(define_expand "adddi3"
[
(set (reg:SI 18) (const_int 0))
(parallel
[
(set (subreg:SI (match_operand:DI 0 "arith_reg_operand" "=r") 1)
(plus:SI (reg:SI 18)
(plus:SI (subreg:SI (match_operand:DI 1 "arith_reg_operand" "r") 1)
(subreg:SI (match_operand:DI 2 "arith_reg_operand" "r") 1))))
(clobber (reg:SI 18))])
(parallel
[
(set (subreg:SI (match_dup 0) 0)
(plus:SI (reg:SI 18)
(plus:SI (subreg:SI (match_dup 1) 0)
(subreg:SI (match_dup 2) 0))))
(clobber (reg:SI 18))])]
""
"")
(define_insn "addsi3_
i
"
(define_insn "addsi3_
real
"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(plus:SI (match_operand:SI 1 "arith_reg_operand" "%0")
(plus:SI (match_operand:SI 1 "arith_reg_operand" "%0")
(match_operand:SI 2 "arith_operand" "rI")))]
(match_operand:SI 2 "arith_operand" "rI")))]
...
@@ -226,7 +295,7 @@
...
@@ -226,7 +295,7 @@
(define_expand "addsi3"
(define_expand "addsi3"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(plus:SI (match_operand:SI 1 "arith_
reg_
operand" "%0")
(plus:SI (match_operand:SI 1 "arith_operand" "%0")
(match_operand:SI 2 "arith_operand" "rI")))]
(match_operand:SI 2 "arith_operand" "rI")))]
""
""
"")
"")
...
@@ -237,7 +306,7 @@
...
@@ -237,7 +306,7 @@
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
(define_insn "subdi3"
(define_insn "subdi3"
[
(set (match_operand:DI 0 "arith_reg_operand" "=
&
r")
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
(minus:DI (match_operand:DI 1 "arith_reg_operand" "0")
(minus:DI (match_operand:DI 1 "arith_reg_operand" "0")
(match_operand:DI 2 "arith_reg_operand" "r")))
(match_operand:DI 2 "arith_reg_operand" "r")))
(clobber (reg:SI 18))]
(clobber (reg:SI 18))]
...
@@ -248,27 +317,95 @@
...
@@ -248,27 +317,95 @@
(set_attr "type" "arith")])
(set_attr "type" "arith")])
(define_insn "subsi3"
(define_insn "subsi3"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r
,r
")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(minus:SI (match_operand:SI 1 "arith_reg_operand" "0
,0
")
(minus:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "arith_operand" "r
,I
")))]
(match_operand:SI 2 "arith_operand" "r")))]
""
""
"@
"sub %2,%0"
sub %2,%0
add %M2,%0"
[
(set_attr "type" "arith")
]
)
[
(set_attr "type" "arith")
]
)
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;;
Multiplicat
ion instructions
;;
Divis
ion instructions
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; we take advantage of the library routines which don't clobber as many
;; registers as a normal function call would.
(define_insn ""
[
(set (reg:SI 0)
(udiv:SI (reg:SI 4) (reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 6))
(clobber (reg:SI 4))
(use (match_operand:SI 0 "register_operand" "r"))]
""
"jsr @%0%#"
[
(set_attr "type" "sfunc")
(set_attr "length" "4")
(set_attr "needs_delay_slot" "yes")])
(define_expand "udivsi3"
[
(set (reg:SI 4) (match_operand:SI 1 "general_operand" "g"))
(set (reg:SI 5) (match_operand:SI 2 "general_operand" "g"))
(set (match_dup 3) (symbol_ref:SI "__udivsi3"))
(parallel
[
(set (reg:SI 0)
(udiv:SI (reg:SI 4)
(reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 6))
(clobber (reg:SI 4))
(use (match_dup 3))])
(set (match_operand:SI 0 "general_operand" "=g")
(reg:SI 0))]
""
"operands
[
3
]
= gen_reg_rtx(SImode);")
(define_insn ""
[
(set (reg:SI 0)
(div:SI (reg:SI 4) (reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 3))
(use (match_operand:SI 0 "register_operand" "r"))]
""
"jsr @%0%#"
[
(set_attr "type" "sfunc")
(set_attr "length" "4")
(set_attr "needs_delay_slot" "yes")])
(define_expand "divsi3"
[
(set (reg:SI 4) (match_operand:SI 1 "general_operand" "g"))
(set (reg:SI 5) (match_operand:SI 2 "general_operand" "g"))
(set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
(parallel
[
(set (reg:SI 0)
(div:SI (reg:SI 4)
(reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 3))
(use (match_dup 3))])
(set (match_operand:SI 0 "general_operand" "=g")
(reg:SI 0))]
""
"operands
[
3
]
= gen_reg_rtx(SImode);")
;; -------------------------------------------------------------------------
;; Multiplication instructions
;; -------------------------------------------------------------------------
(define_insn ""
(define_insn ""
[
(set (reg:SI 21)
[
(set (reg:SI 21)
(mult:SI (zero_extend:SI
(mult:SI (zero_extend:SI (match_operand:HI 1 "arith_reg_operand" "r"))
(match_operand:HI 1 "arith_reg_operand" "r"))
(zero_extend:SI (match_operand:HI 2 "arith_reg_operand" "r"))))]
(zero_extend:SI
(match_operand:HI 2 "arith_reg_operand" "r"))))]
""
""
"mulu %2,%1"
"mulu %2,%1"
[
(set_attr "type" "smpy")
]
)
[
(set_attr "type" "smpy")
]
)
...
@@ -305,12 +442,124 @@
...
@@ -305,12 +442,124 @@
""
""
"")
"")
;; mulsi3 on the SH2 can be done in one instruction, on the SH1 we generate
;; a call to a routine which clobbers known registers.
(define_insn ""
[
(set (reg:SI 0)
(mult:SI (reg:SI 4) (reg:SI 5)))
(clobber (reg:SI 21))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 3))
(clobber (reg:SI 2))
(clobber (reg:SI 1))
(use (match_operand:SI 0 "register_operand" "r"))]
""
"jsr @%0%#"
[
(set_attr "type" "sfunc")
(set_attr "length" "4")
(set_attr "needs_delay_slot" "yes")])
(define_expand "mulsi3_call"
[
(set (reg:SI 4) (match_operand:SI 1 "general_operand" "g"))
(set (reg:SI 5) (match_operand:SI 2 "general_operand" "g"))
(set (match_dup 3) (symbol_ref:SI "__mulsi3"))
(parallel
[
(set (reg:SI 0)
(mult:SI (reg:SI 4)
(reg:SI 5)))
(clobber (reg:SI 21))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 3))
(clobber (reg:SI 2))
(clobber (reg:SI 1))
(use (match_dup 3))])
(set (match_operand:SI 0 "general_operand" "=g")
(reg:SI 0))]
""
"operands
[
3
]
= gen_reg_rtx(SImode);")
(define_insn "mul_l"
[
(set (reg:SI 21)
(mult:SI (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH2"
"mul.l %1,%0"
[
(set_attr "type" "smpy")
]
)
(define_expand "mulsi3"
[
(set (reg:SI 21)
(mult:SI (match_operand:SI 1 "arith_reg_operand" "r")
(match_operand:SI 2 "arith_reg_operand" "r")))
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(reg:SI 21))]
""
"
{
if (!TARGET_SH2)
{
emit_insn (gen_mulsi3_call (operands
[
0
]
, operands
[
1
]
, operands
[
2
]
));
DONE;
}
}")
(define_insn ""
[
(set (reg:DI 20)
(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH2"
"dmuls.l %2,%1"
[
(set_attr "type" "dmpy")
]
)
(define_expand "mulsidi3"
[
(set (reg:DI 20)
(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))
(set (match_operand:DI 0 "arith_reg_operand" "=r")
(reg:DI 20))]
"TARGET_SH2"
"")
(define_insn ""
[
(set (reg:DI 20)
(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH2"
"dmulu.l %2,%1"
[
(set_attr "type" "dmpy")
]
)
(define_expand "umulsidi3"
[
(set (reg:DI 20)
(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))
(set (match_operand:DI 0 "arith_reg_operand" "=r")
(reg:DI 20))]
"TARGET_SH2"
"")
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; Logical operations
;; Logical operations
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
(define_insn "andsi3"
(define_insn "and_ffff"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(and:SI (match_operand:SI 1 "arith_reg_operand" "r")
(const_int 65535)))]
""
"extu.w %1,%0"
[
(set_attr "type" "arith")
]
)
(define_insn "and_ff"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(and:SI (match_operand:SI 1 "arith_reg_operand" "r")
(const_int 255)))]
""
"extu.b %1,%0"
[
(set_attr "type" "arith")
]
)
(define_insn ""
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,z")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,z")
(and:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(and:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(match_operand:SI 2 "logical_operand" "r,L")))]
(match_operand:SI 2 "logical_operand" "r,L")))]
...
@@ -318,6 +567,13 @@
...
@@ -318,6 +567,13 @@
"and %2,%0"
"and %2,%0"
[
(set_attr "type" "arith")
]
)
[
(set_attr "type" "arith")
]
)
(define_expand "andsi3"
[
(set (match_operand:SI 0 "arith_reg_operand" "")
(and:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "logical_operand" "")))]
""
"")
(define_insn "iorsi3"
(define_insn "iorsi3"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,z")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,z")
(ior:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(ior:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
...
@@ -326,9 +582,9 @@
...
@@ -326,9 +582,9 @@
"or %2,%0")
"or %2,%0")
(define_insn "xorsi3"
(define_insn "xorsi3"
[
(set (match_operand:SI 0 "arith_reg_operand" "=
r,z
")
[
(set (match_operand:SI 0 "arith_reg_operand" "=
z,r
")
(xor:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(xor:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(match_operand:SI 2 "logical_operand" "
r,L
")))]
(match_operand:SI 2 "logical_operand" "
L,r
")))]
""
""
"xor %2,%0"
"xor %2,%0"
[
(set_attr "type" "arith")
]
)
[
(set_attr "type" "arith")
]
)
...
@@ -370,15 +626,34 @@
...
@@ -370,15 +626,34 @@
""
""
"{ if (GET_CODE(operands
[
2
]
) != CONST_INT || INTVAL(operands
[
2
]
) != 1) FAIL;}")
"{ if (GET_CODE(operands
[
2
]
) != CONST_INT || INTVAL(operands
[
2
]
) != 1) FAIL;}")
;;
;; shift left
(define_insn "ashlsi3_k"
(define_insn "ashlsi3_k"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
(match_operand:SI 2 "immediate_operand" "
K,n
")))
(match_operand:SI 2 "immediate_operand" "
M,K
")))
(clobber (reg:SI 18))]
(clobber (reg:SI 18))]
""
"CONST_OK_FOR_K (INTVAL (operands
[
2
]
))"
"@
shll %0
shll%O2 %0")
; seperate pattern for shifts by any N. Look at pnum_clobbers
; to see if this is being recognised inside combine. If so, dont
; match, since combine will try and merge shifts, which will break
; scheduling
(define_insn "ashlsi3_n"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "immediate_operand" "n")))
(clobber (reg:SI 18))]
"(! pnum_clobbers)"
"
*
return output_shift(
\"
shll
\"
, operands
[
0
]
, operands
[
2
]
, ASHIFT);"
"
*
return output_shift(
\"
shll
\"
, operands
[
0
]
, operands
[
2
]
, ASHIFT);"
[
(set_attr "length" "
2,
12")
[
(set_attr "length" "12")
(set_attr "in_delay_slot" "
yes,
no")
(set_attr "in_delay_slot" "no")
(set_attr "type" "arith")])
(set_attr "type" "arith")])
(define_expand "ashlsi3"
(define_expand "ashlsi3"
...
@@ -387,48 +662,104 @@
...
@@ -387,48 +662,104 @@
(match_operand:SI 2 "immediate_operand" "")))
(match_operand:SI 2 "immediate_operand" "")))
(clobber (reg:SI 18))])]
(clobber (reg:SI 18))])]
""
""
"if (!ok_shift_value(operands
[
2
]
, ASHIFT)) FAIL;")
"if (gen_shifty_op (ASHIFT, operands)) DONE; else FAIL;")
;
; arithmetic shift right
;
(define_insn "ashrsi3_k"
(define_insn "ashrsi3_k"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(
const_int 1
)))
(
match_operand:SI 2 "immediate_operand" "M"
)))
(clobber (reg:SI 18))]
(clobber (reg:SI 18))]
""
"
INTVAL(operands
[
2
]
) == 1
"
"shar %0"
"shar %0"
[
(set_attr "type" "arith")
]
)
[
(set_attr "type" "arith")
]
)
(define_insn "ashrsi3_16"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))
(clobber (reg:SI 18))]
"INTVAL(operands
[
2
]
) == 16"
"shlr16 %0
\;
exts.w %0,%0"
[
(set_attr "type" "arith")
(set_attr "length" "4")])
; an arithmetic shift right by 16 is better as a logical shift and a
; sign extend
;(define_split
;
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
; (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
; (const_int 16)))
; (clobber (reg:SI 18))]
; ""
;
[
(set (match_dup 3) (match_dup 0))
; (set (match_dup 3) (lshiftrt:SI (match_dup 3) (const_int 16)))
; (set (match_dup 0) (sign_extend:SI (subreg:HI (match_dup 3) 0)))]
; "operands
[
3
]
= gen_reg_rtx (SImode);")
(define_insn "ashrsi3_n"
[
(set (reg:SI 4)
(ashiftrt:SI (reg:SI 4)
(match_operand:SI 0 "immediate_operand" "i")))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
""
"jsr @%1%#"
[
(set_attr "type" "sfunc")
(set_attr "in_delay_slot" "no")
(set_attr "length" "4")
(set_attr "needs_delay_slot" "yes")])
(define_expand "ashrsi3"
(define_expand "ashrsi3"
[
(parallel
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(parallel
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "r")
(match_operand:SI 2 "nonmemory_operand" "M")))
(match_operand:SI 2 "nonmemory_operand" "M")))
(clobber (reg:SI 18))])]
(clobber (reg:SI 18))])]
""
""
"
"if (gen_shifty_op (ASHIFTRT, operands)) DONE; else FAIL;")
{
if (GET_CODE (operands
[
2
]
) != CONST_INT ||
; logical shift right
INTVAL (operands
[
2
]
) != 1) FAIL;
;
}
")
(define_insn "lshrsi3_k"
(define_insn "lshrsi3_k"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
(match_operand:SI 2 "immediate_operand" "
K,n
")))
(match_operand:SI 2 "immediate_operand" "
M,K
")))
(clobber (reg:SI 18))]
(clobber (reg:SI 18))]
""
"CONST_OK_FOR_K (INTVAL (operands
[
2
]
))"
"@
shlr %0
shlr%O2 %0")
; seperate pattern for shifts by any N. Look at pnum_clobbers
; to see if this is being recognised inside combine. If so, dont
; match, since combine will try and merge shifts, which will break
; scheduling - this could be handled with a large number of
; define_splits
(define_insn "lshrsi3_n"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "immediate_operand" "n")))
(clobber (reg:SI 18))]
"!pnum_clobbers"
"
*
return output_shift (
\"
shlr
\"
, operands
[
0
]
, operands
[
2
]
, LSHIFTRT);"
"
*
return output_shift (
\"
shlr
\"
, operands
[
0
]
, operands
[
2
]
, LSHIFTRT);"
[
(set_attr "length" "
2,
12")
[
(set_attr "length" "12")
(set_attr "in_delay_slot" "
yes,
no")
(set_attr "in_delay_slot" "no")
(set_attr "type" "arith")])
(set_attr "type" "arith")])
(define_expand "lshrsi3"
(define_expand "lshrsi3"
[
(parallel
[
(set (match_operand:SI 0 "arith_reg_operand" "")
[
(parallel
[
(set (match_operand:SI 0 "arith_reg_operand" "")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "
nonmemory
_operand" "")))
(match_operand:SI 2 "
immediate
_operand" "")))
(clobber (reg:SI 18))])]
(clobber (reg:SI 18))])]
""
""
"if (
!ok_shift_value (operands
[
2
]
)) FAIL; ")
"if (
gen_shifty_op (LSHIFTRT, operands)) DONE; else FAIL;")
(define_insn "ashldi3_k"
(define_insn "ashldi3_k"
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
...
@@ -485,7 +816,6 @@
...
@@ -485,7 +816,6 @@
"{ if (GET_CODE (operands
[
2
]
) != CONST_INT
"{ if (GET_CODE (operands
[
2
]
) != CONST_INT
|| INTVAL (operands
[
2
]
) != 1) FAIL; } ")
|| INTVAL (operands
[
2
]
) != 1) FAIL; } ")
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; Unary arithmetic
;; Unary arithmetic
...
@@ -512,7 +842,7 @@
...
@@ -512,7 +842,7 @@
(not:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
(not:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
""
""
"not %1,%0"
"not %1,%0"
[
(set_attr "type" "arith")
]
)
[
(set_attr "type" "arith")
]
)
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
...
@@ -546,170 +876,187 @@
...
@@ -546,170 +876,187 @@
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
(define_insn "extendsidi2"
(define_insn "extendsidi2"
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
[
(set (match_operand:DI 0 "arith_reg_operand" "=r,r")
(sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "0")))]
(sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "0,r")))
(clobber (reg:SI 18))]
""
""
"mov %1,%0
\;
shll %0
\;
subc %0,%0"
"@
[
(set_attr "length" "6")
]
)
mov %1,%0
\;
shll %0
\;
subc %0,%0 ! b sidi2
mov %1,%0
\;
mov %1,%R0
\;
shll %0
\;
subc %0,%0 ! a sidi2"
[
(set_attr "length" "6,8")
]
)
(define_insn "extendhisi2"
(define_insn "extendhisi2"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r
,z,r
")
(sign_extend:SI (match_operand:HI 1 "arith_
reg_operand" "r
")))]
(sign_extend:SI (match_operand:HI 1 "arith_
operand" "r,u,m
")))]
""
""
"exts.w %1,%0")
"@
exts.w %1,%0
mov.w %1,%0
mov.w %1,%0"
[
(set_attr "type" "arith,load,load")
]
)
(define_insn "extendqisi2"
(define_insn "extendqisi2"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r
,z,r
")
(sign_extend:SI (match_operand:QI 1 "
arith_reg_operand" "r
")))]
(sign_extend:SI (match_operand:QI 1 "
general_movsrc_operand" "r,U,m
")))]
""
""
"exts.b %1,%0")
"@
exts.b %1,%0
mov.b %1,%0 !p9
mov.b %1,%0 !p8"
[
(set_attr "type" "arith,load,load")
]
)
(define_insn "extendqihi2"
(define_insn "extendqihi2"
[
(set (match_operand:HI 0 "arith_reg_operand" "=r")
[
(set (match_operand:HI 0 "arith_reg_operand" "=r
,z,r
")
(sign_extend:HI (match_operand:QI 1 "
arith_reg_operand" "r
")))]
(sign_extend:HI (match_operand:QI 1 "
general_movsrc_operand" "r,U,m
")))]
""
""
"exts.b %1,%0")
"@
exts.b %1,%0
mov.b %1,%0 !p7
mov.b %1,%0 ! p6"
[
(set_attr "type" "arith,load,load")
]
)
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; Move instructions
;; Move instructions
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
(define_insn ""
;; define push and pop so it is easy for sh.c
[
(set (match_operand:SI 0 "push_operand" "=<,<")
(match_operand:SI 1 "arith_reg_operand" "r,l"))]
""
"@
mov.l %1,%0
sts.l pr,%0"
[
(set_attr "type" "store")
]
)
(define_insn ""
[
(set (match_operand:SI 0 "arith_reg_operand" "=r,l")
(match_operand:SI 1 "pop_operand" "=>,>"))]
""
"@
mov.l %1,%0
lds.l %1,pr"
[
(set_attr "type" "load,pload")
]
)
(define_insn "push"
(define_insn "push"
[
(set (mem:SI (pre_dec:SI (reg:SI 15)))
[
(set (mem:SI (pre_dec:SI (reg:SI 15)))
(match_operand:SI 0 "register_operand" "r,l"))]
(match_operand:SI 0 "register_operand" "r,l
x
"))]
""
""
"@
"@
mov.l %0,@-r15
mov.l %0,@-r15
sts.l pr,@-r15")
sts.l %0,@-r15 ! push"
[
(set_attr "type" "store")
(set_attr "hit_stack" "yes")])
(define_insn "pop"
(define_insn "pop"
[
(set (match_operand:SI 0 "register_operand" "=r,l")
[
(set (match_operand:SI 0 "register_operand" "=r,l
x
")
(mem:SI (post_inc:SI (reg:SI 15))))]
(mem:SI (post_inc:SI (reg:SI 15))))]
""
""
"@
"@
mov.l @r15+,%0
mov.l @r15+,%0
lds.l @r15+,pr"
lds.l @r15+,%0"
[
(set_attr "type" "load,pload")
]
)
[
(set_attr "type" "load,pload")
(set_attr "hit_stack" "yes")])
; some constants are easier to generate with alu operations
; rather than loading from memory
(define_
split
(define_
insn ""
[
(set (match_operand:SI 0 "
register_operand" "=r
")
[
(set (match_operand:SI 0 "
push_operand" "=<,<
")
(match_operand:SI 1 "
painful_immediate_operand" "i
"))]
(match_operand:SI 1 "
arith_reg_operand" "r,xl
"))]
""
""
[
(set (match_dup 0) (const_int 127))
"@
(set (match_dup 0) (plus:SI (match_dup 0)
mov.l %1,%0
(match_dup 2)))]
sts.l %1,%0"
"operands
[
2
]
= GEN_INT (INTVAL(operands
[
1
]
) - 127);"
)
[
(set_attr "type" "store")
]
)
(define_insn "
movsi_i
"
(define_insn ""
[
(set
(match_operand:SI 0 "general_operand" "=r,r,r,m,l,r,r,r,t,x
")
[
(set
(match_operand:SI 0 "arith_reg_operand" "=r,xl
")
(match_operand:SI 1 "
general_movsrc_operand" "r,I,m,r,r,l,t,x,r,r
"))]
(match_operand:SI 1 "
pop_operand" "=>,>
"))]
""
""
"@
"@
mov %1,%0
mov %1,%0
mov.l %1,%0
mov.l %1,%0
mov.l %1,%0
lds.l %1,%0"
lds %1,%0
[
(set_attr "type" "load")
]
)
sts %1,%0
movt %0
sts %1,%0
tst %1,%1
\;
bt T%
*\;bra F%*
\;
sett
\;
T%
*:clrt\;F%*
:%^
lds %1,%0"
[
(set_attr "length" "2,2,2,2,2,2,2,2,10,2")
(set_attr "type" "move,move,load,pload,move,move,move,move,move,move")])
(define_insn "movsi_pcrel"
(define_insn "clrt"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (reg:SI 18) (const_int 0))
]
(match_operand:SI 1 "hard_immediate_operand" "i"))]
""
""
"
*
return output_movepcrel (insn, operands, SImode);"
"clrt")
[
(set_attr "length" "2")
(set_attr "in_delay_slot" "no")
(set_attr "constneed" "yes")
(set_attr "smallestsize" "2")
(set_attr "largestsize" "8")
(set_attr "type" "load")])
(define_insn "movsi_i"
[
(set (match_operand:SI 0 "general_movdst_operand" "=r,r,r,r,r,<m,<,xl,xl,t,r")
(match_operand:SI 1 "general_movsrc_operand" "Q,rI,>m,xl,t,r,xl,r,>,r,i"))]
""
"
*
{
switch (which_alternative)
{
case 0:
switch (get_attr_length(insn))
{
case 2:
return
\"
mov.l %1,%0 ! 2 byte
\"
;
case 12:
return
\"
mov.l TA%
*,%0\;bra TB%*
\;
mov.l @%0,%0
\;
.align 2
\;
TA%
*: .long %1\;TB%*
:%^
\"
;
}
case 1: return
\"
mov %1,%0
\"
;
case 2: return
\"
mov.l %1,%0
\"
;
case 3: return
\"
sts %1,%0
\"
;
case 4: return
\"
movt %0
\"
;
case 5: return
\"
mov.l %1,%0
\"
;
case 6: return
\"
sts.l %1,%0
\"
;
case 7: return
\"
lds %1,%0
\"
;
case 8: return
\"
lds.l %1,%0
\"
;
case 9: return
\"
tst %1,%1
\;
bt T%
*\;bra F%*
\;
sett
\;
T%
*:clrt\;F%*
:%^
\"
;
case 10: return
\"
fake %1,%0
\"
;
}
}"
[
(set_attr "length" "
*
,2,2,2,2,2,2,2,2,6,2")
(set_attr "type" "pcloadsi,move,load,move,store,store,move,load,move,move,move")])
(define_expand "movsi"
(define_expand "movsi"
[
(set (match_operand:SI 0 "general_operand" "")
[
(set (match_operand:SI 0 "general_
movdst_
operand" "")
(match_operand:SI 1 "general_operand" ""))]
(match_operand:SI 1 "general_
movsrc_
operand" ""))]
""
""
"{ if(prepare_move_operands(operands, SImode)) DONE; } ")
"{ if
(prepare_move_operands(operands, SImode)) DONE; } ")
(define_insn "movqi_i"
(define_insn "movqi_i"
[
(set (match_operand:QI 0 "general_operand" "=r,r,r,m,r,m,r,r")
[
(set (match_operand:QI 0 "general_movdst_operand" "=r,r,>m,r,r,l")
(match_operand:QI 1 "general_operand" "r,n,m,r,m,r,x,t"))]
(match_operand:QI 1 "general_movsrc_operand" "ri,<m,r,t,l,r"))]
""
"arith_reg_operand (operands
[
0
]
, QImode)
|| arith_reg_operand (operands
[
1
]
, QImode)"
"@
"@
mov %1,%0
mov %1,%0
mov %1,%0
mov.b %1,%0
mov.b %1,%0
mov.b %1,%0
mov.b %1,%0
movt %0
mov.b %1,%0
mov.b %1,%0
sts %1,%0
sts %1,%0
movt %0")
lds %1,%0"
[
(set_attr "length" "2,2,2,2,2,2")
(set_attr "type" "move,load,store,move,move,move")])
(define_expand "movqi"
(define_expand "movqi"
[
(set (match_operand:QI 0 "general_operand" "")
[
(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
(match_operand:QI 1 "general_operand" ""))]
""
""
"prepare_move_operands(operands, QImode);")
"if (prepare_move_operands(operands, QImode)) DONE; ")
(define_insn "movhi_pcrel"
[
(set (match_operand:HI 0 "arith_reg_operand" "=r")
(match_operand:HI 1 "hard_immediate_operand" "i"))]
""
"
*
return output_movepcrel (insn, operands, SImode);"
[
(set_attr "length" "2")
(set_attr "in_delay_slot" "no")
(set_attr "constneed" "yes")
(set_attr "smallestsize" "2")
(set_attr "largestsize" "8")
(set_attr "type" "load")])
(define_insn "movhi_i"
(define_insn "movhi_i"
[
(set (match_operand:HI 0 "general_
operand" "=r,r,m,z,m,r,r
")
[
(set (match_operand:HI 0 "general_
movdst_operand" "=r,r,r,r,<m,r,r,l
")
(match_operand:HI 1 "general_
operand" "rI,m,r,m,z,x,t
"))]
(match_operand:HI 1 "general_
movsrc_operand" "Q,rI,>m,t,r,i,l,r
"))]
""
""
"@
"
*
mov %1,%0
{
mov.w %1,%0
switch (which_alternative)
mov.w %1,%0
{
mov.w %1,%0
case 0:
mov.w %1,%0
switch (get_attr_length(insn))
sts %1,%0
{
movt %0"
case 2:
[
(set_attr "type" "move,load,store,load,store,move,move")
]
)
return
\"
mov.w %1,%0 ! 2 byte
\"
;
case 12:
return
\"
mov.l TA%
*,%0\;bra TB%*
\;
mov.w @%0,%0
\;
.align 2
\;
TA%
*: .long %1\;TB%*
:%^
\"
;
}
case 1: return
\"
mov %1,%0
\"
;
case 2: return
\"
mov.w %1,%0
\"
;
case 3: return
\"
movt %0
\"
;
case 4: return
\"
mov.w %1,%0
\"
;
case 5: return
\"
fake %1,%0
\"
;
case 6: return
\"
sts %1,%0
\"
;
case 7: return
\"
lds %1,%0
\"
;
}
}"
[
(set_attr "length" "
*
,2,2,2,2,2,2,2")
(set_attr "type" "pcloadhi,move,load,move,store,move,move,move")])
(define_expand "movhi"
(define_expand "movhi"
[
(set (match_operand:HI 0 "general_operand" "")
[
(set (match_operand:HI 0 "general_
movdst_
operand" "")
(match_operand:HI 1 "general_operand" ""))]
(match_operand:HI 1 "general_
movsrc_
operand" ""))]
""
""
"
prepare_move_operands (operands, HImode)
;")
"
if (prepare_move_operands (operands, HImode)) DONE
;")
(define_insn ""
(define_insn ""
[
(set (match_operand:DI 0 "push_operand" "=<")
[
(set (match_operand:DI 0 "push_operand" "=<")
(match_operand:DI 1 "arith_reg_operand" "r"))]
(match_operand:DI 1 "arith_reg_operand" "r"))]
...
@@ -718,68 +1065,59 @@
...
@@ -718,68 +1065,59 @@
[
(set_attr "length" "4")
[
(set_attr "length" "4")
(set_attr "type" "store")])
(set_attr "type" "store")])
(define_insn "movdi_pcrel"
(define_split
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
[
(set (match_operand:DI 0 "general_movdst_operand" "")
(match_operand:DI 1 "hard_immediate_operand" "i"))]
(match_operand:DI 1 "nonimmediate_operand" ""))]
""
"
*
return output_movepcrel (insn, operands, DImode);"
[
(set_attr "length" "4")
(set_attr "in_delay_slot" "no")
(set_attr "constneed" "yes")
(set_attr "smallestsize" "4")
(set_attr "constantsize" "8")
(set_attr "largestsize" "18")
(set_attr "type" "load")])
(define_insn "movdi_k"
[
(set (match_operand:DI 0 "general_operand" "=r,r,m,r,r,m,r")
(match_operand:DI 1 "general_operand" "r,m,r,I,m,r,x"))]
""
""
"
*
return output_movedouble(operands, DImode);"
[
(set (match_dup 2) (match_dup 3))
[
(set_attr "length" "4")
(set (match_dup 4) (match_dup 5))]
(set_attr "type" "move,load,store,move,load,store,load")]
)
"if (prepare_split_double_ops (operands, DImode)) DONE; else FAIL;"
)
(define_insn ""
[
(set (match_operand:DI 0 "general_movdst_operand" "=r,r,r,m,r")
(match_operand:DI 1 "general_movsrc_operand" "Q,r,m,r,i"))]
"register_operand (operands
[
0
]
, DImode)
|| register_operand (operands
[
1
]
, DImode)"
"
*
return output_movedouble (insn, operands, DImode);"
[
(set_attr "length" "
*
,4,4,4,4")
(set_attr "type" "pcloadsi,move,load,store,move")])
(define_expand "movdi"
(define_expand "movdi"
[
(set (match_operand:DI 0 "general_
operand" "
")
[
(set (match_operand:DI 0 "general_
movdst_operand" "=r,m,r
")
(match_operand:DI 1 "general_
operand" "
"))]
(match_operand:DI 1 "general_
movsrc_operand" "m,r,i
"))]
""
""
"
prepare_move_operands (operands, DImode)
;")
"
if (prepare_move_operands(operands, DImode)) DONE
;")
(define_insn ""
(define_insn ""
[
(set (match_operand:DF 0 "push_operand" "=<")
[
(set (match_operand:DF 0 "push_operand" "=<")
(match_operand:DF 1 "arith_reg_operand" "r"))]
(match_operand:DF 1 "arith_reg_operand" "r"))]
""
""
"mov.l %R1,%0
\;
mov.l %1,%0"
"mov.l %R1,%0
\;
mov.l %1,%0"
[
(set_attr "length" "4")
[
(set_attr "length" "4")
(set_attr "type" "store")])
(set_attr "type" "store")])
(define_
insn "movdf_pcrel"
(define_
split
[
(set (match_operand:DF 0 "
arith_reg_operand" "=r
")
[
(set (match_operand:DF 0 "
general_movdst_operand" "
")
(match_operand:DF 1 "
hard_immediate_operand" "i
"))]
(match_operand:DF 1 "
nonimmediate_operand" "
"))]
""
""
"
*
return output_movepcrel (insn, operands, DFmode);"
[
(set (match_dup 2) (match_dup 3))
[
(set_attr "length" "4")
(set (match_dup 4) (match_dup 5))]
(set_attr "in_delay_slot" "no")
"if (prepare_split_double_ops (operands, DFmode)) DONE; else FAIL;")
(set_attr "constneed" "yes")
(set_attr "smallestsize" "4")
(set_attr "constantsize" "8")
(set_attr "largestsize" "18")
(set_attr "type" "load")])
(define_insn "movdf_k"
(define_insn "movdf_k"
[
(set (match_operand:DF 0 "general_operand" "=r,r,m")
[
(set (match_operand:DF 0 "general_movdst_operand" "=r,r,m")
(match_operand:DF 1 "general_operand" "r,m,r"))]
(match_operand:DF 1 "general_movsrc_operand" "r,m,r"))]
""
"register_operand (operands
[
0
]
, DFmode)
"
*
return output_movedouble(operands, DFmode);"
|| register_operand (operands
[
1
]
, DFmode)"
"
*
return output_movedouble (insn, operands, DFmode);"
[
(set_attr "length" "4")
[
(set_attr "length" "4")
(set_attr "type" "move,load,store")])
(set_attr "type" "move,load,store")])
(define_expand "movdf"
(define_expand "movdf"
[
(set (match_operand:DF 0 "general_operand" "")
[
(set (match_operand:DF 0 "general_
movdst_
operand" "")
(match_operand:DF 1 "general_operand" ""))]
(match_operand:DF 1 "general_
movsrc_
operand" ""))]
""
""
"
prepare_move_operands(operands, DFmode)
;")
"
if (prepare_move_operands (operands, DFmode)) DONE
;")
(define_insn ""
(define_insn ""
[
(set (match_operand:SF 0 "push_operand" "=<")
[
(set (match_operand:SF 0 "push_operand" "=<")
...
@@ -787,39 +1125,28 @@
...
@@ -787,39 +1125,28 @@
""
""
"mov.l %1,%0"
"mov.l %1,%0"
[
(set_attr "type" "store")
]
)
[
(set_attr "type" "store")
]
)
(define_insn "movsf_pcrel"
[
(set (match_operand:SF 0 "arith_reg_operand" "=r")
(match_operand:SF 1 "hard_immediate_operand" "i"))]
""
"
*
return output_movepcrel (insn, operands, SFmode);"
[
(set_attr "length" "2")
(set_attr "in_delay_slot" "no")
(set_attr "constneed" "yes")
(set_attr "smallestsize" "2")
(set_attr "largestsize" "8")
(set_attr "type" "load")])
(define_insn "movsf_i"
(define_insn "movsf_i"
[
(set (match_operand:SF 0 "general_
operand" "=r,r,r,m,l,r,m
,r")
[
(set (match_operand:SF 0 "general_
movdst_operand" "=>,r,r,r,r,m,l
,r")
(match_operand:SF 1 "general_
operand" "r,I,m,r,r,l,r,m
"))]
(match_operand:SF 1 "general_
movsrc_operand" "r,<,r,I,m,r,r,l
"))]
""
""
"@
"@
mov.l %1,@%N0
\;
add #4,%N0
add #-4,%1
\;
mov.l @%N1,%0
mov %1,%0
mov %1,%0
mov %1,%0
mov %1,%0
mov.l %1,%0
mov.l %1,%0
mov.l %1,%0
mov.l %1,%0
lds %1,%0
lds %1,%0
sts %1,%0
sts %1,%0"
mov %1,%0
[
(set_attr "type" "store,load,move,move,load,store,move,move")
mov %1,%0"
(set_attr "length" "4,4,
*,*
,
*,*
,
*,*
")])
[
(set_attr "type" "move,move,load,store,move,move,move,move")
]
)
(define_expand "movsf"
(define_expand "movsf"
[
(set (match_operand:SF 0 "general_operand" "")
[
(set (match_operand:SF 0 "general_
movdst_
operand" "")
(match_operand:SF 1 "general_operand" ""))]
(match_operand:SF 1 "general_
movsrc_
operand" ""))]
""
""
"
prepare_move_operands(operands, SFmode)
;")
"
if (prepare_move_operands (operands, SFmode)) DONE
;")
;; ------------------------------------------------------------------------
;; ------------------------------------------------------------------------
...
@@ -839,7 +1166,7 @@
...
@@ -839,7 +1166,7 @@
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))
(pc)))]
(pc)))]
""
""
"
*
return output_branch (0, insn);"
"
*
return output_branch (0, insn
, operands
[
1
]
);"
[
(set_attr "type" "cbranch")
]
)
[
(set_attr "type" "cbranch")
]
)
(define_insn "inverse_branch_true"
(define_insn "inverse_branch_true"
...
@@ -869,12 +1196,7 @@
...
@@ -869,12 +1196,7 @@
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))
(pc)))]
(pc)))]
""
""
"
"from_compare (operands, EQ);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
; There is no bne compare, so we reverse the branch arms.
; There is no bne compare, so we reverse the branch arms.
...
@@ -886,11 +1208,7 @@
...
@@ -886,11 +1208,7 @@
(pc)
(pc)
(label_ref (match_operand 0 "" ""))))]
(label_ref (match_operand 0 "" ""))))]
""
""
"
"from_compare (operands, NE);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "bgt"
(define_expand "bgt"
[
(set (reg:SI 18) (gt:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (gt:SI (match_dup 1) (match_dup 2)))
...
@@ -898,41 +1216,29 @@
...
@@ -898,41 +1216,29 @@
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))
(pc)))]
(pc)))
]
""
""
"
"from_compare (operands, GT);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "blt"
(define_expand "blt"
[
(set (reg:SI 18) (
lt
:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (
ge
:SI (match_dup 1) (match_dup 2)))
(set (pc)
(set (pc)
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)(const_int 1))
(const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))))]
(pc)))]
""
""
"
"from_compare (operands, LT);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "ble"
(define_expand "ble"
[
(set (reg:SI 18) (
le
:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (
gt
:SI (match_dup 1) (match_dup 2)))
(set (pc)
(set (pc)
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)
(pc)))]
(label_ref (match_operand 0 "" ""))))
]
""
""
"
"from_compare (operands, LE);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "bge"
(define_expand "bge"
[
(set (reg:SI 18) (ge:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (ge:SI (match_dup 1) (match_dup 2)))
...
@@ -940,84 +1246,65 @@
...
@@ -940,84 +1246,65 @@
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))
(pc)))]
(pc)))
]
""
""
"
"from_compare (operands, GE);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "bgtu"
(define_expand "bgtu"
[
(set (reg:SI 18) (gtu:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (gtu:SI (match_dup 1) (match_dup 2)))
(set (pc)
(set (pc)
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))
(pc)))]
(pc)))]
""
""
"
"from_compare (operands, GTU); ")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "bltu"
(define_expand "bltu"
[
(set (reg:SI 18) (
lt
u:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (
ge
u:SI (match_dup 1) (match_dup 2)))
(set (pc)
(set (pc)
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(label_ref (match_operand 0 "" "")
)
(pc
)
(pc
)))]
(label_ref (match_operand 0 "" "")
)))]
""
""
"
"from_compare (operands, LTU);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "bgeu"
(define_expand "bgeu"
[
(set (reg:SI 18) (geu:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (geu:SI (match_dup 1) (match_dup 2)))
(set (pc)
(set (pc)
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(label_ref (match_operand 0 "" ""))
(label_ref (match_operand 0 "" ""))
(pc)))]
(pc)))
]
""
""
"
"from_compare (operands, GEU);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
(define_expand "bleu"
(define_expand "bleu"
[
(set (reg:SI 18) (
le
u:SI (match_dup 1) (match_dup 2)))
[
(set (reg:SI 18) (
gt
u:SI (match_dup 1) (match_dup 2)))
(set (pc)
(set (pc)
(if_then_else (eq (reg:SI 18)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(const_int 1))
(
label_ref (match_operand 0 "" "")
)
(
pc
)
(
pc
)))]
(
label_ref (match_operand 0 "" "")
)))]
""
""
"
"from_compare (operands, LEU);")
{
operands
[
1
]
= sh_compare_op0;
operands
[
2
]
= sh_compare_op1;
}")
;; ------------------------------------------------------------------------
;; ------------------------------------------------------------------------
;; Jump and linkage insns
;; Jump and linkage insns
;; ------------------------------------------------------------------------
;; ------------------------------------------------------------------------
(define_insn "jump
_real
"
(define_insn "jump"
[
(set (pc)
[
(set (pc)
(label_ref (match_operand 0 "" "")))]
(label_ref (match_operand 0 "" "")))]
""
""
"
*
"
*
{
{
if (get_attr_length(insn) ==
6
)
if (get_attr_length(insn) ==
10
)
{
{
return
\"
mov.l %I0,r13
\;
jmp @r13%#
\"
;
return
output_far_jump(insn, operands
[
0
]
)
;
}
}
else
else
{
{
...
@@ -1027,15 +1314,6 @@
...
@@ -1027,15 +1314,6 @@
[
(set_attr "type" "jump")
[
(set_attr "type" "jump")
(set_attr "needs_delay_slot" "yes")])
(set_attr "needs_delay_slot" "yes")])
(define_expand "jump"
[
(set (pc) (label_ref (match_operand 0 "" "")))
]
""
"
{
emit_insn(gen_jump_real(operand0));
DONE;
}
")
(define_insn "calli"
(define_insn "calli"
[
(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
[
(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
...
@@ -1063,16 +1341,7 @@
...
@@ -1063,16 +1341,7 @@
(match_operand 1 "" ""))
(match_operand 1 "" ""))
(clobber (reg:SI 17))])]
(clobber (reg:SI 17))])]
""
""
"
"expand_acall(0, operands); DONE;")
{
if (GET_CODE (operands
[
0
]
) == MEM)
{
operands
[
0
]
= gen_rtx(MEM,GET_MODE (operands
[
0
]
),
force_reg (Pmode,
XEXP (operands
[
0
]
, 0)));
}
}")
(define_expand "call_value"
(define_expand "call_value"
[
(parallel
[
(set (match_operand 0 "" "=rf")
[
(parallel
[
(set (match_operand 0 "" "=rf")
...
@@ -1080,16 +1349,7 @@
...
@@ -1080,16 +1349,7 @@
(match_operand 2 "" "")))
(match_operand 2 "" "")))
(clobber (reg:SI 17))])]
(clobber (reg:SI 17))])]
""
""
"
"expand_acall(1, operands); DONE; ")
{
if (GET_CODE (operands
[
1
]
) == MEM)
{
operands
[
1
]
= gen_rtx (MEM, GET_MODE (operands
[
1
]
),
force_reg (Pmode,
XEXP (operands
[
1
]
, 0)));
}
}")
(define_insn "indirect_jump"
(define_insn "indirect_jump"
[
(set (pc)
[
(set (pc)
...
@@ -1100,36 +1360,107 @@
...
@@ -1100,36 +1360,107 @@
(set_attr "in_delay_slot" "no")
(set_attr "in_delay_slot" "no")
(set_attr "length" "4")])
(set_attr "length" "4")])
;; ------------------------------------------------------------------------
;; ------------------------------------------------------------------------
;; Misc insns
;; Misc insns
;; ------------------------------------------------------------------------
;; ------------------------------------------------------------------------
(define_insn "dect"
[
(parallel
[
(set (reg:SI 18)
(eq:SI (match_operand:SI 0 "register_operand" "=r")
(const_int 1)))
(set (match_dup 0)
(plus:SI (match_dup 0)
(const_int -1)))])]
"TARGET_SH2"
"dt %0")
(define_insn "nop"
(define_insn "nop"
[
(const_int 0)
]
[
(const_int 0)
]
""
""
"or r0,r0")
"or r0,r0")
(define_insn "tablejump"
; experimental use of auto inc and dec made these...
[
(set (pc)
; can be deleted
(match_operand:SI 0 "arith_reg_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
(define_insn "fake"
[
(set (match_operand:QI 0 "register_operand" "=r")
(mem:QI (pre_dec:SI (match_operand:SI 1 "register_operand" "r"))))]
""
""
"!table jump
\;
jmp @%0
\;
or r0,r0
\;
%!"
"add #-1,%1
\;
mov.b @%1,%0"
[
(set_attr "length" "4")
]
)
;; Load address of a label. This is only generated by the casesi expand.
(define_insn "mova"
[
(set (reg:SI 0)
(label_ref (match_operand 0 "" "")))]
""
"mova %O0,r0"
[
(set_attr "in_delay_slot" "no")
]
)
;; case instruction for switch statements.
;; Operand 0 is index
;; operand 1 is the minimum bound
;; operand 2 is the maximum bound - minimum bound + 1
;; operand 3 is CODE_LABEL for the table;
;; operand 4 is the CODE_LABEL to go to if index out of range.
(define_expand "casesi"
[
(set (match_dup 5) (match_operand:SI 0 "arith_reg_operand" ""))
(set (match_dup 5) (minus:SI (match_dup 5)
(match_operand:SI 1 "arith_operand" "")))
(set (reg:SI 18)
(gtu:SI (match_dup 5)
(match_operand:SI 2 "arith_operand" "")))
(set (pc)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_dup 6) (plus:SI (match_dup 5) (match_dup 5)))
(set (reg:SI 0) (label_ref (match_operand 3 "" "")))
(parallel
[
(set (reg:SI 0) (plus:SI (reg:SI 0)
(mem:HI (plus:SI (reg:SI 0)
(match_dup 6)))))
(set (match_dup 6) (mem:HI (plus:SI (reg:SI 0) (match_dup 6))))])
(set (pc) (reg:SI 0))]
""
"
{
operands
[
1
]
= copy_to_mode_reg (SImode, operands
[
1
]
);
operands
[
2
]
= copy_to_mode_reg (SImode, operands
[
2
]
);
operands
[
5
]
= gen_reg_rtx (SImode);
operands
[
6
]
= gen_reg_rtx (SImode);
}")
(define_insn "casesi_worker"
[
(set (reg:SI 0)
(plus:SI (reg:SI 0)
(mem:HI (plus:SI (reg:SI 0)
(match_operand:SI 0 "register_operand" "=r")))))
(set (match_dup 0) (mem:HI (plus:SI (reg:SI 0)
(match_dup 0))))]
""
"mov.w @(r0,%0),%0
\;
add %0,r0"
[
(set_attr "needs_delay_slot" "no")
[
(set_attr "needs_delay_slot" "no")
(set_attr "in_delay_slot" "no")
(set_attr "in_delay_slot" "no")
(set_attr "type" "jump")
(set_attr "length" "6")])
(set_attr "dump" "no")])
(define_insn "
return
"
(define_insn ""
[
(return)
]
[
(return)
]
"reload_completed"
"!pragma_interrupt && reload_completed"
"rts %#"
"rts%#"
[
(set_attr "type" "return")
[
(set_attr "type" "return")
]
)
(set_attr "needs_delay_slot" "yes")
(set_attr "dump" "yes")])
(define_insn ""
[
(return)
]
"pragma_interrupt && reload_completed"
"rte%#"
[
(set_attr "type" "rte")
]
)
(define_expand "prologue"
(define_expand "prologue"
[
(const_int 0)
]
[
(const_int 0)
]
...
@@ -1152,7 +1483,7 @@
...
@@ -1152,7 +1483,7 @@
;; Scc instructions
;; Scc instructions
;; ------------------------------------------------------------------------
;; ------------------------------------------------------------------------
(define_insn ""
(define_insn "
movt
"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(eq (reg:SI 18) (const_int 1)))]
(eq (reg:SI 18) (const_int 1)))]
""
""
...
@@ -1219,59 +1550,6 @@
...
@@ -1219,59 +1550,6 @@
""
""
"operands
[
1
]
= prepare_scc_operands (EQ);")
"operands
[
1
]
= prepare_scc_operands (EQ);")
; these patterns give better code then gcc invents if
; left to its own devices
(define_insn "anddi3"
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
(and:DI (match_operand:DI 1 "arith_reg_operand" "%0")
(match_operand:DI 2 "arith_reg_operand" "r")))]
""
"and %2,%0
\;
and %R2,%R0"
[
(set_attr "length" "4")
]
)
(define_insn "iordi3"
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
(ior:DI (match_operand:DI 1 "arith_reg_operand" "%0")
(match_operand:DI 2 "arith_reg_operand" "r")))]
""
"or %2,%0
\;
or %R2,%R0"
[
(set_attr "length" "4")
]
)
(define_insn "xordi3"
[
(set (match_operand:DI 0 "arith_reg_operand" "=r")
(xor:DI (match_operand:DI 1 "arith_reg_operand" "%0")
(match_operand:DI 2 "arith_reg_operand" "r")))]
""
"xor %2,%0
\;
xor %R2,%R0"
[
(set_attr "length" "4")
]
)
;; ------------------------------------------------------------------------
;; Block move
;; ------------------------------------------------------------------------
(define_expand "movstrsi"
[
(parallel
[
(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
(mem:BLK (match_operand:BLK 1 "general_operand" "")))
(use (match_operand:SI 2 "general_operand" ""))
(use (match_operand:SI 3 "immediate_operand" ""))
])]
""
"
{
rtx dest_mem = operands
[
0
]
;
rtx src_mem = operands
[
1
]
;
operands
[
0
]
= copy_to_mode_reg (SImode, XEXP (operands
[
0
]
, 0));
operands
[
1
]
= copy_to_mode_reg (SImode, XEXP (operands
[
1
]
, 0));
expand_block_move (dest_mem, src_mem, operands);
DONE;
}")
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
;; Peepholes
;; Peepholes
;; -------------------------------------------------------------------------
;; -------------------------------------------------------------------------
...
@@ -1281,39 +1559,39 @@
...
@@ -1281,39 +1559,39 @@
[
(set (match_operand:QI 0 "arith_reg_operand" "")
[
(set (match_operand:QI 0 "arith_reg_operand" "")
(mem:QI (match_operand:SI 1 "arith_reg_operand" "")))
(mem:QI (match_operand:SI 1 "arith_reg_operand" "")))
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 1)))]
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 1)))]
"REGNO
(operands
[
1
]
) != REGNO
(operands
[
0
]
)"
"REGNO
(operands
[
1
]
) != REGNO
(operands
[
0
]
)"
"mov.b @%1+,%0")
"mov.b @%1+,%0")
(define_peephole
(define_peephole
[
(set (match_operand:HI 0 "arith_reg_operand" "")
[
(set (match_operand:HI 0 "arith_reg_operand" "")
(mem:HI (match_operand:SI 1 "arith_reg_operand" "")))
(mem:HI (match_operand:SI 1 "arith_reg_operand" "")))
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 2)))]
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 2)))]
"REGNO
(operands
[
1
]
) != REGNO
(operands
[
0
]
)"
"REGNO
(operands
[
1
]
) != REGNO
(operands
[
0
]
)"
"mov.w @%1+,%0")
"mov.w @%1+,%0")
(define_peephole
(define_peephole
[
(set (match_operand:SI 0 "arith_reg_operand" "")
[
(set (match_operand:SI 0 "arith_reg_operand" "")
(mem:SI (match_operand:SI 1 "arith_reg_operand" "")))
(mem:SI (match_operand:SI 1 "arith_reg_operand" "")))
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 4)))]
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 4)))]
"REGNO
(operands
[
1
]
) != REGNO
(operands
[
0
]
)"
"REGNO
(operands
[
1
]
) != REGNO
(operands
[
0
]
)"
"mov.l @%1+,%0")
"mov.l @%1+,%0")
(define_peephole
(define_peephole
[
(set (match_operand:QI 0 "register_operand" "=r")
[
(set (match_operand:QI 0 "register_operand" "=r")
(match_operand:QI 1 "
general
_operand" "g"))
(match_operand:QI 1 "
memory
_operand" "g"))
(set (match_operand:SI 2 "register_operand" "=r")
(set (match_operand:SI 2 "register_operand" "=r")
(sign_extend:SI (match_dup 0)))]
(sign_extend:SI (match_dup 0)))]
"REGNO
(operands
[
0
]
) == REGNO
(operands
[
2
]
)"
"REGNO
(operands
[
0
]
) == REGNO
(operands
[
2
]
)"
"mov.b %1,%0")
"mov.b %1,%0
!p 5
")
(define_peephole
(define_peephole
[
(set (match_operand:QI 0 "register_operand" "=r")
[
(set (match_operand:QI 0 "register_operand" "=r")
(match_operand:QI 1 "general_operand" "g"))
(match_operand:QI 1 "general_
movsrc_
operand" "g"))
(set (match_operand:SI 2 "register_operand" "=r")
(set (match_operand:SI 2 "register_operand" "=r")
(sign_extend:SI (match_dup 0)))]
(sign_extend:SI (match_dup 0)))]
"REGNO
(operands
[
0
]
) != REGNO
(operands
[
2
]
)
"REGNO
(operands
[
0
]
) != REGNO
(operands
[
2
]
)
&& dead_or_set_p (insn, operands
[
0
]
)"
&& dead_or_set_p (insn, operands
[
0
]
)"
"mov.b %1,%2")
"mov.b %1,%2
! p4
")
; notice when a mov.b could be done with a displacement
; notice when a mov.b could be done with a displacement
...
@@ -1322,7 +1600,7 @@
...
@@ -1322,7 +1600,7 @@
(plus:SI (match_dup 0)
(plus:SI (match_dup 0)
(match_operand:SI 1 "byte_index_operand" "i")))
(match_operand:SI 1 "byte_index_operand" "i")))
(set (mem:QI (match_dup 0)) (reg:QI 0))]
(set (mem:QI (match_dup 0)) (reg:QI 0))]
"dead_or_set_p(insn, operands
[
0
]
)"
"dead_or_set_p
(insn, operands
[
0
]
)"
"mov.b r0,@(%O1,%0)")
"mov.b r0,@(%O1,%0)")
(define_peephole
(define_peephole
...
@@ -1330,9 +1608,294 @@
...
@@ -1330,9 +1608,294 @@
(plus:SI (match_dup 0)
(plus:SI (match_dup 0)
(match_operand:SI 1 "byte_index_operand" "i")))
(match_operand:SI 1 "byte_index_operand" "i")))
(set (reg:QI 0) (mem:QI (match_dup 0)))]
(set (reg:QI 0) (mem:QI (match_dup 0)))]
"dead_or_set_p(insn, operands
[
0
]
)"
"dead_or_set_p
(insn, operands
[
0
]
)"
"mov.b @(%O1,%0),r0")
"mov.b @(%O1,%0),r0")
;; -------------------------------------------------------------------------
;; Peepholes
;; -------------------------------------------------------------------------
(define_peephole
[
(set (reg:SI 0) (label_ref (match_operand 0 "" "")))
(set (match_operand:SI 1 "register_operand" "=r")
(reg:SI 0))
(set (reg:SI 0) (label_ref (match_dup 0)))
(set (match_operand:SI 2 "register_operand" "=r")
(reg:SI 0))]
""
"mova %O0,r0
\;
mov r0,%1
\;
mov r0,%2"
[
(set_attr "length" "6")
(set_attr "in_delay_slot" "no")])
; mov r4,r3
; shll r3
; mov r3,r0
;->
; mov r4,r0
; shll r0
(define_peephole
[
(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "register_operand" "r"))
(set (match_dup 0)
(plus:SI (match_dup 0) (match_dup 1)))
(set (match_operand:SI 2 "register_operand" "=r")
(match_dup 0))]
"dead_or_set_p (NEXT_INSN (insn), operands
[
0
]
)"
"mov %1,%2
\;
add %2,%2"
[
(set_attr "length" "4")
]
)
(define_peephole
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(and:SI (match_dup 0)
(const_int 1)))
(set (match_operand:SI 1 "arith_reg_operand" "=r")
(const_int 0))
(set (reg:SI 18)
(eq:SI (match_dup 0) (match_dup 1)))]
"dead_or_set_p (insn, operands
[
0
]
)
&& dead_or_set_p (insn, operands
[
1
]
)"
"rotr %0")
(define_peephole
[
(set (match_operand:SI 0 "arith_reg_operand" "z,r")
(and:SI (match_dup 0)
(match_operand:SI 1 "arith_operand" "L,r")))
(set (reg:SI 18)
(eq:SI (match_dup 0) (const_int 0)))]
"dead_or_set_p (insn, operands
[
0
]
)"
"tst %1,%0 !t5")
(define_peephole
[
(set (match_operand:SI 0 "arith_reg_operand" "z,r")
(and:SI (match_dup 0)
(match_operand:SI 1 "arith_operand" "L,r")))
(set (reg:SI 18)
(eq:SI (match_dup 0) (const_int 0)))]
"dead_or_set_p (insn, operands
[
0
]
)"
"tst %1,%0 !t4")
;; -------------------------------------------------------------------------
;; Combine patterns
;; -------------------------------------------------------------------------
(define_insn ""
[
(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_operand:HI 1 "register_operand" "%0")
(match_operand:SI 2 "register_operand" "r")))]
""
"add %2,%0 ! why")
(define_insn "addc_2"
[
(set (match_operand:SI 0 "arith_reg_operand" "=&r")
(plus:SI (reg:SI 18)
(match_operand:SI 1 "arith_reg_operand" "r")))
(clobber (reg:SI 18))]
""
"mov #0,%0
\;
addc %1,%0 ! addc1"
[
(set_attr "length" "4")
]
)
(define_insn "combine_1"
[
(set (match_operand:SI 0 "arith_reg_operand" "=r")
(sign_extend:SI (mem:QI (match_operand:SI 1 "arith_reg_operand" "r"))))]
""
"mov.b @%1,%0 ! why"
[
(set_attr "type" "load")
]
)
(define_insn "combine_2"
[
(set (reg:SI 18)
(eq (and:SI (match_operand:SI 0 "arith_reg_operand" "z,r")
(match_operand:SI 1 "arith_operand" "L,r"))
(const_int 0)))]
""
"tst %1,%0 !t2")
(define_split
[
(set (pc)
(if_then_else
(match_operator 2 "equality_operator"
[
(match_operand:SI 0 "arith_reg_operand" "r")
(const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))
(clobber (reg:SI 18))]
""
[
(set (reg:SI 18) (eq (and:SI (match_dup 0) (match_dup 0))
(const_int 0)))
(set (pc)
(if_then_else (match_op_dup 2
[
(reg:SI 18) (const_int 1)
]
)
(label_ref (match_dup 1))
(pc)))]
"")
;; -------------------------------------------------------------------------
;; Instructions to cope with inline literal tables
;; -------------------------------------------------------------------------
; 2 byte integer in line
(define_insn "consttable_2"
[
(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")
]
2)]
""
"
*
{
assemble_integer (operands
[
0
]
, 2, 1);
return
\"\"
;
}"
[
(set_attr "length" "2")
(set_attr "in_delay_slot" "no")])
; 4 byte integer in line
(define_insn "consttable_4"
[
(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")
]
4)]
""
"
*
{
assemble_integer (operands
[
0
]
, 4, 1);
return
\"\"
;
}"
[
(set_attr "length" "4")
(set_attr "in_delay_slot" "no")])
; 8 byte integer in line
(define_insn "consttable_8"
[
(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")
]
6)]
""
"
*
{
assemble_integer (operands
[
0
]
, 8, 1);
return
\"\"
;
}"
[
(set_attr "length" "8")
(set_attr "in_delay_slot" "no")])
; align to a two byte boundary
(define_insn "align_2"
[
(unspec_volatile [(const_int 0)
]
10)]
""
".align 1"
[
(set_attr "length" "0")
(set_attr "in_delay_slot" "no")])
; align to a four byte boundary
(define_insn "align_4"
[
(unspec_volatile [(const_int 0)
]
5)]
""
".align 2"
[
(set_attr "in_delay_slot" "no")
]
)
; emitted at the end of the literal table, used to emit the
; 32bit branch labels if needed.
(define_insn "consttable_end"
[
(unspec_volatile [(const_int 0)
]
11)]
""
"
*
return output_jump_label_table ();"
[
(set_attr "in_delay_slot" "no")
]
)
;(define_split
;
[
(set (subreg:SI (match_operand:QI 0 "register_operand" "=r") 0)
; (plus:SI (subreg:SI (match_operand:QI 1 "general_operand" "g") 0)
; (subreg:SI (match_operand:QI 2 "general_operand" "g") 0)))]
; ""
;
[
(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))
; (set (match_dup 1) (subreg:SI (match_dup 3) 0))]
; "operands
[
3
]
= gen_reg_rtx(SImode);")
; byte arithmetic involving constants which need to be sign extended can be
; fixed up...
(define_split
[
(set (subreg:SI (match_operand:QI 0 "register_operand" "=r") 0)
(plus:SI (subreg:SI (match_operand:QI 1 "register_operand" "0") 0)
(subreg:SI (match_operand 2 "immediate_operand" "n") 0)))]
""
[
(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
(set (match_dup 0) (and:SI (match_dup 0) (const_int 255)))]
"{ int i = INTVAL(operands
[
2
]
) & 0xff;
if (i > 127) i = i - 256;
operands
[
3
]
= GEN_INT(i);
operands
[
4
]
= gen_reg_rtx(SImode);} ")
(define_insn "movsi_k"
[
(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "immediate_operand" ""))]
"!pnum_clobbers"
"! this is a fake")
(define_insn "movhi_k"
[
(set (match_operand:HI 0 "register_operand" "=r")
(match_operand:HI 1 "immediate_operand" ""))]
"!pnum_clobbers"
"! this is a fake")
(define_insn "movdi_k"
[
(set (match_operand:DI 0 "register_operand" "=r")
(match_operand:DI 1 "immediate_operand" ""))]
"!pnum_clobbers"
"! this is a fake")
;; -------------------------------------------------------------------------
;; Misc
;; -------------------------------------------------------------------------
;; String/block move insn.
(define_expand "movstrsi"
[
(parallel
[
(set (mem:BLK (match_operand:BLK 0 "" ""))
(mem:BLK (match_operand:BLK 1 "" "")))
(use (match_operand:SI 2 "nonmemory_operand" ""))
(use (match_operand:SI 3 "immediate_operand" ""))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 5))
(clobber (reg:SI 0))])]
""
"
{
if(expand_block_move (operands))
DONE;
else FAIL;
}")
(define_insn "block_move_real"
[
(parallel
[
(set (mem:BLK (reg:SI 4))
(mem:BLK (reg:SI 5)))
(use (match_operand:SI 0 "arith_reg_operand" "r"))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 5))
(clobber (reg:SI 0))])]
""
"jsr @%0%#"
[
(set_attr "length" "4")
(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
(define_insn "block_lump_real"
[
(parallel
[
(set (mem:BLK (reg:SI 4))
(mem:BLK (reg:SI 5)))
(use (match_operand:SI 0 "arith_reg_operand" "r"))
(use (reg:SI 6))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 5))
(clobber (reg:SI 6))
(clobber (reg:SI 0))])]
""
"jsr @%0%#"
[
(set_attr "length" "4")
(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
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