Create one single module for a script group
This changed the way we compile a script group. Instead of compiling
each batch into a seperate module, we now compile the whole script
group into one single module, with each batch as a function (of fused
kernels) in that module. This allows invoke to (fused) kernel
communication via globals variables.
Added commoand line options "-merge" and "-invoke". The former
accepts fused kernel names, input kernels, while the latter accepts
new invoke name, and the original invoke function.
Additional changes:
- Bail out on encountering any unexpected bits in the foreach
signature of any kernel to fuse
- Made kernel fusion handle kernels without inputs.
If a kernel only takes global allocations but no inputs, bcc
needs to use a different signature for the fused kernel.
- Included in rs info the exported variables for the fused kernel.
- Keep all metadata in merged module from the input modules. This
would help correctly handling FP precision. (b/19098612)
- Handles Z (b/19610223)
Change-Id: I5553f86b2e58325f85649078d48685a38f12d62f
diff --git a/lib/Renderscript/RSCompilerDriver.cpp b/lib/Renderscript/RSCompilerDriver.cpp
index 547700e..21beaa2 100644
--- a/lib/Renderscript/RSCompilerDriver.cpp
+++ b/lib/Renderscript/RSCompilerDriver.cpp
@@ -18,11 +18,13 @@
#include "llvm/IR/AssemblyAnnotationWriter.h"
#include <llvm/IR/Module.h>
+#include "llvm/Linker/Linker.h"
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/raw_ostream.h>
#include "bcinfo/BitcodeWrapper.h"
+#include "bcc/Assert.h"
#include "bcc/BCCContext.h"
#include "bcc/Compiler.h"
#include "bcc/Config/Config.h"
@@ -38,6 +40,7 @@
#include "bcc/Support/Sha1Util.h"
#include "bcc/Support/OutputFile.h"
+#include <sstream>
#include <string>
#ifdef HAVE_ANDROID_OS
@@ -327,21 +330,86 @@
}
bool RSCompilerDriver::buildScriptGroup(
- BCCContext& Context, const char* pOutputFilepath, const char*pRuntimePath,
- const std::vector<const Source*>& sources, const std::vector<int>& slots,
- bool dumpIR) {
- llvm::Module* module = fuseKernels(Context, sources, slots);
- if (module == nullptr) {
- return false;
+ BCCContext& Context, const char* pOutputFilepath, const char* pRuntimePath,
+ bool dumpIR, const std::vector<Source*>& sources,
+ const std::list<std::list<std::pair<int, int>>>& toFuse,
+ const std::list<std::string>& fused,
+ const std::list<std::list<std::pair<int, int>>>& invokes,
+ const std::list<std::string>& invokeBatchNames) {
+ // ---------------------------------------------------------------------------
+ // Link all input modules into a single module
+ // ---------------------------------------------------------------------------
+
+ llvm::LLVMContext& context = Context.getLLVMContext();
+ llvm::Module module("Merged Script Group", context);
+
+ llvm::Linker linker(&module);
+ for (Source* source : sources) {
+ if (linker.linkInModule(&source->getModule())) {
+ ALOGE("Linking for module in source failed.");
+ return false;
+ }
}
+ // ---------------------------------------------------------------------------
+ // Create fused kernels
+ // ---------------------------------------------------------------------------
+
+ auto inputIter = toFuse.begin();
+ for (const std::string& nameOfFused : fused) {
+ auto inputKernels = *inputIter++;
+ std::vector<Source*> sourcesToFuse;
+ std::vector<int> slots;
+
+ for (auto p : inputKernels) {
+ sourcesToFuse.push_back(sources[p.first]);
+ slots.push_back(p.second);
+ }
+
+ if (!fuseKernels(Context, sourcesToFuse, slots, nameOfFused, &module)) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Rename invokes
+ // ---------------------------------------------------------------------------
+
+ auto invokeIter = invokes.begin();
+ for (const std::string& newName : invokeBatchNames) {
+ auto inputInvoke = *invokeIter++;
+ auto p = inputInvoke.front();
+ Source* source = sources[p.first];
+ int slot = p.second;
+
+ if (!renameInvoke(Context, source, slot, newName, &module)) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Compile the new module with fused kernels
+ // ---------------------------------------------------------------------------
+
const std::unique_ptr<Source> source(
- Source::CreateFromModule(Context, pOutputFilepath, *module));
+ Source::CreateFromModule(Context, pOutputFilepath, module, true));
RSScript script(*source);
uint8_t bitcode_sha1[SHA1_DIGEST_LENGTH];
const char* compileCommandLineToEmbed = "";
- const char* buildChecksum = nullptr;
+ const char* buildChecksum = "DummyChecksumForScriptGroup";
+ const char* buildFingerprintToEmbed = "";
+
+ RSInfo* info = RSInfo::ExtractFromSource(*source, bitcode_sha1,
+ compileCommandLineToEmbed, buildFingerprintToEmbed);
+ if (info == nullptr) {
+ return false;
+ }
+ script.setInfo(info);
+
+ // Embed the info string directly in the ELF
+ script.setEmbedInfo(true);
+ script.setOptimizationLevel(RSScript::kOptLvl3);
llvm::SmallString<80> output_path(pOutputFilepath);
llvm::sys::path::replace_extension(output_path, ".o");