common_handle_option (continue)
909 case OPT_fcall_used_:
910 fix_register (arg, 0, 1);
911 break;
912
913 case OPT_fcall_saved_:
914 fix_register (arg, 0, 0);
915 break;
916
917 case OPT_fcaller_saves:
918 flag_caller_saves = value;
919 break;
920
921 case OPT_fcommon:
922 flag_no_common = !value;
923 break;
924
925 case OPT_fcprop_registers:
926 flag_cprop_registers = value;
927 break;
928
929 case OPT_fcrossjumping:
930 flag_crossjumping = value;
931 break;
932
933 case OPT_fcse_follow_jumps:
934 flag_cse_follow_jumps = value;
935 break;
936
937 case OPT_fcse_skip_blocks:
938 flag_cse_skip_blocks = value;
939 break;
940
941 case OPT_fdata_sections:
942 flag_data_sections = value;
943 break;
944
945 case OPT_fdefer_pop:
946 flag_defer_pop = value;
947 break;
948
949 case OPT_fdelayed_branch:
950 flag_delayed_branch = value;
951 break;
952
953 case OPT_fdelete_null_pointer_checks:
954 flag_delete_null_pointer_checks = value;
955 break;
选项–fcall-used-`register`使具名寄存器可用于寄存器分配,但其内容可被函数调用所破坏。它可被分配用于临时存储,但必须在函数调用后重新加载。这个选项不可用于有固定用途的寄存器(例如栈框指针或栈指针)。寄存器的名字依赖于目标平台,由机器描述中的REGISTER_NAMES宏来命名。
而选项–fcaller-saved-`register`使具名寄存器可用于保存值,而且其内容不被函数调用破坏。以此选项设置编译的函数必须保持及恢复该寄存器的内容。这个选项不可用于有固定用途的寄存器(例如栈框指针或栈指针)。寄存器的名字依赖于目标平台,由机器描述中的REGISTER_NAMES宏来命名。
这2个选项均由fix_register处理。注意传递给函数的call_used参数。
720 void
721 fix_register (const char *name, int fixed, int call_used) in regclass.c
722 {
723 int i;
724
725 /* Decode the name and update the primary form of
726 the register info. */
727
728 if ((i = decode_reg_name (name)) >= 0)
729 {
730 if ((i == STACK_POINTER_REGNUM
731 #ifdef HARD_FRAME_POINTER_REGNUM
732 || i == HARD_FRAME_POINTER_REGNUM
733 #else
734 || i == FRAME_POINTER_REGNUM
735 #endif
736 )
737 && (fixed == 0 || call_used == 0))
738 {
739 static const char * const what_option[2][2] = {
740 { "call-saved", "call-used" },
741 { "no-such-option", "fixed" }};
742
743 error ("can't use '%s' as a %s register", name,
744 what_option[fixed][call_used]);
745 }
746 else
747 {
748 fixed_regs[i] = fixed;
749 call_used_regs[i] = call_used;
750 #ifdef CALL_REALLY_USED_REGISTERS
751 if (fixed == 0)
752 call_really_used_regs[i] = call_used;
753 #endif
754 }
755 }
756 else
757 {
758 warning ("unknown register name: %s", name);
759 }
760 }
decode_reg_name用于获取寄存器名。对于汇编语言,类如Linux所使用的,使用前缀%来引用寄存器,在下面的681行,strip_reg_name除去这个前缀。注意到,我们可以使用十进制数字或名字来选择寄存器。对于名字,它由reg_names 来匹配。reg_names包含由REGISTER_NAMES指定的寄存器名。
673 int
674 decode_reg_name (const char *asmspec) in varasm.c
675 {
676 if (asmspec != 0)
677 {
678 int i;
679
680 /* Get rid of confusing prefixes. */
681 asmspec = strip_reg_name (asmspec);
682
683 /* Allow a decimal number as a "register name". */
684 for (i = strlen (asmspec) - 1; i >= 0; i--)
685 if (! ISDIGIT (asmspec[i]))
686 break;
687 if (asmspec[0] != 0 && i < 0)
688 {
689 i = atoi (asmspec);
690 if (i < FIRST_PSEUDO_REGISTER && i >= 0)
691 return i;
692 else
693 return -2;
694 }
695
696 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
697 if (reg_names[i][0]
698 && ! strcmp (asmspec, strip_reg_name (reg_names [i])))
699 return i;
700
701 #ifdef ADDITIONAL_REGISTER_NAMES
702 {
703 static const struct { const char *const name; const int number; } table[]
704 = ADDITIONAL_REGISTER_NAMES;
705
706 for (i = 0; i < (int) ARRAY_SIZE (table); i++)
707 if (! strcmp (asmspec, table[i].name))
708 return table[i].number;
709 }
710 #endif /* ADDITIONAL_REGISTER_NAMES */
711
712 if (!strcmp (asmspec, "memory"))
713 return -4;
714
715 if (!strcmp (asmspec, "cc"))
716 return -3;
717
718 return -2;
719 }
720
721 return -1;
722 }
对于x86机器,REGISTER_NAMES定义了基本寄存器集。这部分寄存器可由编译器的真实寄存器号(hard-register-number)索引。
2746 #define HI_REGISTER_NAMES / in i386.h
2747 {"ax","dx","cx","bx","si","di","bp","sp", /
2748 "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)", /
2749 "argp", "flags", "fpsr", "dirflag", "frame", /
2750 "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7", /
2751 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" , /
2752 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", /
2753 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}
2754
2755 #define REGISTER_NAMES HI_REGISTER_NAMES
更者,对于x86机器,ADDITIONAL_REGISTER_NAMES定义了平台中额外的寄存器,但这部分寄存器不能由编译器的真实寄存器号(hard-register-number)索引。
2759 #define ADDITIONAL_REGISTER_NAMES / in i386.h
2760 { { "eax", 0 }, { "edx", 1 }, { "ecx", 2 }, { "ebx", 3 }, /
2761 { "esi", 4 }, { "edi", 5 }, { "ebp", 6 }, { "esp", 7 }, /
2762 { "rax", 0 }, { "rdx", 1 }, { "rcx", 2 }, { "rbx", 3 }, /
2763 { "rsi", 4 }, { "rdi", 5 }, { "rbp", 6 }, { "rsp", 7 }, /
2764 { "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, /
2765 { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 }, /
2766 { "mm0", 8}, { "mm1", 9}, { "mm2", 10}, { "mm3", 11}, /
2767 { "mm4", 12}, { "mm5", 13}, { "mm6", 14}, { "mm7", 15} }
因此在fix_register的748行,fixed_regs由真实寄存器号索引,对于有固定用途的寄存器,相应的比特位为1。这些寄存器不可用于分配通用伪寄存器。
在749行,call_used_regs亦由真实寄存器号索引,对于有固定用途或能被函数调用破坏的寄存器,相应的比特位为1。这些寄存器不可用于分配生命周期跨越多个函数调用的通用伪寄存器,除非在函数调用间对其进行保存/恢复操作。
在750行,宏CALL_REALLY_USED_REGISTERS在我们的目标平台下没有定义。call_really_used_regs亦没有被声明。
回到common_handle_option,在922行,flag_no_common(-fcommon),指明-fno-common 将使得编译器为每个全局变量,在数据段显式地分配空间。否则则是将它们分配于公共块,由链接器来解析(resolve),因此多次声明同一个全局变量将导致链接器把它们解析为1个。可以指定-fno-common来确认程序可以在其他不使用GCC的系统上编译链接。
在942行,flag_data_sections(-fdata-sections)如果非0,在汇编语言输出中,每个数据项被置于其自命名的段中。该段名由数据项名导出。这,仅在具有能使用分段优化空间分配链接器的机器上,带来好处。对于可执行代码的相同优化参见-ffunction-sections。对在其汇编代码中不支持分段的机器,这个选项将导致警告,并被忽略。即便在那些支持的机器上,除非链接器将其用于优化,也不会带来好处。事实上,这可能带来不利的影响,使得目标代码更大,加载更慢。
如果选项-p为概要分析(profiling)设置,这个选项(-fdata-sections)将无效。另外,因为代码重排(rearrangement of the code)的原因,使用-g选项及程序调试可能会有问题。
在950行,flag_delayed_branch(-fdelayed-branch)如果非0,这个选项仅在具有延迟跳转时隙(delayed branch slots)的机器上起作用。这涉及在决定跳转的分支的同时,加载并执行指令。在作出决定后,指令的结果可能被抛弃,取决于指令的位置及所作的决定。如果目标机器支持,这个标识将被各级优化所设置。它亦可被-fno-delayed-branch改写。
common_handle_option (continue)
957 case OPT_fdiagnostics_show_location_:
958 if (!strcmp (arg, "once"))
959 diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
960 else if (!strcmp (arg, "every-line"))
961 diagnostic_prefixing_rule (global_dc)
962 = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
963 else
964 return 0;
965 break;
966
967 case OPT_fdump_unnumbered:
968 flag_dump_unnumbered = value;
969 break;
970
971 case OPT_feliminate_dwarf2_dups:
972 flag_eliminate_dwarf2_dups = value;
973 break;
974
975 case OPT_feliminate_unused_debug_types:
976 flag_eliminate_unused_debug_types = value;
977 break;
978
979 case OPT_feliminate_unused_debug_symbols:
980 flag_debug_only_used_symbols = value;
981 break;
982
983 case OPT_fexceptions:
984 flag_exceptions = value;
985 break;
986
987 case OPT_fexpensive_optimizations:
988 flag_expensive_optimizations = value;
989 break;
990
991 case OPT_ffast_math:
992 set_fast_math_flags (value);
993 break;
994
995 case OPT_ffinite_math_only:
996 flag_finite_math_only = value;
997 break;
998
999 case OPT_ffixed_:
1000 fix_register (arg, 1, 1);
1001 break;
1002
1003 case OPT_ffunction_cse:
1004 flag_no_function_cse = !value;
1005 break;
1006
1007 case OPT_ffloat_store:
1008 flag_float_store = value;
1009 break;
1010
1011 case OPT_fforce_addr:
1012 flag_force_addr = value;
1013 break;
1014
1015 case OPT_fforce_mem:
1016 flag_force_mem = value;
1017 break;
1018
1019 case OPT_ffunction_sections:
1020 flag_function_sections = value;
1021 break;
1022
1023 case OPT_fgcse:
1024 flag_gcse = value;
1025 break;
1026
1027 case OPT_fgcse_lm:
1028 flag_gcse_lm = value;
1029 break;
1030
1031 case OPT_fgcse_sm:
1032 flag_gcse_sm = value;
1033 break;
1034
1035 case OPT_fgcse_las:
1036 flag_gcse_las = value;
1037 break;
1038
1039 case OPT_fguess_branch_probability:
1040 flag_guess_branch_prob = value;
1041 break;
1042
1043 case OPT_fident:
1044 flag_no_ident = !value;
1045 break;
1046
1047 case OPT_fif_conversion:
1048 flag_if_conversion = value;
1049 break;
1050
1051 case OPT_fif_conversion2:
1052 flag_if_conversion2 = value;
1053 break;
1054
1055 case OPT_finhibit_size_directive:
1056 flag_inhibit_size_directive = value;
1057 break;
1058
1059 case OPT_finline:
1060 flag_no_inline = !value;
1061 break;
1062
1063 case OPT_finline_functions:
1064 flag_inline_functions = value;
1065 break;
这段代码涉及下列变量。
flag_dump_unnumbered(-fdump-unnumbered)当使用-d选项调试编译器时,该选项将在输出文件中压制指令号及行号的产生。这使得用diff来比较转储更方便些。
flag_eliminate_dwarf2_dups(-feliminate-dwarf2-dups)如果非0,执行dwarf2的重复消除。
flag_eliminate_unused_debug_types(-feliminate-unused-debug-types)如果非0,执行未使用类型消除。
flag_debug_only_used_symbols(-feliminate-unused-debug-symbols)如果非0,标识只为使用的符号产生调试信息。
flag_exceptions(-fexceptions)如果非0,使能异常处理。这个选项产生额外的,必须的,处理异常抛出及捕获的代码。如果未指明这个选项,诸如Ada,Java及C++这些会抛出异常的语言,将自动指定该选项。
flag_finite_math_only(-ffinite-math-only)如果非0,表示不期望使用NaNs或+-无穷。
flag_no_function_cse(-fno-function-cse)如果非0,将导致构成函数调用的指令隐含地包含函数地址。如果为0(-ffunction-cse),函数调用通过保存在寄存器中的函数地址完成,这将产生更高效的代码。
flag_float_store(-ffloat-store)如果非0,不为浮点值分配寄存器。在某些机器上,这个选项可能导致寄存器扩展精度,超出语言所定义,因此能携带比保存于内存中的浮点值更高精度的值。这个选项仅用于当程序必须限制精度,以严格符号IEEE标准。
flag_force_addr(-ffloat-addr)如果非0,地址进行算术操作时,须被拷贝入寄存器。这会改进生成的代码,因为所需的地址通常之前已被加入寄存器,不需要再加载。
flag_function_sections(-ffunction-sections)如果非0,在汇编语言输出中,每个函数被置入其自命名的段中。段名由函数名导出。这,仅在具有能使用分段优化空间分配链接器的机器上,带来好处。对于数据项的相同优化参见-fdata-sections。对在其汇编代码中不支持分段的机器,这个选项将导致警告,并被忽略。即便在那些支持的机器上,除非链接器将其用于优化,也不会带来好处。事实上,这可能带来不利的影响,使得目标代码更大,加载更慢。
如果选项-p为概要分析(profiling)设置,这个选项(-fdata-sections)将无效。另外,因为代码重排(rearrangement of the code)的原因,使用-g选项及程序调试可能会有问题。
flag_gcse_lm(-fgcse-lm)如果非0,检测循环中的加载、保存操作,其中某些加载操作可以被移至循环前,从而只需做一次。通过此方式执行全局公共子表达式消除优化。这是默认的设置,但除非-Os设置了,它不会有任何作用。该设置亦可通过-no-fgcse-lm改写。
flag_gcse_sm(-fgcse-sm)如果非0,检测循环中的加载、保存操作,其中某些保存操作可以被移至循环后,从而只需做一次。通过此方式执行全局公共子表达式消除优化。这是默认的设置,但除非-Os设置了,它不会有任何作用。该设置亦可通过-no-fgcse-sm改写。
flag_gcse_las(-fgcse-las)如果非0,全局公共子表达式消除遍消除,跟在对同一内存位置的保存操作后的,加载操作(部分及完全冗余)。
flag_no_ident(-fno-ident)如果非0,表示忽略#ident指示。#ident指示带有一个字符串常量参数。在某些系统上,该字符串常量被拷贝入目标文件的特殊的段中。而在其他系统上,该指示被忽略。
flag_inhibit_size_directive(-finhibit-size-directive)如果非0,不输出汇编器的.size指示,以及如果函数被分开为位于不同内存块中的2部分时,其他会导致问题的指示。这个选项是用于编译crtstuff.c(GCC的一部分)的特例,不期望被用于其它目的。
选项-ffast-math,某些数学计算,如果违反一些ISO及IEEE规则,会执行得快一些。例如,设置了这个选项,就会假定,没有负数被传递给sqrt,及所有浮点数都是有效的。设置这个选项导致预处理器定义宏__FAST_MATH__。
这个选项由set_fast_math_flags来处理。
1590 void
1591 set_fast_math_flags (int set) in opts.c
1592 {
1593 flag_trapping_math = !set;
1594 flag_unsafe_math_optimizations = set;
1595 flag_finite_math_only = set;
1596 flag_errno_math = !set;
1597 if (set)
1598 {
1599 flag_signaling_nans = 0;
1600 flag_rounding_math = 0;
1601 }
1602 }
在这个函数中,
flag_trapping_math(-ftrapping-math)如果为0,表示浮点数学计算不会产生(用户可见)的陷入(trap)。这是非停顿IEEE754算术(nonstop IEEE 754 arithmetic)的一个例子。陷入的条件包括除0,溢出,下溢,无效,不景气,但不包括对信号NaNs(signaling NaNs) 的操作。
flag_unsafe_math_optimizations(-funsafe-math-optimizations)如果非0,表示出于速度考量,允许不安全的浮点算术优化。不保证符号IEEE标准,而且操作允许假定参数及其结果都是“正常的”(例如,传给SQRT是非负数)。
flag_errno_math,如果非0,表示前端期望算术操作维护errno,就像内建的SQRT。
flag_signaling_nans(-fsignaling-nans)如果非0,表示禁止信号NaNs(signaling NaNs)可见的变换。这个选项暗示,在任何IEEE信号NaNs上的操作,都会产生(用户可见)的陷入。
flag_rounding_math(-frounding-math)如果非0,表示禁止使用默认浮点取整行为的变换。
common_handle_option (continue)
1067 case OPT_finline_limit_:
1068 case OPT_finline_limit_eq:
1069 set_param_value ("max-inline-insns-single", value / 2);
1070 set_param_value ("max-inline-insns-auto", value / 2);
1071 set_param_value ("max-inline-insns-rtl", value);
1072 break;
1073
1074 case OPT_finstrument_functions:
1075 flag_instrument_function_entry_exit = value;
1076 break;
1077
1078 case OPT_fkeep_inline_functions:
1079 flag_keep_inline_functions =value;
1080 break;
1081
1082 case OPT_fkeep_static_consts:
1083 flag_keep_static_consts = value;
1084 break;
1085
1086 case OPT_fleading_underscore:
1087 flag_leading_underscore = value;
1088 break;
1089
1090 case OPT_floop_optimize:
1091 flag_loop_optimize = value;
1092 break;
1093
1094 case OPT_fmath_errno:
1095 flag_errno_math = value;
1096 break;
1097
1098 case OPT_fmem_report:
1099 mem_report = value;
1100 break;
1101
1102 case OPT_fmerge_all_constants:
1103 flag_merge_constants = value + value;
1104 break;
1105
1106 case OPT_fmerge_constants:
1107 flag_merge_constants = value;
1108 break;
1109
1110 case OPT_fmessage_length_:
1111 pp_set_line_maximum_length (global_dc->printer, value);
1112 break;
1113
1114 case OPT_fmove_all_movables:
1115 flag_move_all_movables = value;
1116 break;
1117
1118 case OPT_fnew_ra:
1119 flag_new_regalloc = value;
1120 break;
1121
1122 case OPT_fnon_call_exceptions:
1123 flag_non_call_exceptions = value;
1124 break;
1125
1126 case OPT_fold_unroll_all_loops:
1127 flag_old_unroll_all_loops = value;
1128 break;
1129
1130 case OPT_fold_unroll_loops:
1131 flag_old_unroll_loops = value;
1132 break;
1133
1134 case OPT_fomit_frame_pointer:
1135 flag_omit_frame_pointer = value;
1136 break;
1137
1138 case OPT_foptimize_register_move:
1139 flag_regmove = value;
1140 break;
1141
1142 case OPT_foptimize_sibling_calls:
1143 flag_optimize_sibling_calls = value;
1144 break;
1145
1146 case OPT_fpack_struct:
1147 flag_pack_struct = value;
1148 break;
1149
1150 case OPT_fpeel_loops:
1151 flag_peel_loops_set = true;
1152 flag_peel_loops = value;
1153 break;
1154
1155 case OPT_fpcc_struct_return:
1156 flag_pcc_struct_return = value;
1157 break;
1158
1159 case OPT_fpeephole:
1160 flag_no_peephole = !value;
1161 break;
1162
1163 case OPT_fpeephole2:
1164 flag_peephole2 = value;
1165 break;
1166
1167 case OPT_fpic:
1168 flag_pic = value;
1169 break;
1170
1171 case OPT_fpie:
1172 flag_pie = value;
1173 break;
1174
1175 case OPT_fprefetch_loop_arrays:
1176 flag_prefetch_loop_arrays = value;
1177 break;
上面,在1067和1068行,选项-finline-limit及–finline-limit=改写了参数"max-inline-insns-single","max-inline-insns-auto"和"max-inline-insns-rtl"(参考表 9:用于i386系统的target_switches)。
flag_instrument_function_entry_exit(-finstrument-functions)如果非0,插入代码,在每个函数的进入后和退出前调用一个函数。这些被调用的函数的原型如下:
void __cyg_profile_func_enter(void *this_fn,void *call_site);
void __cyg_profile_func_exit(void *this_fn,void *call_site);
参数this_fn是当前函数的地址,它可由符号表信息来确定。参数call_site确定调用者(caller,在某些平台上call_site信息是得不到的)。如果当前函数被展开为内联,这些函数的调用被插在内联代码的前后。出于识别的目的,必须存在当前函数的非内联版本,即便它所有的调用都被展开为内联代码。
为了防止这些代码的插入,函数可以被声明为具有属性no_instrument_function。这,对于异常处理句柄及不需要调用概要例程(profiling routines)的函数,是必须的。
flag_keep_inline_functions(-fkeep-inline-functions)如果非0,编译器将产生函数体,即便对该函数的所有引用都被展开为内联代码,并无实际上的调用。默认的选项是 -fno-keep-inline-functions,这时不被调用的函数不创建函数体。
flag_keep_static_consts(-fkeep-static-consts)如果非0,编译单元私有的常量值,即便没有被引用,也为之分配空间。为了防止为未使用的常量分配空间,应使用选项-fno-keep-static-consts。
flag_leading_underscore(-fleading-underscore)如果非0,强制为每个写入目标文件的符号加上前驱的“-”字符。选项-fno-leading-underscore则压制添加这个字符。这个选项用于需要与传统(legacy)汇编代码链接时。
mem_report(-fmem-report)如果非0,当编译器完成任务后,它打印出分配给每个数据类型内存的详细列表及其他内存分配信息。
flag_move_all_movables(-fmove-all-movables),如果非0,把所有不变量(invariant)表达式移出循环。是否产生更好的代码取决于源码中循环的结构。除了Fortran,默认的选项是-fno-move-all-movables。
flag_new_regalloc(-fnew-ra)如果非0,使用图着色寄存器分配器(graph coloring register allocator)。
flag_non_call_exceptions(-fnon-call-exceptions)如果非0,产生代码使得陷入指令(例如无效浮点操作或无效内存寻址)抛出异常。这个选项不普遍,因为它要求平台特定的运行时支持。而且这也仅限于硬件陷入信号,不包括普通的信号,例如SIGALRM或SIGTERM。
flag_old_unroll_all_loops(-fold-unroll-all-loops)如果非0,使能unroll.c中的循环展开(loop unrolling)。所有循环皆展开。这通常不是好的选择。
flag_old_unroll_loops(-fold-unroll-loops)如果非0,使能unroll.c中的循环展开(loop unrolling)。仅能在编译时刻或运行时刻能确知循环次数的循环被展开。
flag_optimize_sibling_calls(-foptimize-sibling-calls)如果非0,优化尾递归调用(recursive tail call)及兄弟调用(sibling call)。这个标识由O2,-O3,和-Os自动设置。默认选项是-fno-optimize-sibling-calls。以下是尾递归调用的例子:
int rewhim(int x,int y) {
. . .
return(rewhim(x+1,y));
}
优化可以通过插入代码跳转会函数顶部实现,而不是进行新的函数调用。下面的兄弟调用展示了相似的情形:
int whim(int x,int y) {
. . .
return(wham(x+1,y));
}
在一个兄弟调用中,对函数wham的调用不可避免,但whim的栈框可由调用删除,从而wham直接把返回值返回给whim的调用者。
flag_pack_struct(-fpack-struct)如果非0,压紧结构体中的成员,使得成员间没有插入实现对齐的空间。这将导致执行代码以较低的效率访问结构体成员,而且亦可使代码不与系统库兼容。
flag_peel_loops(-fpeel-loops)如果非0,使能循环剥离(loop peeling)优化。
flag_no_peephole(-fno-peephole)如果非0, 禁止窥孔优化(peephole)。
flag_prefetch_loop_arrays(-fprefetch-loop-arrays)如果非0,启动循环中数组的预取(prefetch)优化。