394 lines
11 KiB
C++
394 lines
11 KiB
C++
/*
|
|
* Copyright 2011-2012, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <bcinfo/BitcodeTranslator.h>
|
|
#include <bcinfo/BitcodeWrapper.h>
|
|
#include <bcinfo/MetadataExtractor.h>
|
|
|
|
#include <llvm/ADT/StringRef.h>
|
|
#include <llvm/Bitcode/ReaderWriter.h>
|
|
#include <llvm/IR/AssemblyAnnotationWriter.h>
|
|
#include <llvm/IR/LLVMContext.h>
|
|
#include <llvm/IR/Module.h>
|
|
#include <llvm/Support/FileSystem.h>
|
|
#include <llvm/Support/ManagedStatic.h>
|
|
#include <llvm/Support/MemoryBuffer.h>
|
|
#include <llvm/Support/ToolOutputFile.h>
|
|
|
|
#include <ctype.h>
|
|
#include <dlfcn.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// This file corresponds to the standalone bcinfo tool. It prints a variety of
|
|
// information about a supplied bitcode input file.
|
|
|
|
std::string inFile;
|
|
std::string outFile;
|
|
std::string infoFile;
|
|
|
|
extern int opterr;
|
|
extern int optind;
|
|
|
|
bool translateFlag = false;
|
|
bool infoFlag = false;
|
|
bool verbose = true;
|
|
|
|
static int parseOption(int argc, char** argv) {
|
|
int c;
|
|
while ((c = getopt(argc, argv, "itv")) != -1) {
|
|
opterr = 0;
|
|
|
|
switch(c) {
|
|
case '?':
|
|
// ignore any error
|
|
break;
|
|
|
|
case 't':
|
|
translateFlag = true;
|
|
break;
|
|
|
|
case 'i':
|
|
// Turn off verbose so that we only generate the .info file.
|
|
infoFlag = true;
|
|
verbose = false;
|
|
break;
|
|
|
|
case 'v':
|
|
verbose = true;
|
|
break;
|
|
|
|
default:
|
|
// Critical error occurs
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(optind >= argc) {
|
|
fprintf(stderr, "input file required\n");
|
|
return 0;
|
|
}
|
|
|
|
inFile = argv[optind];
|
|
|
|
int l = inFile.length();
|
|
if (l > 3 && inFile[l-3] == '.' && inFile[l-2] == 'b' && inFile[l-1] == 'c') {
|
|
outFile = std::string(inFile.begin(), inFile.end() - 3) + ".ll";
|
|
infoFile = std::string(inFile.begin(), inFile.end() - 3) + ".bcinfo";
|
|
} else {
|
|
outFile = inFile + ".ll";
|
|
infoFile = inFile + ".bcinfo";
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void dumpReduceInfo(FILE *info, const char *Kind, const char *Name) {
|
|
if (Name)
|
|
fprintf(info, " %s(%s)\n", Kind, Name);
|
|
}
|
|
|
|
static int dumpInfo(bcinfo::MetadataExtractor *ME) {
|
|
if (!ME) {
|
|
return 1;
|
|
}
|
|
|
|
FILE *info = fopen(infoFile.c_str(), "w");
|
|
if (!info) {
|
|
fprintf(stderr, "Could not open info file %s\n", infoFile.c_str());
|
|
return 2;
|
|
}
|
|
|
|
fprintf(info, "exportVarCount: %zu\n", ME->getExportVarCount());
|
|
const char **varNameList = ME->getExportVarNameList();
|
|
for (size_t i = 0; i < ME->getExportVarCount(); i++) {
|
|
fprintf(info, "%s\n", varNameList[i]);
|
|
}
|
|
|
|
fprintf(info, "exportFuncCount: %zu\n", ME->getExportFuncCount());
|
|
const char **funcNameList = ME->getExportFuncNameList();
|
|
for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
|
|
fprintf(info, "%s\n", funcNameList[i]);
|
|
}
|
|
|
|
fprintf(info, "exportForEachCount: %zu\n",
|
|
ME->getExportForEachSignatureCount());
|
|
const char **nameList = ME->getExportForEachNameList();
|
|
const uint32_t *sigList = ME->getExportForEachSignatureList();
|
|
const uint32_t *inputCountList = ME->getExportForEachInputCountList();
|
|
for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
|
|
fprintf(info, "%u - %s - %u\n", sigList[i], nameList[i],
|
|
inputCountList[i]);
|
|
}
|
|
|
|
fprintf(info, "exportReduceCount: %zu\n", ME->getExportReduceCount());
|
|
const bcinfo::MetadataExtractor::Reduce *reduceList =
|
|
ME->getExportReduceList();
|
|
for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
|
|
const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i];
|
|
fprintf(info, "%u - %s - %u - %u\n", reduce.mSignature, reduce.mReduceName,
|
|
reduce.mInputCount, reduce.mAccumulatorDataSize);
|
|
dumpReduceInfo(info, "initializer", reduce.mInitializerName);
|
|
dumpReduceInfo(info, "accumulator", reduce.mAccumulatorName);
|
|
dumpReduceInfo(info, "combiner", reduce.mCombinerName);
|
|
dumpReduceInfo(info, "outconverter", reduce.mOutConverterName);
|
|
dumpReduceInfo(info, "halter", reduce.mHalterName);
|
|
}
|
|
|
|
fprintf(info, "objectSlotCount: %zu\n", ME->getObjectSlotCount());
|
|
const uint32_t *slotList = ME->getObjectSlotList();
|
|
for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
|
|
fprintf(info, "%u\n", slotList[i]);
|
|
}
|
|
|
|
fclose(info);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void dumpMetadata(bcinfo::MetadataExtractor *ME) {
|
|
if (!ME) {
|
|
return;
|
|
}
|
|
|
|
printf("RSFloatPrecision: ");
|
|
switch (ME->getRSFloatPrecision()) {
|
|
case bcinfo::RS_FP_Full:
|
|
printf("Full\n\n");
|
|
break;
|
|
case bcinfo::RS_FP_Relaxed:
|
|
printf("Relaxed\n\n");
|
|
break;
|
|
default:
|
|
printf("UNKNOWN\n\n");
|
|
break;
|
|
}
|
|
|
|
printf("exportVarCount: %zu\n", ME->getExportVarCount());
|
|
const char **varNameList = ME->getExportVarNameList();
|
|
for (size_t i = 0; i < ME->getExportVarCount(); i++) {
|
|
printf("var[%zu]: %s\n", i, varNameList[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("exportFuncCount: %zu\n", ME->getExportFuncCount());
|
|
const char **funcNameList = ME->getExportFuncNameList();
|
|
for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
|
|
printf("func[%zu]: %s\n", i, funcNameList[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("exportForEachSignatureCount: %zu\n",
|
|
ME->getExportForEachSignatureCount());
|
|
const char **nameList = ME->getExportForEachNameList();
|
|
const uint32_t *sigList = ME->getExportForEachSignatureList();
|
|
const uint32_t *inputCountList = ME->getExportForEachInputCountList();
|
|
for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
|
|
printf("exportForEachSignatureList[%zu]: %s - 0x%08x - %u\n", i, nameList[i],
|
|
sigList[i], inputCountList[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("exportReduceCount: %zu\n", ME->getExportReduceCount());
|
|
const bcinfo::MetadataExtractor::Reduce *reduceList = ME->getExportReduceList();
|
|
for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
|
|
const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i];
|
|
printf("exportReduceList[%zu]: %s - 0x%08x - %u - %u\n", i, reduce.mReduceName,
|
|
reduce.mSignature, reduce.mInputCount, reduce.mAccumulatorDataSize);
|
|
dumpReduceInfo(stdout, "initializer", reduce.mInitializerName);
|
|
dumpReduceInfo(stdout, "accumulator", reduce.mAccumulatorName);
|
|
dumpReduceInfo(stdout, "combiner", reduce.mCombinerName);
|
|
dumpReduceInfo(stdout, "outconverter", reduce.mOutConverterName);
|
|
dumpReduceInfo(stdout, "halter", reduce.mHalterName);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("pragmaCount: %zu\n", ME->getPragmaCount());
|
|
const char **keyList = ME->getPragmaKeyList();
|
|
const char **valueList = ME->getPragmaValueList();
|
|
for (size_t i = 0; i < ME->getPragmaCount(); i++) {
|
|
printf("pragma[%zu]: %s - %s\n", i, keyList[i], valueList[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("objectSlotCount: %zu\n", ME->getObjectSlotCount());
|
|
const uint32_t *slotList = ME->getObjectSlotList();
|
|
for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
|
|
printf("objectSlotList[%zu]: %u\n", i, slotList[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static size_t readBitcode(const char **bitcode) {
|
|
if (!inFile.length()) {
|
|
fprintf(stderr, "input file required\n");
|
|
return 0;
|
|
}
|
|
|
|
struct stat statInFile;
|
|
if (stat(inFile.c_str(), &statInFile) < 0) {
|
|
fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
|
|
return 0;
|
|
}
|
|
|
|
if (!S_ISREG(statInFile.st_mode)) {
|
|
fprintf(stderr, "Input file should be a regular file.\n");
|
|
return 0;
|
|
}
|
|
|
|
FILE *in = fopen(inFile.c_str(), "r");
|
|
if (!in) {
|
|
fprintf(stderr, "Could not open input file %s\n", inFile.c_str());
|
|
return 0;
|
|
}
|
|
|
|
size_t bitcodeSize = statInFile.st_size;
|
|
|
|
*bitcode = (const char*) calloc(1, bitcodeSize + 1);
|
|
size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in);
|
|
|
|
if (nread != bitcodeSize)
|
|
fprintf(stderr, "Could not read all of file %s\n", inFile.c_str());
|
|
|
|
fclose(in);
|
|
return nread;
|
|
}
|
|
|
|
|
|
static void releaseBitcode(const char **bitcode) {
|
|
if (bitcode && *bitcode) {
|
|
free((void*) *bitcode);
|
|
*bitcode = nullptr;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
if(!parseOption(argc, argv)) {
|
|
fprintf(stderr, "failed to parse option\n");
|
|
return 1;
|
|
}
|
|
|
|
const char *bitcode = nullptr;
|
|
size_t bitcodeSize = readBitcode(&bitcode);
|
|
|
|
unsigned int version = 0;
|
|
|
|
bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
|
|
if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
|
|
version = bcWrapper.getTargetAPI();
|
|
if (verbose) {
|
|
printf("Found bitcodeWrapper\n");
|
|
}
|
|
} else if (translateFlag) {
|
|
version = 12;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("targetAPI: %u\n", version);
|
|
printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
|
|
printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
|
|
}
|
|
|
|
std::unique_ptr<bcinfo::BitcodeTranslator> BT;
|
|
BT.reset(new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version));
|
|
if (!BT->translate()) {
|
|
fprintf(stderr, "failed to translate bitcode\n");
|
|
return 3;
|
|
}
|
|
|
|
std::unique_ptr<bcinfo::MetadataExtractor> ME;
|
|
ME.reset(new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
|
|
BT->getTranslatedBitcodeSize()));
|
|
if (!ME->extract()) {
|
|
fprintf(stderr, "failed to get metadata\n");
|
|
return 4;
|
|
}
|
|
|
|
if (verbose) {
|
|
dumpMetadata(ME.get());
|
|
|
|
const char *translatedBitcode = BT->getTranslatedBitcode();
|
|
size_t translatedBitcodeSize = BT->getTranslatedBitcodeSize();
|
|
|
|
llvm::LLVMContext ctx;
|
|
llvm::llvm_shutdown_obj called_on_exit;
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> mem;
|
|
|
|
mem = llvm::MemoryBuffer::getMemBuffer(
|
|
llvm::StringRef(translatedBitcode, translatedBitcodeSize),
|
|
inFile.c_str(), false);
|
|
|
|
std::unique_ptr<llvm::Module> module;
|
|
llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError =
|
|
llvm::parseBitcodeFile(mem.get()->getMemBufferRef(), ctx);
|
|
std::error_code ec = moduleOrError.getError();
|
|
if (!ec) {
|
|
module = std::move(moduleOrError.get());
|
|
ec = module->materializeAll();
|
|
}
|
|
std::string errmsg;
|
|
if (ec) {
|
|
errmsg = ec.message();
|
|
module.reset();
|
|
if (errmsg.size()) {
|
|
fprintf(stderr, "error: %s\n", errmsg.c_str());
|
|
} else {
|
|
fprintf(stderr, "error: failed to parse bitcode file\n");
|
|
}
|
|
return 5;
|
|
}
|
|
|
|
std::unique_ptr<llvm::tool_output_file> tof(
|
|
new llvm::tool_output_file(outFile.c_str(), ec,
|
|
llvm::sys::fs::F_None));
|
|
std::unique_ptr<llvm::AssemblyAnnotationWriter> ann;
|
|
module->print(tof->os(), ann.get());
|
|
|
|
tof->keep();
|
|
}
|
|
|
|
if (infoFlag) {
|
|
if (dumpInfo(ME.get()) != 0) {
|
|
fprintf(stderr, "Error dumping info file\n");
|
|
return 6;
|
|
}
|
|
}
|
|
|
|
releaseBitcode(&bitcode);
|
|
|
|
return 0;
|
|
}
|