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
 |