Merge pull request #948 from egaburov/ptxgen-fix

changed pxtgen.cpp to be real C++ program.
This commit is contained in:
Dmitry Babokin
2015-01-29 20:37:12 +03:00
2 changed files with 109 additions and 182 deletions

View File

@@ -33,7 +33,7 @@
all: ptxcc ptxgen all: ptxcc ptxgen
CXX=clang++ CXX=clang++
CXXFLAGS += -O3 CXXFLAGS += -O3 --std=c++11
CXXFLAGS += -I/opt/local/include CXXFLAGS += -I/opt/local/include
LD=clang++ LD=clang++

View File

@@ -56,39 +56,44 @@ static std::string lValueToString(const T& value)
return oss.str(); return oss.str();
} }
typedef struct stat Stat; struct Exception : public std::exception
{
std::string s;
#define PTXGENStatus int Exception(std::string ss) : s(ss) {}
enum { ~Exception() throw () {} // Updated
PTXGEN_SUCCESS = 0x0000, const char* what() const throw() { return s.c_str(); }
PTXGEN_FILE_IO_ERROR = 0x0001, };
PTXGEN_BAD_ALLOC_ERROR = 0x0002,
PTXGEN_LIBNVVM_COMPILATION_ERROR = 0x0004, struct NVVMProg
PTXGEN_LIBNVVM_ERROR = 0x0008, {
PTXGEN_INVALID_USAGE = 0x0010, nvvmProgram prog;
PTXGEN_LIBNVVM_HOME_UNDEFINED = 0x0020, NVVMProg()
PTXGEN_LIBNVVM_VERIFICATION_ERROR = 0x0040 {
if (nvvmCreateProgram(&prog) != NVVM_SUCCESS)
throw Exception(std::string("Failed to create the compilation unit."));
}
~NVVMProg() { nvvmDestroyProgram(&prog); }
nvvmProgram get() const {return prog; }
}; };
static PTXGENStatus getLibDeviceName(const int computeArch, std::string &libDeviceName) static std::string getLibDeviceName(const int computeArch)
{ {
const char *env = getenv("LIBNVVM_HOME"); const char *env = getenv("LIBNVVM_HOME");
#ifdef LIBNVVM_HOME #ifdef LIBNVVM_HOME
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x) #define TOSTRING(x) STRINGIFY(x)
const std::string libnvvmPath(env ? env : TOSTRING(LIBNVVM_HOME)); const std::string libnvvmPath1(env ? env : TOSTRING(LIBNVVM_HOME));
#undef TOSTRING #undef TOSTRING
#undef STRINGIFY #undef STRINGIFY
#else #else
const std::string libnvvmPath(env); const std::string libnvvmPath1(env);
#endif #endif
const std::string libnvvmPath(env == nullptr ? libnvvmPath1 : std::string(env));
if (libnvvmPath.empty()) if (libnvvmPath.empty())
{ throw Exception("The environment variable LIBNVVM_HOME is undefined");
fprintf(stderr, "The environment variable LIBNVVM_HOME is undefined\n");
return PTXGEN_LIBNVVM_HOME_UNDEFINED;
}
/* Use libdevice for compute_20, if the target is not compute_20, compute_30, /* Use libdevice for compute_20, if the target is not compute_20, compute_30,
* or compute_35. */ * or compute_35. */
@@ -99,194 +104,109 @@ static PTXGENStatus getLibDeviceName(const int computeArch, std::string &libDevi
lValueToString(LIBDEVICE_MINOR_VERSION) + lValueToString(LIBDEVICE_MINOR_VERSION) +
".bc"; ".bc";
libDeviceName = libnvvmPath + libdevice; return libnvvmPath + libdevice;
return PTXGEN_SUCCESS;
} }
static PTXGENStatus addFileToProgram(const std::string &filename, nvvmProgram prog) static void addFileToProgram(const std::string &filename, NVVMProg &prog)
{ {
char *buffer;
size_t size;
Stat fileStat;
/* Open the input file. */ /* Open the input file. */
FILE *f = fopen(filename.c_str(), "rb"); FILE *f = fopen(filename.c_str(), "rb");
if (f == NULL) { if (f == NULL)
fprintf(stderr, "Failed to open %s\n", filename.c_str()); throw Exception(std::string("Failed to open ") + filename);
return PTXGEN_FILE_IO_ERROR;
}
/* Allocate buffer for the input. */ /* Allocate buffer for the input. */
struct stat fileStat;
fstat(fileno(f), &fileStat); fstat(fileno(f), &fileStat);
buffer = (char *) malloc(fileStat.st_size); std::string buffer(fileStat.st_size,0);
if (buffer == NULL) {
fprintf(stderr, "Failed to allocate memory\n"); /* Read input file */
return PTXGEN_BAD_ALLOC_ERROR; const size_t size = fread(&buffer[0], 1, fileStat.st_size, f);
} const auto error = ferror(f);
size = fread(buffer, 1, fileStat.st_size, f);
if (ferror(f)) {
fprintf(stderr, "Failed to read %s\n", filename.c_str());
fclose(f);
free(buffer);
return PTXGEN_FILE_IO_ERROR;
}
fclose(f); fclose(f);
if (error)
throw Exception(std::string("Failed to read ") + filename + ".");
if (nvvmAddModuleToProgram(prog, buffer, size, filename.c_str()) != NVVM_SUCCESS) { /* Add IR block to a program */
fprintf(stderr, if (nvvmAddModuleToProgram(prog.get(), buffer.c_str(), size, filename.c_str()) != NVVM_SUCCESS)
"Failed to add the module %s to the compilation unit\n", throw Exception(
filename.c_str()); std::string("Failed to add the module ") + filename + " to the compilation unit.");
free(buffer);
return PTXGEN_LIBNVVM_ERROR;
}
free(buffer);
return PTXGEN_SUCCESS;
} }
static PTXGENStatus generatePTX( static void printWarningsAndErrors(NVVMProg &prog)
std::vector<std::string> nvvmOptions, {
std::vector<std::string> nvvmFiles, size_t logSize;
std::ostream &out, if (nvvmGetProgramLogSize(prog.get(), &logSize) == NVVM_SUCCESS)
{
std::string log(logSize,0);
if (nvvmGetProgramLog(prog.get(), &log[0]) == NVVM_SUCCESS && logSize > 1)
{
std::cerr << "--------------------------------------\n";
std::cerr << log << std::endl;
std::cerr << "--------------------------------------\n";
}
else throw Exception("Failed to get the compilation log.");
}
else throw Exception("Failed to get the compilation log size.");
}
static std::string generatePTX(
const std::vector<std::string> &nvvmOptions,
const std::vector<std::string> &nvvmFiles,
const int computeArch) const int computeArch)
{ {
nvvmProgram prog; std::string ptxString;
PTXGENStatus status;
/* Create the compiliation unit. */ /* Create the compiliation unit. */
if (nvvmCreateProgram(&prog) != NVVM_SUCCESS) NVVMProg prog;
{
fprintf(stderr, "Failed to create the compilation unit\n");
return PTXGEN_LIBNVVM_ERROR;
}
/* Add libdevice. */ /* Add libdevice. */
std::string libDeviceName; try
status = getLibDeviceName(computeArch, libDeviceName);
if (status != PTXGEN_SUCCESS)
{ {
nvvmDestroyProgram(&prog); const std::string &libDeviceName = getLibDeviceName(computeArch);
return status; addFileToProgram(libDeviceName, prog);
} }
status = addFileToProgram(libDeviceName, prog); catch (const std::exception &ex)
if (status != PTXGEN_SUCCESS)
{ {
fprintf(stderr, "Please double-check LIBNVVM_HOME environmental variable.\n"); throw Exception(ex.what());
nvvmDestroyProgram(&prog);
return status;
} }
std::vector<const char*> options;
for (const auto &f : nvvmFiles)
addFileToProgram(f, prog);
/* Add the module to the compilation unit. */ for (const auto &o : nvvmOptions)
for (int i = 0; i < (int)nvvmFiles.size(); ++i) options.push_back(o.c_str());
{
status = addFileToProgram(nvvmFiles[i], prog); try
if (status != PTXGEN_SUCCESS) {
{ if (nvvmVerifyProgram(prog.get(), options.size(), &options[0]) != NVVM_SUCCESS)
nvvmDestroyProgram(&prog); throw Exception("Failed to verify the compilation unit.");
return status;
}
}
const int numOptions = nvvmOptions.size();
std::vector<const char*> options(numOptions);
for (int i = 0; i < numOptions; i++)
options[i] = nvvmOptions[i].c_str();
/* Verify the compilation unit. */
if (nvvmVerifyProgram(prog, numOptions, &options[0]) != NVVM_SUCCESS)
{
fprintf(stderr, "Failed to verify the compilation unit\n");
status |= PTXGEN_LIBNVVM_VERIFICATION_ERROR;
}
/* Print warnings and errors. */
{
size_t logSize;
if (nvvmGetProgramLogSize(prog, &logSize) != NVVM_SUCCESS)
{
fprintf(stderr, "Failed to get the compilation log size\n");
status |= PTXGEN_LIBNVVM_ERROR;
}
else
{
std::string log(logSize,0);
if (nvvmGetProgramLog(prog, &log[0]) != NVVM_SUCCESS)
{
fprintf(stderr, "Failed to get the compilation log\n");
status |= PTXGEN_LIBNVVM_ERROR;
}
else
{
fprintf(stderr, "%s\n", log.c_str());
}
}
}
if (status & PTXGEN_LIBNVVM_VERIFICATION_ERROR)
{
nvvmDestroyProgram(&prog);
return status;
}
/* Compile the compilation unit. */ /* Compile the compilation unit. */
if (nvvmCompileProgram(prog, numOptions, &options[0]) != NVVM_SUCCESS) if (nvvmCompileProgram(prog.get(), options.size(), &options[0]) == NVVM_SUCCESS)
{
fprintf(stderr, "Failed to generate PTX from the compilation unit\n");
status |= PTXGEN_LIBNVVM_COMPILATION_ERROR;
}
else
{
size_t ptxSize;
if (nvvmGetCompiledResultSize(prog, &ptxSize) != NVVM_SUCCESS)
{ {
fprintf(stderr, "Failed to get the PTX output size\n"); size_t ptxSize;
status |= PTXGEN_LIBNVVM_ERROR; if (nvvmGetCompiledResultSize(prog.get(), &ptxSize) == NVVM_SUCCESS)
}
else
{
std::string ptx(ptxSize,0);
if (nvvmGetCompiledResult(prog, &ptx[0]) != NVVM_SUCCESS)
{ {
fprintf(stderr, "Failed to get the PTX output\n"); ptxString.resize(ptxSize);
status |= PTXGEN_LIBNVVM_ERROR; if (nvvmGetCompiledResult(prog.get(), &ptxString[0]) != NVVM_SUCCESS)
} throw Exception("Failed to get the PTX output.");
else
{
out << ptx;
} }
else throw Exception("Failed to get the PTX output size.");
} }
else throw Exception("Failed to generate PTX from the compilation unit.");
}
catch (const std::exception &ex)
{
std::cerr << "NVVM exception: " << ex.what() << std::endl;
printWarningsAndErrors(prog);
throw Exception("");
} }
/* Print warnings and errors. */ return ptxString;
{ };
size_t logSize;
if (nvvmGetProgramLogSize(prog, &logSize) != NVVM_SUCCESS)
{
fprintf(stderr, "Failed to get the compilation log size\n");
status |= PTXGEN_LIBNVVM_ERROR;
}
else
{
std::string log(logSize,0);
if (nvvmGetProgramLog(prog, &log[0]) != NVVM_SUCCESS)
{
fprintf(stderr, "Failed to get the compilation log\n");
status |= PTXGEN_LIBNVVM_ERROR;
}
else
{
fprintf(stderr, "%s\n", log.c_str());
}
}
}
/* Release the resources. */
nvvmDestroyProgram(&prog);
return PTXGEN_SUCCESS;
}
static void showUsage() static void showUsage()
{ {
@@ -434,11 +354,18 @@ int main(int argc, char *argv[])
std::vector<std::string> nvvmFiles; std::vector<std::string> nvvmFiles;
nvvmFiles.push_back(fileIR); nvvmFiles.push_back(fileIR);
std::ofstream outputPTX(filePTX.c_str());
assert(outputPTX);
const int ret = generatePTX(nvvmOptions, nvvmFiles, outputPTX, computeArch); try
outputPTX.open(filePTX.c_str()); {
return ret; std::ofstream outputPTX(filePTX.c_str());
outputPTX << generatePTX(nvvmOptions, nvvmFiles, computeArch);
}
catch (const std::exception &ex)
{
std::cerr << "Error: ptxgen failed with exception \n " << ex.what() << std::endl;
return -1;
}
return 0;
} }