699 lines
23 KiB
C++
699 lines
23 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/MetadataExtractor.h"
|
|
|
|
#include "bcinfo/BitcodeWrapper.h"
|
|
#include "rsDefines.h"
|
|
|
|
#define LOG_TAG "bcinfo"
|
|
#include <log/log.h>
|
|
|
|
#include "Assert.h"
|
|
|
|
#include "llvm/Bitcode/ReaderWriter.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#ifdef __ANDROID__
|
|
#include "Properties.h"
|
|
#endif
|
|
|
|
#include <cstdlib>
|
|
|
|
namespace bcinfo {
|
|
|
|
namespace {
|
|
|
|
llvm::StringRef getStringOperand(const llvm::Metadata *node) {
|
|
if (auto *mds = llvm::dyn_cast_or_null<const llvm::MDString>(node)) {
|
|
return mds->getString();
|
|
}
|
|
return llvm::StringRef();
|
|
}
|
|
|
|
bool extractUIntFromMetadataString(uint32_t *value,
|
|
const llvm::Metadata *m) {
|
|
llvm::StringRef SigString = getStringOperand(m);
|
|
if (SigString != "") {
|
|
if (!SigString.getAsInteger(10, *value)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const char *createStringFromValue(llvm::Metadata *m) {
|
|
auto ref = getStringOperand(m);
|
|
char *c = new char[ref.size() + 1];
|
|
memcpy(c, ref.data(), ref.size());
|
|
c[ref.size()] = '\0';
|
|
return c;
|
|
}
|
|
|
|
const char *createStringFromOptionalValue(llvm::MDNode *n, unsigned opndNum) {
|
|
llvm::Metadata *opnd;
|
|
if (opndNum >= n->getNumOperands() || !(opnd = n->getOperand(opndNum)))
|
|
return nullptr;
|
|
return createStringFromValue(opnd);
|
|
}
|
|
|
|
// Collect metadata from NamedMDNodes that contain a list of names
|
|
// (strings).
|
|
//
|
|
// Inputs:
|
|
//
|
|
// NamedMetadata - An LLVM metadata node, each of whose operands have
|
|
// a string as their first entry
|
|
//
|
|
// NameList - A reference that will hold an allocated array of strings
|
|
//
|
|
// Count - A reference that will hold the length of the allocated
|
|
// array of strings
|
|
//
|
|
// Return value:
|
|
//
|
|
// Return true on success, false on error.
|
|
//
|
|
// Upon success, the function sets NameList to an array of strings
|
|
// corresponding the names found in the metadata. The function sets
|
|
// Count to the number of entries in NameList.
|
|
//
|
|
// An error occurs if one of the metadata operands doesn't have a
|
|
// first entry.
|
|
bool populateNameMetadata(const llvm::NamedMDNode *NameMetadata,
|
|
const char **&NameList, size_t &Count) {
|
|
if (!NameMetadata) {
|
|
NameList = nullptr;
|
|
Count = 0;
|
|
return true;
|
|
}
|
|
|
|
Count = NameMetadata->getNumOperands();
|
|
if (!Count) {
|
|
NameList = nullptr;
|
|
return true;
|
|
}
|
|
|
|
NameList = new const char *[Count];
|
|
|
|
for (size_t i = 0; i < Count; i++) {
|
|
llvm::MDNode *Name = NameMetadata->getOperand(i);
|
|
if (Name && Name->getNumOperands() > 0) {
|
|
NameList[i] = createStringFromValue(Name->getOperand(0));
|
|
} else {
|
|
ALOGE("Metadata operand does not contain a name string");
|
|
for (size_t AllocatedIndex = 0; AllocatedIndex < i; AllocatedIndex++) {
|
|
delete [] NameList[AllocatedIndex];
|
|
}
|
|
delete [] NameList;
|
|
NameList = nullptr;
|
|
Count = 0;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // end anonymous namespace
|
|
|
|
// Name of metadata node where pragma info resides (should be synced with
|
|
// slang.cpp)
|
|
static const llvm::StringRef PragmaMetadataName = "#pragma";
|
|
|
|
// Name of metadata node where exported variable names reside (should be
|
|
// synced with slang_rs_metadata.h)
|
|
static const llvm::StringRef ExportVarMetadataName = "#rs_export_var";
|
|
|
|
// Name of metadata node where exported function names reside (should be
|
|
// synced with slang_rs_metadata.h)
|
|
static const llvm::StringRef ExportFuncMetadataName = "#rs_export_func";
|
|
|
|
// Name of metadata node where exported ForEach name information resides
|
|
// (should be synced with slang_rs_metadata.h)
|
|
static const llvm::StringRef ExportForEachNameMetadataName =
|
|
"#rs_export_foreach_name";
|
|
|
|
// Name of metadata node where exported ForEach signature information resides
|
|
// (should be synced with slang_rs_metadata.h)
|
|
static const llvm::StringRef ExportForEachMetadataName = "#rs_export_foreach";
|
|
|
|
// Name of metadata node where exported general reduce information resides
|
|
// (should be synced with slang_rs_metadata.h)
|
|
static const llvm::StringRef ExportReduceMetadataName = "#rs_export_reduce";
|
|
|
|
// Name of metadata node where RS object slot info resides (should be
|
|
// synced with slang_rs_metadata.h)
|
|
static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots";
|
|
|
|
static const llvm::StringRef ThreadableMetadataName = "#rs_is_threadable";
|
|
|
|
// Name of metadata node where the checksum for this build is stored. (should
|
|
// be synced with libbcc/lib/Core/Source.cpp)
|
|
static const llvm::StringRef ChecksumMetadataName = "#rs_build_checksum";
|
|
|
|
// Name of metadata node which contains a list of compile units that have debug
|
|
// metadata. If this is null then there is no debug metadata in the compile
|
|
// unit.
|
|
static const llvm::StringRef DebugInfoMetadataName = "llvm.dbg.cu";
|
|
|
|
const char MetadataExtractor::kWrapperMetadataName[] = "#rs_wrapper";
|
|
|
|
MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
|
|
: mModule(nullptr), mBitcode(bitcode), mBitcodeSize(bitcodeSize),
|
|
mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
|
|
mExportReduceCount(0), mExportVarNameList(nullptr),
|
|
mExportFuncNameList(nullptr), mExportForEachNameList(nullptr),
|
|
mExportForEachSignatureList(nullptr),
|
|
mExportForEachInputCountList(nullptr),
|
|
mExportReduceList(nullptr),
|
|
mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr),
|
|
mObjectSlotCount(0), mObjectSlotList(nullptr),
|
|
mRSFloatPrecision(RS_FP_Full), mIsThreadable(true),
|
|
mBuildChecksum(nullptr), mHasDebugInfo(false) {
|
|
BitcodeWrapper wrapper(bitcode, bitcodeSize);
|
|
mCompilerVersion = wrapper.getCompilerVersion();
|
|
mOptimizationLevel = wrapper.getOptimizationLevel();
|
|
}
|
|
|
|
MetadataExtractor::MetadataExtractor(const llvm::Module *module)
|
|
: mModule(module), mBitcode(nullptr), mBitcodeSize(0),
|
|
mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
|
|
mExportReduceCount(0), mExportVarNameList(nullptr),
|
|
mExportFuncNameList(nullptr), mExportForEachNameList(nullptr),
|
|
mExportForEachSignatureList(nullptr),
|
|
mExportForEachInputCountList(nullptr),
|
|
mExportReduceList(nullptr),
|
|
mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr),
|
|
mObjectSlotCount(0), mObjectSlotList(nullptr),
|
|
mRSFloatPrecision(RS_FP_Full), mIsThreadable(true),
|
|
mBuildChecksum(nullptr) {
|
|
const llvm::NamedMDNode *const wrapperMDNode = module->getNamedMetadata(kWrapperMetadataName);
|
|
bccAssert((wrapperMDNode != nullptr) && (wrapperMDNode->getNumOperands() == 1));
|
|
const llvm::MDNode *const wrapperMDTuple = wrapperMDNode->getOperand(0);
|
|
|
|
bool success = true;
|
|
success &= extractUIntFromMetadataString(&mCompilerVersion, wrapperMDTuple->getOperand(0));
|
|
success &= extractUIntFromMetadataString(&mOptimizationLevel, wrapperMDTuple->getOperand(1));
|
|
bccAssert(success);
|
|
}
|
|
|
|
|
|
MetadataExtractor::~MetadataExtractor() {
|
|
if (mExportVarNameList) {
|
|
for (size_t i = 0; i < mExportVarCount; i++) {
|
|
delete [] mExportVarNameList[i];
|
|
mExportVarNameList[i] = nullptr;
|
|
}
|
|
}
|
|
delete [] mExportVarNameList;
|
|
mExportVarNameList = nullptr;
|
|
|
|
if (mExportFuncNameList) {
|
|
for (size_t i = 0; i < mExportFuncCount; i++) {
|
|
delete [] mExportFuncNameList[i];
|
|
mExportFuncNameList[i] = nullptr;
|
|
}
|
|
}
|
|
delete [] mExportFuncNameList;
|
|
mExportFuncNameList = nullptr;
|
|
|
|
if (mExportForEachNameList) {
|
|
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
|
|
delete [] mExportForEachNameList[i];
|
|
mExportForEachNameList[i] = nullptr;
|
|
}
|
|
}
|
|
delete [] mExportForEachNameList;
|
|
mExportForEachNameList = nullptr;
|
|
|
|
delete [] mExportForEachSignatureList;
|
|
mExportForEachSignatureList = nullptr;
|
|
|
|
delete [] mExportForEachInputCountList;
|
|
mExportForEachInputCountList = nullptr;
|
|
|
|
delete [] mExportReduceList;
|
|
mExportReduceList = nullptr;
|
|
|
|
for (size_t i = 0; i < mPragmaCount; i++) {
|
|
if (mPragmaKeyList) {
|
|
delete [] mPragmaKeyList[i];
|
|
mPragmaKeyList[i] = nullptr;
|
|
}
|
|
if (mPragmaValueList) {
|
|
delete [] mPragmaValueList[i];
|
|
mPragmaValueList[i] = nullptr;
|
|
}
|
|
}
|
|
delete [] mPragmaKeyList;
|
|
mPragmaKeyList = nullptr;
|
|
delete [] mPragmaValueList;
|
|
mPragmaValueList = nullptr;
|
|
|
|
delete [] mObjectSlotList;
|
|
mObjectSlotList = nullptr;
|
|
|
|
delete [] mBuildChecksum;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
bool MetadataExtractor::populateObjectSlotMetadata(
|
|
const llvm::NamedMDNode *ObjectSlotMetadata) {
|
|
if (!ObjectSlotMetadata) {
|
|
return true;
|
|
}
|
|
|
|
mObjectSlotCount = ObjectSlotMetadata->getNumOperands();
|
|
|
|
if (!mObjectSlotCount) {
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<uint32_t[]> TmpSlotList(new uint32_t[mObjectSlotCount]());
|
|
for (size_t i = 0; i < mObjectSlotCount; i++) {
|
|
llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i);
|
|
if (ObjectSlot != nullptr && ObjectSlot->getNumOperands() == 1) {
|
|
if (!extractUIntFromMetadataString(&TmpSlotList[i], ObjectSlot->getOperand(0))) {
|
|
ALOGE("Non-integer object slot value");
|
|
return false;
|
|
}
|
|
} else {
|
|
ALOGE("Corrupt object slot information");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
delete [] mObjectSlotList;
|
|
mObjectSlotList = TmpSlotList.release();
|
|
return true;
|
|
}
|
|
|
|
|
|
void MetadataExtractor::populatePragmaMetadata(
|
|
const llvm::NamedMDNode *PragmaMetadata) {
|
|
if (!PragmaMetadata) {
|
|
return;
|
|
}
|
|
|
|
mPragmaCount = PragmaMetadata->getNumOperands();
|
|
if (!mPragmaCount) {
|
|
return;
|
|
}
|
|
|
|
const char **TmpKeyList = new const char*[mPragmaCount];
|
|
const char **TmpValueList = new const char*[mPragmaCount];
|
|
|
|
for (size_t i = 0; i < mPragmaCount; i++) {
|
|
llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
|
|
if (Pragma != nullptr && Pragma->getNumOperands() == 2) {
|
|
llvm::Metadata *PragmaKeyMDS = Pragma->getOperand(0);
|
|
TmpKeyList[i] = createStringFromValue(PragmaKeyMDS);
|
|
llvm::Metadata *PragmaValueMDS = Pragma->getOperand(1);
|
|
TmpValueList[i] = createStringFromValue(PragmaValueMDS);
|
|
}
|
|
}
|
|
|
|
mPragmaKeyList = TmpKeyList;
|
|
mPragmaValueList = TmpValueList;
|
|
|
|
// Check to see if we have any FP precision-related pragmas.
|
|
std::string Relaxed("rs_fp_relaxed");
|
|
std::string Imprecise("rs_fp_imprecise");
|
|
std::string Full("rs_fp_full");
|
|
bool RelaxedPragmaSeen = false;
|
|
bool FullPragmaSeen = false;
|
|
for (size_t i = 0; i < mPragmaCount; i++) {
|
|
if (!Relaxed.compare(mPragmaKeyList[i])) {
|
|
RelaxedPragmaSeen = true;
|
|
} else if (!Imprecise.compare(mPragmaKeyList[i])) {
|
|
ALOGW("rs_fp_imprecise is deprecated. Assuming rs_fp_relaxed instead.");
|
|
RelaxedPragmaSeen = true;
|
|
} else if (!Full.compare(mPragmaKeyList[i])) {
|
|
FullPragmaSeen = true;
|
|
}
|
|
}
|
|
|
|
if (RelaxedPragmaSeen && FullPragmaSeen) {
|
|
ALOGE("Full and relaxed precision specified at the same time!");
|
|
}
|
|
mRSFloatPrecision = RelaxedPragmaSeen ? RS_FP_Relaxed : RS_FP_Full;
|
|
|
|
#ifdef __ANDROID__
|
|
// Provide an override for precsiion via adb shell setprop
|
|
// adb shell setprop debug.rs.precision rs_fp_full
|
|
// adb shell setprop debug.rs.precision rs_fp_relaxed
|
|
// adb shell setprop debug.rs.precision rs_fp_imprecise
|
|
char PrecisionPropBuf[PROP_VALUE_MAX];
|
|
const std::string PrecisionPropName("debug.rs.precision");
|
|
property_get("debug.rs.precision", PrecisionPropBuf, "");
|
|
if (PrecisionPropBuf[0]) {
|
|
if (!Relaxed.compare(PrecisionPropBuf)) {
|
|
ALOGI("Switching to RS FP relaxed mode via setprop");
|
|
mRSFloatPrecision = RS_FP_Relaxed;
|
|
} else if (!Imprecise.compare(PrecisionPropBuf)) {
|
|
ALOGW("Switching to RS FP relaxed mode via setprop. rs_fp_imprecise was "
|
|
"specified but is deprecated ");
|
|
mRSFloatPrecision = RS_FP_Relaxed;
|
|
} else if (!Full.compare(PrecisionPropBuf)) {
|
|
ALOGI("Switching to RS FP full mode via setprop");
|
|
mRSFloatPrecision = RS_FP_Full;
|
|
} else {
|
|
ALOGE("Unrecognized debug.rs.precision %s", PrecisionPropBuf);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
uint32_t MetadataExtractor::calculateNumInputs(const llvm::Function *Function,
|
|
uint32_t Signature) {
|
|
|
|
if (hasForEachSignatureIn(Signature)) {
|
|
uint32_t OtherCount = 0;
|
|
|
|
OtherCount += hasForEachSignatureUsrData(Signature);
|
|
OtherCount += hasForEachSignatureX(Signature);
|
|
OtherCount += hasForEachSignatureY(Signature);
|
|
OtherCount += hasForEachSignatureZ(Signature);
|
|
OtherCount += hasForEachSignatureCtxt(Signature);
|
|
OtherCount += hasForEachSignatureOut(Signature) &&
|
|
Function->getReturnType()->isVoidTy();
|
|
|
|
return Function->arg_size() - OtherCount;
|
|
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
bool MetadataExtractor::populateForEachMetadata(
|
|
const llvm::NamedMDNode *Names,
|
|
const llvm::NamedMDNode *Signatures) {
|
|
if (!Names && !Signatures && mCompilerVersion == 0) {
|
|
// Handle legacy case for pre-ICS bitcode that doesn't contain a metadata
|
|
// section for ForEach. We generate a full signature for a "root" function
|
|
// which means that we need to set the bottom 5 bits in the mask.
|
|
mExportForEachSignatureCount = 1;
|
|
char **TmpNameList = new char*[mExportForEachSignatureCount];
|
|
size_t RootLen = strlen(kRoot) + 1;
|
|
TmpNameList[0] = new char[RootLen];
|
|
strncpy(TmpNameList[0], kRoot, RootLen);
|
|
|
|
uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
|
|
TmpSigList[0] = 0x1f;
|
|
|
|
mExportForEachNameList = (const char**)TmpNameList;
|
|
mExportForEachSignatureList = TmpSigList;
|
|
return true;
|
|
}
|
|
|
|
if (Signatures) {
|
|
mExportForEachSignatureCount = Signatures->getNumOperands();
|
|
if (!mExportForEachSignatureCount) {
|
|
return true;
|
|
}
|
|
} else {
|
|
mExportForEachSignatureCount = 0;
|
|
mExportForEachSignatureList = nullptr;
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<uint32_t[]> TmpSigList(new uint32_t[mExportForEachSignatureCount]);
|
|
std::unique_ptr<const char *[]> TmpNameList(new const char*[mExportForEachSignatureCount]);
|
|
std::unique_ptr<uint32_t[]> TmpInputCountList(new uint32_t[mExportForEachSignatureCount]);
|
|
|
|
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
|
|
llvm::MDNode *SigNode = Signatures->getOperand(i);
|
|
if (SigNode != nullptr && SigNode->getNumOperands() == 1) {
|
|
if (!extractUIntFromMetadataString(&TmpSigList[i], SigNode->getOperand(0))) {
|
|
ALOGE("Non-integer signature value");
|
|
return false;
|
|
}
|
|
} else {
|
|
ALOGE("Corrupt signature information");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (Names) {
|
|
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
|
|
llvm::MDNode *Name = Names->getOperand(i);
|
|
if (Name != nullptr && Name->getNumOperands() == 1) {
|
|
TmpNameList[i] = createStringFromValue(Name->getOperand(0));
|
|
|
|
// Note that looking up the function by name can fail: One of
|
|
// the uses of MetadataExtractor is as part of the
|
|
// RSEmbedInfoPass, which bcc_compat runs sufficiently late in
|
|
// the phase order that RSKernelExpandPass has already run and
|
|
// the original (UNexpanded) kernel function (TmpNameList[i])
|
|
// may have been deleted as having no references (if it has
|
|
// been inlined into the expanded kernel function and is
|
|
// otherwise unreferenced).
|
|
llvm::Function *Func =
|
|
mModule->getFunction(llvm::StringRef(TmpNameList[i]));
|
|
|
|
TmpInputCountList[i] = (Func != nullptr) ?
|
|
calculateNumInputs(Func, TmpSigList[i]) : 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (mExportForEachSignatureCount != 1) {
|
|
ALOGE("mExportForEachSignatureCount = %zu, but should be 1",
|
|
mExportForEachSignatureCount);
|
|
}
|
|
char *RootName = new char[5];
|
|
strncpy(RootName, "root", 5);
|
|
TmpNameList[0] = RootName;
|
|
}
|
|
|
|
delete [] mExportForEachNameList;
|
|
mExportForEachNameList = TmpNameList.release();
|
|
|
|
delete [] mExportForEachSignatureList;
|
|
mExportForEachSignatureList = TmpSigList.release();
|
|
|
|
delete [] mExportForEachInputCountList;
|
|
mExportForEachInputCountList = TmpInputCountList.release();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MetadataExtractor::populateReduceMetadata(const llvm::NamedMDNode *ReduceMetadata) {
|
|
mExportReduceCount = 0;
|
|
mExportReduceList = nullptr;
|
|
|
|
if (!ReduceMetadata || !(mExportReduceCount = ReduceMetadata->getNumOperands()))
|
|
return true;
|
|
|
|
std::unique_ptr<Reduce[]> TmpReduceList(new Reduce[mExportReduceCount]);
|
|
|
|
for (size_t i = 0; i < mExportReduceCount; i++) {
|
|
llvm::MDNode *Node = ReduceMetadata->getOperand(i);
|
|
if (!Node || Node->getNumOperands() < 3) {
|
|
ALOGE("Missing reduce metadata");
|
|
return false;
|
|
}
|
|
|
|
TmpReduceList[i].mReduceName = createStringFromValue(Node->getOperand(0));
|
|
|
|
if (!extractUIntFromMetadataString(&TmpReduceList[i].mAccumulatorDataSize,
|
|
Node->getOperand(1))) {
|
|
ALOGE("Non-integer accumulator data size value in reduce metadata");
|
|
return false;
|
|
}
|
|
|
|
llvm::MDNode *AccumulatorNode = llvm::dyn_cast<llvm::MDNode>(Node->getOperand(2));
|
|
if (!AccumulatorNode || AccumulatorNode->getNumOperands() != 2) {
|
|
ALOGE("Malformed accumulator node in reduce metadata");
|
|
return false;
|
|
}
|
|
TmpReduceList[i].mAccumulatorName = createStringFromValue(AccumulatorNode->getOperand(0));
|
|
if (!extractUIntFromMetadataString(&TmpReduceList[i].mSignature,
|
|
AccumulatorNode->getOperand(1))) {
|
|
ALOGE("Non-integer signature value in reduce metadata");
|
|
return false;
|
|
}
|
|
// Note that looking up the function by name can fail: One of the
|
|
// uses of MetadataExtractor is as part of the RSEmbedInfoPass,
|
|
// which bcc_compat runs sufficiently late in the phase order that
|
|
// RSKernelExpandPass has already run and the original
|
|
// (UNexpanded) accumulator function (mAccumulatorName) may have
|
|
// been deleted as having no references (if it has been inlined
|
|
// into the expanded accumulator function and is otherwise
|
|
// unreferenced).
|
|
llvm::Function *Func =
|
|
mModule->getFunction(llvm::StringRef(TmpReduceList[i].mAccumulatorName));
|
|
// Why calculateNumInputs() - 1? The "-1" is because we don't
|
|
// want to treat the accumulator argument as an input.
|
|
TmpReduceList[i].mInputCount = (Func ? calculateNumInputs(Func, TmpReduceList[i].mSignature) - 1 : 0);
|
|
|
|
TmpReduceList[i].mInitializerName = createStringFromOptionalValue(Node, 3);
|
|
TmpReduceList[i].mCombinerName = createStringFromOptionalValue(Node, 4);
|
|
TmpReduceList[i].mOutConverterName = createStringFromOptionalValue(Node, 5);
|
|
TmpReduceList[i].mHalterName = createStringFromOptionalValue(Node, 6);
|
|
}
|
|
|
|
mExportReduceList = TmpReduceList.release();
|
|
return true;
|
|
}
|
|
|
|
void MetadataExtractor::readThreadableFlag(
|
|
const llvm::NamedMDNode *ThreadableMetadata) {
|
|
|
|
// Scripts are threadable by default. If we read a valid metadata value for
|
|
// 'ThreadableMetadataName' and it is set to 'no', we mark script as non
|
|
// threadable. All other exception paths retain the default value.
|
|
|
|
mIsThreadable = true;
|
|
if (ThreadableMetadata == nullptr)
|
|
return;
|
|
|
|
llvm::MDNode *mdNode = ThreadableMetadata->getOperand(0);
|
|
if (mdNode == nullptr)
|
|
return;
|
|
|
|
llvm::Metadata *mdValue = mdNode->getOperand(0);
|
|
if (mdValue == nullptr)
|
|
return;
|
|
|
|
if (getStringOperand(mdValue) == "no")
|
|
mIsThreadable = false;
|
|
}
|
|
|
|
void MetadataExtractor::readBuildChecksumMetadata(
|
|
const llvm::NamedMDNode *ChecksumMetadata) {
|
|
|
|
if (ChecksumMetadata == nullptr)
|
|
return;
|
|
|
|
llvm::MDNode *mdNode = ChecksumMetadata->getOperand(0);
|
|
if (mdNode == nullptr)
|
|
return;
|
|
|
|
llvm::Metadata *mdValue = mdNode->getOperand(0);
|
|
if (mdValue == nullptr)
|
|
return;
|
|
|
|
mBuildChecksum = createStringFromValue(mdValue);
|
|
}
|
|
|
|
bool MetadataExtractor::extract() {
|
|
if (!(mBitcode && mBitcodeSize) && !mModule) {
|
|
ALOGE("Invalid/empty bitcode/module");
|
|
return false;
|
|
}
|
|
|
|
std::unique_ptr<llvm::LLVMContext> mContext;
|
|
bool shouldNullModule = false;
|
|
|
|
if (!mModule) {
|
|
mContext.reset(new llvm::LLVMContext());
|
|
std::unique_ptr<llvm::MemoryBuffer> MEM(
|
|
llvm::MemoryBuffer::getMemBuffer(
|
|
llvm::StringRef(mBitcode, mBitcodeSize), "", false));
|
|
std::string error;
|
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::Module> > errval =
|
|
llvm::parseBitcodeFile(MEM.get()->getMemBufferRef(), *mContext);
|
|
if (std::error_code ec = errval.getError()) {
|
|
ALOGE("Could not parse bitcode file");
|
|
ALOGE("%s", ec.message().c_str());
|
|
return false;
|
|
}
|
|
|
|
mModule = errval.get().release();
|
|
shouldNullModule = true;
|
|
}
|
|
|
|
const llvm::NamedMDNode *ExportVarMetadata =
|
|
mModule->getNamedMetadata(ExportVarMetadataName);
|
|
const llvm::NamedMDNode *ExportFuncMetadata =
|
|
mModule->getNamedMetadata(ExportFuncMetadataName);
|
|
const llvm::NamedMDNode *ExportForEachNameMetadata =
|
|
mModule->getNamedMetadata(ExportForEachNameMetadataName);
|
|
const llvm::NamedMDNode *ExportForEachMetadata =
|
|
mModule->getNamedMetadata(ExportForEachMetadataName);
|
|
const llvm::NamedMDNode *ExportReduceMetadata =
|
|
mModule->getNamedMetadata(ExportReduceMetadataName);
|
|
const llvm::NamedMDNode *PragmaMetadata =
|
|
mModule->getNamedMetadata(PragmaMetadataName);
|
|
const llvm::NamedMDNode *ObjectSlotMetadata =
|
|
mModule->getNamedMetadata(ObjectSlotMetadataName);
|
|
const llvm::NamedMDNode *ThreadableMetadata =
|
|
mModule->getNamedMetadata(ThreadableMetadataName);
|
|
const llvm::NamedMDNode *ChecksumMetadata =
|
|
mModule->getNamedMetadata(ChecksumMetadataName);
|
|
const llvm::NamedMDNode *DebugInfoMetadata =
|
|
mModule->getNamedMetadata(DebugInfoMetadataName);
|
|
|
|
if (!populateNameMetadata(ExportVarMetadata, mExportVarNameList,
|
|
mExportVarCount)) {
|
|
ALOGE("Could not populate export variable metadata");
|
|
goto err;
|
|
}
|
|
|
|
if (!populateNameMetadata(ExportFuncMetadata, mExportFuncNameList,
|
|
mExportFuncCount)) {
|
|
ALOGE("Could not populate export function metadata");
|
|
goto err;
|
|
}
|
|
|
|
if (!populateForEachMetadata(ExportForEachNameMetadata,
|
|
ExportForEachMetadata)) {
|
|
ALOGE("Could not populate ForEach signature metadata");
|
|
goto err;
|
|
}
|
|
|
|
if (!populateReduceMetadata(ExportReduceMetadata)) {
|
|
ALOGE("Could not populate export general reduction metadata");
|
|
goto err;
|
|
}
|
|
|
|
populatePragmaMetadata(PragmaMetadata);
|
|
|
|
if (!populateObjectSlotMetadata(ObjectSlotMetadata)) {
|
|
ALOGE("Could not populate object slot metadata");
|
|
goto err;
|
|
}
|
|
|
|
readThreadableFlag(ThreadableMetadata);
|
|
readBuildChecksumMetadata(ChecksumMetadata);
|
|
|
|
mHasDebugInfo = DebugInfoMetadata != nullptr;
|
|
|
|
if (shouldNullModule) {
|
|
mModule = nullptr;
|
|
}
|
|
return true;
|
|
|
|
err:
|
|
if (shouldNullModule) {
|
|
mModule = nullptr;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace bcinfo
|