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
095bb276
Commit
095bb276
authored
Aug 14, 2001
by
Nick Clifton
Committed by
Nick Clifton
Aug 14, 2001
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Handle nested functions which take variable arguments
From-SVN: r44898
parent
98999d8b
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
218 additions
and
67 deletions
+218
-67
gcc/ChangeLog
+12
-0
gcc/config/arm/arm-protos.h
+1
-0
gcc/config/arm/arm.c
+201
-17
gcc/config/arm/arm.h
+4
-50
No files found.
gcc/ChangeLog
View file @
095bb276
2001
-
08
-
14
Nick
Clifton
<
nickc
@cambridge
.
redhat
.
com
>
*
config
/
arm
/
arm
.
c
(
arm_compute_initial_elimination_offset
)
:
New
function
.
(
arm_expand_prologue
)
:
Handled
nested
functions
which
take
a
variable
argument
list
.
*
config
/
arm
/
arm
.
h
(
ARM_INITIAL_ELIMINATION_OFFSET
)
:
Replace
macro
with
an
invocation
of
arm_compute_initial_elimination_offset
.
*
config
/
arm
/
arm
-
protos
.
h
:
Prototype
arm_compute_initial_elimination_offset
.
2001
-
08
-
14
Gerald
Pfeifer
<
pfeifer
@dbai
.
tuwien
.
ac
.
at
>
*
doc
/
install
.
texi
(
Specific
,
avr
)
:
Fix
markup
.
...
...
gcc/config/arm/arm-protos.h
View file @
095bb276
...
...
@@ -34,6 +34,7 @@ extern void arm_expand_prologue PARAMS ((void));
extern
void
assemble_align
PARAMS
((
int
));
extern
const
char
*
arm_strip_name_encoding
PARAMS
((
const
char
*
));
extern
unsigned
long
arm_current_func_type
PARAMS
((
void
));
extern
unsigned
int
arm_compute_initial_elimination_offset
PARAMS
((
unsigned
int
,
unsigned
int
));
#ifdef TREE_CODE
extern
int
arm_return_in_memory
PARAMS
((
tree
));
...
...
gcc/config/arm/arm.c
View file @
095bb276
...
...
@@ -7875,6 +7875,170 @@ emit_sfm (base_reg, count)
return
par
;
}
/* Compute the distance from register FROM to register TO.
These can be the arg pointer (26), the soft frame pointer (25),
the stack pointer (13) or the hard frame pointer (11).
Typical stack layout looks like this:
old stack pointer -> | |
----
| | \
| | saved arguments for
| | vararg functions
| | /
--
hard FP & arg pointer -> | | \
| | stack
| | frame
| | /
--
| | \
| | call saved
| | registers
soft frame pointer -> | | /
--
| | \
| | local
| | variables
| | /
--
| | \
| | outgoing
| | arguments
current stack pointer -> | | /
--
For a given funciton some or all of these stack compomnents
may not be needed, giving rise to the possibility of
eliminating some of the registers.
The values returned by this function must reflect the behaviour
of arm_expand_prologue() and arm_compute_save_reg_mask().
The sign of the number returned reflects the direction of stack
growth, so the values are positive for all eliminations except
from the soft frame pointer to the hard frame pointer. */
unsigned
int
arm_compute_initial_elimination_offset
(
from
,
to
)
unsigned
int
from
;
unsigned
int
to
;
{
unsigned
int
local_vars
=
(
get_frame_size
()
+
3
)
&
~
3
;
unsigned
int
outgoing_args
=
current_function_outgoing_args_size
;
unsigned
int
stack_frame
;
unsigned
int
call_saved_registers
;
unsigned
long
func_type
;
func_type
=
arm_current_func_type
();
/* Volatile functions never return, so there is
no need to save call saved registers. */
call_saved_registers
=
0
;
if
(
!
IS_VOLATILE
(
func_type
))
{
unsigned
int
reg
;
for
(
reg
=
0
;
reg
<=
10
;
reg
++
)
if
(
regs_ever_live
[
reg
]
&&
!
call_used_regs
[
reg
])
call_saved_registers
+=
4
;
if
(
!
TARGET_APCS_FRAME
&&
!
frame_pointer_needed
&&
regs_ever_live
[
HARD_FRAME_POINTER_REGNUM
]
&&
!
call_used_regs
[
HARD_FRAME_POINTER_REGNUM
])
call_saved_registers
+=
4
;
if
(
flag_pic
&&
regs_ever_live
[
PIC_OFFSET_TABLE_REGNUM
])
call_saved_registers
+=
4
;
if
(
regs_ever_live
[
LR_REGNUM
]
/* If a stack frame is going to be created, the LR will
be saved as part of that, so we do not need to allow
for it here. */
&&
!
frame_pointer_needed
)
call_saved_registers
+=
4
;
}
/* The stack frame contains 4 registers - the old frame pointer,
the old stack pointer, the return address and PC of the start
of the function. */
stack_frame
=
frame_pointer_needed
?
16
:
0
;
/* FIXME: we should allow for saved floating point registers. */
/* OK, now we have enough information to compute the distances.
There must be an entry in these switch tables for each pair
of registers in ELIMINABLE_REGS, even if some of the entries
seem to be redundant or useless. */
switch
(
from
)
{
case
ARG_POINTER_REGNUM
:
switch
(
to
)
{
case
THUMB_HARD_FRAME_POINTER_REGNUM
:
return
0
;
case
FRAME_POINTER_REGNUM
:
/* This is the reverse of the soft frame pointer
to hard frame pointer elimination below. */
if
(
call_saved_registers
==
0
&&
stack_frame
==
0
)
return
0
;
return
(
call_saved_registers
+
stack_frame
-
4
);
case
ARM_HARD_FRAME_POINTER_REGNUM
:
/* If there is no stack frame then the hard
frame pointer and the arg pointer coincide. */
if
(
stack_frame
==
0
&&
call_saved_registers
!=
0
)
return
0
;
/* FIXME: Not sure about this. Maybe we should always return 0 ? */
return
(
frame_pointer_needed
&&
current_function_needs_context
&&
!
current_function_anonymous_args
)
?
4
:
0
;
case
STACK_POINTER_REGNUM
:
/* If nothing has been pushed on the stack at all
then this will return -4. This *is* correct! */
return
call_saved_registers
+
stack_frame
+
local_vars
+
outgoing_args
-
4
;
default
:
abort
();
}
break
;
case
FRAME_POINTER_REGNUM
:
switch
(
to
)
{
case
THUMB_HARD_FRAME_POINTER_REGNUM
:
return
0
;
case
ARM_HARD_FRAME_POINTER_REGNUM
:
/* The hard frame pointer points to the top entry in the
stack frame. The soft frame pointer to the bottom entry
in the stack frame. If there is no stack frame at all,
then they are identical. */
if
(
call_saved_registers
==
0
&&
stack_frame
==
0
)
return
0
;
return
-
(
call_saved_registers
+
stack_frame
-
4
);
case
STACK_POINTER_REGNUM
:
return
local_vars
+
outgoing_args
;
default
:
abort
();
}
break
;
default
:
/* You cannot eliminate from the stack pointer.
In theory you could eliminate from the hard frame
pointer to the stack pointer, but this will never
happen, since if a stack frame is not needed the
hard frame pointer will never be used. */
abort
();
}
}
/* Generate the prologue instructions for entry into an ARM function. */
void
...
...
@@ -7887,6 +8051,8 @@ arm_expand_prologue ()
unsigned
long
live_regs_mask
;
unsigned
long
func_type
;
int
fp_offset
=
0
;
int
saved_pretend_args
=
0
;
unsigned
int
args_to_push
;
func_type
=
arm_current_func_type
();
...
...
@@ -7894,6 +8060,9 @@ arm_expand_prologue ()
if
(
IS_NAKED
(
func_type
))
return
;
/* Make a copy of c_f_p_a_s as we may need to modify it locally. */
args_to_push
=
current_function_pretend_args_size
;
/* Compute which register we will have to save onto the stack. */
live_regs_mask
=
arm_compute_save_reg_mask
();
...
...
@@ -7920,8 +8089,8 @@ arm_expand_prologue ()
1. The last argument register.
2. A slot on the stack above the frame. (This only
works if the function is not a varargs function).
If neither of these places is available, we abort (for now)
.
3. Register r3, after pushing the argument registers
onto the stack
.
Note - we only need to tell the dwarf2 backend about the SP
adjustment in the second variant; the static chain register
...
...
@@ -7934,7 +8103,7 @@ arm_expand_prologue ()
insn
=
gen_rtx_SET
(
SImode
,
insn
,
ip_rtx
);
insn
=
emit_insn
(
insn
);
}
else
if
(
current_function_pretend_args_size
==
0
)
else
if
(
args_to_push
==
0
)
{
rtx
dwarf
;
insn
=
gen_rtx_PRE_DEC
(
SImode
,
stack_pointer_rtx
);
...
...
@@ -7953,13 +8122,27 @@ arm_expand_prologue ()
dwarf
,
REG_NOTES
(
insn
));
}
else
/* FIXME - the way to handle this situation is to allow
the pretend args to be dumped onto the stack, then
reuse r3 to save IP. This would involve moving the
copying of SP into IP until after the pretend args
have been dumped, but this is not too hard. */
/* [See e.g. gcc.c-torture/execute/nest-stdar-1.c.] */
error
(
"Unable to find a temporary location for static chain register"
);
{
/* Store the args on the stack. */
if
(
current_function_anonymous_args
)
insn
=
emit_multi_reg_push
((
0xf0
>>
(
args_to_push
/
4
))
&
0xf
);
else
insn
=
emit_insn
(
gen_addsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
GEN_INT
(
-
args_to_push
)));
RTX_FRAME_RELATED_P
(
insn
)
=
1
;
saved_pretend_args
=
1
;
fp_offset
=
args_to_push
;
args_to_push
=
0
;
/* Now reuse r3 to preserve IP. */
insn
=
gen_rtx_REG
(
SImode
,
3
);
insn
=
gen_rtx_SET
(
SImode
,
insn
,
ip_rtx
);
(
void
)
emit_insn
(
insn
);
}
}
if
(
fp_offset
)
...
...
@@ -7974,16 +8157,16 @@ arm_expand_prologue ()
RTX_FRAME_RELATED_P
(
insn
)
=
1
;
}
if
(
current_function_pretend_args_size
)
if
(
args_to_push
)
{
/* Push the argument registers, or reserve space for them. */
if
(
current_function_anonymous_args
)
insn
=
emit_multi_reg_push
((
0xf0
>>
(
current_function_pretend_args_size
/
4
))
&
0xf
);
((
0xf0
>>
(
args_to_push
/
4
))
&
0xf
);
else
insn
=
emit_insn
(
gen_addsi3
(
stack_pointer_rtx
,
stack_pointer_rtx
,
GEN_INT
(
-
current_function_pretend_args_size
)));
GEN_INT
(
-
args_to_push
)));
RTX_FRAME_RELATED_P
(
insn
)
=
1
;
}
...
...
@@ -8045,25 +8228,26 @@ arm_expand_prologue ()
if
(
frame_pointer_needed
)
{
/* Create the new frame pointer. */
insn
=
GEN_INT
(
-
(
4
+
current_function_pretend_args_size
+
fp_offset
));
insn
=
GEN_INT
(
-
(
4
+
args_to_push
+
fp_offset
));
insn
=
emit_insn
(
gen_addsi3
(
hard_frame_pointer_rtx
,
ip_rtx
,
insn
));
RTX_FRAME_RELATED_P
(
insn
)
=
1
;
if
(
IS_NESTED
(
func_type
))
{
/* Recover the static chain register. */
if
(
regs_ever_live
[
3
]
==
0
)
if
(
regs_ever_live
[
3
]
==
0
||
saved_pretend_args
)
{
insn
=
gen_rtx_REG
(
SImode
,
3
);
insn
=
gen_rtx_SET
(
SImode
,
ip_rtx
,
insn
);
insn
=
emit_insn
(
insn
);
(
void
)
emit_insn
(
insn
);
}
else
/* if (current_function_pretend_args_size == 0) */
{
insn
=
gen_rtx_PLUS
(
SImode
,
hard_frame_pointer_rtx
,
GEN_INT
(
4
));
insn
=
gen_rtx_MEM
(
SImode
,
insn
);
insn
=
gen_rtx_SET
(
SImode
,
ip_rtx
,
insn
);
insn
=
emit_insn
(
insn
);
(
void
)
emit_insn
(
insn
);
}
}
}
...
...
gcc/config/arm/arm.h
View file @
095bb276
...
...
@@ -1639,57 +1639,11 @@ typedef struct
/* Define the offset between two registers, one to be eliminated, and the
other its replacement, at the start of a routine. */
#define ARM_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
{ \
int volatile_func = IS_VOLATILE (arm_current_func_type ()); \
if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
{ \
if (! current_function_needs_context || ! frame_pointer_needed) \
(OFFSET) = 0; \
else \
(OFFSET) = 4; \
} \
else if ((FROM) == FRAME_POINTER_REGNUM \
&& (TO) == STACK_POINTER_REGNUM) \
(OFFSET) = current_function_outgoing_args_size \
+ ROUND_UP (get_frame_size ()); \
else \
do \
{ \
int regno; \
int offset = 12; \
int saved_hard_reg = 0; \
\
if (! volatile_func) \
{ \
for (regno = 0; regno <= 10; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
saved_hard_reg = 1, offset += 4; \
if (! TARGET_APCS_FRAME \
&& ! frame_pointer_needed \
&& regs_ever_live[HARD_FRAME_POINTER_REGNUM] \
&& ! call_used_regs[HARD_FRAME_POINTER_REGNUM]) \
saved_hard_reg = 1, offset += 4; \
/* PIC register is a fixed reg, so call_used_regs set. */
\
if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) \
saved_hard_reg = 1, offset += 4; \
for (regno = FIRST_ARM_FP_REGNUM; \
regno <= LAST_ARM_FP_REGNUM; regno++) \
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
offset += 12; \
} \
if ((FROM) == FRAME_POINTER_REGNUM) \
(OFFSET) = - offset; \
else \
{ \
if (! frame_pointer_needed) \
offset -= 16; \
if (! volatile_func \
&& (regs_ever_live[LR_REGNUM]
/*|| saved_hard_reg */
)) \
offset += 4; \
offset += current_function_outgoing_args_size; \
(OFFSET) = ROUND_UP (get_frame_size ()) + offset; \
} \
(OFFSET) = arm_compute_initial_elimination_offset (FROM, TO); \
} \
}
while (0)
/* Note: This macro must match the code in thumb_function_prologue(). */
#define THUMB_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
...
...
@@ -1727,7 +1681,7 @@ typedef struct
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
if (TARGET_ARM) \
ARM_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET) \
ARM_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET)
;
\
else \
THUMB_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET)
...
...
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