Files
clang-p2996/openmp/runtime/tools/objcopy.cpp
Jim Cownie 4cc4bb4c60 I apologise in advance for the size of this check-in. At Intel we do
understand that this is not friendly, and are working to change our
internal code-development to make it easier to make development
features available more frequently and in finer (more functional)
chunks. Unfortunately we haven't got that in place yet, and unpicking
this into multiple separate check-ins would be non-trivial, so please
bear with me on this one. We should be better in the future.

Apologies over, what do we have here?

GGC 4.9 compatibility
--------------------
* We have implemented the new entrypoints used by code compiled by GCC
4.9 to implement the same functionality in gcc 4.8. Therefore code
compiled with gcc 4.9 that used to work will continue to do so.
However, there are some other new entrypoints (associated with task
cancellation) which are not implemented. Therefore user code compiled
by gcc 4.9 that uses these new features will not link against the LLVM
runtime. (It remains unclear how to handle those entrypoints, since
the GCC interface has potentially unpleasant performance implications
for join barriers even when cancellation is not used)

--- new parallel entry points ---
new entry points that aren't OpenMP 4.0 related
These are implemented fully :-
      GOMP_parallel_loop_dynamic()
      GOMP_parallel_loop_guided()
      GOMP_parallel_loop_runtime()
      GOMP_parallel_loop_static()
      GOMP_parallel_sections()
      GOMP_parallel()

--- cancellation entry points ---
Currently, these only give a runtime error if OMP_CANCELLATION is true
because our plain barriers don't check for cancellation while waiting
        GOMP_barrier_cancel()
        GOMP_cancel()
        GOMP_cancellation_point()
        GOMP_loop_end_cancel()
        GOMP_sections_end_cancel()

--- taskgroup entry points ---
These are implemented fully.
      GOMP_taskgroup_start()
      GOMP_taskgroup_end()

--- target entry points ---
These are empty (as they are in libgomp)
     GOMP_target()
     GOMP_target_data()
     GOMP_target_end_data()
     GOMP_target_update()
     GOMP_teams()

Improvements in Barriers and Fork/Join
--------------------------------------
* Barrier and fork/join code is now in its own file (which makes it
easier to understand and modify).
* Wait/release code is now templated and in its own file; suspend/resume code is also templated
* There's a new, hierarchical, barrier, which exploits the
cache-hierarchy of the Intel(r) Xeon Phi(tm) coprocessor to improve
fork/join and barrier performance.

***BEWARE*** the new source files have *not* been added to the legacy
Cmake build system. If you want to use that fixes wil be required.

Statistics Collection Code
--------------------------
* New code has been added to collect application statistics (if this
is enabled at library compile time; by default it is not). The
statistics code itself is generally useful, the lightweight timing
code uses the X86 rdtsc instruction, so will require changes for other
architectures.
The intent of this code is not for users to tune their codes but
rather 
1) For timing code-paths inside the runtime
2) For gathering general properties of OpenMP codes to focus attention
on which OpenMP features are most used. 

Nested Hot Teams
----------------
* The runtime now maintains more state to reduce the overhead of
creating and destroying inner parallel teams. This improves the
performance of code that repeatedly uses nested parallelism with the
same resource allocation. Set the new KMP_HOT_TEAMS_MAX_LEVEL
envirable to a depth to enable this (and, of course, OMP_NESTED=true
to enable nested parallelism at all).

Improved Intel(r) VTune(Tm) Amplifier support
---------------------------------------------
* The runtime provides additional information to Vtune via the
itt_notify interface to allow it to display better OpenMP specific
analyses of load-imbalance.

Support for OpenMP Composite Statements
---------------------------------------
* Implement new entrypoints required by some of the OpenMP 4.1
composite statements.

Improved ifdefs
---------------
* More separation of concepts ("Does this platform do X?") from
platforms ("Are we compiling for platform Y?"), which should simplify
future porting.


ScaleMP* contribution
---------------------
Stack padding to improve the performance in their environment where
cross-node coherency is managed at the page level.

Redesign of wait and release code
---------------------------------
The code is simplified and performance improved.

Bug Fixes
---------
    *Fixes for Windows multiple processor groups.
    *Fix Fortran module build on Linux: offload attribute added.
    *Fix entry names for distribute-parallel-loop construct to be consistent with the compiler codegen.
    *Fix an inconsistent error message for KMP_PLACE_THREADS environment variable.

llvm-svn: 219214
2014-10-07 16:25:50 +00:00

523 lines
15 KiB
C++

/*
* $Revision: 42951 $
* $Date: 2014-01-21 14:41:41 -0600 (Tue, 21 Jan 2014) $
*/
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#include <iostream>
#include <strstream>
#include <fstream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <cstring>
using namespace std;
typedef std::string string_t;
typedef std::vector< string_t > strings_t;
typedef std::map< string_t, string_t > str_hash_t;
typedef std::pair< string_t, string_t > str_pair_t;
#ifdef _WIN32
typedef long long int64_t;
#endif
string_t
shift( strings_t & strs ) {
string_t first = strs.front();
strs.erase( strs.begin() );
return first;
} // shift
string_t
find(
str_hash_t const & hash,
string_t const & key
) {
string_t value;
str_hash_t::const_iterator it = hash.find( key );
if ( it != hash.end() ) {
value = it->second;
}; // if
return value;
} // find
void die( string_t const & message ) {
std::cerr << message << std::endl;
exit( 1 );
} // die
void stop( string_t const & message ) {
printf( "%s\n", message.c_str() );
exit( 1 );
}
// An entry in the symbol table of a .obj file.
struct symbol_t {
long long name;
unsigned value;
unsigned short section_num;
unsigned short type;
char storage_class;
char nAux;
}; // struct symbol_t
class _rstream_t : public std::istrstream {
private:
const char * buf;
protected:
_rstream_t( pair< const char *, streamsize > p )
: istrstream( p.first, p.second ), buf( p.first )
{
}
~_rstream_t() {
delete [] buf;
}
}; // class _rstream_t
/* A stream encapuslating the content of a file or the content of a string, overriding the
>> operator to read various integer types in binary form, as well as a symbol table
entry.
*/
class rstream_t : public _rstream_t {
private:
template< typename type_t >
inline rstream_t & do_read( type_t & x ) {
read( (char*) & x, sizeof( type_t ) );
return * this;
}
static pair<const char*, streamsize> getBuf(const char *fileName) {
ifstream raw(fileName,ios::binary | ios::in);
if(!raw.is_open())
stop("rstream.getBuf: Error opening file");
raw.seekg(0,ios::end);
streampos fileSize = raw.tellg();
if(fileSize < 0)
stop("rstream.getBuf: Error reading file");
char *buf = new char[fileSize];
raw.seekg(0,ios::beg);
raw.read(buf, fileSize);
return pair<const char*, streamsize>(buf,fileSize);
}
public:
// construct from a string
rstream_t( const char * buf, streamsize size ) :
_rstream_t( pair< const char *, streamsize >( buf, size ) )
{}
/* construct from a file whole content is fully read once to initialize the content of
this stream
*/
rstream_t( string_t const & fileName )
: _rstream_t( getBuf( fileName.c_str() ) )
{
}
rstream_t & operator >>( int & x ) {
return do_read(x);
}
rstream_t & operator >>(unsigned &x) {
return do_read(x);
}
rstream_t & operator>>(short &x) {
return do_read(x);
}
rstream_t & operator>>(unsigned short &x) {
return do_read(x);
}
rstream_t & operator>>( symbol_t & e ) {
read((char*)&e, 18);
return *this;
}
}; // class rstream_t
// string table in a .OBJ file
class StringTable {
private:
map<string, unsigned> directory;
size_t length;
char *data;
// make <directory> from <length> bytes in <data>
void makeDirectory(void) {
unsigned i = 4;
while(i < length) {
string s = string(data + i);
directory.insert(make_pair(s, i));
i += s.size() + 1;
}
}
// initialize <length> and <data> with contents specified by the arguments
void init(const char *_data) {
unsigned _length = *(unsigned*)_data;
if(_length < sizeof(unsigned) || _length != *(unsigned*)_data)
stop("StringTable.init: Invalid symbol table");
if(_data[_length - 1]) {
// to prevent runaway strings, make sure the data ends with a zero
data = new char[length = _length + 1];
data[_length] = 0;
} else {
data = new char[length = _length];
}
*(unsigned*)data = length;
memcpy( data + sizeof(unsigned), _data + sizeof(unsigned), length - sizeof(unsigned) );
makeDirectory();
}
public:
StringTable( rstream_t & f ) {
/* Construct string table by reading from f.
*/
streampos s;
unsigned strSize;
char *strData;
s = f.tellg();
f>>strSize;
if(strSize < sizeof(unsigned))
stop("StringTable: Invalid string table");
strData = new char[strSize];
*(unsigned*)strData = strSize;
// read the raw data into <strData>
f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
s = f.tellg() - s;
if(s < strSize)
stop("StringTable: Unexpected EOF");
init(strData);
delete[]strData;
}
StringTable(const set<string> &strings) {
/* Construct string table from given strings.
*/
char *p;
set<string>::const_iterator it;
size_t s;
// count required size for data
for(length = sizeof(unsigned), it = strings.begin(); it != strings.end(); ++it) {
size_t l = (*it).size();
if(l > (unsigned) 0xFFFFFFFF)
stop("StringTable: String too long");
if(l > 8) {
length += l + 1;
if(length > (unsigned) 0xFFFFFFFF)
stop("StringTable: Symbol table too long");
}
}
data = new char[length];
*(unsigned*)data = length;
// populate data and directory
for(p = data + sizeof(unsigned), it = strings.begin(); it != strings.end(); ++it) {
const string &str = *it;
size_t l = str.size();
if(l > 8) {
directory.insert(make_pair(str, p - data));
memcpy(p, str.c_str(), l);
p[l] = 0;
p += l + 1;
}
}
}
~StringTable() {
delete[] data;
}
/* Returns encoding for given string based on this string table.
Error if string length is greater than 8 but string is not in
the string table--returns 0.
*/
int64_t encode(const string &str) {
int64_t r;
if(str.size() <= 8) {
// encoded directly
((char*)&r)[7] = 0;
strncpy((char*)&r, str.c_str(), 8);
return r;
} else {
// represented as index into table
map<string,unsigned>::const_iterator it = directory.find(str);
if(it == directory.end())
stop("StringTable::encode: String now found in string table");
((unsigned*)&r)[0] = 0;
((unsigned*)&r)[1] = (*it).second;
return r;
}
}
/* Returns string represented by x based on this string table.
Error if x references an invalid position in the table--returns
the empty string.
*/
string decode(int64_t x) const {
if(*(unsigned*)&x == 0) {
// represented as index into table
unsigned &p = ((unsigned*)&x)[1];
if(p >= length)
stop("StringTable::decode: Invalid string table lookup");
return string(data + p);
} else {
// encoded directly
char *p = (char*)&x;
int i;
for(i = 0; i < 8 && p[i]; ++i);
return string(p, i);
}
}
void write(ostream &os) {
os.write(data, length);
}
};
void
obj_copy(
string_t const & src, // Name of source file.
string_t const & dst, // Name of destination file.
str_hash_t const & redefs // List of redefinititions.
) {
set< string > strings; // set of all occurring symbols, appropriately prefixed
streampos fileSize;
size_t strTabStart;
unsigned symTabStart;
unsigned symNEntries;
int i;
string const error_reading = "Error reading \"" + src + "\" file: ";
rstream_t in( src );
in.seekg( 0, ios::end );
fileSize = in.tellg();
in.seekg( 8 );
in >> symTabStart >> symNEntries;
strTabStart = symTabStart + 18 * size_t( symNEntries );
in.seekg( strTabStart );
if ( in.eof() ) {
stop( error_reading + "Unexpected end of file" );
}
StringTable stringTableOld( in ); // Read original string table.
if ( in.tellg() != fileSize ) {
stop( error_reading + "Unexpected data after string table" );
}
// compute set of occurring strings with prefix added
for ( i = 0; i < symNEntries; ++ i ) {
symbol_t e;
in.seekg( symTabStart + i * 18 );
if ( in.eof() ) {
stop("hideSymbols: Unexpected EOF");
}
in >> e;
if ( in.fail() ) {
stop("hideSymbols: File read error");
}
if ( e.nAux ) {
i += e.nAux;
}
const string & s = stringTableOld.decode( e.name );
// if symbol is extern and found in <hide>, prefix and insert into strings,
// otherwise, just insert into strings without prefix
string_t name = find( redefs, s );
strings.insert( name != "" && e.storage_class == 2 ? name : s );
}
ofstream out( dst.c_str(), ios::trunc | ios::out | ios::binary );
if ( ! out.is_open() ) {
stop("hideSymbols: Error opening output file");
}
// make new string table from string set
StringTable stringTableNew = StringTable( strings );
// copy input file to output file up to just before the symbol table
in.seekg( 0 );
char * buf = new char[ symTabStart ];
in.read( buf, symTabStart );
out.write( buf, symTabStart );
delete [] buf;
// copy input symbol table to output symbol table with name translation
for ( i = 0; i < symNEntries; ++ i ) {
symbol_t e;
in.seekg( symTabStart + i * 18 );
if ( in.eof() ) {
stop("hideSymbols: Unexpected EOF");
}
in >> e;
if ( in.fail() ) {
stop("hideSymbols: File read error");
}
const string & s = stringTableOld.decode( e.name );
out.seekp( symTabStart + i * 18 );
string_t name = find( redefs, s );
e.name = stringTableNew.encode( ( e.storage_class == 2 && name != "" ) ? name : s );
out.write( (char*) & e, 18 );
if ( out.fail() ) {
stop( "hideSymbols: File write error" );
}
if ( e.nAux ) {
// copy auxiliary symbol table entries
int nAux = e.nAux;
for (int j = 1; j <= nAux; ++j ) {
in >> e;
out.seekp( symTabStart + ( i + j ) * 18 );
out.write( (char*) & e, 18 );
}
i += nAux;
}
}
// output string table
stringTableNew.write( out );
}
void
split( string_t const & str, char ch, string_t & head, string_t & tail ) {
string_t::size_type pos = str.find( ch );
if ( pos == string_t::npos ) {
head = str;
tail = "";
} else {
head = str.substr( 0, pos );
tail = str.substr( pos + 1 );
}; // if
} // split
void help() {
std::cout
<< "NAME\n"
<< " objcopy -- copy and translate object files\n"
<< "\n"
<< "SYNOPSIS\n"
<< " objcopy options... source destination\n"
<< "\n"
<< "OPTIONS\n"
<< " --help Print this help and exit.\n"
<< " --redefine-sym old=new\n"
<< " Rename \"old\" symbol in source object file to \"new\" symbol in\n"
<< " destination object file.\n"
<< " --redefine-syms sym_file\n"
<< " For each pair \"old new\" in sym_file rename \"old\" symbol in \n"
<< " source object file to \"new\" symbol in destination object file.\n"
<< "\n"
<< "ARGUMENTS\n"
<< " source The name of source object file.\n"
<< " destination\n"
<< " The name of destination object file.\n"
<< "\n"
<< "DESCRIPTION\n"
<< " This program implements a minor bit of Linux* OS's objcopy utility on Windows* OS.\n"
<< " It can copy object files and edit its symbol table.\n"
<< "\n"
<< "EXAMPLES\n"
<< " \n"
<< " > objcopy --redefine-sym fastcpy=__xxx_fastcpy a.obj b.obj\n"
<< "\n";
} // help
int
main( int argc, char const * argv[] ) {
strings_t args( argc - 1 );
str_hash_t redefs;
strings_t files;
std::copy( argv + 1, argv + argc, args.begin() );
while ( args.size() > 0 ) {
string_t arg = shift( args );
if ( arg.substr( 0, 2 ) == "--" ) {
// An option.
if ( 0 ) {
} else if ( arg == "--help" ) {
help();
return 0;
} else if ( arg == "--redefine-sym" ) {
if ( args.size() == 0 ) {
die( "\"" + arg + "\" option requires an argument" );
}; // if
// read list of symbol pairs "old new" from command line.
string_t redef = shift( args );
string_t old_sym;
string_t new_sym;
split( redef, '=', old_sym, new_sym );
if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
die( "Illegal redefinition: \"" + redef + "\"; neither old symbol nor new symbol may be empty" );
}; // if
redefs.insert( str_pair_t( old_sym, new_sym ) );
} else if ( arg == "--redefine-syms" ) {
if ( args.size() == 0 ) {
die( "\"" + arg + "\" option requires an argument" );
}; // if
// read list of symbol pairs "old new" from file.
string_t fname = shift( args );
string_t redef;
ifstream ifs( fname.c_str() );
while ( ifs.good() ) {
getline( ifs, redef );// get pair of old/new symbols separated by space
string_t old_sym;
string_t new_sym;
// AC: gcount() does not work here (always return 0), so comment it
//if ( ifs.gcount() ) { // skip empty lines
split( redef, ' ', old_sym, new_sym );
if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
break; // end of file reached (last empty line)
//die( "Illegal redefinition: \"" + redef + "\"; neither old symbol nor new symbol may be empty" );
}; // if
redefs.insert( str_pair_t( old_sym, new_sym ) );
//}
}
} else {
die( "Illegal option: \"" + arg + "\"" );
}; // if
} else {
// Not an option, a file name.
if ( files.size() >= 2 ) {
die( "Too many files specified; two files required (use --help option for help)" );
}; // if
files.push_back( arg );
}; // if
}; // while
if ( files.size() < 2 ) {
die( "Not enough files specified; two files required (use --help option for help)" );
}; // if
obj_copy( files[ 0 ], files[ 1 ], redefs );
return 0;
} // main
// end of file //