Screen bitcode for non-RS functions before linking with runtime lib

Bug: 19425238
Bug: 20894432

Perform the screening of non-RenderScript functions in the script before
linking against the runtime lib.  Previously, this used to be done after
linking with the runtime lib, LTO passes and just before code
generation.

This allows vendors to link against a different runtime library that may
not have all the functions as the CPU reference driver and add new
builtins specific to their driver.

Moreover, symbols introduced by LLVM optimizations no longer need any
special handling.

Change-Id: I5628aa15547a9d56ef7e6550fcb45e8ffa821ade
diff --git a/include/bcc/Compiler.h b/include/bcc/Compiler.h
index 468a808..75cde37 100644
--- a/include/bcc/Compiler.h
+++ b/include/bcc/Compiler.h
@@ -79,7 +79,6 @@
   bool mEnableOpt;
 
   enum ErrorCode runPasses(Script &pScript, llvm::raw_pwrite_stream &pResult);
-  enum ErrorCode screenGlobals(Script &pScript);
 
   bool addCustomPasses(Script &pScript, llvm::legacy::PassManager &pPM);
   bool addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM);
@@ -113,6 +112,11 @@
   { mEnableOpt = pEnable; }
 
   ~Compiler();
+
+  // Compare undefined external functions in pScript against a 'whitelist' of
+  // all RenderScript functions.  Returns error if any external function that is
+  // not in this whitelist is callable from the script.
+  enum ErrorCode screenGlobalFunctions(Script &pScript);
 };
 
 } // end namespace bcc
diff --git a/lib/Core/Compiler.cpp b/lib/Core/Compiler.cpp
index 1b8c350..c314b6c 100644
--- a/lib/Core/Compiler.cpp
+++ b/lib/Core/Compiler.cpp
@@ -415,11 +415,32 @@
   if (arch.getArch() == llvm::Triple::x86_64)
     pPM.add(createRSX86_64CallConvPass());
 
-  // Add pass to check for illegal function calls.
-  pPM.add(createRSScreenFunctionsPass());
-
   // Add pass to mark script as threadable.
   pPM.add(createRSIsThreadablePass());
 
   return true;
 }
+
+enum Compiler::ErrorCode Compiler::screenGlobalFunctions(Script &pScript) {
+  llvm::Module &module = pScript.getSource().getModule();
+
+  // Materialize the bitcode module in case this is a lazy-load module.  Do not
+  // clear the materializer by calling materializeAllPermanently since the
+  // runtime library has not been merged into the module yet.
+  if (module.getMaterializer() != nullptr) {
+    std::error_code ec = module.materializeAll();
+    if (ec) {
+      ALOGE("Failed to materialize module `%s' when screening globals! (%s)",
+            module.getModuleIdentifier().c_str(), ec.message().c_str());
+      return kErrMaterialization;
+    }
+  }
+
+  // Add pass to check for illegal function calls.
+  llvm::legacy::PassManager pPM;
+  pPM.add(createRSScreenFunctionsPass());
+  pPM.run(module);
+
+  return kSuccess;
+
+}
diff --git a/lib/Renderscript/RSCompilerDriver.cpp b/lib/Renderscript/RSCompilerDriver.cpp
index 942a1f3..21874f2 100644
--- a/lib/Renderscript/RSCompilerDriver.cpp
+++ b/lib/Renderscript/RSCompilerDriver.cpp
@@ -119,6 +119,12 @@
     pScript.getSource().addBuildChecksumMetadata(pBuildChecksum);
   }
 
+  // Verify that the only external functions in pScript are Renderscript
+  // functions.  Fail if verification returns an error.
+  if (mCompiler.screenGlobalFunctions(pScript) != Compiler::kSuccess) {
+    return Compiler::kErrInvalidSource;
+  }
+
   //===--------------------------------------------------------------------===//
   // Link RS script with Renderscript runtime.
   //===--------------------------------------------------------------------===//