00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #if defined(BUILD_OS_DARWIN)
00056 #include <darwin_elf.h>
00057 #else
00058 #include <elf.h>
00059 #endif
00060 #include <stdlib.h>
00061 #include <stdio.h>
00062 #include <sys/types.h>
00063 #include <sys/stat.h>
00064 #include <fcntl.h>
00065 #include <unistd.h>
00066 #ifndef __MINGW32__
00067 #include <sys/mman.h>
00068 #endif
00069 #include <ctype.h>
00070 #include <string.h>
00071 #include <ar.h>
00072 #ifndef __MINGW32__
00073 #include <sys/errno.h>
00074 #endif // __MINGW32__
00075 #include "defs.h"
00076 #include "config.h"
00077 #include "config_ipa.h"
00078 #include "strtab.h"
00079 #include "erglob.h"
00080 #include "flags.h"
00081 #include "ipa_option.h"
00082 #include "tracing.h"
00083
00084 #include "dwarf_DST_mem.h"
00085 #include "ipc_defs.h"
00086 #include "ipc_file.h"
00087 #include "ipc_option.h"
00088
00089 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00090
00091 #include "ipo_main.h"
00092 #include "ipc_partition.h"
00093 INT number_of_partitions = 1;
00094
00095 #endif
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 #include <vector>
00109
00110 typedef std::vector <char *, mempool_allocator<char *> > ARRAY_OF_STRINGS;
00111
00112 #define USER_NOT_SPEC 0x0 // User did not specify anything regarding this symbol
00113 #define USER_MUST_INLINE 0x1 // User specified Must inline this pu
00114 #define USER_NO_INLINE 0x2 // User specified Must NOT inline this pu
00115
00116 #define SKIP_NOT_SPEC 0x0 // skip equal to the PU name
00117 #define SKIP_EQUAL 0x1 // skip equal to the PU name
00118
00119 static INLINE_PU_MAP user_inline_request;
00120
00121 static ARRAY_OF_STRINGS must_routines;
00122
00123 static INLINE_PU_MAP skip_request;
00124
00125 struct Hash_Symbols_For_Inlining {
00126 void operator()(char *symname, UINT act) {
00127 user_inline_request[symname] = act;
00128 if (act == USER_MUST_INLINE)
00129 must_routines.push_back(symname);
00130 } ;
00131 };
00132
00133 struct Hash_Symbols_For_Skipping {
00134 void operator()(char *symname, UINT act) {
00135 skip_request[symname] = act;
00136 } ;
00137 };
00138
00139 static INLINE_EDGE_MAP user_inline_edge_request;
00140
00141 struct Hash_Edges_For_Inlining {
00142 void operator()(char* edge, UINT act) {
00143 mINT32 edge_index = atoi(edge);
00144 user_inline_edge_request[edge_index] = act;
00145 } ;
00146 };
00147
00148
00149 template <class SYM, class INLINE_MAP>
00150 static UINT
00151 User_Specified_Info(SYM name, INLINE_MAP& request)
00152 {
00153 typename INLINE_MAP::iterator result = request.find(name);
00154
00155 if (result != request.end()) {
00156 return (result->second);
00157 }
00158 else
00159 return (USER_NOT_SPEC);
00160 }
00161
00162 UINT
00163 User_Specified_Name_Info(char* name)
00164 {
00165 return User_Specified_Info(name, user_inline_request);
00166 }
00167
00168 UINT
00169 User_Specified_Edge_Info(INT edge_index)
00170 {
00171 return User_Specified_Info(edge_index, user_inline_edge_request);
00172 }
00173
00174 BOOL
00175 Is_User_Not_Specified(UINT info)
00176 {
00177 return (info == USER_NOT_SPEC);
00178 }
00179
00180 BOOL
00181 Is_User_Must_Inline(UINT info)
00182 {
00183 return (info == USER_MUST_INLINE);
00184 }
00185
00186 BOOL
00187 Is_User_No_Inline(UINT info)
00188 {
00189 return (info == USER_NO_INLINE);
00190 }
00191
00192 static UINT
00193 User_Specified_Skip_Info(char* name)
00194 {
00195 return User_Specified_Info(name, skip_request);
00196 }
00197
00198 BOOL
00199 Is_Skip_Not_Specified(char *name)
00200 {
00201 return (User_Specified_Skip_Info(name) == SKIP_NOT_SPEC);
00202 }
00203
00204 BOOL
00205 Is_Skip_Equal(char *name)
00206 {
00207 return (User_Specified_Skip_Info(name) == SKIP_EQUAL);
00208 }
00209
00210 #ifdef _STANDALONE_INLINER
00211
00212 #include "ipc_type_merge.h"
00213 #include "ipc_utils.h"
00214 #include "inline.h"
00215
00216 static ARRAY_OF_STRINGS filenames;
00217 static ARRAY_OF_STRINGS libnames;
00218 static MEM_POOL Multifile_Pool;
00219 static BOOL multifile_mempool_initialized = FALSE;
00220
00221 struct Process_Specified_Files {
00222 void operator()(char* filename, UINT unused) {
00223 filenames.push_back(filename);
00224 };
00225 };
00226
00227 struct Process_Specified_Libraries {
00228 void operator()(char* libname, UINT unused) {
00229 libnames.push_back(libname);
00230 };
00231 };
00232
00233 void
00234 Process_Non_Local_Files()
00235 {
00236 if (! multifile_mempool_initialized) {
00237 multifile_mempool_initialized = TRUE;
00238 MEM_POOL_Initialize (&Multifile_Pool, "TY Merge Pool", 0);
00239 Initialize_Type_Merging_Hash_Tables (&Multifile_Pool);
00240 }
00241
00242 for (int i = 0; i < filenames.size(); ++i) {
00243 Process_Nonlocal_File(filenames[i], NULL);
00244 }
00245 }
00246
00247
00248 static void
00249 process_archive_member (off_t offset, void* base, void *handle, int fd, char* libname)
00250 {
00251 struct ar_hdr *header;
00252 char* name;
00253 char* member_name;
00254 void* member_base;
00255
00256
00257 header = (struct ar_hdr *) ((char *)base + offset);
00258 name = Read_Member_Name (header, handle, Malloc_Mem_Pool);
00259 member_name = (char*) MEM_POOL_Alloc(Malloc_Mem_Pool, (strlen (libname) + strlen (name) + 3));
00260 sprintf (member_name, "%s(%s)", libname, name);
00261
00262 member_base = (char *)base + offset + sizeof(struct ar_hdr);
00263 if ((UINT64)member_base & 0xf) {
00264
00265 UINT64 member_file_size = atoi (header->ar_size);
00266 member_base = MEM_POOL_Alloc(Malloc_Mem_Pool, member_file_size);
00267 if (lseek(fd, offset, SEEK_SET) == -1 ||
00268 read (fd, member_base, member_file_size) != member_file_size) {
00269 fprintf(stderr, "Cannot read %s in %s\n", name, libname);
00270 return;
00271 }
00272 }
00273
00274 MEM_POOL_FREE (Malloc_Mem_Pool, name);
00275
00276 Process_Nonlocal_File(member_name, member_base);
00277
00278 }
00279
00280 static void
00281 process_archive (int fd, void* base, UINT64 file_size, BOOL allflag, char* libname)
00282 {
00283 char* sym_name;
00284 off_t offset = 0;
00285 void* handle;
00286
00287 handle = Digest_Archive (base, Malloc_Mem_Pool, file_size);
00288
00289 if (handle == NULL) return;
00290
00291 if (allflag) {
00292 offset = Next_Archive_Member ((char *)base, 0, file_size);
00293 while (offset) {
00294 process_archive_member (offset, base, handle, fd, libname);
00295 offset = Next_Archive_Member ((char *)base, offset, file_size);
00296 }
00297
00298 } else {
00299 for (int i = 0; i < must_routines.size(); ++i) {
00300
00301 if (offset = Defined_By_Archive (must_routines[i], handle)) {
00302 process_archive_member (offset, base, handle, fd, libname);
00303 }
00304 }
00305
00306 }
00307 Cleanup_Archive_Handle (handle, Malloc_Mem_Pool);
00308
00309 }
00310
00311 static void
00312 process_library(char *libname)
00313 {
00314 char *filename;
00315 void *map_addr;
00316 int fd;
00317 struct stat stat_buf;
00318
00319 fd = open(libname, O_RDONLY, 0);
00320
00321 if ( (fd == -1) || (fstat(fd, &stat_buf) == -1) ) {
00322 fprintf(stderr, "Bad library used -- %s\n", libname);
00323 return;
00324 }
00325 map_addr = (char *) mmap ( NULL, stat_buf.st_size,
00326 (PROT_READ | PROT_WRITE),
00327 MAP_PRIVATE, fd, 0 );
00328
00329 process_archive(fd, map_addr, stat_buf.st_size, INLINE_All, libname);
00330
00331 }
00332
00333 void
00334 Process_Non_Local_Libraries()
00335 {
00336 if (! multifile_mempool_initialized) {
00337 multifile_mempool_initialized = TRUE;
00338 MEM_POOL_Initialize (&Multifile_Pool, "TY Merge Pool", 0);
00339 Initialize_Type_Merging_Hash_Tables (&Multifile_Pool);
00340 }
00341
00342 for (int i = 0; i < libnames.size(); ++i) {
00343 process_library(libnames[i]);
00344 }
00345 }
00346
00347 #endif // _STANDALONE_INLINER
00348
00349 template <class DATA, class ACTION>
00350 static void
00351 Add_Symbols(char *args, DATA data, ACTION perform_action
00352 #ifdef KEY
00353 , const char * opt
00354 #endif
00355 )
00356 {
00357 #ifdef KEY
00358 if (! args)
00359 {
00360 ErrMsg (EC_No_Opt_Val, opt, "INLINE");
00361 return;
00362 }
00363 #endif // KEY
00364 BOOL more_symbols = TRUE;
00365
00366 do {
00367 char *endc;
00368
00369 if ( (endc = strchr(args, ',')) == NULL ) {
00370 more_symbols = FALSE;
00371 }
00372 else {
00373 *endc++ = '\0';
00374 }
00375
00376 if ( *args != '\0' ) {
00377 perform_action(args, data);
00378 args = endc;
00379 }
00380 }
00381 while ( more_symbols );
00382 }
00383
00384
00385 #ifndef __MINGW32__
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 static void
00402 Process_Option_File ( const char *file_name , const char *type_name)
00403 {
00404 INT fd;
00405 struct stat stat_buf;
00406 char *buffer;
00407
00408 fd = open ( file_name, O_RDONLY, 0 );
00409 if ( (fd == -1)
00410 || (fstat(fd, &stat_buf) == -1) )
00411 {
00412 ErrMsg ( EC_Inv_SpecFile, type_name, file_name );
00413 return;
00414 }
00415 buffer = (char *) mmap ( NULL, stat_buf.st_size,
00416 (PROT_READ | PROT_WRITE),
00417 MAP_PRIVATE, fd, 0 );
00418
00419 while ( buffer != NULL && *buffer != 0 ) {
00420 char *endc = strchr ( buffer, '\n' );
00421 char *option = buffer;
00422 char *cmnt;
00423
00424
00425 buffer = endc ? endc+1 : endc;
00426
00427
00428 if ( *option == '#' ) continue;
00429
00430
00431 if ( endc != NULL ) {
00432 *endc = 0;
00433 } else {
00434 endc = strchr ( option, 0 );
00435 }
00436
00437
00438 cmnt = strchr ( option, '#' );
00439 if ( cmnt != NULL ) {
00440 *(endc=cmnt) = 0;
00441 }
00442
00443
00444 cmnt = endc - 1;
00445 while ( cmnt >= option && ( *cmnt == ' ' || *cmnt == '\t' ) ) {
00446 *cmnt-- = 0;
00447 }
00448
00449
00450 if ( *option != 0 ) {
00451 if ( *option != '-'
00452 || ! Process_Command_Line_Group ( option+1,
00453 Common_Option_Groups ) )
00454 {
00455 ErrMsg ( EC_SpecFile_Opt, option, type_name, file_name );
00456 }
00457 }
00458 }
00459
00460 close ( fd );
00461 }
00462 #endif
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 void
00475 Process_Inline_Options ( void )
00476 {
00477 OPTION_LIST *ol;
00478
00479 #ifndef __MINGW32__
00480
00481
00482
00483
00484
00485
00486 for ( ol = INLINE_Spec_Files; ol != NULL; ol = OLIST_next(ol) ) {
00487 if ( OLIST_val(ol) != NULL ) {
00488 Process_Option_File ( OLIST_val(ol), "INLINE" );
00489 }
00490 }
00491 #endif
00492
00493
00494 #ifdef KEY
00495
00496
00497 for ( ol = INLINE_List_Names; ol != NULL; ol = OLIST_next(ol) ) {
00498 if ( strcmp ( OLIST_opt(ol), "must" ) == 0 ) {
00499 Add_Symbols( OLIST_val(ol), USER_MUST_INLINE, Hash_Symbols_For_Inlining(), "must" );
00500 }
00501 else if ( strcmp ( OLIST_opt(ol), "never" ) == 0 ) {
00502 Add_Symbols( OLIST_val(ol), USER_NO_INLINE, Hash_Symbols_For_Inlining(), "never" );
00503 }
00504 else if ( strcmp ( OLIST_opt(ol), "skip" ) == 0 ) {
00505 Add_Symbols( OLIST_val(ol), USER_NO_INLINE, Hash_Edges_For_Inlining(), "skip" );
00506 }
00507 else if ( strcmp ( OLIST_opt(ol), "edge" ) == 0 ) {
00508 INLINE_None = TRUE;
00509 Add_Symbols( OLIST_val(ol), USER_MUST_INLINE, Hash_Edges_For_Inlining(), "edge" );
00510 }
00511 else if ( strcmp ( OLIST_opt(ol), "in_edge" ) == 0 ) {
00512 Add_Symbols( OLIST_val(ol), USER_MUST_INLINE, Hash_Edges_For_Inlining(), "in" );
00513 }
00514 #ifdef _STANDALONE_INLINER
00515
00516 else if ( strcmp ( OLIST_opt(ol), "file" ) == 0 ) {
00517 Add_Symbols( OLIST_val(ol), NULL, Process_Specified_Files(), "file" );
00518 }
00519 else if ( strcmp ( OLIST_opt(ol), "library" ) == 0 ) {
00520 Add_Symbols( OLIST_val(ol), NULL, Process_Specified_Libraries(), "library" );
00521 }
00522 #endif // _STANDALONE_INLINER
00523 else {
00524 char flag[256];
00525 sprintf (flag, "INLINE:%s", OLIST_opt(ol));
00526 ErrMsg (EC_Not_In_Grp, OLIST_opt(ol), "INLINE", flag);
00527 }
00528 }
00529 #else
00530 for ( ol = INLINE_List_Names; ol != NULL; ol = OLIST_next(ol) ) {
00531 if ( strcmp ( OLIST_opt(ol), "must" ) == 0 ) {
00532 Add_Symbols( OLIST_val(ol), USER_MUST_INLINE, Hash_Symbols_For_Inlining());
00533 }
00534 else if ( strcmp ( OLIST_opt(ol), "never" ) == 0 ) {
00535 Add_Symbols( OLIST_val(ol), USER_NO_INLINE, Hash_Symbols_For_Inlining() );
00536 }
00537 else if ( strcmp ( OLIST_opt(ol), "skip" ) == 0 ) {
00538 Add_Symbols( OLIST_val(ol), USER_NO_INLINE, Hash_Edges_For_Inlining() );
00539 }
00540 else if ( strcmp ( OLIST_opt(ol), "edge" ) == 0 ) {
00541 INLINE_None = TRUE;
00542 Add_Symbols( OLIST_val(ol), USER_MUST_INLINE, Hash_Edges_For_Inlining() );
00543 }
00544 else if ( strcmp ( OLIST_opt(ol), "in_edge" ) == 0 ) {
00545 Add_Symbols( OLIST_val(ol), USER_MUST_INLINE, Hash_Edges_For_Inlining() );
00546 }
00547 #ifdef _STANDALONE_INLINER
00548 else if ( strcmp ( OLIST_opt(ol), "file" ) == 0 ) {
00549 Add_Symbols( OLIST_val(ol), NULL, Process_Specified_Files() );
00550 }
00551 else if ( strcmp ( OLIST_opt(ol), "library" ) == 0 ) {
00552 Add_Symbols( OLIST_val(ol), NULL, Process_Specified_Libraries() );
00553 }
00554 #endif // _STANDALONE_INLINER
00555 else {
00556 FmtAssert ( FALSE,
00557 ( "Unknown -INLINE option: %s", OLIST_opt(ol) ) );
00558 }
00559 }
00560 #endif // KEY
00561
00562
00563 if ( INLINE_All && INLINE_None ) {
00564 ErrMsg ( EC_Opt_Conflict, "-INLINE:all", "-INLINE:none",
00565 "-INLINE:all" );
00566 INLINE_None = FALSE;
00567 }
00568 }
00569
00570 #ifndef __MINGW32__
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 void
00581 Process_IPA_Skip_Options ( void )
00582 {
00583 OPTION_LIST *ol;
00584
00585
00586
00587 for ( ol = IPA_Skip; ol != NULL; ol = OLIST_next(ol) ) {
00588 if ( strcmp ( OLIST_opt(ol), "skip_equal" ) == 0 ) {
00589 #ifdef KEY
00590 Add_Symbols( OLIST_val(ol), SKIP_EQUAL, Hash_Symbols_For_Skipping(), "skip_equal");
00591 #else
00592 Add_Symbols( OLIST_val(ol), SKIP_EQUAL, Hash_Symbols_For_Skipping());
00593 #endif
00594 }
00595 else {
00596 FmtAssert ( FALSE,
00597 ( "Unknown -skip option: %s", OLIST_opt(ol) ) );
00598 }
00599 }
00600
00601 }
00602
00603 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00604
00605
00606 static void
00607 Add_Symbols_to_Partition_Group ( char *args, INT partition_grp )
00608 {
00609 DevWarn("Partition groups are not yet ported to new symtab");
00610 }
00611
00612 void
00613 Process_IPA_Specfile_Options ( void )
00614 {
00615 OPTION_LIST *ol;
00616 register INT partition_grp = 1;
00617
00618
00619
00620
00621
00622
00623
00624 for ( ol = IPA_Spec_Files; ol != NULL; ol = OLIST_next(ol) ) {
00625 if ( OLIST_val(ol) != NULL ) {
00626 Process_Option_File ( OLIST_val(ol), "IPA" );
00627 }
00628 }
00629
00630 Process_IPA_Skip_Options();
00631
00632
00633 for ( ol = IPA_Group_Names; ol != NULL; ol = OLIST_next(ol), partition_grp++ ) {
00634 if ( strcmp ( OLIST_opt(ol), "partition_group" ) == 0 ) {
00635 Add_Symbols_to_Partition_Group ( strdup(OLIST_val(ol)), partition_grp );
00636 }
00637 else {
00638 FmtAssert ( FALSE,
00639 ( "Unknown IPA_Group_Names option: %s", OLIST_opt(ol) ) );
00640 }
00641 }
00642 number_of_partitions = partition_grp;
00643 }
00644
00645 #endif
00646 #endif