am 29f866bc: Merge "Mark whether a script is threadable"
* commit '29f866bc3b116aa748e6e6cd3eaf3b00b3e659ae':
Mark whether a script is threadable
diff --git a/bcinfo/MetadataExtractor.cpp b/bcinfo/MetadataExtractor.cpp
index acc6915..4d868c8 100644
--- a/bcinfo/MetadataExtractor.cpp
+++ b/bcinfo/MetadataExtractor.cpp
@@ -60,6 +60,7 @@
// synced with slang_rs_metadata.h)
static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots";
+static const llvm::StringRef ThreadableMetadataName = "#rs_is_threadable";
MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
: mModule(nullptr), mBitcode(bitcode), mBitcodeSize(bitcodeSize),
@@ -68,7 +69,8 @@
mExportForEachNameList(nullptr), mExportForEachSignatureList(nullptr),
mExportForEachInputCountList(nullptr), mPragmaCount(0),
mPragmaKeyList(nullptr), mPragmaValueList(nullptr), mObjectSlotCount(0),
- mObjectSlotList(nullptr), mRSFloatPrecision(RS_FP_Full) {
+ mObjectSlotList(nullptr), mRSFloatPrecision(RS_FP_Full),
+ mIsThreadable(true) {
BitcodeWrapper wrapper(bitcode, bitcodeSize);
mCompilerVersion = wrapper.getCompilerVersion();
mOptimizationLevel = wrapper.getOptimizationLevel();
@@ -82,7 +84,8 @@
mExportForEachNameList(nullptr), mExportForEachSignatureList(nullptr),
mExportForEachInputCountList(nullptr), mPragmaCount(0),
mPragmaKeyList(nullptr), mPragmaValueList(nullptr), mObjectSlotCount(0),
- mObjectSlotList(nullptr), mRSFloatPrecision(RS_FP_Full) {
+ mObjectSlotList(nullptr), mRSFloatPrecision(RS_FP_Full),
+ mIsThreadable(true) {
mCompilerVersion = RS_VERSION; // Default to the actual current version.
mOptimizationLevel = 3;
}
@@ -425,6 +428,36 @@
}
+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::Value *mdValue = mdNode->getOperand(0);
+ if (mdValue == nullptr)
+ return;
+
+ const char *value = createStringFromValue(mdValue);
+ if (value == nullptr)
+ return;
+
+ if (strcmp(value, "no") == 0)
+ mIsThreadable = false;
+ return;
+
+}
+
+
bool MetadataExtractor::extract() {
if (!(mBitcode && mBitcodeSize) && !mModule) {
ALOGE("Invalid/empty bitcode/module");
@@ -463,6 +496,8 @@
mModule->getNamedMetadata(PragmaMetadataName);
const llvm::NamedMDNode *ObjectSlotMetadata =
mModule->getNamedMetadata(ObjectSlotMetadataName);
+ const llvm::NamedMDNode *ThreadableMetadata =
+ mModule->getNamedMetadata(ThreadableMetadataName);
if (!populateVarNameMetadata(ExportVarMetadata)) {
@@ -488,6 +523,8 @@
return false;
}
+ readThreadableFlag(ThreadableMetadata);
+
return true;
}
diff --git a/include/bcc/Renderscript/RSTransforms.h b/include/bcc/Renderscript/RSTransforms.h
index 9fe418b..647ac4d 100644
--- a/include/bcc/Renderscript/RSTransforms.h
+++ b/include/bcc/Renderscript/RSTransforms.h
@@ -32,9 +32,9 @@
llvm::ModulePass * createRSEmbedInfoPass();
+llvm::ModulePass * createRSScreenFunctionsPass();
-llvm::ModulePass *
-createRSScreenFunctionsPass();
+llvm::ModulePass * createRSIsThreadablePass();
} // end namespace bcc
diff --git a/include/bcinfo/MetadataExtractor.h b/include/bcinfo/MetadataExtractor.h
index 6d53a29..3648889 100644
--- a/include/bcinfo/MetadataExtractor.h
+++ b/include/bcinfo/MetadataExtractor.h
@@ -61,6 +61,9 @@
enum RSFloatPrecision mRSFloatPrecision;
+ // Flag to mark that script is threadable. True by default.
+ bool mIsThreadable;
+
// Helper functions for extraction
bool populateVarNameMetadata(const llvm::NamedMDNode *VarNameMetadata);
bool populateFuncNameMetadata(const llvm::NamedMDNode *FuncNameMetadata);
@@ -68,6 +71,7 @@
const llvm::NamedMDNode *Signatures);
bool populateObjectSlotMetadata(const llvm::NamedMDNode *ObjectSlotMetadata);
void populatePragmaMetadata(const llvm::NamedMDNode *PragmaMetadata);
+ void readThreadableFlag(const llvm::NamedMDNode *ThreadableMetadata);
uint32_t calculateNumInputs(const llvm::Function *Function,
uint32_t Signature);
@@ -269,6 +273,11 @@
static bool hasForEachSignatureKernel(uint32_t sig) {
return sig & 0x20;
}
+
+ bool isThreadable() {
+ return mIsThreadable;
+ }
+
};
} // namespace bcinfo
diff --git a/lib/Core/Compiler.cpp b/lib/Core/Compiler.cpp
index c88ecc3..a2ebab5 100644
--- a/lib/Core/Compiler.cpp
+++ b/lib/Core/Compiler.cpp
@@ -197,6 +197,14 @@
// This has to come after LTO, since we don't want to examine functions that
// are never actually called.
passes.add(createRSScreenFunctionsPass());
+ passes.add(createRSIsThreadablePass());
+
+ // RSEmbedInfoPass needs to come after we have scanned for non-threadable
+ // functions.
+ // Script passed to RSCompiler must be a RSScript.
+ RSScript &script = static_cast<RSScript &>(pScript);
+ if (script.getEmbedInfo())
+ passes.add(createRSEmbedInfoPass());
// Add passes to the pass manager to emit machine code through MC layer.
if (mTarget->addPassesToEmitMC(passes, mc_context, pResult,
@@ -356,14 +364,9 @@
}
bool Compiler::addExpandForEachPass(Script &pScript, llvm::PassManager &pPM) {
- // Script passed to RSCompiler must be a RSScript.
- RSScript &script = static_cast<RSScript &>(pScript);
-
// Expand ForEach on CPU path to reduce launch overhead.
bool pEnableStepOpt = true;
pPM.add(createRSForEachExpandPass(pEnableStepOpt));
- if (script.getEmbedInfo())
- pPM.add(createRSEmbedInfoPass());
return true;
}
diff --git a/lib/Renderscript/Android.mk b/lib/Renderscript/Android.mk
index 3280909..251b32c 100644
--- a/lib/Renderscript/Android.mk
+++ b/lib/Renderscript/Android.mk
@@ -32,6 +32,7 @@
RSMetadata.cpp \
RSScript.cpp \
RSInvokeHelperPass.cpp \
+ RSIsThreadablePass.cpp \
RSScreenFunctionsPass.cpp \
RSStubsWhiteList.cpp \
RSScriptGroupFusion.cpp
diff --git a/lib/Renderscript/RSEmbedInfo.cpp b/lib/Renderscript/RSEmbedInfo.cpp
index 0d7f360..0ae97a2 100644
--- a/lib/Renderscript/RSEmbedInfo.cpp
+++ b/lib/Renderscript/RSEmbedInfo.cpp
@@ -83,6 +83,7 @@
const uint32_t *objectSlotList = me.getObjectSlotList();
const char **pragmaKeyList = me.getPragmaKeyList();
const char **pragmaValueList = me.getPragmaValueList();
+ bool isThreadable = me.isThreadable();
size_t i;
// We use a simple text format here that the compatibility library can
@@ -118,6 +119,7 @@
s << pragmaKeyList[i] << " - "
<< pragmaValueList[i] << "\n";
}
+ s << "isThreadable: " << ((isThreadable) ? "yes" : "no") << "\n";
s.flush();
return str;
diff --git a/lib/Renderscript/RSIsThreadablePass.cpp b/lib/Renderscript/RSIsThreadablePass.cpp
new file mode 100644
index 0000000..33de8fc
--- /dev/null
+++ b/lib/Renderscript/RSIsThreadablePass.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2015, 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 "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Support/Log.h"
+
+#include <cstdlib>
+
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Function.h>
+#include <llvm/Pass.h>
+
+namespace { // anonymous namespace
+
+// Create a Module pass that screens all the global functions in the module and
+// check if any non-threadable function is callable. If so, we mark the
+// Module as non-threadable by adding a metadata flag '#rs_is_threadable'
+
+class RSIsThreadablePass : public llvm::ModulePass {
+private:
+ static char ID;
+
+ std::vector<std::string> nonThreadableFns = {
+ "_Z22rsgBindProgramFragment19rs_program_fragment",
+ "_Z19rsgBindProgramStore16rs_program_store",
+ "_Z20rsgBindProgramVertex17rs_program_vertex",
+ "_Z20rsgBindProgramRaster17rs_program_raster",
+ "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler",
+ "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation",
+ "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation",
+ "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation",
+ "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4",
+ "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4",
+ "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4",
+ "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4",
+ "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff",
+ "_Z11rsgGetWidthv",
+ "_Z12rsgGetHeightv",
+ "_Z11rsgDrawRectfffff",
+ "_Z11rsgDrawQuadffffffffffff",
+ "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff",
+ "_Z24rsgDrawSpriteScreenspacefffff",
+ "_Z11rsgDrawMesh7rs_mesh",
+ "_Z11rsgDrawMesh7rs_meshj",
+ "_Z11rsgDrawMesh7rs_meshjjj",
+ "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_",
+ "_Z11rsgDrawPath7rs_path",
+ "_Z13rsgClearColorffff",
+ "_Z13rsgClearDepthf",
+ "_Z11rsgDrawTextPKcii",
+ "_Z11rsgDrawText13rs_allocationii",
+ "_Z14rsgMeasureTextPKcPiS1_S1_S1_",
+ "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_",
+ "_Z11rsgBindFont7rs_font",
+ "_Z12rsgFontColorffff",
+ "_Z18rsgBindColorTarget13rs_allocationj",
+ "_Z18rsgBindDepthTarget13rs_allocation",
+ "_Z19rsgClearColorTargetj",
+ "_Z19rsgClearDepthTargetv",
+ "_Z24rsgClearAllRenderTargetsv",
+ "_Z7rsGetDtv",
+ "_Z5colorffff",
+ "_Z9rsgFinishv",
+ };
+
+ bool isPresent(std::vector<std::string> &list, std::string name) {
+ auto lower = std::lower_bound(list.begin(),
+ list.end(),
+ name);
+
+ if (lower != list.end() && name.compare(*lower) == 0)
+ return true;
+ return false;
+ }
+
+public:
+ RSIsThreadablePass()
+ : ModulePass (ID) {
+ std::sort(nonThreadableFns.begin(), nonThreadableFns.end());
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+
+ bool runOnModule(llvm::Module &M) override {
+ bool threadable = true;
+
+ auto &FunctionList(M.getFunctionList());
+ for (auto &F: FunctionList) {
+ if (isPresent(nonThreadableFns, F.getName().str())) {
+ threadable = false;
+ break;
+ }
+ }
+
+ llvm::LLVMContext &context = M.getContext();
+ llvm::MDString *val =
+ llvm::MDString::get(context, (threadable) ? "yes" : "no");
+ llvm::NamedMDNode *node =
+ M.getOrInsertNamedMetadata("#rs_is_threadable");
+ node->addOperand(llvm::MDNode::get(context, val));
+
+ return false;
+ }
+
+};
+
+}
+
+char RSIsThreadablePass::ID = 0;
+
+namespace bcc {
+
+llvm::ModulePass *
+createRSIsThreadablePass () {
+ return new RSIsThreadablePass();
+}
+
+}