GCC-3.4.6源代码学习笔记(69)

来源:互联网 发布:js函数注释规范 编辑:程序博客网 时间:2024/04/28 03:06

4.3.3. 初始化库函数调用表

机器描述文件给出了一个途径把特定的操作构建为RTL形式。对于指令生成,编译器尝试打开已编码的RTL代码(如果是开放编码的(open-coded),没有进行真正的函数调用,只是在同等代码的展开;而封闭编码的(close-coded)则导致函数的调用。在编译器界(compiler circles),短语“开放编码”(open coded)的含义甚至更为宽泛。例如,某些机器具有花哨的指令来完成某些计算中的几步,比如计算多项式的POLY指令,或使用数组下标的INDEX指令(有时带有内建的构建检查)。事实证明,给定架构的在特定实现上,执行多个简单的指令比使用这个花哨指令要快。这在有可选加速硬件的微编码(microcoded)系统中,更容易发生——例如,INDEX可能微编码了一个乘法,需要十多个时钟周期,而更简单的MUL然后ADD使用硬件乘法器,故能在几个时钟周期完成。现今,除了并行分发(parallel-issue)微处理器,通常都会发生:例如,x86ENTER指令,在某些x86 CPU上,比等效的指令序列更慢。(尤其在因为某些特别的知识,例如,“我们知道在这个叶函数(leaf function)中,不需要分开的栈,栈框指针,也不需要任何栈调整”,编译器可以省略一些步骤的情况下)编译器开发者,在避免了使用慢的ENTEREXIT指令时,会这样说“ 我们开放编码了函数的进入与退出”)。如果不可能,编译器将调用库例程来处理操作。

 

lang_dependent_init (continue)

 

4540     init_optabs ();

 

5177 void

5178 init_optabs (void)                                                                                      in optabs.c

5179 {

5180   unsigned int i;

5181

5182   /* Start by initializing all tables to contain CODE_FOR_nothing.  */

5183

5184   for (i = 0; i < NUM_RTX_CODE; i++)

5185     setcc_gen_code[i] = CODE_FOR_nothing;

5186

5187 #ifdef HAVE_conditional_move

5188   for (i = 0; i < NUM_MACHINE_MODES; i++)

5189     movcc_gen_code[i] = CODE_FOR_nothing;

5190 #endif

 

由表示条件(比如,EQLT等)的rtx-code索引的setcc_gen_code给出了指令码,来构建测试该条件的条件保存指令。而由机器模式索引的movcc_gen_code给出了指令码,来构建一个条件移动指令。

 

init_optabs (continue)

 

5192   add_optab = init_optab (PLUS);

5193   addv_optab = init_optabv (PLUS);

5194   sub_optab = init_optab (MINUS);

5195   subv_optab = init_optabv (MINUS);

5196   smul_optab = init_optab (MULT);

5197   smulv_optab = init_optabv (MULT);

5198   smul_highpart_optab = init_optab (UNKNOWN);

5199   umul_highpart_optab = init_optab (UNKNOWN);

5200   smul_widen_optab = init_optab (UNKNOWN);

5201   umul_widen_optab = init_optab (UNKNOWN);

5202   sdiv_optab = init_optab (DIV);

5203   sdivv_optab = init_optabv (DIV);

5204   sdivmod_optab = init_optab (UNKNOWN);

5205   udiv_optab = init_optab (UDIV);

5206   udivmod_optab = init_optab (UNKNOWN);

5207   smod_optab = init_optab (MOD);

5208   umod_optab = init_optab (UMOD);

5209   ftrunc_optab = init_optab (UNKNOWN);

5210   and_optab = init_optab (AND);

5211   ior_optab = init_optab (IOR);

5212   xor_optab = init_optab (XOR);

5213   ashl_optab = init_optab (ASHIFT);

5214   ashr_optab = init_optab (ASHIFTRT);

5215   lshr_optab = init_optab (LSHIFTRT);

5216   rotl_optab = init_optab (ROTATE);

5217   rotr_optab = init_optab (ROTATERT);

5218   smin_optab = init_optab (SMIN);

5219   smax_optab = init_optab (SMAX);

5220   umin_optab = init_optab (UMIN);

5221   umax_optab = init_optab (UMAX);

5222   pow_optab = init_optab (UNKNOWN);

5223   atan2_optab = init_optab (UNKNOWN);

5224

5225   /* These three have codes assigned exclusively for the sake of

5226     have_insn_for.  */

5227   mov_optab = init_optab (SET);

5228   movstrict_optab = init_optab (STRICT_LOW_PART);

5229   cmp_optab = init_optab (COMPARE);

5230

5231   ucmp_optab = init_optab (UNKNOWN);

5232   tst_optab = init_optab (UNKNOWN);

5233

5234   eq_optab = init_optab (EQ);

5235   ne_optab = init_optab (NE);

5236   gt_optab = init_optab (GT);

5237   ge_optab = init_optab (GE);

5238   lt_optab = init_optab (LT);

5239   le_optab = init_optab (LE);

5240   unord_optab = init_optab (UNORDERED);

5241

5242   neg_optab = init_optab (NEG);

5243   negv_optab = init_optabv (NEG);

5244   abs_optab = init_optab (ABS);

5245   absv_optab = init_optabv (ABS);

5246   addcc_optab = init_optab (UNKNOWN);

5247   one_cmpl_optab = init_optab (NOT);

5248   ffs_optab = init_optab (FFS);

5249   clz_optab = init_optab (CLZ);

5250   ctz_optab = init_optab (CTZ);

5251   popcount_optab = init_optab (POPCOUNT);

5252   parity_optab = init_optab (PARITY);

5253   sqrt_optab = init_optab (SQRT);

5254   floor_optab = init_optab (UNKNOWN);

5255   ceil_optab = init_optab (UNKNOWN);

5256   round_optab = init_optab (UNKNOWN);

5257   btrunc_optab = init_optab (UNKNOWN);

5258   nearbyint_optab = init_optab (UNKNOWN);

5259   sin_optab = init_optab (UNKNOWN);

5260   cos_optab = init_optab (UNKNOWN);

5261   exp_optab = init_optab (UNKNOWN);

5262   log_optab = init_optab (UNKNOWN);

5263   tan_optab = init_optab (UNKNOWN);

5264   atan_optab = init_optab (UNKNOWN);

5265   strlen_optab = init_optab (UNKNOWN);

5266   cbranch_optab = init_optab (UNKNOWN);

5267   cmov_optab = init_optab (UNKNOWN);

5268   cstore_optab = init_optab (UNKNOWN);

5269   push_optab = init_optab (UNKNOWN);

5270

5271   vec_extract_optab = init_optab (UNKNOWN);

5272   vec_set_optab = init_optab (UNKNOWN);

5273   vec_init_optab = init_optab (UNKNOWN);

 

上面init_optabinit_optabv左边是形如XXX_optab的宏,它从optab_table选择对应的项。optab_table是具有optab类型的全局数组。

 

41      struct optab_handlers GTY(())                                                                   in optabs.h

42      {

43        enum insn_code insn_code;

44        rtx libfunc;

45      };

 

在其定义中,insn_code域指出在特定的机器模式(on a particular machine mode)下,如何为该操作生成指令。如果目标机器没有这样的指令,它就是CODE_FOR_nothing。域libfunc是可以用于执行该操作的库函数名。

 

47      struct optab GTY(())                                                                                in optabs.h

48      {

49        enum rtx_code code;

50        struct optab_handlers handlers[NUM_MACHINE_MODES];

51      };

52      typedef struct optab * optab;

 

在后端的章节里,我们将会知道insn_code描述了目标机器所能支持的指令(作为结果,insn_code必须由工具从机器描述文件产生)。而rtx_code描述了由前端产生的,与目标机器无关的,RTL形式的指令。结构体optabrtx_code映射到insn_code。注意到handlers是一个数组,因为在目标机器,不同机器模式(mode)的操作,通常需要不同的指令。

 

4910 static inline optab

4911 init_optab (enum rtx_code code)                                                          in optabs.c

4912 {

4913   optab op = new_optab ();

4914   op->code = code;

4915   code_to_optab[(int) code] = op;

4916   return op;

4917 }

 

4921 static inline optab

4922 init_optabv (enum rtx_code code)

4923 {

4924   optab op = new_optab ();

4925   op->code = code;

4926   return op;

4927 }

 

这里操作名字后跟“v”的操作版本与没有“v”的版本共享同一个rtx-code,其区别在于,对于“v”版本,如果其计算结果发生溢出,会引发陷阱(trap)。这通过flag_trapv的值来选定适用的版本。

 

init_optabs (continue)

 

5274   /* Conversions.  */

5275   sext_optab = init_convert_optab (SIGN_EXTEND);

5276   zext_optab = init_convert_optab (ZERO_EXTEND);

5277   trunc_optab = init_convert_optab (TRUNCATE);

5278   sfix_optab = init_convert_optab (FIX);

5279   ufix_optab = init_convert_optab (UNSIGNED_FIX);

5280   sfixtrunc_optab = init_convert_optab (UNKNOWN);

5281   ufixtrunc_optab = init_convert_optab (UNKNOWN);

5282   sfloat_optab = init_convert_optab (FLOAT);

5283   ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);

 

C++中,我们可以使用例如(int) f这样的语句进行类型转换。这干净方便,不需要考虑数据表达的细节。不过,这不是理所当然和免费的。必须为每个被允许的类型转换定义转换的方法。这就是convert_optab的来由。

上面,在init_convert_optab的左手边,宏XXX_optabconvert_optab_table中选择对应的项。convert_optab_table是具有convert_optab类型全局数组。

 

57      struct convert_optab GTY(())                                                                    in optabs.h

58      {

59        enum rtx_code code;

60        struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];

61      };

62      typedef struct convert_optab *convert_optab;

 

在其定义中,handlers是一个2维数组,记录了模式间的转换。

 

4930 static inline convert_optab

4931 init_convert_optab (enum rtx_code code)                                                     in optabs.c

4932 {

4933   convert_optab op = new_convert_optab ();

4934   op->code = code;

4935   return op;

4936 }

 

这里movstr_optab记录了执行块移动的指令的insn_codeclrstr_optab记录了执行块清除的指令的insn_codecmpstr_optabcmpmem_optab记录了2种执行块比较的指令的insn_code。而reload_in_optabreload_out_optab记录了,在执行特殊对象的输出及输入重新载入时(input and output reloads),所需要的指令的insn_code。它们提供了一个地方来传递一个工作寄存器(scratch register)。

 

init_optabs (continue)

 

5285   for (i = 0; i < NUM_MACHINE_MODES; i++)

5286   {

5287     movstr_optab[i] = CODE_FOR_nothing;

5288     clrstr_optab[i] = CODE_FOR_nothing;

5289     cmpstr_optab[i] = CODE_FOR_nothing;

5290     cmpmem_optab[i] = CODE_FOR_nothing;

5291

5292 #ifdef HAVE_SECONDARY_RELOADS

5293     reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;

5294 #endif

5295   }

5296

5297   /* Fill in the optabs with the insns we support.  */

5298   init_all_optabs ();

 

现在从前端看来,所有的optabs已经填入了相应的rtx_code,但前端不知道任何关于insn_code的事情,这是后端的事。为了完成optabs,后端特别地从机器描述文件,由genopinit工具产生了函数init_all_optabs。它帮助填入insn_code,下面是该函数的代码片段。

 

  sext_optab->handlers[SImode][HImode].insn_code = CODE_FOR_extendhisi2;

  sext_optab->handlers[HImode][QImode].insn_code = CODE_FOR_extendqihi2;

  sext_optab->handlers[SImode][QImode].insn_code = CODE_FOR_extendqisi2;

  setcc_gen_code[EQ] = CODE_FOR_seq;

  setcc_gen_code[NE] = CODE_FOR_sne;

  setcc_gen_code[GT] = CODE_FOR_sgt;

  setcc_gen_code[GTU] = CODE_FOR_sgtu;

 

  bcc_gen_fctn[EQ] = gen_beq;

  bcc_gen_fctn[NE] = gen_bne;

  bcc_gen_fctn[GT] = gen_bgt;

  bcc_gen_fctn[GTU] = gen_bgtu;

 

上面sext_optabconvert_optab_table中选出用于符号扩展的convert_optabHandlers的第一个索引是目标模式第二个是源模式。在赋值语句的右边是insn_code

现在setcc_gen_code已经为正确的insn_code初始化如果目标机器提供这样的指令。注意到。setcc_gen_code中不是所有的机器模式都能匹配到有意义的insn_code即非CODE_FOR_nothing),这意味着这部分不能开放编码open coded),而只能调用库例程。

再者,具有类型rtx_fun的全局数组bcc_gen_fctn给出测试条件,诸如EQ(等于),LT(小于),的方法。显然,gen_XXX也是从机器描述文件产生的,可以在insn_emit.c中找到其定义。

 

init_optabs (continue)

 

5300   /* Initialize the optabs with the names of the library functions.  */

5301   init_integral_libfuncs (add_optab, "add", '3');

5302   init_floating_libfuncs (add_optab, "add", '3');

5303   init_integral_libfuncs (addv_optab, "addv", '3');

5304   init_floating_libfuncs (addv_optab, "add", '3');

5305   init_integral_libfuncs (sub_optab, "sub", '3');

5306   init_floating_libfuncs (sub_optab, "sub", '3');

5307   init_integral_libfuncs (subv_optab, "subv", '3');

5308   init_floating_libfuncs (subv_optab, "sub", '3');

5309   init_integral_libfuncs (smul_optab, "mul", '3');

5310   init_floating_libfuncs (smul_optab, "mul", '3');

5311   init_integral_libfuncs (smulv_optab, "mulv", '3');

5312   init_floating_libfuncs (smulv_optab, "mul", '3');

5313   init_integral_libfuncs (sdiv_optab, "div", '3');

5314   init_floating_libfuncs (sdiv_optab, "div", '3');

5315   init_integral_libfuncs (sdivv_optab, "divv", '3');

5316   init_integral_libfuncs (udiv_optab, "udiv", '3');

5317   init_integral_libfuncs (sdivmod_optab, "divmod", '4');

5318   init_integral_libfuncs (udivmod_optab, "udivmod", '4');

5319   init_integral_libfuncs (smod_optab, "mod", '3');

5320   init_integral_libfuncs (umod_optab, "umod", '3');

5321   init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');

5322   init_integral_libfuncs (and_optab, "and", '3');

5323   init_integral_libfuncs (ior_optab, "ior", '3');

5324   init_integral_libfuncs (xor_optab, "xor", '3');

5325   init_integral_libfuncs (ashl_optab, "ashl", '3');

5326   init_integral_libfuncs (ashr_optab, "ashr", '3');

5327   init_integral_libfuncs (lshr_optab, "lshr", '3');

5328   init_integral_libfuncs (smin_optab, "min", '3');

5329   init_floating_libfuncs (smin_optab, "min", '3');

5330   init_integral_libfuncs (smax_optab, "max", '3');

5331   init_floating_libfuncs (smax_optab, "max", '3');

5332   init_integral_libfuncs (umin_optab, "umin", '3');

5333   init_integral_libfuncs (umax_optab, "umax", '3');

5334   init_integral_libfuncs (neg_optab, "neg", '2');

5335   init_floating_libfuncs (neg_optab, "neg", '2');

5336   init_integral_libfuncs (negv_optab, "negv", '2');

5337   init_floating_libfuncs (negv_optab, "neg", '2');

5338   init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');

5339   init_integral_libfuncs (ffs_optab, "ffs", '2');

5340   init_integral_libfuncs (clz_optab, "clz", '2');

5341   init_integral_libfuncs (ctz_optab, "ctz", '2');

5342   init_integral_libfuncs (popcount_optab, "popcount", '2');

5343   init_integral_libfuncs (parity_optab, "parity", '2');

5344

5345   /* Comparison libcalls for integers MUST come in pairs, signed/unsigned.  */

5346   init_integral_libfuncs (cmp_optab, "cmp", '2');

5347   init_integral_libfuncs (ucmp_optab, "ucmp", '2');

5348   init_floating_libfuncs (cmp_optab, "cmp", '2');

5349

5350  /* EQ etc are floating point only.  */

5351   init_floating_libfuncs (eq_optab, "eq", '2');

5352   init_floating_libfuncs (ne_optab, "ne", '2');

5353   init_floating_libfuncs (gt_optab, "gt", '2');

5354   init_floating_libfuncs (ge_optab, "ge", '2');

5355   init_floating_libfuncs (lt_optab, "lt", '2');

5356   init_floating_libfuncs (le_optab, "le", '2');

5357   init_floating_libfuncs (unord_optab, "unord", '2');

 

接下来是初始化optabhandlerlibfunc成员,这个域记录了可以执行由insn_code所指出的操作的库函数(但注意,这个库函数不一定存在)。

 

4991 static void

4992 init_integral_libfuncs (optab optable, const char *opname, int suffix)                     in optabs.c

4993 {

4994   int maxsize = 2*BITS_PER_WORD;

4995   if (maxsize < LONG_LONG_TYPE_SIZE)

4996     maxsize = LONG_LONG_TYPE_SIZE;

4997   init_libfuncs (optable, word_mode,

4998               mode_for_size (maxsize, MODE_INT, 0),

4999               opname, suffix);

5000 }

 

4998行,mode_for_size在指定的类别中(这里是MODE_INT),找出具有指定精度(这里由maxsize 表示)的机器模式。

 

4955 static void

4956 init_libfuncs (optab optable, int first_mode, int last_mode,                            in optabs.c

4957          const char *opname, int suffix)

4958 {

4959   int mode;

4960   unsigned opname_len = strlen (opname);

4961

4962   for (mode = first_mode; (int) mode <= (int) last_mode;

4963        mode = (enum machine_mode) ((int) mode + 1))

4964  {

4965     const char *mname = GET_MODE_NAME (mode);

4966     unsigned mname_len = strlen (mname);

4967     char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);

4968     char *p;

4969     const char *q;

4970

4971     p = libfunc_name;

4972    *p++ = '_';

4973     *p++ = '_';

4974     for (q = opname; *q; )

4975      *p++ = *q++;

4976     for (q = mname; *q; q++)

4977      *p++ = TOLOWER (*q);

4978     *p++ = suffix;

4979     *p = '/0';

4980

4981     optable->handlers[(int) mode].libfunc

4982       = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));

4983   }

4984 }

 

4981行之前,仅是构建库函数名。在4982行,在ggcgcc垃圾收集器)管理的栈上分配字符串。以5301行代码为例,所声明的库函数有:__addqi3__addhi3__addsi3__adddi3。不过这些库函数并没有实现,因为目标机器描述文件已经告诉了编译器,可以完成这个操作的指令的细节。

 

init_optabs (continue)

 

5359   /* Conversions.  */

5360   init_interclass_conv_libfuncs (sfloat_optab, "float", MODE_INT, MODE_FLOAT);

5361   init_interclass_conv_libfuncs (sfix_optab, "fix",   MODE_FLOAT, MODE_INT);

5362   init_interclass_conv_libfuncs (ufix_optab, "fixuns", MODE_FLOAT, MODE_INT);

 

对于类别间的转换,例如intfloat,这涉及到数据表达形式的转换。需要由以下的 init_interclass_conv_libfuncs填充handlers

 

5018 static void

5019 init_interclass_conv_libfuncs (convert_optab tab, const char *opname,           in optabs.c

5020                           enum mode_class from_class,

5021                           enum mode_class to_class)

5022 {

5023   enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);

5024   enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);

5025   size_t opname_len = strlen (opname);

5026   size_t max_mname_len = 0;

5027

5028   enum machine_mode fmode, tmode;

5029   const char *fname, *tname;

5030   const char *q;

5031   char *libfunc_name, *suffix;

5032   char *p;

5033

5034   for (fmode = first_from_mode;

5035        fmode != VOIDmode;

5036        fmode = GET_MODE_WIDER_MODE (fmode))

5037     max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));

5038

5039   for (tmode = first_to_mode;

5040        tmode != VOIDmode;

5041        tmode = GET_MODE_WIDER_MODE (tmode))

5042     max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));

5043

5044   libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);

5045   libfunc_name[0] = '_';

5046   libfunc_name[1] = '_';

5047   memcpy (&libfunc_name[2], opname, opname_len);

5048   suffix = libfunc_name + opname_len + 2;

5049

5050   for (fmode = first_from_mode; fmode != VOIDmode;

5051        fmode = GET_MODE_WIDER_MODE (fmode))

5052     for (tmode = first_to_mode; tmode != VOIDmode;

5053          tmode = GET_MODE_WIDER_MODE (tmode))

5054     {

5055       fname = GET_MODE_NAME (fmode);

5056       tname = GET_MODE_NAME (tmode);

5057

5058       p = suffix;

5059       for (q = fname; *q; p++, q++)

5060         *p = TOLOWER (*q);

5061       for (q = tname; *q; p++, q++)

5062         *p = TOLOWER (*q);

5063

5064       *p = '/0';

5065

5066       tab->handlers[tmode][fmode].libfunc

5067         = init_one_libfunc (ggc_alloc_string (libfunc_name,

5068                                        p - libfunc_name));

5069     }

5070 }

 

同样,这里声明的大多数转换库函数都没有真正实现(参考libgcc2.c)。它们有对应的指令。

 

init_optabs (continue)

 

5364   /* sext_optab is also used for FLOAT_EXTEND.  */

5365   init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);

5366   init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);

 

前面我们看到,单精度和双精度浮点数实际上是不同的表示方式,因而从单精度扩展到双精度也好,从双精度截短到单精度也好,本质上这是个转换。因此,也需要准备转换函数。

 

5077 static void

5078 init_intraclass_conv_libfuncs (convert_optab tab, const char *opname,           in optabs.c

5079                      enum mode_class class, bool widening)

5080 {

5081   enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);

5082   size_t opname_len = strlen (opname);

5083   size_t max_mname_len = 0;

5084

5085   enum machine_mode nmode, wmode;

5086   const char *nname, *wname;

5087  const char *q;

5088   char *libfunc_name, *suffix;

5089   char *p;

5090

5091   for (nmode = first_mode; nmode != VOIDmode;

5092        nmode = GET_MODE_WIDER_MODE (nmode))

5093     max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));

5094

5095   libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);

5096   libfunc_name[0] = '_';

5097   libfunc_name[1] = '_';

5098   memcpy (&libfunc_name[2], opname, opname_len);

5099   suffix = libfunc_name + opname_len + 2;

5100

5101   for (nmode = first_mode; nmode != VOIDmode;

5102        nmode = GET_MODE_WIDER_MODE (nmode))

5103     for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;

5104         wmode = GET_MODE_WIDER_MODE (wmode))

5105     {

5106       nname = GET_MODE_NAME (nmode);

5107       wname = GET_MODE_NAME (wmode);

5108

5109       p = suffix;

5110       for (q = widening ? nname : wname; *q; p++, q++)

5111         *p = TOLOWER (*q);

5112       for (q = widening ? wname : nname; *q; p++, q++)

5113         *p = TOLOWER (*q);

5114

5115       *p++ = '2';

5116       *p = '/0';

5117

5118       tab->handlers[widening ? wmode : nmode]

5119                  [widening ? nmode : wmode].libfunc

5120           = init_one_libfunc (ggc_alloc_string (libfunc_name,

5121                                          p - libfunc_name));

5122     }

5123 }

 

同样这些转换库函数都没有实现,这些操作还是依赖机器描述文件给出的指令。

 

init_optabs (continue)

 

5368   /* Use cabs for double complex abs, since systems generally have cabs.

5369     Don't define any libcall for float complex, so that cabs will be used.  */

5370   if (complex_double_type_node)

5371     abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc

5372       = init_one_libfunc ("cabs");

5373

5374   /* The ffs function operates on `int'.  */

5375   ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc

5376     = init_one_libfunc ("ffs");

5377

5378   abort_libfunc = init_one_libfunc ("abort");

5379   memcpy_libfunc = init_one_libfunc ("memcpy");

5380   memmove_libfunc = init_one_libfunc ("memmove");

5381   bcopy_libfunc = init_one_libfunc ("bcopy");

5382   memcmp_libfunc = init_one_libfunc ("memcmp");

5383   bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");

5384   memset_libfunc = init_one_libfunc ("memset");

5385   bzero_libfunc = init_one_libfunc ("bzero");

5386   setbits_libfunc = init_one_libfunc ("__setbits");

5387

5388   unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS

5389                                        ? "_Unwind_SjLj_Resume"

5390                                         : "_Unwind_Resume");

5391 #ifndef DONT_USE_BUILTIN_SETJMP

5392   setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");

5393   longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");

5394 #else

5395   setjmp_libfunc = init_one_libfunc ("setjmp");

5396   longjmp_libfunc = init_one_libfunc ("longjmp");

5397 #endif

5398   unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");

5399   unwind_sjlj_unregister_libfunc

5400     = init_one_libfunc ("_Unwind_SjLj_Unregister");

5401

5402   /* For function entry/exit instrumentation.  */

5403   profile_function_entry_libfunc

5404     = init_one_libfunc ("__cyg_profile_func_enter");

5405   profile_function_exit_libfunc

5406     = init_one_libfunc ("__cyg_profile_func_exit");

5407

5408   gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");

5409   gcov_init_libfunc = init_one_libfunc ("__gcov_init");

5410

5411   if (HAVE_conditional_trap)

5412     trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);

5413

5414   /* Allow the target to add more libcalls or rename some, etc.  */

5415   targetm.init_libfuncs ();

5416 }

 

gcc的安装目录下有lib子目录,里面是编译器用到的库文件(当然,是根据gcc的源代码,在安装gcc时编译出来的)。使用nm工具,可以找出上面大多数的库函数名。5415行的钩子init_libfuncs使得目标机器有机会加入自己的库函数或重命名某些库函数,不过对于x86机器,这不需要。