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
2b7972b0
Commit
2b7972b0
authored
Apr 28, 1998
by
Michael Meissner
Committed by
Michael Meissner
Apr 28, 1998
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update m32r port
From-SVN: r19465
parent
77be0cab
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
941 additions
and
144 deletions
+941
-144
gcc/ChangeLog
+57
-0
gcc/config/m32r/m32r.c
+419
-75
gcc/config/m32r/m32r.h
+190
-33
gcc/config/m32r/m32r.md
+271
-34
gcc/config/m32r/t-m32r
+2
-0
gcc/configure
+1
-1
gcc/configure.in
+1
-1
No files found.
gcc/ChangeLog
View file @
2b7972b0
Tue Apr 28 08:55:26 1998 Michael Meissner <meissner@cygnus.com>
* m32r.c (*_oper{and|ator}): Change enum arguments and return
values to int, so they can be prototyped even in files that don't
include rtl.h.
({small,large}_insn_p): Ditto.
(m32r_select_cc_mode): Ditto.
(gen_compare): Ditto.
(function_arg_partial_nregs): Ditto.
(m32r_setup_incoming_varargs): Ditto.
(init_reg_tables): Add prototype.
(m32r_frame_info): Add prolog_size field.
(m32r_compute_frame_size): Calculate the size of the prologue.
(m32r_first_insn_address): Return prologue size.
(m32r_output_function_prologue): Calculate frame size before
printing out information. Print out the prologue size.
* m32r.h: Prototype all functions in m32r.c.
(FIRST_INSN_ADDRESS): Declare, returning prologue size.
* m32r.md (bcc functions): Cast enum's to int.
* m32r.c (conditional_move_operand): Silence a debug message.
({small,long}_insn): New predicates.
* m32r.h (TARGET_M32R): New macro.
(PREDICATE_CODES): Rearrange somewhat, add small_insn/long_insn.
(HAIFA_P): Define as 1/0 depending on whether the Haifa scheduler
was selected.
(ISSUE_RATE): Define as 2.
* m32r.md (insn_size): New attribute.
({,rev_}branch_insn): Add .s qualifier to branches believed to be
short.
(m32r): New attribute.
* configure.in (enable_haifa): Switch m32r to Haifa by default.
* configure: Regenerate.
(Changes from Nick Clifton <nickc@cygnus.com>)
* m32r.h (EXTRA_CONSTRAINT): Implement 'S' constraint to perfoirm
the equivalent of a negated 'I' constraint.
(PRESERVE_DEATH_INFO_REGNO_P): Define in order to allow peephole
optimisation to work.
* m32r.md (cmp_ne_small_const_insn): Use 'S' constriant rather
than 'I' since the value is negated.
(peephole): Add peephole optimisation to cope with optimization of
divide and subtracts of the same operands.
* m32r.c zero_and_one, emit_cond_move): Add support for MVFC.
* m32r.h: Ditto.
* m32r.md: Ditto.
* m32r.h (PREDICATE_CODES): Add declaration of machine specific
predicates.
Tue Apr 28 07:25:53 1998 Manfred Hollstein <manfred@s-direktnet.de>
* Makefile.in (libgcc2.ready): Revert last patch (Apr 24).
...
...
gcc/config/m32r/m32r.c
View file @
2b7972b0
/* Subroutines used for code generation on the Mitsubishi M32R cpu.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 1996, 1997
, 1998
Free Software Foundation, Inc.
This file is part of GNU CC.
...
...
@@ -41,8 +41,6 @@ rtx m32r_compare_op0, m32r_compare_op1;
/* Array of valid operand punctuation characters. */
char
m32r_punct_chars
[
256
];
static
void
init_reg_tables
();
/* Selected code model. */
char
*
m32r_model_string
=
M32R_MODEL_DEFAULT
;
enum
m32r_model
m32r_model
;
...
...
@@ -51,6 +49,10 @@ enum m32r_model m32r_model;
char
*
m32r_sdata_string
=
M32R_SDATA_DEFAULT
;
enum
m32r_sdata
m32r_sdata
;
/* Forward declaration. */
static
void
init_reg_tables
PROTO
((
void
));
/* Called by OVERRIDE_OPTIONS to initialize various things. */
void
...
...
@@ -84,6 +86,7 @@ m32r_init ()
m32r_sdata
=
M32R_SDATA_USE
;
else
error
(
"bad value (%s) for -msdata switch"
,
m32r_sdata_string
);
}
/* Vectors to keep interesting information about registers where it can easily
...
...
@@ -95,7 +98,8 @@ m32r_init ()
they all fit (as bit numbers) in a 32 bit word (again). Each real mode is
mapped into one m32r_mode_class mode. */
enum
m32r_mode_class
{
enum
m32r_mode_class
{
C_MODE
,
S_MODE
,
D_MODE
,
T_MODE
,
O_MODE
,
SF_MODE
,
DF_MODE
,
TF_MODE
,
OF_MODE
...
...
@@ -113,9 +117,11 @@ enum m32r_mode_class {
/* Modes for quad-word and smaller quantities. */
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
/* Value is 1 if register/mode pair is acceptable on arc. */
unsigned
int
m32r_hard_regno_mode_ok
[
FIRST_PSEUDO_REGISTER
]
=
{
unsigned
int
m32r_hard_regno_mode_ok
[
FIRST_PSEUDO_REGISTER
]
=
{
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
T_MODES
,
S_MODES
,
S_MODES
,
S_MODES
,
S_MODES
,
C_MODES
...
...
@@ -412,21 +418,23 @@ m32r_init_expanders ()
/* Acceptable arguments to the call insn. */
int
call_address_operand
(
op
,
mode
)
call_address_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
return
symbolic_operand
(
op
,
mode
);
return
symbolic_operand
(
op
,
int_
mode
);
/* Constants and values in registers are not OK, because
the m32r BL instruction can only support PC relative branching. */
/* Constants and values in registers are not OK, because
the m32r BL instruction can only support PC relative branching. */
}
int
call_operand
(
op
,
mode
)
call_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
if
(
GET_CODE
(
op
)
!=
MEM
)
return
0
;
op
=
XEXP
(
op
,
0
);
...
...
@@ -436,9 +444,9 @@ call_operand (op, mode)
/* Returns 1 if OP is a symbol reference. */
int
symbolic_operand
(
op
,
mode
)
symbolic_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
switch
(
GET_CODE
(
op
))
{
...
...
@@ -446,6 +454,7 @@ symbolic_operand (op, mode)
case
LABEL_REF
:
case
CONST
:
return
1
;
default
:
return
0
;
}
...
...
@@ -454,9 +463,9 @@ symbolic_operand (op, mode)
/* Return 1 if OP is a reference to an object in .sdata/.sbss. */
int
small_data_operand
(
op
,
mode
)
small_data_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
!
TARGET_SDATA_USE
)
return
0
;
...
...
@@ -477,9 +486,9 @@ small_data_operand (op, mode)
/* Return 1 if OP is a symbol that can use 24 bit addressing. */
int
addr24_operand
(
op
,
mode
)
addr24_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
==
LABEL_REF
)
return
TARGET_ADDR24
;
...
...
@@ -509,24 +518,24 @@ addr24_operand (op, mode)
/* Return 1 if OP is a symbol that needs 32 bit addressing. */
int
addr32_operand
(
op
,
mode
)
addr32_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
==
LABEL_REF
)
return
TARGET_ADDR32
;
if
(
GET_CODE
(
op
)
==
SYMBOL_REF
)
return
(
!
addr24_operand
(
op
)
&&
!
small_data_operand
(
op
));
return
(
!
addr24_operand
(
op
,
int_mode
)
&&
!
small_data_operand
(
op
,
int_mode
));
if
(
GET_CODE
(
op
)
==
CONST
&&
GET_CODE
(
XEXP
(
op
,
0
))
==
PLUS
&&
GET_CODE
(
XEXP
(
XEXP
(
op
,
0
),
0
))
==
SYMBOL_REF
&&
GET_CODE
(
XEXP
(
XEXP
(
op
,
0
),
1
))
==
CONST_INT
)
{
return
(
!
addr24_operand
(
op
)
&&
!
small_data_operand
(
op
));
return
(
!
addr24_operand
(
op
,
int_mode
)
&&
!
small_data_operand
(
op
,
int_mode
));
}
return
0
;
...
...
@@ -535,9 +544,9 @@ addr32_operand (op, mode)
/* Return 1 if OP is a function that can be called with the `bl' insn. */
int
call26_operand
(
op
,
mode
)
call26_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
==
SYMBOL_REF
)
return
!
LARGE_NAME_P
(
XSTR
(
op
,
0
));
...
...
@@ -548,9 +557,9 @@ call26_operand (op, mode)
/* Returns 1 if OP is an acceptable operand for seth/add3. */
int
seth_add3_operand
(
op
,
mode
)
seth_add3_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
==
SYMBOL_REF
||
GET_CODE
(
op
)
==
LABEL_REF
)
...
...
@@ -570,9 +579,9 @@ seth_add3_operand (op, mode)
useful in comparisons. */
int
cmp_int16_operand
(
op
,
mode
)
cmp_int16_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
!=
CONST_INT
)
return
0
;
...
...
@@ -581,10 +590,10 @@ cmp_int16_operand (op, mode)
/* Return true if OP is an unsigned 16 bit immediate value. */
static
int
uint16_operand
(
op
,
mode
)
int
uint16_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
!=
CONST_INT
)
return
0
;
...
...
@@ -594,10 +603,12 @@ uint16_operand (op, mode)
/* Return true if OP is a register or signed 8 bit value. */
int
reg_or_int16_operand
(
op
,
mode
)
reg_or_int16_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
if
(
GET_CODE
(
op
)
==
REG
||
GET_CODE
(
op
)
==
SUBREG
)
return
register_operand
(
op
,
mode
);
if
(
GET_CODE
(
op
)
!=
CONST_INT
)
...
...
@@ -608,10 +619,12 @@ reg_or_int16_operand (op, mode)
/* Return true if OP is a register or an unsigned 16 bit value. */
int
reg_or_uint16_operand
(
op
,
mode
)
reg_or_uint16_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
if
(
GET_CODE
(
op
)
==
REG
||
GET_CODE
(
op
)
==
SUBREG
)
return
register_operand
(
op
,
mode
);
if
(
GET_CODE
(
op
)
!=
CONST_INT
)
...
...
@@ -622,10 +635,12 @@ reg_or_uint16_operand (op, mode)
/* Return true if OP is a register or signed 16 bit value for compares. */
int
reg_or_cmp_int16_operand
(
op
,
mode
)
reg_or_cmp_int16_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
if
(
GET_CODE
(
op
)
==
REG
||
GET_CODE
(
op
)
==
SUBREG
)
return
register_operand
(
op
,
mode
);
if
(
GET_CODE
(
op
)
!=
CONST_INT
)
...
...
@@ -636,9 +651,9 @@ reg_or_cmp_int16_operand (op, mode)
/* Return true if OP is a const_int requiring two instructions to load. */
int
two_insn_const_operand
(
op
,
mode
)
two_insn_const_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
if
(
GET_CODE
(
op
)
!=
CONST_INT
)
return
0
;
...
...
@@ -653,15 +668,16 @@ two_insn_const_operand (op, mode)
move source. */
int
move_src_operand
(
op
,
mode
)
move_src_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
switch
(
GET_CODE
(
op
))
{
case
SYMBOL_REF
:
case
CONST
:
return
addr24_operand
(
op
,
mode
);
return
addr24_operand
(
op
,
int_
mode
);
case
CONST_INT
:
/* ??? We allow more cse opportunities if we only allow constants
loadable with one insn, and split the rest into two. The instances
...
...
@@ -704,10 +720,11 @@ move_src_operand (op, mode)
move source. */
int
move_double_src_operand
(
op
,
mode
)
move_double_src_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
switch
(
GET_CODE
(
op
))
{
case
CONST_INT
:
...
...
@@ -722,7 +739,7 @@ move_double_src_operand (op, mode)
/* (subreg (mem ...) ...) can occur here if the inner part was once a
pseudo-reg and is now a stack slot. */
if
(
GET_CODE
(
SUBREG_REG
(
op
))
==
MEM
)
return
move_double_src_operand
(
SUBREG_REG
(
op
),
mode
);
return
move_double_src_operand
(
SUBREG_REG
(
op
),
int_
mode
);
else
return
register_operand
(
op
,
mode
);
case
MEM
:
...
...
@@ -739,10 +756,11 @@ move_double_src_operand (op, mode)
/* Return true if OP is an acceptable argument for a move destination. */
int
move_dest_operand
(
op
,
mode
)
move_dest_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
switch
(
GET_CODE
(
op
))
{
case
REG
:
...
...
@@ -805,9 +823,9 @@ easy_df_const (op)
/* Return 1 if OP is an EQ or NE comparison operator. */
int
eqne_comparison_operator
(
op
,
mode
)
eqne_comparison_operator
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
rtx_code
code
=
GET_CODE
(
op
);
...
...
@@ -819,9 +837,9 @@ eqne_comparison_operator (op, mode)
/* Return 1 if OP is a signed comparison operator. */
int
signed_comparison_operator
(
op
,
mode
)
signed_comparison_operator
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
enum
rtx_code
code
=
GET_CODE
(
op
);
...
...
@@ -835,35 +853,70 @@ signed_comparison_operator (op, mode)
This is used in insn length calcs. */
int
memreg_operand
(
op
,
mode
)
memreg_operand
(
op
,
int_
mode
)
rtx
op
;
enum
machine_mode
mode
;
int
int_
mode
;
{
return
GET_CODE
(
op
)
==
MEM
&&
GET_CODE
(
XEXP
(
op
,
0
))
==
REG
;
}
/* Return non-zero if the operand is an insn that is a small insn.
Allow const_int 0 as well, which is a placeholder for NOP slots. */
int
small_insn_p
(
op
,
int_mode
)
rtx
op
;
int
int_mode
;
{
if
(
GET_CODE
(
op
)
==
CONST_INT
&&
INTVAL
(
op
)
==
0
)
return
1
;
if
(
GET_RTX_CLASS
(
GET_CODE
(
op
))
!=
'i'
)
return
0
;
return
get_attr_length
(
op
)
==
2
;
}
/* Return non-zero if the operand is an insn that is a large insn. */
int
large_insn_p
(
op
,
int_mode
)
rtx
op
;
int
int_mode
;
{
if
(
GET_RTX_CLASS
(
GET_CODE
(
op
))
!=
'i'
)
return
0
;
return
get_attr_length
(
op
)
!=
2
;
}
/* Comparisons. */
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
enum
machine_mode
int
m32r_select_cc_mode
(
op
,
x
,
y
)
enum
rtx_code
op
;
int
op
;
rtx
x
,
y
;
{
return
CCmode
;
return
(
int
)
CCmode
;
}
/* X and Y are two things to compare using CODE. Emit the compare insn and
return the rtx for compare [arg0 of the if_then_else]. */
return the rtx for compare [arg0 of the if_then_else].
If need_compare is true then the comparison insn must be generated, rather
than being susummed into the following branch instruction. */
rtx
gen_compare
(
code
,
x
,
y
)
enum
rtx_code
code
;
gen_compare
(
int_code
,
x
,
y
,
need_compare
)
int
int_
code
;
rtx
x
;
rtx
y
;
int
need_compare
;
{
enum
rtx_code
code
=
(
enum
rtx_code
)
int_code
;
enum
rtx_code
compare_code
;
enum
rtx_code
branch_code
;
enum
machine_mode
mode
=
SELECT_CC_MODE
(
code
,
x
,
y
);
...
...
@@ -884,7 +937,122 @@ gen_compare (code, x, y)
case
GEU
:
compare_code
=
LTU
;
branch_code
=
EQ
;
break
;
}
if
(
!
TARGET_OLD_COMPARE
)
if
(
need_compare
)
{
switch
(
compare_code
)
{
case
EQ
:
if
(
GET_CODE
(
y
)
==
CONST_INT
&&
CMP_INT16_P
(
INTVAL
(
y
))
/* reg equal to small const. */
&&
y
!=
const0_rtx
)
{
rtx
tmp
=
gen_reg_rtx
(
SImode
);
emit_insn
(
gen_cmp_ne_small_const_insn
(
tmp
,
x
,
y
));
x
=
tmp
;
y
=
const0_rtx
;
}
else
if
(
CONSTANT_P
(
y
))
/* reg equal to const. */
{
rtx
tmp
=
force_reg
(
GET_MODE
(
x
),
y
);
y
=
tmp
;
}
if
(
register_operand
(
y
,
SImode
)
/* reg equal to reg. */
||
y
==
const0_rtx
)
/* req equal to zero. */
{
emit_insn
(
gen_cmp_eqsi_insn
(
x
,
y
));
return
gen_rtx
(
code
,
mode
,
cc_reg
,
const0_rtx
);
}
break
;
case
LT
:
if
(
register_operand
(
y
,
SImode
)
||
(
GET_CODE
(
y
)
==
CONST_INT
&&
CMP_INT16_P
(
INTVAL
(
y
))))
{
rtx
tmp
=
gen_reg_rtx
(
SImode
);
/* reg compared to reg. */
switch
(
code
)
{
case
LT
:
emit_insn
(
gen_cmp_ltsi_insn
(
x
,
y
));
code
=
EQ
;
break
;
case
LE
:
if
(
y
==
const0_rtx
)
tmp
=
const1_rtx
;
else
emit_insn
(
gen_cmp_ne_small_const_insn
(
tmp
,
y
,
const1_rtx
));
emit_insn
(
gen_cmp_ltsi_insn
(
x
,
tmp
));
code
=
EQ
;
break
;
case
GT
:
if
(
GET_CODE
(
y
)
==
CONST_INT
)
tmp
=
gen_rtx
(
PLUS
,
SImode
,
y
,
const1_rtx
);
else
emit_insn
(
gen_cmp_ne_small_const_insn
(
tmp
,
y
,
const1_rtx
));
emit_insn
(
gen_cmp_ltsi_insn
(
x
,
tmp
));
code
=
NE
;
break
;
case
GE
:
emit_insn
(
gen_cmp_ltsi_insn
(
x
,
y
));
code
=
NE
;
break
;
default
:
abort
();
}
return
gen_rtx
(
code
,
mode
,
cc_reg
,
const0_rtx
);
}
break
;
case
LTU
:
if
(
register_operand
(
y
,
SImode
)
||
(
GET_CODE
(
y
)
==
CONST_INT
&&
CMP_INT16_P
(
INTVAL
(
y
))))
{
rtx
tmp
=
gen_reg_rtx
(
SImode
);
/* reg (unsigned) compared to reg. */
switch
(
code
)
{
case
LTU
:
emit_insn
(
gen_cmp_ltusi_insn
(
x
,
y
));
code
=
EQ
;
break
;
case
LEU
:
if
(
y
==
const0_rtx
)
tmp
=
const1_rtx
;
else
emit_insn
(
gen_cmp_ne_small_const_insn
(
tmp
,
y
,
const1_rtx
));
emit_insn
(
gen_cmp_ltusi_insn
(
x
,
tmp
));
code
=
EQ
;
break
;
case
GTU
:
if
(
GET_CODE
(
y
)
==
CONST_INT
)
tmp
=
gen_rtx
(
PLUS
,
SImode
,
y
,
const1_rtx
);
else
emit_insn
(
gen_cmp_ne_small_const_insn
(
tmp
,
y
,
const1_rtx
));
emit_insn
(
gen_cmp_ltusi_insn
(
x
,
tmp
));
code
=
NE
;
break
;
case
GEU
:
emit_insn
(
gen_cmp_ltusi_insn
(
x
,
y
));
code
=
NE
;
break
;
default
:
abort
();
}
return
gen_rtx
(
code
,
mode
,
cc_reg
,
const0_rtx
);
}
break
;
default
:
abort
();
}
}
else
if
(
!
TARGET_OLD_COMPARE
)
{
/* reg/reg equal comparison */
if
(
compare_code
==
EQ
...
...
@@ -950,12 +1118,13 @@ gen_compare (code, x, y)
/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */
int
function_arg_partial_nregs
(
cum
,
mode
,
type
,
named
)
function_arg_partial_nregs
(
cum
,
int_
mode
,
type
,
named
)
CUMULATIVE_ARGS
*
cum
;
enum
machine_mode
mode
;
int
int_
mode
;
tree
type
;
int
named
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
int
ret
;
int
size
=
(((
mode
==
BLKmode
&&
type
)
?
int_size_in_bytes
(
type
)
...
...
@@ -979,13 +1148,14 @@ function_arg_partial_nregs (cum, mode, type, named)
and mode MODE, and we rely on this fact. */
void
m32r_setup_incoming_varargs
(
cum
,
mode
,
type
,
pretend_size
,
no_rtl
)
m32r_setup_incoming_varargs
(
cum
,
int_
mode
,
type
,
pretend_size
,
no_rtl
)
CUMULATIVE_ARGS
*
cum
;
enum
machine_mode
mode
;
int
int_
mode
;
tree
type
;
int
*
pretend_size
;
int
no_rtl
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
int
first_anon_arg
;
if
(
no_rtl
)
...
...
@@ -1128,6 +1298,7 @@ struct m32r_frame_info
unsigned
int
args_size
;
/* # bytes that outgoing arguments take up */
unsigned
int
reg_size
;
/* # bytes needed to store regs */
unsigned
int
var_size
;
/* # bytes that variables take up */
unsigned
int
prolog_size
;
/* # bytes that the prologue takes up */
unsigned
int
gmask
;
/* mask of saved gp registers */
unsigned
int
save_fp
;
/* nonzero if fp must be saved */
unsigned
int
save_lr
;
/* nonzero if lr (return addr) must be saved */
...
...
@@ -1153,6 +1324,9 @@ static struct m32r_frame_info zero_frame_info;
#define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])
#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM])
#define SHORT_INSN_SIZE 2
/* size of small instructions */
#define LONG_INSN_SIZE 4
/* size of long instructions */
/* Return the bytes needed to compute the frame pointer from the current
stack pointer.
...
...
@@ -1164,7 +1338,7 @@ m32r_compute_frame_size (size)
{
int
regno
;
unsigned
int
total_size
,
var_size
,
args_size
,
pretend_size
,
extra_size
;
unsigned
int
reg_size
;
unsigned
int
reg_size
,
prolog_size
,
frame_size
;
unsigned
int
gmask
;
enum
m32r_function_type
fn_type
;
int
interrupt_p
;
...
...
@@ -1175,6 +1349,7 @@ m32r_compute_frame_size (size)
extra_size
=
FIRST_PARM_OFFSET
(
0
);
total_size
=
extra_size
+
pretend_size
+
args_size
+
var_size
;
reg_size
=
0
;
prolog_size
=
0
;
gmask
=
0
;
/* See if this is an interrupt handler. Call used registers must be saved
...
...
@@ -1204,6 +1379,33 @@ m32r_compute_frame_size (size)
handler will do the right thing if this changes total_size. */
total_size
=
M32R_STACK_ALIGN
(
total_size
);
/* Calculate prologue size. Obviously any changes to
m32r_output_function_prologue must be mirrored here. */
if
(
pretend_size
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* addi sp,-pretend_size */
prolog_size
+=
SHORT_INSN_SIZE
*
(
reg_size
/
UNITS_PER_WORD
);
/* pushes */
frame_size
=
total_size
-
(
pretend_size
+
reg_size
);
if
(
frame_size
==
0
)
;
/* nothing to do */
else
if
(
frame_size
<=
128
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* addi sp,-<frame> */
else
{
if
((
prolog_size
%
LONG_INSN_SIZE
)
!=
0
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* nop */
if
(
frame_size
<=
32768
)
prolog_size
+=
LONG_INSN_SIZE
;
/* add3 sp,sp,-<frame> */
else
prolog_size
+=
(
LONG_INSN_SIZE
/* ld24 tmp,<frame>/sub sp,tmp */
+
SHORT_INSN_SIZE
);
}
if
(
frame_pointer_needed
)
prolog_size
+=
SHORT_INSN_SIZE
;
/* mv fp,sp */
/* Save computed information. */
current_frame_info
.
total_size
=
total_size
;
current_frame_info
.
extra_size
=
extra_size
;
...
...
@@ -1211,6 +1413,7 @@ m32r_compute_frame_size (size)
current_frame_info
.
var_size
=
var_size
;
current_frame_info
.
args_size
=
args_size
;
current_frame_info
.
reg_size
=
reg_size
;
current_frame_info
.
prolog_size
=
prolog_size
;
current_frame_info
.
gmask
=
gmask
;
current_frame_info
.
initialized
=
reload_completed
;
...
...
@@ -1218,7 +1421,22 @@ m32r_compute_frame_size (size)
return
total_size
;
}
/* Set up the stack and frame pointer (if desired) for the function. */
/* When the `length' insn attribute is used, this macro specifies the
value to be assigned to the address of the first insn in a
function. If not specified, 0 is used. */
int
m32r_first_insn_address
()
{
if
(
!
current_frame_info
.
initialized
)
m32r_compute_frame_size
(
get_frame_size
());
return
current_frame_info
.
prolog_size
;
}
/* Set up the stack and frame pointer (if desired) for the function.
Note, if this is changed, you need to mirror the changes in
m32r_compute_frame_size which calculates the prolog size. */
void
m32r_output_function_prologue
(
file
,
size
)
...
...
@@ -1239,17 +1457,19 @@ m32r_output_function_prologue (file, size)
ASM_COMMENT_START
);
}
total_size
=
(
!
current_frame_info
.
initialized
?
m32r_compute_frame_size
(
size
)
:
current_frame_info
.
total_size
);
/* This is only for the human reader. */
fprintf
(
file
,
"
\t
%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d
\n
"
,
ASM_COMMENT_START
,
ASM_COMMENT_START
,
fprintf
(
file
,
"
\t
%s BEGIN PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d, prolog= %d
\n
"
,
ASM_COMMENT_START
,
current_frame_info
.
var_size
,
current_frame_info
.
reg_size
/
4
,
current_frame_info
.
args_size
,
current_frame_info
.
extra_size
);
total_size
=
(
!
current_frame_info
.
initialized
?
m32r_compute_frame_size
(
size
)
:
current_frame_info
.
total_size
);
current_frame_info
.
extra_size
,
current_frame_info
.
prolog_size
);
/* These cases shouldn't happen. Catch them now. */
if
(
total_size
==
0
&&
gmask
)
...
...
@@ -1767,3 +1987,127 @@ m32r_print_operand_address (file, addr)
break
;
}
}
/* Return true if the operands are the constants 0 and 1. */
int
zero_and_one
(
operand1
,
operand2
)
rtx
operand1
;
rtx
operand2
;
{
return
GET_CODE
(
operand1
)
==
CONST_INT
&&
GET_CODE
(
operand2
)
==
CONST_INT
&&
(
((
INTVAL
(
operand1
)
==
0
)
&&
(
INTVAL
(
operand2
)
==
1
))
||
((
INTVAL
(
operand1
)
==
1
)
&&
(
INTVAL
(
operand2
)
==
0
)));
}
/* Return non-zero if the operand is suitable for use in a conditional move sequence. */
int
conditional_move_operand
(
operand
,
int_mode
)
rtx
operand
;
int
int_mode
;
{
enum
machine_mode
mode
=
(
enum
machine_mode
)
int_mode
;
/* Only defined for simple integers so far... */
if
(
mode
!=
SImode
&&
mode
!=
HImode
&&
mode
!=
QImode
)
return
FALSE
;
/* At the moment we can hanndle moving registers and loading constants. */
/* To be added: Addition/subtraction/bitops/multiplication of registers. */
switch
(
GET_CODE
(
operand
))
{
case
REG
:
return
1
;
case
CONST_INT
:
return
INT8_P
(
INTVAL
(
operand
));
default
:
#if 0
fprintf (stderr, "Test for cond move op of type: %s\n",
GET_RTX_NAME (GET_CODE (operand)));
#endif
return
0
;
}
}
/* Return true if the code is a test of the carry bit */
int
carry_compare_operand
(
op
,
int_mode
)
rtx
op
;
int
int_mode
;
{
rtx
x
;
if
(
GET_MODE
(
op
)
!=
CCmode
&&
GET_MODE
(
op
)
!=
VOIDmode
)
return
FALSE
;
if
(
GET_CODE
(
op
)
!=
NE
&&
GET_CODE
(
op
)
!=
EQ
)
return
FALSE
;
x
=
XEXP
(
op
,
0
);
if
(
GET_CODE
(
x
)
!=
REG
||
REGNO
(
x
)
!=
CARRY_REGNUM
)
return
FALSE
;
x
=
XEXP
(
op
,
1
);
if
(
GET_CODE
(
x
)
!=
CONST_INT
||
INTVAL
(
x
)
!=
0
)
return
FALSE
;
return
TRUE
;
}
/* Generate the correct assembler code to handle the conditional loading of a
value into a register. It is known that the operands satisfy the
conditional_move_operand() function above. The destination is operand[0].
The condition is operand [1]. The 'true' value is operand [2] and the
'false' value is operand [3]. */
char
*
emit_cond_move
(
operands
,
insn
)
rtx
*
operands
;
rtx
insn
;
{
static
char
buffer
[
100
];
buffer
[
0
]
=
0
;
/* Destination must be a register. */
if
(
GET_CODE
(
operands
[
0
])
!=
REG
)
abort
();
if
(
!
conditional_move_operand
(
operands
[
2
],
SImode
))
abort
();
if
(
!
conditional_move_operand
(
operands
[
3
],
SImode
))
abort
();
/* Check to see if the test is reversed. */
if
(
GET_CODE
(
operands
[
1
])
==
NE
)
{
rtx
tmp
=
operands
[
2
];
operands
[
2
]
=
operands
[
3
];
operands
[
3
]
=
tmp
;
}
/* Catch a special case where 0 or 1 is being loaded into the destination.
Since we already have these values in the C bit we can use a special
instruction. */
if
(
zero_and_one
(
operands
[
2
],
operands
[
3
]))
{
char
*
dest
=
reg_names
[
REGNO
(
operands
[
0
])];
sprintf
(
buffer
,
"mvfc %s, cbr"
,
dest
);
/* If the true value was '0' then we need to invert the results of the move. */
if
(
INTVAL
(
operands
[
2
])
==
0
)
sprintf
(
buffer
+
strlen
(
buffer
),
"
\n\t
xor3 %s, %s, #1"
,
dest
,
dest
);
return
buffer
;
}
return
buffer
;
}
gcc/config/m32r/m32r.h
View file @
2b7972b0
/* Definitions of target machine for GNU compiler, Mitsubishi M32R cpu.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 1996, 1997
, 1998
Free Software Foundation, Inc.
This file is part of GNU CC.
...
...
@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION fprintf (stderr, " (m32r)")
/* Switch Recognition by gcc.c. Add -G xx support */
#undef SWITCH_TAKES_ARG
...
...
@@ -48,17 +49,18 @@ Boston, MA 02111-1307, USA. */
/* __M32R__ is defined by the existing compiler so we use that. */
#define CPP_PREDEFINES "-Acpu(m32r) -Amachine(m32r) -D__M32R__"
/* Additional flags for the preprocessor. */
#define CPP_SPEC ""
#define CC1_SPEC "%{G*}"
#undef ASM_SPEC
/* Options to pass on to the assembler. */
#undef ASM_SPEC
#define ASM_SPEC "%{v}"
#if 0 /* not supported yet */
#undef ASM_SPEC
#define ASM_SPEC "%{v} %{mrelax:-relax}"
#else
#define ASM_SPEC "%{v}"
#endif
#undef ASM_FINAL_SPEC
...
...
@@ -72,9 +74,11 @@ Boston, MA 02111-1307, USA. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC "%{!shared:crt0.o%s crtsysc.o%s} crtinit.o%s"
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtfini.o%s"
#undef LIB_SPEC
/* Run-time compilation parameters selecting different hardware subsets. */
...
...
@@ -105,6 +109,10 @@ extern int target_flags;
#define TARGET_OLD_COMPARE_MASK 8
#define TARGET_OLD_COMPARE (target_flags & TARGET_OLD_COMPARE_MASK)
/* Target machine to compile for. */
#define TARGET_M32R 1
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
...
...
@@ -147,6 +155,8 @@ extern int target_flags;
extern
char
*
m32r_model_string
;
extern
char
*
m32r_sdata_string
;
#define TARGET_OPTIONS \
{ \
{ "model=", &m32r_model_string }, \
...
...
@@ -239,10 +249,10 @@ extern enum m32r_sdata m32r_sdata;
#define M32R_SDATA_DEFAULT "none"
/* Define this macro as a C expression for the initializer of an array of
string to tell the driver program which options are defaults for this
string
s
to tell the driver program which options are defaults for this
target and thus do not need to be handled specially when using
`MULTILIB_OPTIONS'. */
#define MULTILIB_DEFAULTS { "mmodel=small" }
#define MULTILIB_DEFAULTS { "mmodel=small"
, "m32r"
}
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
...
...
@@ -253,8 +263,6 @@ extern enum m32r_sdata m32r_sdata;
Don't use this macro to turn on various extra optimizations for
`-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
extern
void
m32r_init
();
#define OVERRIDE_OPTIONS \
do { \
/* These need to be done at start up. It's convenient to do them here. */
\
...
...
@@ -404,7 +412,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */
#define FIRST_PSEUDO_REGISTER 18
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
...
...
@@ -420,6 +428,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
16 - arg pointer
17 - carry flag
By default, the extension registers are not available. */
#define FIXED_REGISTERS \
...
...
@@ -427,6 +436,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 0, 1, \
1, 0 }
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
...
...
@@ -439,6 +449,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
/* Zero or more C statements that may conditionally modify two variables
`fixed_regs' and `call_used_regs' (both of type `char []') after they
have been initialized from the two preceding macros.
...
...
@@ -531,11 +542,12 @@ enum reg_class {
#define REG_CLASS_CONTENTS \
{ {0}, {0x20000}, {0x1ffff}, {0x3ffff} }
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
extern
enum
reg_class
m32r_regno_reg_class
[];
extern
enum
reg_class
m32r_regno_reg_class
[
FIRST_PSEUDO_REGISTER
];
#define REGNO_REG_CLASS(REGNO) \
(m32r_regno_reg_class[REGNO])
...
...
@@ -622,7 +634,11 @@ extern enum reg_class m32r_regno_reg_class[];
C. If C is not defined as an extra constraint, the value returned should
be 0 regardless of VALUE. */
/* Q is for symbolic addresses loadable with ld24.
R is for symbolic addresses when ld24 can't be used. */
R is for symbolic addresses when ld24 can't be used.
S is for an 8 bit signed integer in the range +128 to -127 */
#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128)
#define EXTRA_CONSTRAINT(VALUE, C) \
((C) == 'Q' \
? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
...
...
@@ -630,6 +646,8 @@ extern enum reg_class m32r_regno_reg_class[];
: (C) == 'R' \
? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
|| addr32_operand (VALUE, VOIDmode)) \
: (C) == 'S' \
? ((GET_CODE (VALUE) == CONST_INT) && INVERTED_SIGNED_8BIT (INTVAL (VALUE))) \
: 0)
/* Stack layout and stack pointer usage. */
...
...
@@ -717,6 +735,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
#define CARRY_REGNUM 17
#define M32R_MAX_INT_REGS 16
#define GPR_P(REGNO) ((unsigned) (REGNO) < M32R_MAX_INT_REGS)
/* Eliminating the frame and arg pointers. */
...
...
@@ -907,7 +926,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
compiler when this occurs, and how many of the words should go in
registers. */
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
function_arg_partial_nregs (&CUM,
(int)
MODE, TYPE, NAMED)
/* A C expression that indicates when an argument must be passed by
reference. If nonzero for an argument, a copy of that argument is
...
...
@@ -1218,9 +1237,8 @@ do { \
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
extern
enum
machine_mode
m32r_select_cc_mode
();
#define SELECT_CC_MODE(OP, X, Y) \
m32r_select_cc_mode (OP, X, Y
)
((enum machine_mode)m32r_select_cc_mode ((int)OP, X, Y)
)
/* Return non-zero if SELECT_CC_MODE will never return MODE for a
floating point inequality comparison. */
...
...
@@ -1313,6 +1331,38 @@ m32r_select_cc_mode (OP, X, Y)
the improvement wasn't significant and in a couple of cases caused a
significant de-optimization. */
/* #define ENABLE_REGMOVE_PASS */
/* A C statement (sans semicolon) to update the integer variable COST based on
the relationship between INSN that is dependent on DEP_INSN through the
dependence LINK. The default is to make no adjustment to COST. This can be
used for example to specify to the scheduler that an output- or
anti-dependence does not incur the same cost as a data-dependence. */
/* #define ADJUST_COST(INSN,LINK,DEP_INSN,COST) \
(COST) = m32r_adjust_cost (INSN, LINK, DEP_INSN, COST) */
/* A C statement (sans semicolon) to update the integer scheduling
priority `INSN_PRIORITY(INSN)'. Reduce the priority to execute
the INSN earlier, increase the priority to execute INSN later.
Do not define this macro if you do not need to adjust the
scheduling priorities of insns. */
/* #define ADJUST_PRIORITY (INSN) */
/* Macro to determine whether the Haifa scheduler is used. */
#ifdef HAIFA
#define HAIFA_P 1
#else
#define HAIFA_P 0
#endif
/* Indicate how many instructions can be issued at the same time. */
#define ISSUE_RATE 2
/* When the `length' insn attribute is used, this macro specifies the
value to be assigned to the address of the first insn in a
function. If not specified, 0 is used. */
#define FIRST_INSN_ADDRESS m32r_first_insn_address ()
/* Section selection. */
...
...
@@ -1344,7 +1394,7 @@ DTORS_SECTION_FUNCTION \
SDATA_SECTION_FUNCTION \
SBSS_SECTION_FUNCTION
#define SDATA_SECTION_FUNCTION
\
#define SDATA_SECTION_FUNCTION
\
void \
sdata_section () \
{ \
...
...
@@ -1355,7 +1405,7 @@ sdata_section () \
} \
} \
#define SBSS_SECTION_FUNCTION
\
#define SBSS_SECTION_FUNCTION
\
void \
sbss_section () \
{ \
...
...
@@ -1429,7 +1479,6 @@ extern void m32r_select_section ();
|| MEDIUM_NAME_P (SYMBOL_NAME) \
|| LARGE_NAME_P (SYMBOL_NAME))
extern
void
m32r_encode_section_info
();
#define ENCODE_SECTION_INFO(DECL) m32r_encode_section_info (DECL)
/* Decode SYM_NAME and store the real name part in VAR, sans
...
...
@@ -1487,7 +1536,6 @@ do { \
/* Control the assembler format that we output. */
/* Output at beginning of assembler file. */
extern
void
m32r_asm_file_start
();
#define ASM_FILE_START(FILE) m32r_asm_file_start (FILE)
/* A C string constant describing how to begin a comment in the target
...
...
@@ -1582,7 +1630,7 @@ do { \
#undef ASM_OUTPUT_LABELREF
#define ASM_OUTPUT_LABELREF(FILE, NAME) \
do { \
char *real_name; \
char *
real_name; \
STRIP_NAME_ENCODING (real_name, (NAME)); \
fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name); \
} while (0)
...
...
@@ -1713,8 +1761,6 @@ do { \
handling the required alignment of the variable. The alignment is
specified as the number of bits. */
extern void sbss_section ();
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
...
...
@@ -1833,35 +1879,146 @@ do { \
/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
is a valid machine specific attribute for DECL.
The attributes in ATTRIBUTES have previously been assigned to TYPE. */
extern
int
m32r_valid_machine_attribute
();
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
m32r_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
/* A C expression that returns zero if the attributes on TYPE1 and TYPE2 are
incompatible, one if they are compatible, and two if they are
nearly compatible (which causes a warning to be generated). */
extern
int
m32r_comp_type_attributes
();
#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
m32r_comp_type_attributes (TYPE1, TYPE2)
/* Give newly defined TYPE some default attributes. */
extern
void
m32r_set_default_type_attributes
();
#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
m32r_set_default_type_attributes (TYPE)
/* Define the information needed to generate branch and scc 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
*
m32r_compare_op0
,
*
m32r_compare_op1
;
/* Define the function that build the compare insn for scc and bcc. */
extern
struct
rtx_def
*
gen_compare
();
extern
struct
rtx_def
*
m32r_compare_op0
;
extern
struct
rtx_def
*
m32r_compare_op1
;
/* M32R function types. */
enum
m32r_function_type
{
enum
m32r_function_type
{
M32R_FUNCTION_UNKNOWN
,
M32R_FUNCTION_NORMAL
,
M32R_FUNCTION_INTERRUPT
};
#define M32R_INTERRUPT_P(TYPE) \
((TYPE) == M32R_FUNCTION_INTERRUPT)
/* Compute the type of a function from its DECL. */
enum
m32r_function_type
m32r_compute_function_type
();
/* Define this if you have defined special-purpose predicates in the
file `MACHINE.c'. This macro is called within an initializer of an
array of structures. The first field in the structure is the name
of a predicate and the second field is an array of rtl codes. For
each predicate, list all rtl codes that can be in expressions
matched by the predicate. The list should have a trailing comma. */
#define PREDICATE_CODES \
{ "conditional_move_operand", { REG, SUBREG, CONST_INT }}, \
{ "carry_compare_operand", { EQ, NE }}, \
{ "eqne_comparison_operator", { EQ, NE }}, \
{ "signed_comparison_operator", { EQ, NE, LT, LE, GT, GE }}, \
{ "move_dest_operand", { REG, SUBREG, MEM }}, \
{ "move_src_operand", { REG, SUBREG, MEM, CONST_INT, \
CONST_DOUBLE, LABEL_REF, CONST, \
SYMBOL_REF }}, \
{ "move_double_src_operand", { REG, SUBREG, MEM, CONST_INT, \
CONST_DOUBLE }}, \
{ "two_insn_const_operand", { CONST_INT }}, \
{ "symbolic_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
{ "reg_or_int16_operand", { REG, SUBREG, CONST_INT }}, \
{ "reg_or_uint16_operand", { REG, SUBREG, CONST_INT }}, \
{ "reg_or_cmp_int16_operand", { REG, SUBREG, CONST_INT }}, \
{ "reg_or_zero_operand", { REG, SUBREG, CONST_INT }}, \
{ "cmp_int16_operand", { CONST_INT }}, \
{ "call_address_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
{ "small_insn_p", { INSN, CALL_INSN, JUMP_INSN }}, \
{ "large_insn_p", { INSN, CALL_INSN, JUMP_INSN }},
/* Functions declared in m32r.c */
#ifndef PROTO
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
#define PROTO(ARGS) ARGS
#else
#define PROTO(ARGS) ()
#endif
#endif
#ifdef BUFSIZE
/* stdio.h has been included, ok to use FILE * */
#define STDIO_PROTO(ARGS) PROTO(ARGS)
#else
#define STDIO_PROTO(ARGS) ()
#endif
#ifndef TREE_CODE
union
tree_node
;
#define Tree union tree_node *
#else
#define Tree tree
#endif
#ifndef RTX_CODE
struct
rtx_def
;
#define Rtx struct rtx_def *
#else
#define Rtx rtx
#endif
extern
void
sbss_section
PROTO
((
void
));
extern
void
sdata_section
PROTO
((
void
));
extern
void
m32r_init
PROTO
((
void
));
extern
int
m32r_valid_machine_decl_attribute
PROTO
((
Tree
,
Tree
,
Tree
,
Tree
));
extern
int
m32r_comp_type_attributes
PROTO
((
Tree
,
Tree
));
extern
void
m32r_select_section
PROTO
((
Tree
,
int
));
extern
void
m32r_encode_section_info
PROTO
((
Tree
));
extern
void
m32r_init_expanders
PROTO
((
void
));
extern
int
call_address_operand
PROTO
((
Rtx
,
int
));
extern
int
call_operand
PROTO
((
Rtx
,
int
));
extern
int
symbolic_operand
PROTO
((
Rtx
,
int
));
extern
int
small_data_operand
PROTO
((
Rtx
,
int
));
extern
int
addr24_operand
PROTO
((
Rtx
,
int
));
extern
int
addr32_operand
PROTO
((
Rtx
,
int
));
extern
int
call26_operand
PROTO
((
Rtx
,
int
));
extern
int
seth_add3_operand
PROTO
((
Rtx
,
int
));
extern
int
cmp_int16_operand
PROTO
((
Rtx
,
int
));
extern
int
uint16_operand
PROTO
((
Rtx
,
int
));
extern
int
reg_or_int16_operand
PROTO
((
Rtx
,
int
));
extern
int
reg_or_uint16_operand
PROTO
((
Rtx
,
int
));
extern
int
reg_or_cmp_nt16_operand
PROTO
((
Rtx
,
int
));
extern
int
two_insn_const_operand
PROTO
((
Rtx
,
int
));
extern
int
move_src_operand
PROTO
((
Rtx
,
int
));
extern
int
move_double_src_operand
PROTO
((
Rtx
,
int
));
extern
int
move_dest_operand
PROTO
((
Rtx
,
int
));
extern
int
easy_di_const
PROTO
((
Rtx
));
extern
int
easy_df_const
PROTO
((
Rtx
));
extern
int
eqne_comparison_operator
PROTO
((
Rtx
,
int
));
extern
int
signed_comparison_operator
PROTO
((
Rtx
,
int
));
extern
int
memreg_operand
PROTO
((
Rtx
,
int
));
extern
int
small_insn_p
PROTO
((
Rtx
,
int
));
extern
int
large_insn_p
PROTO
((
Rtx
,
int
));
extern
int
m32r_select_cc_mode
PROTO
((
int
,
Rtx
,
Rtx
));
extern
Rtx
gen_compare
PROTO
((
int
,
Rtx
,
Rtx
,
int
));
extern
int
function_arg_partial_nregs
PROTO
((
CUMULATIVE_ARGS
*
,
int
,
Tree
,
int
));
extern
void
m32r_setup_incoming_varargs
PROTO
((
CUMULATIVE_ARGS
*
,
int
,
Tree
,
int
*
,
int
));
extern
int
m32r_address_code
PROTO
((
Rtx
));
extern
enum
m32r_function_type
m32r_compute_function_type
PROTO
((
Tree
));
extern
unsigned
m32r_compute_frame_size
PROTO
((
int
));
extern
int
m32r_first_insn_address
PROTO
((
void
));
extern
void
m32r_output_function_prologue
STDIO_PROTO
((
FILE
*
,
int
));
extern
void
m32r_output_function_epilogue
STDIO_PROTO
((
FILE
*
,
int
));
extern
void
m32r_finalize_pic
PROTO
((
void
));
extern
void
m32r_initialize_trampoline
PROTO
((
Rtx
,
Rtx
,
Rtx
));
extern
void
m32r_asm_file_start
STDIO_PROTO
((
FILE
*
));
extern
void
m32r_print_operand
STDIO_PROTO
((
FILE
*
,
Rtx
,
int
));
extern
void
m32r_print_operand_address
STDIO_PROTO
((
FILE
*
,
Rtx
));
extern
int
zero_and_one
PROTO
((
Rtx
,
Rtx
));
extern
int
conditional_move_operand
PROTO
((
Rtx
,
int
));
extern
int
carry_compare_operand
PROTO
((
Rtx
,
int
));
extern
char
*
emit_cond_move
PROTO
((
Rtx
*
,
Rtx
));
/* Needed by a peephole optimisation. */
#define PRESERVE_DEATH_INFO_REGNO_P(regno) (regno < FIRST_PSEUDO_REGISTER)
gcc/config/m32r/m32r.md
View file @
2b7972b0
;; Machine description of the Mitsubishi M32R cpu for GNU C compiler
;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
;; Copyright (C) 1996, 1997
, 1998
Free Software Foundation, Inc.
;; This file is part of GNU CC.
...
...
@@ -65,11 +65,135 @@
(define_asm_attributes
[
(set_attr "length" "4")
(set_attr "type" "multi")])
;; Whether an instruction is 16-bit or 32-bit
(define_attr "insn_size" "short,long"
(if_then_else (eq_attr "length" "2")
(const_string "short")
(const_string "long")))
(define_attr "m32r" "no,yes"
(const (symbol_ref "(TARGET_M32R != 0)")))
;; ::::::::::::::::::::
;; ::
;; :: Function Units
;; ::
;; ::::::::::::::::::::
;; On most RISC machines, there are instructions whose results are not
;; available for a specific number of cycles. Common cases are instructions
;; that load data from memory. On many machines, a pipeline stall will result
;; if the data is referenced too soon after the load instruction.
;; In addition, many newer microprocessors have multiple function units,
;; usually one for integer and one for floating point, and often will incur
;; pipeline stalls when a result that is needed is not yet ready.
;; The descriptions in this section allow the specification of how much time
;; must elapse between the execution of an instruction and the time when its
;; result is used. It also allows specification of when the execution of an
;; instruction will delay execution of similar instructions due to function
;; unit conflicts.
;; For the purposes of the specifications in this section, a machine is divided
;; into "function units", each of which execute a specific class of
;; instructions in first-in-first-out order. Function units that accept one
;; instruction each cycle and allow a result to be used in the succeeding
;; instruction (usually via forwarding) need not be specified. Classic RISC
;; microprocessors will normally have a single function unit, which we can call
;;
`memory'. The newer "superscalar" processors will often have function units
;; for floating point operations, usually at least a floating point adder and
;; multiplier.
;; Each usage of a function units by a class of insns is specified with a
;; `
define_function_unit' expression, which looks like this:
;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY TEST READY-DELAY
;; ISSUE-DELAY
[
CONFLICT-LIST
]
)
;; NAME is a string giving the name of the function unit.
;; MULTIPLICITY is an integer specifying the number of identical units in the
;; processor. If more than one unit is specified, they will be scheduled
;; independently. Only truly independent units should be counted; a pipelined
;; unit should be specified as a single unit. (The only common example of a
;; machine that has multiple function units for a single instruction class that
;; are truly independent and not pipelined are the two multiply and two
;; increment units of the CDC 6600.)
;; SIMULTANEITY specifies the maximum number of insns that can be executing in
;; each instance of the function unit simultaneously or zero if the unit is
;; pipelined and has no limit.
;; All
`define_function_unit' definitions referring to function unit NAME must
;; have the same name and values for MULTIPLICITY and SIMULTANEITY.
;; TEST is an attribute test that selects the insns we are describing in this
;; definition. Note that an insn may use more than one function unit and a
;; function unit may be specified in more than one `
define_function_unit'.
;; READY-DELAY is an integer that specifies the number of cycles after which
;; the result of the instruction can be used without introducing any stalls.
;; ISSUE-DELAY is an integer that specifies the number of cycles after the
;; instruction matching the TEST expression begins using this unit until a
;; subsequent instruction can begin. A cost of N indicates an N-1 cycle delay.
;; A subsequent instruction may also be delayed if an earlier instruction has a
;; longer READY-DELAY value. This blocking effect is computed using the
;; SIMULTANEITY, READY-DELAY, ISSUE-DELAY, and CONFLICT-LIST terms. For a
;; normal non-pipelined function unit, SIMULTANEITY is one, the unit is taken
;; to block for the READY-DELAY cycles of the executing insn, and smaller
;; values of ISSUE-DELAY are ignored.
;; CONFLICT-LIST is an optional list giving detailed conflict costs for this
;; unit. If specified, it is a list of condition test expressions to be
;; applied to insns chosen to execute in NAME following the particular insn
;; matching TEST that is already executing in NAME. For each insn in the list,
;; ISSUE-DELAY specifies the conflict cost; for insns not in the list, the cost
;; is zero. If not specified, CONFLICT-LIST defaults to all instructions that
;; use the function unit.
;; Typical uses of this vector are where a floating point function unit can
;; pipeline either single- or double-precision operations, but not both, or
;; where a memory unit can pipeline loads, but not stores, etc.
;; As an example, consider a classic RISC machine where the result of a load
;; instruction is not available for two cycles (a single "delay" instruction is
;; required) and where only one load instruction can be executed
;; simultaneously. This would be specified as:
;; (define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)
;; For the case of a floating point function unit that can pipeline
;; either single or double precision, but not both, the following could be
;; specified:
;;
;; (define_function_unit "fp" 1 0
;; (eq_attr "type" "sp_fp") 4 4
;;
[
(eq_attr "type" "dp_fp")
]
)
;;
;; (define_function_unit "fp" 1 0
;; (eq_attr "type" "dp_fp") 4 4
;;
[
(eq_attr "type" "sp_fp")
]
)
;; Note: The scheduler attempts to avoid function unit conflicts and uses all
;; the specifications in the
`define_function_unit' expression. It has
;; recently come to our attention that these specifications may not allow
;; modeling of some of the newer "superscalar" processors that have insns using
;; multiple pipelined units. These insns will cause a potential conflict for
;; the second unit used during their execution and there is no way of
;; representing that conflict. We welcome any examples of how function unit
;; conflicts work in such processors and suggestions for their representation.
;; Function units of the M32R
;; Units that take one cycle do not need to be specified.
;; (define_function_unit {name} {
num-units} {n-users
} {test}
;; (define_function_unit {name} {
multiplicity} {simulataneity
} {test}
;; {ready-delay} {issue-delay} [{conflict-list}])
;; References to loaded registers should wait a cycle.
...
...
@@ -94,6 +218,7 @@
(not (eq_attr "length" "2"))
1 0
[(eq_attr "length" "2")])
;; Expand prologue as RTL
;; ??? Unfinished.
...
...
@@ -915,6 +1040,7 @@
DONE;
}")
;; The cmp_xxx_insn patterns set the condition bit to the result of the
;; comparison. There isn't a "compare equal" instruction so cmp_eqsi_insn
;; is quite inefficient. However, it is rarely used.
...
...
@@ -924,10 +1050,23 @@
(eq:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_cmp_int16_operand" "r,P")))
(clobber (match_scratch:SI 2 "=&r,&r"))]
"TARGET_OLD_COMPARE"
"@
mv %2,%0
\;
sub %2,%1
\;
cmpui %2,#1
add3 %2,%0,%#%N1
\;
cmpui %2,#1"
""
"*
{
if (which_alternative == 0)
{
return \"mv %2,%0\;sub %2,%1\;cmpui %2,#1\";
}
else
{
if (INTVAL (operands [1]) == 0)
return \"cmpui %0, #1\";
else if (REGNO (operands [2]) == REGNO (operands [0]))
return \"addi %0,%#%N1\;cmpui %2,#1\";
else
return \"add3 %2,%0,%#%N1\;cmpui %2,#1\";
}
}"
[(set_attr "type" "compare,compare")
(set_attr "length" "8,8")])
...
...
@@ -939,17 +1078,23 @@
"@
cmp %0,%1
cmpi %0,%#%1"
[
(set_attr "type" "compare")
]
)
[(set_attr "type" "compare,compare")
(set_attr "length" "4,6")])
(define_insn "cmp_ltusi_insn"
[(set (reg:CC 17)
(ltu:CC (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "reg_or_uint16_operand" "r,K")))]
""
"@
cmpu %0,%1
cmpui %0,%#%1"
[
(set_attr "type" "compare")
]
)
"*
{
if (which_alternative == 0)
return \"cmpu %0,%1\";
else
return \"cmpui %0,%#%1\";
}"
[(set_attr "type" "compare")
(set_attr "length" "4,6")])
;; reg == small constant comparisons are best handled by putting the result
;; of the comparison in a tmp reg and then using beqz/bnez.
...
...
@@ -957,13 +1102,15 @@
;; it contains 0/non-zero.
(define_insn "cmp_ne_small_const_insn"
[
(set (match_operand:SI 0 "register_operand" "=r")
(ne:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "cmp_int16_operand" "P")))]
[(set (match_operand:SI 0 "register_operand" "=r
,r
")
(ne:SI (match_operand:SI 1 "register_operand" "
0,
r")
(match_operand:SI 2 "cmp_int16_operand" "
S,
P")))]
""
"add3 %0,%1,%#%N2"
"@
addi %0,%#%N2
add3 %0,%1,%#%N2"
[(set_attr "type" "compare")
(set_attr "length" "4")])
(set_attr "length" "
2,
4")])
;; These control RTL generation for conditional jump insns.
...
...
@@ -975,7 +1122,7 @@
""
"
{
operands
[
1
]
= gen_compare (
EQ, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)EQ, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bne"
...
...
@@ -986,7 +1133,7 @@
""
"
{
operands
[
1
]
= gen_compare (
NE, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)NE, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bgt"
...
...
@@ -997,7 +1144,7 @@
""
"
{
operands
[
1
]
= gen_compare (
GT, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)GT, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "ble"
...
...
@@ -1008,7 +1155,7 @@
""
"
{
operands
[
1
]
= gen_compare (
LE, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)LE, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bge"
...
...
@@ -1019,7 +1166,7 @@
""
"
{
operands
[
1
]
= gen_compare (
GE, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)GE, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "blt"
...
...
@@ -1030,7 +1177,7 @@
""
"
{
operands
[
1
]
= gen_compare (
LT, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)LT, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bgtu"
...
...
@@ -1041,7 +1188,7 @@
""
"
{
operands
[
1
]
= gen_compare (
GTU, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)GTU, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bleu"
...
...
@@ -1052,7 +1199,7 @@
""
"
{
operands
[
1
]
= gen_compare (
LEU, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)LEU, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bgeu"
...
...
@@ -1063,7 +1210,7 @@
""
"
{
operands
[
1
]
= gen_compare (
GEU, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)GEU, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
(define_expand "bltu"
...
...
@@ -1074,7 +1221,7 @@
""
"
{
operands
[
1
]
= gen_compare (
LTU, m32r_compare_op0, m32r_compare_op1
);
operands[1] = gen_compare (
(int)LTU, m32r_compare_op0, m32r_compare_op1, FALSE
);
}")
;; Now match both normal and inverted jump.
...
...
@@ -1088,10 +1235,11 @@
""
"*
{
if (GET_CODE (operands
[
1
]
) == NE)
return
\"
bc %l0
\"
;
else
return
\"
bnc %l0
\"
;
static char instruction[40];
sprintf (instruction, \"%s%s %%l0\",
(GET_CODE (operands[1]) == NE) ? \"bc\" : \"bnc\",
(get_attr_length (insn) == 2) ? \".s\" : \"\");
return instruction;
}"
[(set_attr "type" "branch")
; We use 400/800 instead of 512,1024 to account for inaccurate insn
...
...
@@ -1116,10 +1264,11 @@
""
"*
{
if (GET_CODE (operands
[
1
]
) == EQ)
return
\"
bc %l0
\"
;
else
return
\"
bnc %l0
\"
;
static char instruction[40];
sprintf (instruction, \"%s%s %%l0\",
(GET_CODE (operands[1]) == EQ) ? \"bc\" : \"bnc\",
(get_attr_length (insn) == 2) ? \".s\" : \"\");
return instruction;
}"
[(set_attr "type" "branch")
; We use 400/800 instead of 512,1024 to account for inaccurate insn
...
...
@@ -1452,6 +1601,51 @@
"
*
return
\"
nop ; flush-icache
\"
;"
[
(set_attr "type" "misc")
]
)
;; Conditional move instructions
;; Based on those done for the d10v
(define_expand "movsicc"
[
(set (match_operand:SI 0 "register_operand" "r")
(if_then_else:SI (match_operand 1 "" "")
(match_operand:SI 2 "conditional_move_operand" "O")
(match_operand:SI 3 "conditional_move_operand" "O")
)
)
]
""
"
{
if (! zero_and_one (operands
[
2
]
, operands
[
3
]
))
FAIL;
/
* Generate the comparision that will set the carry flag. *
/
operands
[
1
]
= gen_compare ((int)GET_CODE (operands
[
1
]
), m32r_compare_op0,
m32r_compare_op1, TRUE);
/
* See other movsicc pattern below for reason why. *
/
emit_insn (gen_blockage());
}")
;; Generate the conditional instructions based on how the carry flag is examined.
(define_insn "
*
movsicc_internal"
[
(set (match_operand:SI 0 "register_operand" "r")
(if_then_else:SI (match_operand 1 "carry_compare_operand" "")
(match_operand:SI 2 "conditional_move_operand" "O")
(match_operand:SI 3 "conditional_move_operand" "O")
)
)]
"zero_and_one (operands
[
2
]
, operands
[
3
]
)"
"
*
return emit_cond_move (operands, insn);"
[
(set_attr "type" "move")
(set_attr "length" "8")
]
)
;; Split up troublesome insns for better scheduling.
;; Peepholes go at the end.
...
...
@@ -1467,3 +1661,46 @@
"st %1,@+%0"
[
(set_attr "type" "store")
(set_attr "length" "2")])
;; This case is triggered by compiling this code:
;;
;; extern void sub(int
*
);
;; void main (void)
;; {
;; int i=2,j=3,k;
;; while (i < j) sub(
&k);
;; i = j / k;
;; sub(
&i);
;; i = j - k;
;; sub(
&i);
;; }
;;
;; Without the peephole the following assembler is generated for the
;; divide and subtract expressions:
;;
;; div r5,r4
;; mv r4,r5
;; st r4,@(4,sp)
;; bl sub
;;
;; Simialr code is produced for the subtract expression. With this
;; peephole the redundant move is eliminated.
;;
;; This optimisation onbly works if PRESERVE_DEATH_INFO_REGNO_P is
;; defined in m32r.h
(define_peephole
[
(set (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "register_operand" "r")
)
(set (mem:SI (plus: SI (match_operand:SI 2 "register_operand" "r")
(match_operand:SI 3 "immediate_operand" "J")))
(match_dup 0)
)
]
"dead_or_set_p (insn, operands
[
0
]
)"
"st %1,@(%3,%2)"
[
(set_attr "type" "store")
(set_attr "length" "4")
]
)
gcc/config/m32r/t-m32r
View file @
2b7972b0
...
...
@@ -39,6 +39,7 @@ crtfini.o: $(srcdir)/config/m32r/initfini.c $(GCC_PASSES) $(CONFIG_H)
-DCRT_FINI -finhibit-size-directive -fno-inline-functions \
-g0 -c $(srcdir)/config/m32r/initfini.c -o crtfini.o
# -mmodel={small,medium} requires separate libraries.
# We don't build libraries for the large model, instead we use the medium
# libraries. The only difference is that the large model can handle jumps
...
...
@@ -48,6 +49,7 @@ MULTILIB_OPTIONS = mmodel=small/mmodel=medium
MULTILIB_DIRNAMES = small medium
MULTILIB_MATCHES = mmodel?medium=mmodel?large
# Set MULTILIB_EXTRA_OPTS so shipped libraries have small data in .sdata and
# SHN_M32R_SCOMMON.
# This is important for objects referenced in system header files.
...
...
gcc/configure
View file @
2b7972b0
...
...
@@ -4580,7 +4580,7 @@ fi
if
[
x
$enable_haifa
=
x
]
then
case
$target
in
alpha
*
-
*
|
hppa1.?-
*
|
powerpc
*
-
*
|
rs6000-
*
|
*
sparc-
*
)
alpha
*
-
*
|
hppa1.?-
*
|
powerpc
*
-
*
|
rs6000-
*
|
*
sparc-
*
|
m32r
*
-
*
)
enable_haifa
=
yes
;;
esac
fi
...
...
gcc/configure.in
View file @
2b7972b0
...
...
@@ -2891,7 +2891,7 @@ fi
if [[ x$enable_haifa = x ]]
then
case $target in
alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*)
alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*
| m32r*-*
)
enable_haifa=yes;;
esac
fi
...
...
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