Backport upstream patches to fix ICEs when using -fdebug-types-section.
[official-gcc.git] / gcc-4_6 / function_reordering_plugin / function_reordering_plugin.c
blob5c762e1183279db29a501ba39bdfc149b2624159
1 /* Function re-ordering plugin for gold.
2 Copyright (C) 2011 Free Software Foundation, Inc.
3 Contributed by Sriraman Tallam (tmsriram@google.com)
4 and Easwaran Raman (eraman@google.com).
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* This plugin should be invoked only when callgraph edge profile
21 information is available in the object files generated using the
22 compiler flag -fcallgraph-profiles-sections. The callgraph edge
23 profiles are stored in special sections marked .gnu.callgraph.*
25 This plugin reads the callgraph sections and constructs an annotated
26 callgraph. It then repeatedly groups sections that are connected by
27 hot edges and passes the new function layout to the linker. The
28 layout is based on the procedure reordering algorithm described
29 in the paper :
31 "Profile guided code positioning", K. Pettis, R. Hansen
32 Proceedings of PLDI 1990.
34 This plugin dumps the final layout order of the functions in a file
35 called "final_layout.txt". To change the output file, pass the new
36 file name with --plugin-opt. To dump to stderr instead, just pass
37 stderr to --plugin-opt. */
39 #if HAVE_STDINT_H
40 #include <stdint.h>
41 #endif
42 #include <stdint.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <assert.h>
46 #include <string.h>
47 #if defined (__ELF__)
48 #include <elf.h>
49 #endif
50 #include "config.h"
51 #include "plugin-api.h"
52 #include "callgraph.h"
54 /* #include <elf.h> Not available on Darwin.
55 Rather than dealing with cross-compilation includes, hard code the
56 values we need, as these will not change. */
57 #ifndef SHT_NULL
58 #define SHT_NULL 0
59 #endif
60 #ifndef SHT_PROGBITS
61 #define SHT_PROGBITS 1
62 #endif
64 enum ld_plugin_status claim_file_hook (const struct ld_plugin_input_file *file,
65 int *claimed);
66 enum ld_plugin_status all_symbols_read_hook ();
68 static ld_plugin_register_claim_file register_claim_file_hook = NULL;
69 static ld_plugin_register_all_symbols_read
70 register_all_symbols_read_hook = NULL;
71 static ld_plugin_get_input_section_count get_input_section_count = NULL;
72 static ld_plugin_get_input_section_type get_input_section_type = NULL;
73 static ld_plugin_get_input_section_name get_input_section_name = NULL;
74 static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
75 static ld_plugin_update_section_order update_section_order = NULL;
76 static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
78 /* The file where the final function order will be stored.
79 It can be set by using the plugin option as --plugin-opt
80 "file=<name>". To dump to stderr, say --plugin-opt "file=stderr". */
82 static char *out_file = NULL;
84 static int is_api_exist = 0;
86 /* The plugin does nothing when no-op is 1. */
87 static int no_op = 0;
89 /* Copies new output file name out_file */
90 void get_filename (const char *name)
92 XNEWVEC_ALLOC (out_file, char, (strlen (name) + 1));
93 strcpy (out_file, name);
96 /* Process options to plugin. Options with prefix "group=" are special.
97 They specify the type of grouping. The option "group=none" makes the
98 plugin do nothing. Options with prefix "file=" set the output file
99 where the final function order must be stored. */
100 void
101 process_option (const char *name)
103 const char *option_group = "group=";
104 const char *option_file = "file=";
106 /* Check if option is "group=" */
107 if (strncmp (name, option_group, strlen (option_group)) == 0)
109 if (strcmp (name + strlen (option_group), "none") == 0)
110 no_op = 1;
111 else
112 no_op = 0;
113 return;
116 /* Check if option is "file=" */
117 if (strncmp (name, option_file, strlen (option_file)) == 0)
119 get_filename (name + strlen (option_file));
120 return;
123 /* Unknown option, set no_op to 1. */
124 no_op = 1;
125 fprintf (stderr, "Unknown option to function reordering plugin :%s\n",
126 name);
129 /* Plugin entry point. */
130 enum ld_plugin_status
131 onload (struct ld_plugin_tv *tv)
133 struct ld_plugin_tv *entry;
134 for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
136 switch (entry->tv_tag)
138 case LDPT_API_VERSION:
139 break;
140 case LDPT_GOLD_VERSION:
141 break;
142 case LDPT_OPTION:
143 process_option (entry->tv_u.tv_string);
144 /* If no_op is set, do not do anything else. */
145 if (no_op) return LDPS_OK;
146 break;
147 case LDPT_REGISTER_CLAIM_FILE_HOOK:
148 register_claim_file_hook = *entry->tv_u.tv_register_claim_file;
149 break;
150 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
151 register_all_symbols_read_hook
152 = *entry->tv_u.tv_register_all_symbols_read;
153 break;
154 case LDPT_GET_INPUT_SECTION_COUNT:
155 get_input_section_count = *entry->tv_u.tv_get_input_section_count;
156 break;
157 case LDPT_GET_INPUT_SECTION_TYPE:
158 get_input_section_type = *entry->tv_u.tv_get_input_section_type;
159 break;
160 case LDPT_GET_INPUT_SECTION_NAME:
161 get_input_section_name = *entry->tv_u.tv_get_input_section_name;
162 break;
163 case LDPT_GET_INPUT_SECTION_CONTENTS:
164 get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
165 break;
166 case LDPT_UPDATE_SECTION_ORDER:
167 update_section_order = *entry->tv_u.tv_update_section_order;
168 break;
169 case LDPT_ALLOW_SECTION_ORDERING:
170 allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
171 break;
172 default:
173 break;
177 assert (!no_op);
179 if (register_all_symbols_read_hook != NULL
180 && register_claim_file_hook != NULL
181 && get_input_section_count != NULL
182 && get_input_section_type != NULL
183 && get_input_section_name != NULL
184 && get_input_section_contents != NULL
185 && update_section_order != NULL
186 && allow_section_ordering != NULL)
187 is_api_exist = 1;
188 else
189 return LDPS_OK;
191 /* Register handlers. */
192 assert ((*register_all_symbols_read_hook) (all_symbols_read_hook)
193 == LDPS_OK);
194 assert ((*register_claim_file_hook) (claim_file_hook)
195 == LDPS_OK);
196 return LDPS_OK;
199 static int is_ordering_specified = 0;
201 /* This function is called by the linker for every new object it encounters. */
203 enum ld_plugin_status
204 claim_file_hook (const struct ld_plugin_input_file *file, int *claimed)
206 unsigned int count = 0;
207 struct ld_plugin_section section;
208 unsigned int shndx;
210 (void) claimed;
212 /* Plugin APIs are supported if this is called. */
213 assert (is_api_exist);
215 if (is_ordering_specified == 0)
217 /* Inform the linker to prepare for section reordering. */
218 (*allow_section_ordering) ();
219 is_ordering_specified = 1;
222 (*get_input_section_count) (file->handle, &count);
224 for (shndx = 0; shndx < count; ++shndx)
226 unsigned int type = SHT_NULL;
227 char *name = NULL;
229 section.handle = file->handle;
230 section.shndx = shndx;
231 (*get_input_section_type) (section, &type);
233 (*get_input_section_name) (section, &name);
234 push_allocated_ptr (name);
235 if (type == SHT_PROGBITS && is_prefix_of (".text.", name))
237 map_section_name_to_index (name, file->handle, shndx);
239 else if (is_prefix_of (".gnu.callgraph.text", name))
241 /* Process callgraph sections. */
242 unsigned char *section_contents_ptr = NULL;
243 size_t length;
244 (*get_input_section_contents) (section,
245 (const unsigned char **)&section_contents_ptr,
246 &length);
247 unsigned char *section_contents;
248 XNEWVEC_ALLOC (section_contents, unsigned char, length);
249 memcpy (section_contents, section_contents_ptr, length);
250 parse_callgraph_section_contents (file->handle,
251 section_contents,
252 (unsigned int)length);
256 return LDPS_OK;
259 /* This function is called by the linker after all the symbols have been read.
260 At this stage, it is fine to tell the linker the desired function order. */
262 enum ld_plugin_status
263 all_symbols_read_hook (void)
265 unsigned int num_entries;
266 unsigned int i;
267 struct ld_plugin_section *section_list;
268 void **handles;
269 unsigned int *shndx;
270 FILE *fp = NULL;
272 /* Plugin APIs are supported if this is called. */
273 assert (is_api_exist);
275 if (is_callgraph_empty ())
276 return LDPS_OK;
278 /* Open the file to write the final layout */
279 if (out_file != NULL)
281 if (strcmp (out_file, "stderr") == 0)
282 fp = stderr;
283 else
284 fp = fopen (out_file, "w");
286 fprintf (fp, "# Remove lines starting with \'#\' to"
287 " pass to --section-ordering-file\n");
288 fprintf (fp, "# Lines starting with \'#\' are the edge profiles\n");
291 find_pettis_hansen_function_layout (fp);
292 num_entries = get_layout (fp, &handles, &shndx);
293 XNEWVEC_ALLOC (section_list, struct ld_plugin_section, num_entries);
295 for (i = 0; i < num_entries; i++)
297 section_list[i].handle = handles[i];
298 section_list[i].shndx = shndx[i];
301 if (out_file != NULL
302 && strcmp (out_file, "stderr") != 0)
303 fclose (fp);
304 /* Pass the new order of functions to the linker. */
305 update_section_order (section_list, num_entries);
306 cleanup ();
307 return LDPS_OK;