Studying note of GCC-3.4.6 source (178)
来源:互联网 发布:福建安全知识网络竞赛 编辑:程序博客网 时间:2024/05/29 11:45
5.13.5.3.2.2.3. Inline normal function
After handling functiondemanding inlining (by using “always_inline”), inlining rest functions are upto the compiler. As long as we don’t prohbit function by inlining option “-fno-inline”explicitly, flag_really_no_inlineat line 1326 is 0.
cgraph_decide_inline (continue)
1320 #ifdef ENABLE_CHECKING
1321 for (node = cgraph_nodes;node; node = node->next)
1322 if (node->aux || node->output)
1323 abort ();
1324 #endif
1325
1326 if (!flag_really_no_inline)
1327 {
1328 cgraph_decide_inlining_of_small_functions(inlined, inlined_callees);
1329 #ifdef ENABLE_CHECKING
1330 for (node =cgraph_nodes;node; node = node->next)
1331 if (node->aux || node->output)
1332 abort ();
1333 #endif
1334
1335 if (cgraph_dump_file)
1336 fprintf (cgraph_dump_file, "/nDecidingon functions called once:/n");
Here, parameter inlined and inlined_callees are used as storage,their contents set previously are irrelevant, and will be overwirtten in late.In below analysis, it uses Fibonacci heaps to sort function by instructionnumber after expansion. The detail of Fibonacci heaps is not covered here.
1100 static void
1101 cgraph_decide_inlining_of_small_functions (struct cgraph_node**inlined, in cgraphunit.c
1102 structcgraph_node **inlined_callees)
1103 {
1104 int i;
1105 struct cgraph_node *node;
1106 fibheap_t heap = fibheap_new ();
1107 struct fibnode **heap_node =
1108 xcalloc (cgraph_max_uid,sizeof (structfibnode *));
1109 int ninlined, ninlined_callees;
1110 int max_insns = ((HOST_WIDEST_INT) initial_insns
1111 * (100 + PARAM_VALUE (PARAM_INLINE_UNIT_GROWTH))/ 100);
1112
1113 /* Put all inline candidates into the heap. */
1114
1115 for (node = cgraph_nodes; node; node = node->next)
1116 {
1117 if (!node->local.inlinable || !node->callers
1118 || node->local.disregard_inline_limits)
1119 continue;
1120
1121 if (!cgraph_default_inline_p(node))
1122 {
1123 cgraph_set_inline_failed (node,
1124 N_("--param max-inline-insns-single limitreached"));
1125 continue;
1126 }
1127 heap_node[node->uid] =
1128 fibheap_insert (heap, cgraph_estimate_growth (node), node);
1129 }
As it is the compiler to make the decision, then if the functionshould be inlined, besides the inlinability, also depends on its size afterexpanding. For function declaring “inline”, this limitation is MAX_INLINE_INSNS_SINGLE(500 by default), while for other functions, the limitation is MAX_INLINE_INSNS_AUTO (100 by default). Notethat, the unit is instruction, not line.
1068 static bool
1069 cgraph_default_inline_p (struct cgraph_node *n) in cgraphunit.c
1070 {
1071 if (!DECL_INLINE (n->decl) || !DECL_SAVED_TREE(n->decl))
1072 returnfalse;
1073 if (DECL_DECLARED_INLINE_P (n->decl))
1074 returnn->global.insns < MAX_INLINE_INSNS_SINGLE;
1075 else
1076 returnn->global.insns < MAX_INLINE_INSNS_AUTO;
1077 }
If function fails in inlining, it needs to tell the caller about thefailure reason, unless the caller has been inline forcely (at that time, its inline_failedis NULL).
1081 static void
1082 cgraph_set_inline_failed (struct cgraph_node *node, constchar *reason) in cgraphunit.c
1083 {
1084 structcgraph_edge *e;
1085
1086 if (cgraph_dump_file)
1087 fprintf (cgraph_dump_file, "Inliningfailed: %s/n", reason);
1088 for (e = node->callers; e; e = e->next_caller)
1089 if (e->inline_failed)
1090 e->inline_failed = reason;
1091 }
Once the size of the function is within the limitation, add it into Fibonacciheaps, but what used as the key value is the increment of instruction numberdues to its expansion.
918 static int
919 cgraph_estimate_growth (struct cgraph_node *node) in cgraphunit.c
920 {
921 int growth = 0;
922 int calls_saved = 0;
923 int clones_added = 0;
924 structcgraph_edge *e;
925
926 for (e = node->callers; e; e = e->next_caller)
927 if (e->inline_failed)
928 {
929 growth += ((cgraph_estimate_size_after_inlining(1, e->caller, node)
930 -
931 e->caller->global.insns)*e->caller->global.cloned_times);
932 calls_saved += e->caller->global.cloned_times;
933 clones_added +=e->caller->global.cloned_times;
934 }
935
936 /* ??? Wrong forself recursive functions or cases where we decide to not
937 inline for different reasons, but it is notbig deal as in that case
938 we will keep thebody around, but we will also avoid some inlining. */
939 if (!node->needed &&!node->origin && !DECL_EXTERNAL (node->decl))
940 growth -= node->global.insns,clones_added--;
941
942 if (!calls_saved)
943 calls_saved = 1;
944
945 returngrowth;
946 }
However as now the analysises of its callers, callees haven’t beendone, it is a rough estimation (not include the size of functions calleddirectly or indirectly). With the advancing of below function analysis, theestimation approaches correct result. Because in below it will frequentlyoverwrite the key value of nodes, out of efficiency consideration, use Fibonacciheaps.
At line 1133, fibheap_extract_min removes node of minus keyvalue from Fibonacci heaps. At beginning, this value is just the instructionnumber of the function multiplies with the times it is invoked. Obviously,beginning at function with smallest key value is a good start, it is mostpossible the function at bottom of the call stack.
cgraph_decide_inlining_of_small_functions (continue)
1131 if (cgraph_dump_file)
1132 fprintf (cgraph_dump_file,"/nDeciding on smaller functions:/n");
1133 while (overall_insns <= max_insns&& (node = fibheap_extract_min (heap)))
1134 {
1135 struct cgraph_edge *e;
1136 int old_insns = overall_insns;
1137
1138 heap_node[node->uid] = NULL;
1139 if (cgraph_dump_file)
1140 fprintf (cgraph_dump_file,
1141 "/nConsidering %s with %i insns/n"
1142 " Estimated growth is %+i insns./n",
1143 cgraph_node_name (node),node->global.insns,
1144 cgraph_estimate_growth (node));
1145 if (!cgraph_default_inline_p(node))
1146 {
1147 cgraph_set_inline_failed (node,
1148 N_("--param max-inline-insns-singlelimit reached after inlining into the callee"));
1149 continue;
1150 }
1151 ninlined_callees = cgraph_inlined_callees(node, inlined_callees);
1152 for (e = node->callers; e; e = e->next_caller)
1153 if (e->inline_failed)
1154 {
1155 /* Marking recursive function inlinine has sane semanticand
1156 thus we should not warnon it. */
1157 if(e->caller == node)
1158 {
1159 e->inline_failed = "";
1160 continue;
1161 }
1162 ninlined = cgraph_inlined_into (e->caller, inlined);
1163 if(e->callee->output)
1164 e->inline_failed = "";
1165 if(e->callee->output
1166 || !cgraph_check_inline_limits(e->caller, node, inlined,
1167 ninlined,&e->inline_failed))
1168 {
1169 for(i = 0; i < ninlined; i++)
1170 inlined[i]->output = 0, inlined[i]->aux= 0;
1171 if (cgraph_dump_file)
1172 fprintf (cgraph_dump_file, " Not inlining into%s./n",
1173 cgraph_node_name (e->caller));
1174 continue;
1175 }
1176 cgraph_mark_inline (e->caller, node, inlined,ninlined,
1177 inlined_callees,ninlined_callees);
1178 if(heap_node[e->caller->uid])
1179 fibheap_replace_key (heap,heap_node[e->caller->uid],
1180 cgraph_estimate_growth(e->caller));
1181
1182 /* Size of the functions we updated into has changed, soupdate
1183 the keys. */
1184 for (i = 0; i < ninlined; i++)
1185 {
1186 inlined[i]->output = 0,inlined[i]->aux = 0;
1187 if (heap_node[inlined[i]->uid])
1188 fibheap_replace_key (heap,heap_node[inlined[i]->uid],
1189 cgraph_estimate_growth(inlined[i]));
1190 }
1191 if (cgraph_dump_file)
1192 fprintf (cgraph_dump_file,
1193 " Inlined into %s which now has %iinsns./n",
1194 cgraph_node_name (e->caller),
1195 e->caller->global.insns);
1196 }
1197
1198 /* Similarly all functions called by thefunction we just inlined
1199 are now called more times; update keys. */
1200
1201 for (e = node->callees; e; e = e->next_callee)
1202 if (e->inline_failed &&heap_node[e->callee->uid])
1203 fibheap_replace_key (heap,heap_node[e->callee->uid],
1204 cgraph_estimate_growth(e->callee));
1205
1206 for (i = 0;i < ninlined_callees; i++)
1207 {
1208 struct cgraph_edge *e;
1209
1210 for (e =inlined_callees[i]->callees; e; e = e->next_callee)
1211 if (e->inline_failed &&heap_node[e->callee->uid])
1212 fibheap_replace_key (heap,heap_node[e->callee->uid],
1213 cgraph_estimate_growth(e->callee));
1214
1215 inlined_callees[i]->output = 0;
1216 inlined_callees[i]->aux = 0;
1217 }
1218 if (cgraph_dump_file)
1219 fprintf (cgraph_dump_file,
1220 " Inlined %i times for a net change of%+i insns./n",
1221 node->global.cloned_times, overall_insns- old_insns);
1222 }
1223 while ((node= fibheap_extract_min (heap)) != NULL)
1224 if(!node->local.disregard_inline_limits)
1225 cgraph_set_inline_failed(node, N_("--param inline-unit-growth limit reached"));
1226 fibheap_delete (heap);
1227 free (heap_node);
1228}
Except giving priority to function of smaller expanding size, thecompiler inlines function in the same way, once function expansion arrivesthreshold, no inlining is allowed anymore. The criterion, one way is the totalincrement of the instruction number, it is controlled by max_insns at line 1133 (by default,compiler allows increasing instruction number by 50%); on the other way isshown by cgraph_check_inline_limits.
1018 static bool
1019 cgraph_check_inline_limits (struct cgraph_node *to, structcgraph_node *what,
1020 structcgraph_node **inlined, int ninlined,
1021 const char**reason)
1022 {
1023 int i;
1024 int times = 0;
1025 structcgraph_edge *e;
1026 int newsize;
1027 int limit;
1028
1029 for (e =to->callees; e; e = e->next_callee)
1030 if (e->callee == what)
1031 times++;
1032
1033 /* When inlininglarge function body called once into small function,
1034 take the inlinedfunction as base for limiting the growth. */
1035 if (to->local.self_insns >what->local.self_insns)
1036 limit = to->local.self_insns;
1037 else
1038 limit = what->local.self_insns;
1039
1040 limit += limit * PARAM_VALUE(PARAM_LARGE_FUNCTION_GROWTH) / 100;
1041
1042 newsize = cgraph_estimate_size_after_inlining(times, to, what);
1043 if (newsize > PARAM_VALUE(PARAM_LARGE_FUNCTION_INSNS)
1044 && newsize > limit)
1045 {
1046 *reason = N_("--paramlarge-function-growth limit reached");
1047 returnfalse;
1048 }
1049 for (i = 0; i< ninlined; i++)
1050 {
1051 newsize =
1052 cgraph_estimate_size_after_inlining(INLINED_TIMES (inlined[i]) *
1053 times, inlined[i], what);
1054 if (newsize > PARAM_VALUE(PARAM_LARGE_FUNCTION_INSNS)
1055 && newsize >
1056 inlined[i]->local.self_insns *
1057 (100 + PARAM_VALUE(PARAM_LARGE_FUNCTION_GROWTH)) / 100)
1058 {
1059 *reason = N_("--paramlarge-function-growth limit reached while inlining the caller");
1060 return false;
1061 }
1062 }
1063 return true;
1064 }
PARAM_LARGE_FUNCTION_GROWTH is used to control instruction numberincrement in inlining large function, in percent (100% by default), obviouslyif a large function is inlined for more than 1 times, it will exceed thisconstrain. And PARAM_LARGE_FUNCTION_INSNS is a value, when 87 estimatedinstruction number is larger than it, the function is considered as largerfunction.
output at line 1163, in current situation, it is set by cgraph_inlined_calleesat line 1151 as outputis 0 oringinally, and in loop at line 1152, after every treatment it wouldreset ouputfield of relative node (line 1170 and 1186), so if now find that outputof the funciton has been set, obvious there is other functions inlines thisfunction, then current function can’t be inlined by other callers (but it wouldstill inline this function) to prevent the times of expansion of this functinfrom increasing exponently.
As long as the function passes check at line 1165 and 1166, it isregarded as can be inlined, and by cgraph_mark_inline to update the parameter.As result, the cost to expand it changes also, so needs unpdate the node in Heapstoo (if it is still there).
In cgraph_decide_inlining_of_small_functionsat last, if the increment of instruction numbe exceeds the restrain, then leftfunctions aren’t allowed inlining. As heaps sorts functions by expandedinstruction number, can image those left are relative large ones.
cgraph_decide_inline (continue)
1338 /* And finallydecide what functions are called once. */
1339
1340 for (i = nnodes - 1; i >= 0; i--)
1341 {
1342 node = order[i];
1343
1344 if(node->callers && !node->callers->next_caller &&!node->needed
1345 && node->local.inlinable&& node->callers->inline_failed
1346 && !DECL_EXTERNAL (node->decl)&& !DECL_COMDAT (node->decl))
1347 {
1348 bool ok = true;
1349 struct cgraph_node *node1;
1350
1351 /* Verify that we won't duplicate the caller. */
1352 for (node1 = node->callers->caller;
1353 node1->callers &&!node1->callers->inline_failed
1354 && ok; node1 =node1->callers->caller)
1355 if (node1->callers->next_caller|| node1->needed)
1356 ok = false;
1357 if (ok)
1358 {
1359 const char*dummy_reason;
1360 if (cgraph_dump_file)
1361 fprintf (cgraph_dump_file,
1362 "/nConsidering %s %i insns./n"
1363 " Called once from %s %i insns./n",
1364 cgraph_node_name (node),node->global.insns,
1365 cgraph_node_name(node->callers->caller),
1366 node->callers->caller->global.insns);
1367 ninlined = cgraph_inlined_into(node->callers->caller,
1368 inlined);
1369 old_insns = overall_insns;
1370
1371 /* Inliningfunctions once would never cause inlining warnings. */
1372 if (cgraph_check_inline_limits
1373 (node->callers->caller, node,inlined, ninlined,
1374 &dummy_reason))
1375 {
1376 ninlined_callees =
1377 cgraph_inlined_callees (node,inlined_callees);
1378 cgraph_mark_inline(node->callers->caller, node, inlined,
1379 ninlined, inlined_callees,
1380 ninlined_callees);
1381 for (y =0; y < ninlined_callees; y++)
1382 inlined_callees[y]->output =0, inlined_callees[y]->aux = 0;
1383 if (cgraph_dump_file)
1384 fprintf (cgraph_dump_file,
1385 " Inlined into %s which now has %iinsns"
1386 " for a net change of %+i insns./n",
1387 cgraph_node_name(node->callers->caller),
1388 node->callers->caller->global.insns,
1389 overall_insns - old_insns);
1390 }
1391 else
1392 {
1393 if (cgraph_dump_file)
1394 fprintf (cgraph_dump_file,
1395 " Inline limit reached, notinlined./n");
1396 }
1397 for(y = 0; y < ninlined; y++)
1398 inlined[y]->output = 0, inlined[y]->aux= 0;
1399 }
1400 }
1401 }
1402 }
1403 cgraph_remove_unreachable_nodes ();
1404
1405 if (cgraph_dump_file)
1406 fprintf (cgraph_dump_file,
1407 "/nInlined %i calls, eliminated %ifunctions, "
1408 "%i insns turned to %iinsns./n/n",
1409 ncalls_inlined, nfunctions_inlined, initial_insns,
1410 overall_insns);
1411 free (order);
1412 free (inlined);
1413 free (inlined_callees);
1414 }
Back cgraph_decide_inline, for small function onlybe called once, and is wrong to kill above, the compiler still gives a way out,after all the benefit of inlining these small functions is relatively large. Atline 1403, it does accessibility analysis to remove unreachable functions.
5.13.5.3.2.3. Set cgraph_global_info_ready
Return to cgraph_optimize, in above processing globalfield of cgraph_node nodes have been set, at line 1596, set cgraph_global_info_readyto show this fact.
- Studying note of GCC-3.4.6 source (178)
- Studying note of GCC-3.4.6 source (6)
- Studying note of GCC-3.4.6 source (1)
- Studying note of GCC-3.4.6 source (2)
- Studying note of GCC-3.4.6 source (3)
- Studying note of GCC-3.4.6 source (4)
- Studying note of GCC-3.4.6 source (5)
- Studying note of GCC-3.4.6 source (7)
- Studying note of GCC-3.4.6 source (8)
- Studying note of GCC-3.4.6 source (9)
- Studying note of GCC-3.4.6 source (10)
- Studying note of GCC-3.4.6 source (10 cont1)
- Studying note of GCC-3.4.6 source (10 cont2)
- Studying note of GCC-3.4.6 source (10 cont3)
- Studying note of GCC-3.4.6 source (10 cont4)
- Studying note of GCC-3.4.6 source (11)
- Studying note of GCC-3.4.6 source (12)
- Studying note of GCC-3.4.6 source (13)
- woefuoewjafdsaufomewoaufodmsalfueowamf
- HTTP常见错误代码列表汇总及解决方案
- .net 序列化与反序列化的三个例子 Serializable
- GCC-3.4.6源代码学习笔记(178)
- 感悟人生!!!
- Studying note of GCC-3.4.6 source (178)
- 面试题:给定一个包含4300000000个32位证书的顺序文件,求出一个至少包含两次的整数
- 信赖的
- Spring配置Quartz任务调度
- 转自:博客园paul_wbc的《应届毕业生生存法则》
- C#集合的概述、动态数组ArrayList
- 中断 Uevent
- c
- c#.net ArrayList的用法