mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-29 14:01:18 +08:00
As described in PR84877. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84877 The local copy of parameter on stack is not aligned. For BLKmode paramters, a local copy on the stack will be saved. There are three cases: 1) arguments passed partially on the stack, partially via registers. 2) arguments passed fully on the stack. 3) arguments passed via registers. After the change here, in all three cases, the stack slot for the local parameter copy is aligned by the data type. The stack slot is the DECL_RTL of the parameter. All the references thereafter in the function will refer to this RTL. To populate the local copy on the stack, For case 1) and 2), there are operations to move data from the caller's stack (from incoming rtl) into callee's stack. For case 3), the registers are directly saved into the stack slot. In all cases, the destination address is properly aligned. But for case 1) and case 2), the source address is not aligned by the type. It is defined by the PCS how the arguments are prepared. The block move operation is fulfilled by emit_block_move (). As far as I can see, it will use the smaller alignment of source and destination. This looks fine as long as we don't use instructions which requires a strict larger alignment than the address actually has. Here, it only changes receiving parameters. The function assign_stack_local_1 will be called in various places. Usually, the caller will constraint the ALIGN parameter. For example via STACK_SLOT_ALIGNMENT macro. assign_parm_setup_block will call assign_stack_local () with alignment from the parameter type which in this case could be larger than MAX_SUPPORTED_STACK_ALIGNMENT. The alignment operation for parameter copy on the stack is similar to stack vars. First, enough space is reserved on the stack. The size is fixed at compile time. Instructions are emitted to dynamically get an aligned address at runtime within this piece of memory. This will unavoidably increase the usage of stack. However, it really depends on how many over-aligned parameters are passed by value. gcc/ 2018-11-21 Renlin Li <renlin.li@arm.com> PR middle-end/84877 * explow.h (get_dynamic_stack_size): Declare it as external. * explow.c (record_new_stack_level): Remove function static attribute. * function.c (assign_stack_local_1): Dynamically align the stack slot addr for parameter copy on the stack. gcc/testsuite/ 2018-11-21 Renlin Li <renlin.li@arm.com> PR middle-end/84877 * gcc.dg/pr84877.c: New. From-SVN: r266345
140 lines
5.4 KiB
C
140 lines
5.4 KiB
C
/* Export function prototypes from explow.c.
|
|
Copyright (C) 2015-2018 Free Software Foundation, Inc.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC 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 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC 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 GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef GCC_EXPLOW_H
|
|
#define GCC_EXPLOW_H
|
|
|
|
/* Return a memory reference like MEMREF, but which is known to have a
|
|
valid address. */
|
|
extern rtx validize_mem (rtx);
|
|
|
|
extern rtx use_anchored_address (rtx);
|
|
|
|
/* Copy given rtx to a new temp reg and return that. */
|
|
extern rtx copy_to_reg (rtx);
|
|
|
|
/* Like copy_to_reg but always make the reg Pmode. */
|
|
extern rtx copy_addr_to_reg (rtx);
|
|
|
|
/* Like copy_to_reg but always make the reg the specified mode MODE. */
|
|
extern rtx copy_to_mode_reg (machine_mode, rtx);
|
|
|
|
/* Copy given rtx to given temp reg and return that. */
|
|
extern rtx copy_to_suggested_reg (rtx, rtx, machine_mode);
|
|
|
|
/* Copy a value to a register if it isn't already a register.
|
|
Args are mode (in case value is a constant) and the value. */
|
|
extern rtx force_reg (machine_mode, rtx);
|
|
|
|
/* Return given rtx, copied into a new temp reg if it was in memory. */
|
|
extern rtx force_not_mem (rtx);
|
|
|
|
/* Return mode and signedness to use when an argument or result in the
|
|
given mode is promoted. */
|
|
extern machine_mode promote_function_mode (const_tree, machine_mode, int *,
|
|
const_tree, int);
|
|
|
|
/* Return mode and signedness to use when an object in the given mode
|
|
is promoted. */
|
|
extern machine_mode promote_mode (const_tree, machine_mode, int *);
|
|
|
|
/* Return mode and signedness to use when object is promoted. */
|
|
machine_mode promote_decl_mode (const_tree, int *);
|
|
|
|
/* Return mode and signedness to use when object is promoted. */
|
|
machine_mode promote_ssa_mode (const_tree, int *);
|
|
|
|
/* Remove some bytes from the stack. An rtx says how many. */
|
|
extern void adjust_stack (rtx);
|
|
|
|
/* Add some bytes to the stack. An rtx says how many. */
|
|
extern void anti_adjust_stack (rtx);
|
|
|
|
/* Add some bytes to the stack while probing it. An rtx says how many. */
|
|
extern void anti_adjust_stack_and_probe (rtx, bool);
|
|
|
|
/* Support for building allocation/probing loops for stack-clash
|
|
protection of dyamically allocated stack space. */
|
|
extern void compute_stack_clash_protection_loop_data (rtx *, rtx *, rtx *,
|
|
HOST_WIDE_INT *, rtx);
|
|
extern void emit_stack_clash_protection_probe_loop_start (rtx *, rtx *,
|
|
rtx, bool);
|
|
extern void emit_stack_clash_protection_probe_loop_end (rtx, rtx,
|
|
rtx, bool);
|
|
|
|
/* This enum is used for the following two functions. */
|
|
enum save_level {SAVE_BLOCK, SAVE_FUNCTION, SAVE_NONLOCAL};
|
|
|
|
/* Save the stack pointer at the specified level. */
|
|
extern void emit_stack_save (enum save_level, rtx *);
|
|
|
|
/* Restore the stack pointer from a save area of the specified level. */
|
|
extern void emit_stack_restore (enum save_level, rtx);
|
|
|
|
/* Invoke emit_stack_save for the nonlocal_goto_save_area. */
|
|
extern void update_nonlocal_goto_save_area (void);
|
|
|
|
/* Record a new stack level. */
|
|
extern void record_new_stack_level (void);
|
|
|
|
/* Allocate some space on the stack dynamically and return its address. */
|
|
extern rtx allocate_dynamic_stack_space (rtx, unsigned, unsigned,
|
|
HOST_WIDE_INT, bool);
|
|
|
|
/* Calculate the necessary size of a constant dynamic stack allocation from the
|
|
size of the variable area. */
|
|
extern void get_dynamic_stack_size (rtx *, unsigned, unsigned, HOST_WIDE_INT *);
|
|
|
|
/* Returns the address of the dynamic stack space without allocating it. */
|
|
extern rtx get_dynamic_stack_base (poly_int64, unsigned);
|
|
|
|
/* Return an rtx doing runtime alignment to REQUIRED_ALIGN on TARGET. */
|
|
extern rtx align_dynamic_address (rtx, unsigned);
|
|
|
|
/* Emit one stack probe at ADDRESS, an address within the stack. */
|
|
extern void emit_stack_probe (rtx);
|
|
|
|
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
|
|
FIRST is a constant and size is a Pmode RTX. These are offsets from
|
|
the current stack pointer. STACK_GROWS_DOWNWARD says whether to add
|
|
or subtract them from the stack pointer. */
|
|
extern void probe_stack_range (HOST_WIDE_INT, rtx);
|
|
|
|
/* Return an rtx that refers to the value returned by a library call
|
|
in its original home. This becomes invalid if any more code is emitted. */
|
|
extern rtx hard_libcall_value (machine_mode, rtx);
|
|
|
|
/* Return an rtx that refers to the value returned by a function
|
|
in its original home. This becomes invalid if any more code is emitted. */
|
|
extern rtx hard_function_value (const_tree, const_tree, const_tree, int);
|
|
|
|
/* Convert arg to a valid memory address for specified machine mode that points
|
|
to a specific named address space, by emitting insns to perform arithmetic
|
|
if necessary. */
|
|
extern rtx memory_address_addr_space (machine_mode, rtx, addr_space_t);
|
|
|
|
extern rtx eliminate_constant_term (rtx, rtx *);
|
|
|
|
/* Like memory_address_addr_space, except assume the memory address points to
|
|
the generic named address space. */
|
|
#define memory_address(MODE,RTX) \
|
|
memory_address_addr_space ((MODE), (RTX), ADDR_SPACE_GENERIC)
|
|
|
|
#endif /* GCC_EXPLOW_H */
|