Next: Scalar Return, Previous: Stack Arguments, Up: Stack and Calling
这节描述了让你控制不同类型的参数如何在寄存器中传递, 或者它们如何被安排在栈中的宏。
— Macro: FUNCTION_ARG (cum, mode, type, named) 一个C表达式,控制函数的参数是否在寄存器中传递,以及在那个寄存器中传递。
参数为cum,其总结了所有之前的参数;mode,参数的机器模式; type,参数的数据类型,作为一个树节点或者0如果不知道(这发生于C支持库的 函数);named,其为1对于普通参数,0对于无名参数, 对应于在被调用函数原型中的‘...’。type可以为一个不完全类型, 如果之前产生了语法错误。
表达式的值通常为一个在其中传递参数的硬件寄存器的
reg
RTX,或者0, 在栈上传递参数。对于像VAX和68000的机器,其通常所有参数被压栈,则定义为0就行。
表达式的值也可以为一个
parallel
RTX。这用于当参数在多个位置传递的时候。parallel
的机器模式应该为整个参数的机器模式。parallel
保存了任意数目的expr_list
对; 每一个描述了该部分参数在哪里传递,reg
RTX的机器模式指示了该部分的参数有多大。expr_list
的第二个操作数为一个const_int, 其给出了该部分起始处与整个参数的偏移字节数。作为一个特例,parallel
RTX中的第一个expr_list
的第一个操作数可以为0。 这意味着整个参数也在栈中存储。该宏最后一次被调用的时候,
MODE == VOIDmode
, 并且结果被传递给call
或者call_value
指令模式,分别作为其操作数2和3。通常使ISO库stdarg.h在一些参数在寄存器中传递的机器上工作的方法, 是使无名参数在栈上传递。这通过使
FUNCTION_ARG
当named为0时返回0来实现。你可以在该宏的定义中,使用钩子
targetm.calls.must_pass_in_stack
来确定该 参数是否为一个必须在栈中传递的类型。如果REG_PARM_STACK_SPACE
没有定义并且FUNCTION_ARG
对于这样的参数返回非0,则编译器会abort。 如果REG_PARM_STACK_SPACE
被定义,则参数会在栈中计算并且然后加载到寄存器中。
该target钩子应该返回
true
,如果我们不应该只在寄存器中传递type。 文件expr.h中有一个定义,其通常是合适的,更多的文档请参考expr.h。
定义该宏,如果target机器具有“寄存器窗口”, 这样函数看到的参数寄存器没有必要与调用者传递参数的寄存器相同。
对于这样的机器,
FUNCTION_ARG
计算调用者传递值的寄存器,FUNCTION_INCOMING_ARG
应该按照类似的方式定义, 来告诉被调用的函数参数在哪里到来。如果
FUNCTION_INCOMING_ARG
没有定义,则FUNCTION_ARG
具有这两种用途。
该target钩子返回在参数的起始处必须被放入寄存器的字节数。 值必须为0对于参数全部放在寄存器中或者全部压入栈中。
一些机器上,特定的参数必须部分在寄存器中传递并且部分在内存中传递。 在这些机器上,通常参数的起始一些字在寄存器中传递,其余的在栈上。 如果一个多字的参数(
double
或者结构体)跨越了边界, 则其起始的一些字必须在寄存器中传递并且剩余的被压栈。 该宏告诉编译器这种情况什么时候发生,以及多少字节应该在寄存器中。
FUNCTION_ARG
对于这些参数应该返回第一个寄存器,被调用者用于该参数; 通常FUNCTION_INCOMING_ARG
用于被调用的函数。
该target钩子应该返回
true
, 如果cum所指示的位置的参数应该按照引用的方式来传递。如果钩子返回真,则参数的副本在内存中产生并且指向参数的指针被替代参数本身来传递。 指针按照传递该类型的指针的方式来传递。
由该钩子的参数所描述的函数的参数已知为通过引用来传递的。钩子应该返回真, 如果函数参数应该由被调用者复制,而不是调用者。
对于任何该钩子返回真的参数,如果其可以被确定参数没有被修改,则不需要产生副本。
该钩子的缺省版本总是返回假。
一个C类型,用来声明一个变量, 被用作
FUNCTION_ARG
的第一个参数以及其它相关的值。对于一些target机器, 类型int
可以满足并且目前可以保持参数的字节数。不需要在
CUMULATIVE_ARGS
中记录任何已经在栈中传递的参数的信息。 编译器有其它变量来记录。对于所有参数在栈上传递的target机器, 不需要在CUMULATIVE_ARGS
中保存任何事物;然而, 数据结构体必须存在并且不能为空,因此可以使用int
。
If defined, this macro is called before generating any code for a function, but after the cfun descriptor for the function has been created. The back end may use this macro to update cfun to reflect an ABI other than that which would normally be used by default. If the compiler is generating code for a compiler-generated function, fndecl may be
NULL
.
一条C语句(没有分号),用于初始化变量cum,在参数列表的起始处。 变量具有类型
CUMULATIVE_ARGS
。fntype的值为树节点, 为将要接受参数的函数的数据类型,或者为0如果参数是传给编译器支持库的函数。 对于直接调用,没有libcall,fndecl包含了被编译的函数。 fndecl在当INIT_CUMULATIVE_ARGS
被用于查找被编译的函数的参数时, 也被设置。n_named_args被设为命名参数的个数,包括一个结构体返回地址, 如果其作为参数被传递。当处理流入参数时,n_named_args被设为-1。当处理对编译器支持库的函数的调用时,libname指示了为哪一个函数。 其为一个
symbol_ref
rtx,包含了函数的名字,作为字符串。libname为0, 当一个普通C函数被处理。因此,每次该宏被调用时, 或者libname或者fntype为非 0,但不会同时非0。
类似于
INIT_CUMULATIVE_ARGS
,但只用于流出的libcall, 其接受一个MODE
参数而不是fntype。如果该宏没有定义, 则使用INIT_CUMULATIVE_ARGS (cum, NULL_RTX, libname,0)
来替代。
类似于
INIT_CUMULATIVE_ARGS
,但会覆盖其,用于查找被编译的函数的参数。 如果该宏没有被定义,则使用INIT_CUMULATIVE_ARGS
来替代。传递给libname的值总是为0,因为库函数具有特定的调用约定,从来不被GCC编译。 参数libname的存在是为了与
INIT_CUMULATIVE_ARGS
对称。
一条C语句(没有分号),来更新总结变量cum来在参数列表中前进一个参数。 值mode, type和named描述了那个参数。一旦执行后, 变量cum便适合分析随后的参数。
该宏不需要做任何事情,如果要询问的参数是在栈中传递的。 编译器知道如何追踪用于参数的栈空间,不需要任何特殊帮助。
If defined, a C expression that is the number of bytes to add to the offset of the argument passed in memory. This is needed for the SPU, which passes
char
andshort
arguments in the preferred slot that is in the middle of the quad word instead of starting at the top.
如果被定义,则为一个C表达式,其确定是否使用额外的空间来填补参数, 以及按照什么方向。值应该为类型
enum direction
:或者upward
, 向上填补参数,downward
向下,或者none
不进行填补。填补的数目总是刚足够达到下一个
FUNCTION_ARG_BOUNDARY
的倍数; 该宏不进行控制。该宏具有一个缺省定义,其对大多数系统是对的。对于小端机器,缺省为向上填补。 对于大端机器,缺省为如果参数的大小比
int
短则向下填补,否则向上。
如果定义,则为一个C表达式,其确定va_arg的缺省实现是否会尝试向下填补, 在读取下一个参数之前,如果那个参数比
PARM_BOUNDARY
所控制的对齐空间要小。 如果该宏没有定义,则所有这样的参数都被向下填补, 如果BYTES_BIG_ENDIAN
为真。
指定了寄存器和内存间移动的块的最后一个元素的填补。first为非0, 如果这是唯一的元素。定义该宏,允许更好的处理在大端机器上寄存器函数参数, 不使用
PARALLEL
rtl。特别的,MUST_PASS_IN_STACK
不需要测试填充和寄存器中的类型的机器模式, 因为在寄存器中不在有“错误的”部分;例如, 一个三字节的聚合类型可能在寄存器的高部传递,如果需要的话。
如果定义,为一个C表达式,其给出了指定的mode和type的参数的对齐边界位数。 如果没有定义,则
PARM_BOUNDARY
用于所有参数。
一个C表达式,其为非0,如果regno为硬件寄存器的编号, 函数参数有时在其中传递。这不包括隐式参数,像静态链和结构体值的地址。 在许多机器上,没有寄存器可以用于此目的,因为所有函数参数都被压到栈上。
该钩子应该返回真,如果参数type作为两个标量参数传递。缺省的, GCC将尝试将复数参数打包成target的字大小。 一些ABI要求复数参数要被拆分开并且作为单独的部分对待。例如,在AIX64上, 复数浮点应该在一对浮点寄存器中传递,即使复数浮点可以适合一个64位的浮点寄存器。
该钩子的缺省值为
NULL
,其被最为假来对待。
This hook returns the va_list type of the calling convention specified by fndecl. The default version of this hook returns
va_list_type_node
.
This hook returns the va_list type of the calling convention specified by the type of type. If type is not a valid va_list type, it returns
NULL_TREE
.
This hook returns the va_list type of the calling convention specified by fndecl. The default version of this hook returns
va_list_type_node
.
This hook returns the va_list type of the calling convention specified by the type of type. If type is not a valid va_list type, it returns
NULL_TREE
.
该钩子执行target特定的
VA_ARG_EXPR
的gimplification。 前两个参数对应于va_arg
的参数;后两个作为gimplify.c:gimplify_expr
。
定义该钩子返回非0,如果port可以处理具有机器模式mode的指针。 缺省版本对于
ptr_mode
和Pmode
都返回真。
定义该钩子来返回非0,如果port准备好了处理涉及标量机器模式mode的insn。 对于被考虑支持的一个标量机器模式,所有的基本算术和比较都必须能工作。
缺省版本返回真,对于任何要求处理基本C类型(被port定义)的机器模式。 包括在optabs.c中的代码支持的双字算术。
定义该钩子来返回非0,如果port准备好了处理涉及向量模式mode的insn。 最起码,其必须有该机器模式的move指令模式。
Define this to return nonzero for machine modes for which the port has small register classes. If this target hook returns nonzero for a given mode, the compiler will try to minimize the lifetime of registers in mode. The hook may be called with
VOIDmode
as argument. In this case, the hook is expected to return nonzero if it returns nonzero for any mode.On some machines, it is risky to let hard registers live across arbitrary insns. Typically, these machines have instructions that require values to be in specific registers (like an accumulator), and reload will fail if the required hard register is used for another purpose across such an insn.
Passes before reload do not know which hard registers will be used in an instruction, but the machine modes of the registers set or used in the instruction are already known. And for some machines, register classes are small for, say, integer registers but not for floating point registers. For example, the AMD x86-64 architecture requires specific registers for the legacy x86 integer instructions, but there are many SSE registers for floating point operations. On such targets, a good strategy may be to return nonzero from this hook for
INTEGRAL_MODE_P
machine modes but zero for the SSE register classes.The default version of this hook retuns false for any mode. It is always safe to redefine this hook to return with a nonzero value. But if you unnecessarily define it, you will reduce the amount of optimizations that can be performed in some cases. If you do not define this hook to return a nonzero value when it is required, the compiler will run out of spill registers and print a fatal error message.