在上面605行, set_target_switch处理与目标平台相关的选项。所有这些选项都以“-m”开头。
3829 void
3830 set_target_switch (const char *name) in toplev.c
3831 {
3832 size_t j;
3833 int valid_target_option = 0;
3834
3835 for (j = 0; j < ARRAY_SIZE (target_switches); j++)
3836 if (!strcmp (target_switches [j].name, name))
3837 {
3838 if (target_switches [j].value < 0)
3839 target_flags &= ~target_switches[j].value;
3840 else
3841 target_flags |= target_switches [j].value;
3842 if (name[0] != 0)
3843 {
3844 if (target_switches [j].value < 0)
3845 target_flags_explicit |= -target_switches [j].value;
3846 else
3847 target_flags_explicit |= target_switches [j].value;
3848 }
3849 valid_target_option = 1;
3850 }
3851
3852 #ifdef TARGET_OPTIONS
3853 if (!valid_target_option)
3854 for (j = 0; j < ARRAY_SIZE (target_options); j++)
3855 {
3856 int len = strlen (target_options [j].prefix);
3857 if (target_options [j].value)
3858 {
3859 if (!strcmp (target_options [j].prefix, name))
3860 {
3861 *target_options [j].variable = target_options [j].value;
3862 valid_target_option = 1;
3863 }
3864 }
3865 else
3866 {
3867 if (!strncmp (target_options [j].prefix, name, len))
3868 {
3869 *target_options [j].variable = name + len;
3870 valid_target_option = 1;
3871 }
3872 }
3873 }
3874 #endif
3875
3876 if (!valid_target_option)
3877 error ("invalid option `%s'", name);
3878 }
上面第3835行,target_switches在toplev.c中定义如下。
1166 static const struct in toplev.c
1167 {
1168 const char *const name;
1169 const int value;
1170 const char *const description;
1171 }
1172 target_switches[] = TARGET_SWITCHES;
target_switches从TARGET_SWITCHES获取其内容,TARGET_SWITCHES是目标平台指定的,对于x86系统,与平台相关的选项显示如下,它们定义在i386.h文件中。
选项名
|
值 |
描述 |
80387 |
MASK_80387 |
使用硬件fp |
no-80387 |
-MASK_80387 |
不使用硬件fp |
hard-float |
MASK_80387 |
使用硬件fp |
soft-float |
-MASK_80387 |
不使用硬件fp |
no-soft-float |
MASK_80387 |
使用硬件fp |
386 |
0 |
"" /*Deprecated.*/ 已过时 |
486 |
0 |
"" /*Deprecated.*/ 已过时 |
pentium |
0 |
"" /*Deprecated.*/ 已过时 |
pentiumpro |
0 |
"" /*Deprecated.*/ 已过时 |
pni |
0 |
"" |
no-pni |
0 |
"" /*Deprecated.*/ 已过时 |
intel-syntax |
0 |
"" /*Deprecated.*/ 已过时 |
no-intel-syntax |
0 |
"" /*Deprecated.*/ 已过时 |
rtd |
MASK_RTD |
等同于stdcall |
no-rtd |
-MASK_RTD |
使用普通的调用惯例 |
align-double |
MASK_ALIGN_DOUBLE |
对齐某些double到dword边界 |
no-align-double |
-MASK_ALIGN_DOUBLE |
对齐double到word边界 |
svr3-shlib |
MASK_SVR3_SHLIB |
未初始化的局部变量置于.bss段 |
no-svr3-shlib |
-MASK_SVR3_SHLIB |
未初始化的局部变量置于.data段 |
ieee-fp |
MASK_IEEE_FP |
浮点比较使用IEEE标准 |
no-ieee-fp |
-MASK_IEEE_FP |
浮点比较不使用IEEE标准 |
fp-ret-in-387 |
MASK_FLOAT_RETURNS |
函数返回值置于FPU的寄存器 |
no-fp-ret-in-387 |
-MASK_FLOAT_RETURNS |
不使用FPU的寄存器保存函数返回值 |
no-fancy-math-387 |
MASK_NO_FANCY_MATH_387 |
不要为FPU产生sin,cos,sqrt指令 |
fancy-math-387 |
-MASK_NO_FANCY_MATH_387 |
为FPU产生sin,cos,sqrt指令 |
omit-leaf-frame-pointer |
MASK_OMIT_LEAF_FRAME_POINTER |
在叶子函数(即不在其中调用其他函数)中,忽略栈框指针 |
no-omit-leaf-frame-pointer |
-MASK_OMIT_LEAF_FRAME_POINTER |
"" |
stack-arg-probe |
MASK_STACK_PROBE |
启动栈探测(stack probing) |
no-stack-arg-probe |
-MASK_STACK_PROBE |
"" |
windows |
0 |
0 /* undocumented */ |
dll |
0 |
0 /* undocumented */ |
align-stringops |
-MASK_NO_ALIGN_STROPS |
对齐字符串操作的目的位置 |
no-align-stringops |
MASK_NO_ALIGN_STROPS |
不对齐字符串操作的目的位置 |
inline-all-stringops |
MASK_INLINE_ALL_STROPS |
内联所有已知字符串操作 |
no-inline-all-stringops |
-MASK_INLINE_ALL_STROPS |
不内联所有已知字符串操作 |
push-args |
-MASK_NO_PUSH_ARGS |
使用push指令保存溢出的参数(outgoing argument) |
no-push-args |
MASK_NO_PUSH_ARGS |
不使用push指令保存溢出的参数(outgoing argument) |
accumulate-outgoing-args |
MASK_ACCUMULATE_OUTGOING_ARGS |
使用push指令保存溢出的参数(outgoing argument) |
no-accumulate-outgoing-args |
-MASK_ACCUMULATE_OUTGOING_ARGS |
不使用push指令保存溢出的参数(outgoing argument) |
mmx |
MASK_MMX |
支持使用MMX的内建函数 |
no-mmx |
-MASK_MMX |
不支持使用MMX的内建函数 |
3dnow |
MASK_3DNOW |
支持使用3DNow!的内建函数 |
no-3dnow |
-MASK_3DNOW |
不支持使用3DNow!的内建函数 |
sse |
MASK_SSE |
支持使用MMX和SSE的内建函数,及MMX和SSE用于代码生成 |
no-sse |
-MASK_SSE |
不支持使用MMX和SSE的内建函数,及MMX和SSE用于代码生成 |
sse2 |
MASK_SSE2 |
支持使用MMX,SSE和SSE2的内建函数,及MMX,SSE和SSE2用于代码生成 |
no-sse2 |
-MASK_SSE2 |
不支持使用MMX,SSE和SSE2的内建函数,及MMX,SSE和SSE2用于代码生成 |
sse3 |
MASK_SSE3 |
支持使用MMX,SSE,SSE2和SSE3的内建函数,及MMX,SSE,SSE2和SSE3用于代码生成 |
no-sse3 |
-MASK_SSE3 |
不支持使用MMX,SSE,SSE2和SSE3的内建函数,及MMX,SSE,SSE2和SSE3用于代码生成 |
128bit-long-double |
MASK_128BIT_LONG_DOUBLE |
sizeof(long double) 是16 |
96bit-long-double |
-MASK_128BIT_LONG_DOUBLE |
sizeof(long double) 是12 |
64 |
MASK_64BIT |
产生64位x86-64代码 |
32 |
-MASK_64BIT |
产生32位i386代码 |
ms-bitfields |
MASK_MS_BITFIELD_LAYOUT |
使用原生的(MS)位域布局 |
no-ms-bitfields |
-MASK_MS_BITFIELD_LAYOUT |
使用gcc默认的位域布局 |
red-zone |
-MASK_NO_RED_ZONE |
在x86-64代码中使用红区(red-zone) |
no-red-zone |
MASK_NO_RED_ZONE |
不在x86-64代码中使用红区(red-zone) |
tls-direct-seg-refs |
MASK_TLS_DIRECT_SEG_REFS |
当访问tls数据时,直接引用%gs |
no-tls-direct-seg-refs |
-MASK_TLS_DIRECT_SEG_REFS |
当访问tls数据时,不直接引用%gs |
默认选项 |
TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT| TARGET_TLS_DIRECT_SEG_REFS_DEFAULT |
表 9:用于i386系统的target_switches
上面在3839行,target_flags包含了位旗标来指示我们正在为之编译的机器的亚型,而target_flags_explicit是target_flags的一个掩模(mask),target_flags包含了X的比特,如果X出现在命令行上。
而在3854行,target_options也是与目标平台相关的选项,但这些选项必须被赋值。它的内容从TARGET_OPTIONS得来,而TARGET_OPTIONS在i386.h中定义。
1176 #ifdef TARGET_OPTIONS in toplev.c
1177 static const struct
1178 {
1179 const char *const prefix;
1180 const char **const variable;
1181 const char *const description;
1182 const char *const value;
1183 }
1184 target_options[] = TARGET_OPTIONS;
1185 #endif
前缀
|
变量 |
描述 |
值 |
tune= |
&ix86_tune_string |
为指定的CPU调度指令 |
0 |
fpmath= |
&ix86_fpmath_string |
使用给定的指令集产生浮点数学计算 |
0 |
arch= |
&ix86_arch_string |
为指定的CPC产生代码 |
0 |
regparm= |
&ix86_regparm_string |
用于传递参数的寄存器数目 |
0 |
align-loops= [obsolete] |
&ix86_align_loops_string |
对齐循环代码至该值的2的指数倍边界 |
0 |
align-jumps=[obsolete] |
&ix86_align_jumps_string |
跳转目的对齐至该值的2的指数倍边界 |
0 |
align-functions=[obsolete] |
&ix86_align_funcs_string |
函数的起始地址对齐至该值的2的指数倍边界 |
0 |
preferred-stack-boundary= |
x86_preferred_stack_boundary_string |
尽量把栈对齐在该值的2的指数倍边界 |
0 |
branch-cost= |
&ix86_branch_cost_string |
跳转的代价(1-5,任意单位) |
0 |
cmodel= |
&ix86_cmodel_string |
使用指定的x86-64代码模式 |
0 |
debug-arg |
&ix86_debug_arg_string |
"" /* Undocumented. */ |
0 |
asm= |
&ix86_asm_string |
使用指定的汇编方言 |
0 |
tls-dialect= |
&ix86_tls_dialect_string |
使用指定的线程局部储存方言 |
0 |
表 10:用于i386系统的target_options
注意到上表中的值域总是0,因此在set_target_switch,3865行的代码块总是得到执行,使对应的variable得到设置。
在decode_options的605行,当调用set_target_switch时,传入的参数是“”,这等同于0,从而从TARGET_SWITCHES获得值。
在设置了选项的默认值后,在615行, OPTIMIZATION_OPTIONS根据指定的目标平台调整这些默认值。对于x86系统,这个宏及相关函数有如下定义。
512 #define OPTIMIZATION_OPTIONS(LEVEL, SIZE) / in i386.h
513 optimization_options ((LEVEL), (SIZE))
1502 void
1503 optimization_options (int level, int size ATTRIBUTE_UNUSED) in i386.c
1504 {
1505 /* For -O2 and beyond, turn off -fschedule-insns by default. It tends to
1506 make the problem with not enough registers even worse. */
1507 #ifdef INSN_SCHEDULING
1508 if (level > 1)
1509 flag_schedule_insns = 0;
1510 #endif
1511
1512 /* The default values of these switches depend on the TARGET_64BIT
1513 that is not known at this moment. Mark these values with 2 and
1514 let user the to override these. In case there is no command line option
1515 specifying them, we will set the defaults in override_options. */
1516 if (optimize >= 1)
1517 flag_omit_frame_pointer = 2;
1518 flag_pcc_struct_return = 2;
1519 flag_asynchronous_unwind_tables = 2;
1520 }
上面,flag_schedule_insn和flag_omit_frame_pointer 之前已碰到。而其他,其细节如下。
flag_pcc_struct_return(-fpcc-struct-return),如果为非0值,生成代码,把所有的结构体存放在内存中来返回,即便它们小得可以放进寄存器。通过寄存器或内存返回结构体的确切的协定(precise convention),依赖于目标平台。虽然产生效率受损的代码,但在与由别的编译器生成的目标文件链接时,可能需要这个选项。
同样(-freg-struct-return),如果为非0值,生成代码,把小的结构体放入寄存器返回。如果它们不是小到可以放入寄存器,则通过内存返回。通过寄存器或内存返回结构体的确切的协定(precise convention),依赖于目标平台。
flag_asynchronous_unwind_tables(-fasynchronous-unwind-tables),如果为非0值,当目标机器支持时,生成DWARF2格式的回退表(unwind table)。表精切记录了每个指令的边界,因此它可以在异步事件(asynchronous events,例如调试器或垃圾收集器)中,用于回退栈(stack unwinding)。