5.13.5.3.2.2.3. Inline normal function
After handling function demanding inlining (by using “always_inline”), inlining rest functions are up to the compiler. As long as we don’t prohbit function by inlining option “-fno-inline” explicitly, flag_really_no_inline at 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 , "/nDeciding on 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 instruction number 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 struct cgraph_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 (struct fibnode *));
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 limit reached"));
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 function should be inlined, besides the inlinability, also depends on its size after expanding. 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). Note that, 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 return false;
1073 if (DECL_DECLARED_INLINE_P (n->decl))
1074 return n->global.insns < MAX_INLINE_INSNS_SINGLE;
1075 else
1076 return n->global.insns < MAX_INLINE_INSNS_AUTO;
1077 }
If function fails in inlining, it needs to tell the caller about the failure reason, unless the caller has been inline forcely (at that time, its inline_failed is NULL).
1081 static void
1082 cgraph_set_inline_failed (struct cgraph_node *node, const char *reason) in cgraphunit.c
1083 {
1084 struct cgraph_edge *e;
1085
1086 if (cgraph_dump_file )
1087 fprintf (cgraph_dump_file , "Inlining failed: %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 Fibonacci heaps, but what used as the key value is the increment of instruction number dues 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 struct cgraph_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 for self recursive functions or cases where we decide to not
937 inline for different reasons, but it is not big deal as in that case
938 we will keep the body 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 return growth;
946 }
However as now the analysises of its callers, callees haven’t been done, it is a rough estimation (not include the size of functions called directly or indirectly). With the advancing of below function analysis, the estimation approaches correct result. Because in below it will frequently overwrite the key value of nodes, out of efficiency consideration, use Fibonacci heaps.
At line 1133, fibheap_extract_min removes node of minus key value from Fibonacci heaps. At beginning, this value is just the instruction number of the function multiplies with the times it is invoked. Obviously, beginning at function with smallest key value is a good start, it is most possible 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-single limit 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 semantic and
1156 thus we should not warn on 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, so update
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 %i insns./n",
1194 cgraph_node_name (e->caller),
1195 e->caller->global.insns);
1196 }
1197
1198 /* Similarly all functions called by the function 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, the compiler inlines function in the same way, once function expansion arrives threshold, no inlining is allowed anymore. The criterion, one way is the total increment 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 is shown by cgraph_check_inline_limits .
1018 static bool
1019 cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
1020 struct cgraph_node **inlined, int ninlined,
1021 const char **reason)
1022 {
1023 int i;
1024 int times = 0;
1025 struct cgraph_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 inlining large function body called once into small function,
1034 take the inlined function 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_("--param large-function-growth limit reached");
1047 return false;
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_("--param large-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 number increment in inlining large function, in percent (100% by default), obviously if a large function is inlined for more than 1 times, it will exceed this constrain. And PARAM_LARGE_FUNCTION_INSNS is a value, when 87 estimated instruction number is larger than it, the function is considered as larger function.
output at line 1163, in current situation, it is set by cgraph_inlined_callees at line 1151 as output is 0 oringinally, and in loop at line 1152, after every treatment it would reset ouput field of relative node (line 1170 and 1186), so if now find that output of the funciton has been set, obvious there is other functions inlines this function, then current function can’t be inlined by other callers (but it would still inline this function) to prevent the times of expansion of this functin from increasing exponently.
As long as the function passes check at line 1165 and 1166, it is regarded 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 Heaps too (if it is still there).
In cgraph_decide_inlining_of_small_functions at last, if the increment of instruction numbe exceeds the restrain, then left functions aren’t allowed inlining. As heaps sorts functions by expanded instruction number, can image those left are relative large ones.
cgraph_decide_inline (continue)
1338 /* And finally decide 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 /* Inlining functions 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 %i insns"
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, not inlined./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 %i functions, "
1408 "%i insns turned to %i insns./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 only be 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. At line 1403, it does accessibility analysis to remove unreachable functions.
Return to cgraph_optimize , in above processing global field of cgraph_node nodes have been set, at line 1596, set cgraph_global_info_ready to show this fact.