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
2861fe6d
Commit
2861fe6d
authored
Dec 24, 1991
by
Richard Stallman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial revision
From-SVN: r140
parent
a2b22788
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
667 additions
and
0 deletions
+667
-0
gcc/config/ns32k/ns32k.c
+667
-0
No files found.
gcc/config/ns32k/ns32k.c
0 → 100644
View file @
2861fe6d
/* Subroutines for assembler code output on the NS32000.
Copyright (C) 1988 Free Software Foundation, Inc.
This file is part of GNU CC.
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
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Some output-actions in ns32k.md need these. */
#include <stdio.h>
#include "config.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#ifdef OSF_OS
int
ns32k_num_files
=
0
;
#endif
void
trace
(
s
,
s1
,
s2
)
char
*
s
,
*
s1
,
*
s2
;
{
fprintf
(
stderr
,
s
,
s1
,
s2
);
}
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
int
hard_regno_mode_ok
(
regno
,
mode
)
int
regno
;
int
mode
;
{
switch
(
mode
)
{
case
QImode
:
case
HImode
:
case
PSImode
:
case
SImode
:
case
PDImode
:
case
VOIDmode
:
case
BLKmode
:
if
(
(
regno
<
8
)
||
(
regno
==
16
)
||
(
regno
==
17
)
)
{
return
(
1
);
}
else
{
return
(
0
);
}
case
DImode
:
if
(
(
regno
<
8
)
&&
((
regno
&
1
)
==
0
)
)
{
return
(
1
);
}
else
{
return
(
0
);
}
case
SFmode
:
case
SCmode
:
if
(
TARGET_32081
)
{
if
(
regno
<
16
)
{
return
(
1
);
}
else
{
return
(
0
);
}
}
else
{
if
(
regno
<
8
)
{
return
(
1
);
}
else
{
return
(
0
);
}
}
case
DFmode
:
case
DCmode
:
if
(
(
regno
&
1
)
==
0
)
{
if
(
TARGET_32081
)
{
if
(
regno
<
16
)
{
return
(
1
);
}
else
{
return
(
0
);
}
}
else
{
if
(
regno
<
8
)
{
return
(
1
);
}
else
{
return
(
0
);
}
}
}
else
{
return
(
0
);
}
case
XFmode
:
abort
(
0
);
case
CCmode
:
abort
(
0
);
case
TImode
:
abort
(
0
);
case
XCmode
:
abort
(
0
);
case
TFmode
:
abort
(
0
);
case
TCmode
:
abort
(
0
);
default
:
fprintf
(
stderr
,
"cant match mode %d
\n
"
,
mode
);
abort
(
0
);
}
abort
(
0
);
}
/* ADDRESS_COST calls this. This function is not optimal
for the 32032 & 32332, but it probably is better than
the default. */
int
calc_address_cost
(
operand
)
rtx
operand
;
{
int
i
;
int
cost
=
0
;
if
(
GET_CODE
(
operand
)
==
MEM
)
cost
+=
3
;
if
(
GET_CODE
(
operand
)
==
MULT
)
cost
+=
2
;
#if 0
if (GET_CODE (operand) == REG)
cost += 1; /* not really, but the documentation
says different amount of registers
shouldn't return the same costs */
#endif
switch
(
GET_CODE
(
operand
))
{
case
REG
:
case
CONST
:
case
CONST_INT
:
case
CONST_DOUBLE
:
case
SYMBOL_REF
:
case
LABEL_REF
:
case
POST_DEC
:
case
PRE_DEC
:
break
;
case
MULT
:
case
MEM
:
case
PLUS
:
for
(
i
=
0
;
i
<
GET_RTX_LENGTH
(
GET_CODE
(
operand
));
i
++
)
{
cost
+=
calc_address_cost
(
XEXP
(
operand
,
i
));
}
default
:
break
;
}
return
cost
;
}
/* 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,
NO_REGS is returned. */
enum
reg_class
secondary_reload_class
(
class
,
mode
,
in
)
enum
reg_class
class
;
enum
machine_mode
mode
;
rtx
in
;
{
int
regno
=
true_regnum
(
in
);
if
(
regno
>=
FIRST_PSEUDO_REGISTER
)
regno
=
-
1
;
/* We can place anything into GENERAL_REGS and can put GENERAL_REGS
into anything. */
if
(
class
==
GENERAL_REGS
||
(
regno
>=
0
&&
regno
<
8
))
return
NO_REGS
;
/* Constants, memory, and FP registers can go into FP registers */
if
((
regno
==
-
1
||
(
regno
>=
8
&&
regno
<
16
))
&&
(
class
==
FLOAT_REGS
))
return
NO_REGS
;
/* Otherwise, we need GENERAL_REGS. */
return
GENERAL_REGS
;
}
/* Generate the rtx that comes from an address expression in the md file */
/* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
scale must be converted from an exponent (from ASHIFT) to a
muliplier (for MULT). */
rtx
gen_indexed_expr
(
base
,
index
,
scale
)
rtx
base
,
index
,
scale
;
{
rtx
addr
;
/* This generates an illegal addressing mode, if BASE is
fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
if
(
GET_CODE
(
base
)
!=
REG
&&
GET_CODE
(
base
)
!=
CONST_INT
)
base
=
gen_rtx
(
MEM
,
SImode
,
base
);
addr
=
gen_rtx
(
MULT
,
SImode
,
index
,
gen_rtx
(
CONST_INT
,
VOIDmode
,
1
<<
INTVAL
(
scale
)));
addr
=
gen_rtx
(
PLUS
,
SImode
,
base
,
addr
);
return
addr
;
}
/* Return 1 if OP is a valid operand of mode MODE. This
predicate rejects operands which do not have a mode
(such as CONST_INT which are VOIDmode). */
int
reg_or_mem_operand
(
op
,
mode
)
register
rtx
op
;
enum
machine_mode
mode
;
{
return
(
GET_MODE
(
op
)
==
mode
&&
(
GET_CODE
(
op
)
==
REG
||
GET_CODE
(
op
)
==
SUBREG
||
GET_CODE
(
op
)
==
MEM
));
}
/* Return the best assembler insn template
for moving operands[1] into operands[0] as a fullword. */
static
char
*
singlemove_string
(
operands
)
rtx
*
operands
;
{
if
(
GET_CODE
(
operands
[
1
])
==
CONST_INT
&&
INTVAL
(
operands
[
1
])
<=
7
&&
INTVAL
(
operands
[
1
])
>=
-
8
)
return
"movqd %1,%0"
;
return
"movd %1,%0"
;
}
char
*
output_move_double
(
operands
)
rtx
*
operands
;
{
enum
anon1
{
REGOP
,
OFFSOP
,
POPOP
,
CNSTOP
,
RNDOP
}
optype0
,
optype1
;
rtx
latehalf
[
2
];
/* First classify both operands. */
if
(
REG_P
(
operands
[
0
]))
optype0
=
REGOP
;
else
if
(
offsettable_memref_p
(
operands
[
0
]))
optype0
=
OFFSOP
;
else
if
(
GET_CODE
(
XEXP
(
operands
[
0
],
0
))
==
PRE_DEC
)
optype0
=
POPOP
;
else
optype0
=
RNDOP
;
if
(
REG_P
(
operands
[
1
]))
optype1
=
REGOP
;
else
if
(
CONSTANT_ADDRESS_P
(
operands
[
1
])
||
GET_CODE
(
operands
[
1
])
==
CONST_DOUBLE
)
optype1
=
CNSTOP
;
else
if
(
offsettable_memref_p
(
operands
[
1
]))
optype1
=
OFFSOP
;
else
if
(
GET_CODE
(
XEXP
(
operands
[
1
],
0
))
==
PRE_DEC
)
optype1
=
POPOP
;
else
optype1
=
RNDOP
;
/* Check for the cases that the operand constraints are not
supposed to allow to happen. Abort if we get one,
because generating code for these cases is painful. */
if
(
optype0
==
RNDOP
||
optype1
==
RNDOP
)
abort
();
/* Ok, we can do one word at a time.
Normally we do the low-numbered word first,
but if either operand is autodecrementing then we
do the high-numbered word first.
In either case, set up in LATEHALF the operands to use
for the high-numbered word and in some cases alter the
operands in OPERANDS to be suitable for the low-numbered word. */
if
(
optype0
==
REGOP
)
latehalf
[
0
]
=
gen_rtx
(
REG
,
SImode
,
REGNO
(
operands
[
0
])
+
1
);
else
if
(
optype0
==
OFFSOP
)
latehalf
[
0
]
=
adj_offsettable_operand
(
operands
[
0
],
4
);
else
latehalf
[
0
]
=
operands
[
0
];
if
(
optype1
==
REGOP
)
latehalf
[
1
]
=
gen_rtx
(
REG
,
SImode
,
REGNO
(
operands
[
1
])
+
1
);
else
if
(
optype1
==
OFFSOP
)
latehalf
[
1
]
=
adj_offsettable_operand
(
operands
[
1
],
4
);
else
if
(
optype1
==
CNSTOP
)
{
if
(
CONSTANT_ADDRESS_P
(
operands
[
1
]))
latehalf
[
1
]
=
const0_rtx
;
else
if
(
GET_CODE
(
operands
[
1
])
==
CONST_DOUBLE
)
split_double
(
operands
[
1
],
&
operands
[
1
],
&
latehalf
[
1
]);
}
else
latehalf
[
1
]
=
operands
[
1
];
/* If one or both operands autodecrementing,
do the two words, high-numbered first. */
if
(
optype0
==
POPOP
||
optype1
==
POPOP
)
{
output_asm_insn
(
singlemove_string
(
latehalf
),
latehalf
);
return
singlemove_string
(
operands
);
}
/* Not autodecrementing. Do the two words, low-numbered first. */
output_asm_insn
(
singlemove_string
(
operands
),
operands
);
operands
[
0
]
=
latehalf
[
0
];
operands
[
1
]
=
latehalf
[
1
];
return
singlemove_string
(
operands
);
}
int
check_reg
(
oper
,
reg
)
rtx
oper
;
int
reg
;
{
register
int
i
;
if
(
oper
==
0
)
return
0
;
switch
(
GET_CODE
(
oper
))
{
case
REG
:
return
(
REGNO
(
oper
)
==
reg
)
?
1
:
0
;
case
MEM
:
return
check_reg
(
XEXP
(
oper
,
0
),
reg
);
case
PLUS
:
case
MULT
:
return
check_reg
(
XEXP
(
oper
,
0
),
reg
)
||
check_reg
(
XEXP
(
oper
,
1
),
reg
);
}
return
0
;
}
/* PRINT_OPERAND is defined to call this function,
which is easier to debug than putting all the code in
a macro definition in ns32k.h. */
void
print_operand
(
file
,
x
,
code
)
FILE
*
file
;
rtx
x
;
char
code
;
{
if
(
code
==
'$'
)
PUT_IMMEDIATE_PREFIX
(
file
);
else
if
(
code
==
'?'
)
PUT_EXTERNAL_PREFIX
(
file
);
else
if
(
GET_CODE
(
x
)
==
REG
)
fprintf
(
file
,
"%s"
,
reg_names
[
REGNO
(
x
)]);
else
if
(
GET_CODE
(
x
)
==
MEM
)
output_address
(
XEXP
(
x
,
0
));
else
if
(
GET_CODE
(
x
)
==
CONST_DOUBLE
&&
GET_MODE
(
x
)
!=
DImode
)
if
(
GET_MODE
(
x
)
==
DFmode
)
{
union
{
double
d
;
int
i
[
2
];
}
u
;
u
.
i
[
0
]
=
CONST_DOUBLE_LOW
(
x
);
u
.
i
[
1
]
=
CONST_DOUBLE_HIGH
(
x
);
PUT_IMMEDIATE_PREFIX
(
file
);
fprintf
(
file
,
"0d%.20e"
,
u
.
d
);
}
else
{
union
{
double
d
;
int
i
[
2
];
}
u
;
u
.
i
[
0
]
=
CONST_DOUBLE_LOW
(
x
);
u
.
i
[
1
]
=
CONST_DOUBLE_HIGH
(
x
);
PUT_IMMEDIATE_PREFIX
(
file
);
fprintf
(
file
,
"0f%.20e"
,
u
.
d
);
}
else
{
PUT_IMMEDIATE_PREFIX
(
file
);
output_addr_const
(
file
,
x
);
}
}
/* PRINT_OPERAND_ADDRESS is defined to call this function,
which is easier to debug than putting all the code in
a macro definition in ns32k.h . */
/* Completely rewritten to get this to work with Gas for PC532 Mach.
This function didn't work and I just wasn't able (nor very willing) to
figure out how it worked.
90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
print_operand_address
(
file
,
addr
)
register
FILE
*
file
;
register
rtx
addr
;
{
static
char
scales
[]
=
{
'b'
,
'w'
,
'd'
,
0
,
'q'
,
};
rtx
offset
,
base
,
indexexp
,
tmp
;
int
scale
;
if
(
GET_CODE
(
addr
)
==
PRE_DEC
||
GET_CODE
(
addr
)
==
POST_DEC
)
{
fprintf
(
file
,
"tos"
);
return
;
}
offset
=
NULL
;
base
=
NULL
;
indexexp
=
NULL
;
while
(
addr
!=
NULL
)
{
if
(
GET_CODE
(
addr
)
==
PLUS
)
{
if
(
GET_CODE
(
XEXP
(
addr
,
0
))
==
PLUS
)
{
tmp
=
XEXP
(
addr
,
1
);
addr
=
XEXP
(
addr
,
0
);
}
else
{
tmp
=
XEXP
(
addr
,
0
);
addr
=
XEXP
(
addr
,
1
);
}
}
else
{
tmp
=
addr
;
addr
=
NULL
;
}
switch
(
GET_CODE
(
tmp
))
{
case
PLUS
:
abort
();
case
MEM
:
if
(
base
)
{
indexexp
=
base
;
base
=
tmp
;
}
else
base
=
tmp
;
break
;
case
REG
:
if
(
REGNO
(
tmp
)
<
8
)
if
(
base
)
{
indexexp
=
tmp
;
}
else
base
=
tmp
;
else
if
(
base
)
{
indexexp
=
base
;
base
=
tmp
;
}
else
base
=
tmp
;
break
;
case
MULT
:
indexexp
=
tmp
;
break
;
case
CONST
:
case
CONST_INT
:
case
SYMBOL_REF
:
case
LABEL_REF
:
if
(
offset
)
offset
=
gen_rtx
(
PLUS
,
SImode
,
tmp
,
offset
);
else
offset
=
tmp
;
break
;
default
:
abort
();
}
}
if
(
!
offset
)
offset
=
const0_rtx
;
/* now, offset, base and indexexp are set */
if
(
!
base
)
#ifdef PC_RELATIVE
{
if
(
GET_CODE
(
offset
)
==
LABEL_REF
||
GET_CODE
(
offset
)
==
SYMBOL_REF
)
;
else
#endif
PUT_ABSOLUTE_PREFIX
(
file
);
#ifdef PC_RELATIVE
}
#endif
output_addr_const
(
file
,
offset
);
if
(
base
)
/* base can be (REG ...) or (MEM ...) */
switch
(
GET_CODE
(
base
))
{
/* now we must output base. Possible alternatives are:
(rN) (REG ...)
(sp) (REG ...)
(fp) (REG ...)
(pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
(disp(fp)) (MEM ...) just before possible [rX:y]
(disp(sp)) (MEM ...)
(disp(sb)) (MEM ...)
*/
case
REG
:
fprintf
(
file
,
"(%s)"
,
reg_names
[
REGNO
(
base
)]);
break
;
case
MEM
:
addr
=
XEXP
(
base
,
0
);
base
=
NULL
;
offset
=
NULL
;
while
(
addr
!=
NULL
)
{
if
(
GET_CODE
(
addr
)
==
PLUS
)
{
if
(
GET_CODE
(
XEXP
(
addr
,
0
))
==
PLUS
)
{
tmp
=
XEXP
(
addr
,
1
);
addr
=
XEXP
(
addr
,
0
);
}
else
{
tmp
=
XEXP
(
addr
,
0
);
addr
=
XEXP
(
addr
,
1
);
}
}
else
{
tmp
=
addr
;
addr
=
NULL
;
}
switch
(
GET_CODE
(
tmp
))
{
case
REG
:
base
=
tmp
;
break
;
case
CONST
:
case
CONST_INT
:
case
SYMBOL_REF
:
case
LABEL_REF
:
if
(
offset
)
offset
=
gen_rtx
(
PLUS
,
SImode
,
tmp
,
offset
);
else
offset
=
tmp
;
break
;
default
:
abort
();
}
}
if
(
!
offset
)
offset
=
const0_rtx
;
fprintf
(
file
,
"("
);
output_addr_const
(
file
,
offset
);
if
(
base
)
fprintf
(
file
,
"(%s)"
,
reg_names
[
REGNO
(
base
)]);
else
if
(
TARGET_SB
)
fprintf
(
file
,
"(sb)"
);
else
abort
();
fprintf
(
file
,
")"
);
break
;
default
:
abort
();
}
#ifdef PC_RELATIVE
else
/* no base */
if
(
GET_CODE
(
offset
)
==
LABEL_REF
||
GET_CODE
(
offset
)
==
SYMBOL_REF
)
fprintf
(
file
,
"(pc)"
);
#endif
#ifdef BASE_REG_NEEDED
/* this is defined if the assembler always
needs a base register */
else
if
(
TARGET_SB
)
fprintf
(
file
,
"(sb)"
);
else
abort
();
#endif
/* now print index if we have one */
if
(
indexexp
)
{
if
(
GET_CODE
(
indexexp
)
==
MULT
)
{
scale
=
INTVAL
(
XEXP
(
indexexp
,
1
))
>>
1
;
indexexp
=
XEXP
(
indexexp
,
0
);
}
else
scale
=
0
;
if
(
GET_CODE
(
indexexp
)
!=
REG
||
REGNO
(
indexexp
)
>=
8
)
abort
();
fprintf
(
file
,
"[%s:%c]"
,
reg_names
[
REGNO
(
indexexp
)],
scales
[
scale
]);
}
}
/* National 32032 shifting is so bad that we can get
better performance in many common cases by using other
techniques. */
char
*
output_shift_insn
(
operands
)
rtx
*
operands
;
{
if
(
GET_CODE
(
operands
[
2
])
==
CONST_INT
&&
INTVAL
(
operands
[
2
])
>
0
&&
INTVAL
(
operands
[
2
])
<=
3
)
if
(
GET_CODE
(
operands
[
0
])
==
REG
)
{
if
(
GET_CODE
(
operands
[
1
])
==
REG
)
{
if
(
REGNO
(
operands
[
0
])
==
REGNO
(
operands
[
1
]))
{
if
(
operands
[
2
]
==
const1_rtx
)
return
"addd %0,%0"
;
else
if
(
INTVAL
(
operands
[
2
])
==
2
)
return
"addd %0,%0
\n\t
addd %0,%0"
;
}
if
(
operands
[
2
]
==
const1_rtx
)
return
"movd %1,%0
\n\t
addd %0,%0"
;
operands
[
1
]
=
gen_indexed_expr
(
const0_rtx
,
operands
[
1
],
operands
[
2
]);
return
"addr %a1,%0"
;
}
if
(
operands
[
2
]
==
const1_rtx
)
return
"movd %1,%0
\n\t
addd %0,%0"
;
}
else
if
(
GET_CODE
(
operands
[
1
])
==
REG
)
{
operands
[
1
]
=
gen_indexed_expr
(
const0_rtx
,
operands
[
1
],
operands
[
2
]);
return
"addr %a1,%0"
;
}
else
if
(
INTVAL
(
operands
[
2
])
==
1
&&
GET_CODE
(
operands
[
1
])
==
MEM
&&
rtx_equal_p
(
operands
[
0
],
operands
[
1
]))
{
rtx
temp
=
XEXP
(
operands
[
1
],
0
);
if
(
GET_CODE
(
temp
)
==
REG
||
(
GET_CODE
(
temp
)
==
PLUS
&&
GET_CODE
(
XEXP
(
temp
,
0
))
==
REG
&&
GET_CODE
(
XEXP
(
temp
,
1
))
==
CONST_INT
))
return
"addd %0,%0"
;
}
else
return
"ashd %2,%0"
;
return
"ashd %2,%0"
;
}
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