Next: , Previous: Stack Arguments, Up: Stack and Calling


17.10.7 在寄存器中传递参数

这节描述了让你控制不同类型的参数如何在寄存器中传递, 或者它们如何被安排在栈中的宏。

— Macro: FUNCTION_ARG (cum, mode, type, named)

— 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_ARGnamed为0时返回0来实现。

你可以在该宏的定义中,使用钩子targetm.calls.must_pass_in_stack来确定该 参数是否为一个必须在栈中传递的类型。如果REG_PARM_STACK_SPACE没有定义并且 FUNCTION_ARG对于这样的参数返回非0,则编译器会abort。 如果REG_PARM_STACK_SPACE被定义,则参数会在栈中计算并且然后加载到寄存器中。

— Target Hook: bool TARGET_MUST_PASS_IN_STACK (enum machine_mode mode, tree type)

该target钩子应该返回true,如果我们不应该只在寄存器中传递type。 文件expr.h中有一个定义,其通常是合适的,更多的文档请参考expr.h

— Macro: FUNCTION_INCOMING_ARG (cum, mode, type, named)

定义该宏,如果target机器具有“寄存器窗口”, 这样函数看到的参数寄存器没有必要与调用者传递参数的寄存器相同。

对于这样的机器,FUNCTION_ARG计算调用者传递值的寄存器, FUNCTION_INCOMING_ARG应该按照类似的方式定义, 来告诉被调用的函数参数在哪里到来。

如果FUNCTION_INCOMING_ARG没有定义,则FUNCTION_ARG具有这两种用途。

— Target Hook: int TARGET_ARG_PARTIAL_BYTES (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, bool named)

该target钩子返回在参数的起始处必须被放入寄存器的字节数。 值必须为0对于参数全部放在寄存器中或者全部压入栈中。

一些机器上,特定的参数必须部分在寄存器中传递并且部分在内存中传递。 在这些机器上,通常参数的起始一些字在寄存器中传递,其余的在栈上。 如果一个多字的参数(double或者结构体)跨越了边界, 则其起始的一些字必须在寄存器中传递并且剩余的被压栈。 该宏告诉编译器这种情况什么时候发生,以及多少字节应该在寄存器中。

FUNCTION_ARG对于这些参数应该返回第一个寄存器,被调用者用于该参数; 通常FUNCTION_INCOMING_ARG用于被调用的函数。

— Target Hook: bool TARGET_PASS_BY_REFERENCE (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, bool named)

该target钩子应该返回true, 如果cum所指示的位置的参数应该按照引用的方式来传递。

如果钩子返回真,则参数的副本在内存中产生并且指向参数的指针被替代参数本身来传递。 指针按照传递该类型的指针的方式来传递。

— Target Hook: bool TARGET_CALLEE_COPIES (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, bool named)

由该钩子的参数所描述的函数的参数已知为通过引用来传递的。钩子应该返回真, 如果函数参数应该由被调用者复制,而不是调用者。

对于任何该钩子返回真的参数,如果其可以被确定参数没有被修改,则不需要产生副本。

该钩子的缺省版本总是返回假。

— Macro: CUMULATIVE_ARGS

一个C类型,用来声明一个变量, 被用作FUNCTION_ARG的第一个参数以及其它相关的值。对于一些target机器, 类型int可以满足并且目前可以保持参数的字节数。

不需要在CUMULATIVE_ARGS中记录任何已经在栈中传递的参数的信息。 编译器有其它变量来记录。对于所有参数在栈上传递的target机器, 不需要在CUMULATIVE_ARGS中保存任何事物;然而, 数据结构体必须存在并且不能为空,因此可以使用int

— Macro: OVERRIDE_ABI_FORMAT (fndecl)

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.

— Macro: INIT_CUMULATIVE_ARGS (cum, fntype, libname, fndecl, n_named_args)

一条C语句(没有分号),用于初始化变量cum,在参数列表的起始处。 变量具有类型CUMULATIVE_ARGSfntype的值为树节点, 为将要接受参数的函数的数据类型,或者为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。

— Macro: INIT_CUMULATIVE_LIBCALL_ARGS (cum, mode, libname)

类似于INIT_CUMULATIVE_ARGS,但只用于流出的libcall, 其接受一个MODE参数而不是fntype。如果该宏没有定义, 则使用INIT_CUMULATIVE_ARGS (cum, NULL_RTX, libname,0)来替代。

— Macro: INIT_CUMULATIVE_INCOMING_ARGS (cum, fntype, libname)

类似于INIT_CUMULATIVE_ARGS,但会覆盖其,用于查找被编译的函数的参数。 如果该宏没有被定义,则使用INIT_CUMULATIVE_ARGS来替代。

传递给libname的值总是为0,因为库函数具有特定的调用约定,从来不被GCC编译。 参数libname的存在是为了与INIT_CUMULATIVE_ARGS对称。

— Macro: FUNCTION_ARG_ADVANCE (cum, mode, type, named)

一条C语句(没有分号),来更新总结变量cum来在参数列表中前进一个参数。 值mode, typenamed描述了那个参数。一旦执行后, 变量cum便适合分析随后的参数。

该宏不需要做任何事情,如果要询问的参数是在栈中传递的。 编译器知道如何追踪用于参数的栈空间,不需要任何特殊帮助。

— Macro: FUNCTION_ARG_OFFSET (mode, type)

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 and short arguments in the preferred slot that is in the middle of the quad word instead of starting at the top.

— Macro: FUNCTION_ARG_PADDING (mode, type)

如果被定义,则为一个C表达式,其确定是否使用额外的空间来填补参数, 以及按照什么方向。值应该为类型enum direction:或者upward, 向上填补参数,downward向下,或者none不进行填补。

填补的数目总是刚足够达到下一个FUNCTION_ARG_BOUNDARY的倍数; 该宏不进行控制。

该宏具有一个缺省定义,其对大多数系统是对的。对于小端机器,缺省为向上填补。 对于大端机器,缺省为如果参数的大小比int短则向下填补,否则向上。

— Macro: PAD_VARARGS_DOWN

如果定义,则为一个C表达式,其确定va_arg的缺省实现是否会尝试向下填补, 在读取下一个参数之前,如果那个参数比PARM_BOUNDARY所控制的对齐空间要小。 如果该宏没有定义,则所有这样的参数都被向下填补, 如果BYTES_BIG_ENDIAN为真。

— Macro: BLOCK_REG_PADDING (mode, type, first)

指定了寄存器和内存间移动的块的最后一个元素的填补。first为非0, 如果这是唯一的元素。定义该宏,允许更好的处理在大端机器上寄存器函数参数, 不使用PARALLEL rtl。特别的, MUST_PASS_IN_STACK不需要测试填充和寄存器中的类型的机器模式, 因为在寄存器中不在有“错误的”部分;例如, 一个三字节的聚合类型可能在寄存器的高部传递,如果需要的话。

— Macro: FUNCTION_ARG_BOUNDARY (mode, type)

如果定义,为一个C表达式,其给出了指定的mode和type的参数的对齐边界位数。 如果没有定义,则PARM_BOUNDARY用于所有参数。

— Macro: FUNCTION_ARG_REGNO_P (regno)

一个C表达式,其为非0,如果regno为硬件寄存器的编号, 函数参数有时在其中传递。这不包括隐式参数,像静态链和结构体值的地址。 在许多机器上,没有寄存器可以用于此目的,因为所有函数参数都被压到栈上。

— Target Hook: bool TARGET_SPLIT_COMPLEX_ARG (tree type)

该钩子应该返回真,如果参数type作为两个标量参数传递。缺省的, GCC将尝试将复数参数打包成target的字大小。 一些ABI要求复数参数要被拆分开并且作为单独的部分对待。例如,在AIX64上, 复数浮点应该在一对浮点寄存器中传递,即使复数浮点可以适合一个64位的浮点寄存器。

该钩子的缺省值为NULL,其被最为假来对待。

— Target Hook: tree TARGET_BUILD_BUILTIN_VA_LIST (void)

该钩子返回一个target的va_list的类型节点。缺省版本返回void*

— Target Hook: tree TARGET_FN_ABI_VA_LIST (tree fndecl)

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.

— Target Hook: tree TARGET_CANONICAL_VA_LIST_TYPE (tree type)

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 Hook: tree TARGET_FN_ABI_VA_LIST (tree fndecl)

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.

— Target Hook: tree TARGET_CANONICAL_VA_LIST_TYPE (tree type)

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 Hook: tree TARGET_GIMPLIFY_VA_ARG_EXPR (tree valist, tree type, tree *pre_p, tree *post_p)

该钩子执行target特定的VA_ARG_EXPR的gimplification。 前两个参数对应于va_arg的参数;后两个作为gimplify.c:gimplify_expr

— Target Hook: bool TARGET_VALID_POINTER_MODE (enum machine_mode mode)

定义该钩子返回非0,如果port可以处理具有机器模式mode的指针。 缺省版本对于ptr_modePmode都返回真。

— Target Hook: bool TARGET_SCALAR_MODE_SUPPORTED_P (enum machine_mode mode)

定义该钩子来返回非0,如果port准备好了处理涉及标量机器模式mode的insn。 对于被考虑支持的一个标量机器模式,所有的基本算术和比较都必须能工作。

缺省版本返回真,对于任何要求处理基本C类型(被port定义)的机器模式。 包括在optabs.c中的代码支持的双字算术。

— Target Hook: bool TARGET_VECTOR_MODE_SUPPORTED_P (enum machine_mode mode)

定义该钩子来返回非0,如果port准备好了处理涉及向量模式mode的insn。 最起码,其必须有该机器模式的move指令模式。

— Target Hook: bool TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P (enum machine_mode mode)

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.