Refactor attribute stripping for libbcc and llvm-rs-as.

There is an existing StripUnknownAttributes pass we use to remove
attributes unknown to old versions of LLVM before writing out bitcode.
This is needed to avoid errors when writing or reading the bitcode.

This change does three things:
- Refactors code so that we can strip unknown attributes without
  depending on the pass infrastructure, and so that we have a library
  to strip unknown attributes.  This is needed so that we can use this
  functionality in places where we're not using the pass manager and
  so that we can use it outside of slang (specifically, in libbcc).
- Strips unknown attributes in llvm-rs-as, in order to satisfy
  frameworks/compile/libbcc/tests/run-lit-tests.sh
  (test_reduce_general_metadata.ll).  See details below.
- Updates some stale comments.

Why do we need to strip unknown attributes in llvm-rs-as, even if the
input .ll does not contain those attributes?  Because the LLVM parser
calls llvm::UpgradeCallsToIntrinsic() to canonicalize the attributes
of intrinsic functions.  For example, test_reduce_general_metadata.ll
contains a call to @llvm.memcpy.p0i8.p0i8.i64, which gets
canonicalized to have the argmemonly attribute.

Remember that we're writing an old fixed version of bitcode, older
than the "native" LLVM IR we're using, so there may be attributes in
that IR that are not representible in that old fixed version of
bitcode.  Furthermore, argmemonly is one of a set of attributes that
seem to be designed as "transient" -- they can appear in the IR
(possibly only on intrinsics, or as the result of some analysis?) but
can never appear in bitcode.

Bug: 37720701

Test: aosp_x86_64-eng FORCE_BUILD_LLVM_DISABLE_NDEBUG=true
      1) slang/tests
      2) slang/lit-tests
      3) RsTest (32-bit, 64-bit) -- but did not run math_fp16 (http://b/62452374)
      4) RsTest_11 -- but then got runtime error (http://b/62452065)
      5) cts -m RenderscriptTest

Change-Id: I481f9a9d9ea5a0bd164ac4eeb68dd479eba5a187
(cherry picked from commit 88cd94d5165bf8a266d3f3095946fc25bc4809af)
diff --git a/Android.bp b/Android.bp
index f0bda4f..72c5acf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -63,6 +63,7 @@
     "libLLVMBitWriter_2_9",
     "libLLVMBitWriter_2_9_func",
     "libLLVMBitWriter_3_2",
+    "libStripUnkAttr",
 ]
 
 // Exported header files
@@ -173,7 +174,6 @@
         "slang_rs_reflect_utils.cpp",
         "slang_rs_special_func.cpp",
         "slang_rs_special_kernel_param.cpp",
-        "strip_unknown_attributes.cpp",
     ],
 
     static_libs: ["libslang"] + static_libraries_needed_by_slang,
@@ -220,4 +220,5 @@
     "BitWriter_2_9",
     "BitWriter_2_9_func",
     "BitWriter_3_2",
+    "StripUnkAttr",
 ]
diff --git a/StripUnkAttr/Android.bp b/StripUnkAttr/Android.bp
new file mode 100644
index 0000000..0df9c47
--- /dev/null
+++ b/StripUnkAttr/Android.bp
@@ -0,0 +1,12 @@
+// For the host and device
+// =====================================================
+cc_library_static {
+    name: "libStripUnkAttr",
+    host_supported: true,
+    defaults: ["slang-defaults"],
+
+    srcs: [
+        "strip_unknown_attributes.cpp",
+        "strip_unknown_attributes_pass.cpp",
+    ],
+}
diff --git a/strip_unknown_attributes.cpp b/StripUnkAttr/strip_unknown_attributes.cpp
similarity index 65%
copy from strip_unknown_attributes.cpp
copy to StripUnkAttr/strip_unknown_attributes.cpp
index d41dd8f..5657e04 100644
--- a/strip_unknown_attributes.cpp
+++ b/StripUnkAttr/strip_unknown_attributes.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013, The Android Open Source Project
+ * Copyright 2017, 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.
@@ -16,13 +16,11 @@
 
 #include "strip_unknown_attributes.h"
 
+#include "llvm/IR/Function.h"
+
 namespace slang {
 
-StripUnknownAttributes::StripUnknownAttributes() : ModulePass(ID) {
-}
-
-
-bool StripUnknownAttributes::runOnFunction(llvm::Function &F) {
+bool stripUnknownAttributes(llvm::Function &F) {
   bool changed = false;
   for (llvm::Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
        I != E; ++I) {
@@ -42,23 +40,4 @@
   return changed;
 }
 
-
-bool StripUnknownAttributes::runOnModule(llvm::Module &M) {
-  bool Changed = false;
-  for (llvm::Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
-    Changed |= runOnFunction(*I);
-  }
-  return Changed;
-}
-
-
-llvm::ModulePass * createStripUnknownAttributesPass() {
-  return new StripUnknownAttributes();
-}
-
-
-char StripUnknownAttributes::ID = 0;
-static llvm::RegisterPass<StripUnknownAttributes> RPSUA(
-    "StripUnknownAttributes", "Strip Unknown Attributes Pass");
-
 }  // namespace slang
diff --git a/strip_unknown_attributes.h b/StripUnkAttr/strip_unknown_attributes.h
similarity index 65%
copy from strip_unknown_attributes.h
copy to StripUnkAttr/strip_unknown_attributes.h
index 8610cd5..c6df22a 100644
--- a/strip_unknown_attributes.h
+++ b/StripUnkAttr/strip_unknown_attributes.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013, The Android Open Source Project
+ * Copyright 2017, 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.
@@ -14,29 +14,23 @@
  * limitations under the License.
  */
 
-#include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
+namespace llvm {
+class Function;
+}
 
 namespace slang {
 
-// Remove any readnone/readonly attributes from function parameters.
+// Remove any readnone/readonly attributes from function parameters,
+// and remove any argmemonly attributes from functions.
+//
 // Jellybean's LLVM version didn't support readnone/readonly as anything
 // other than function attributes, so it will fail verification otherwise.
 // Since we never ran the verifier in Jellybean, it ends up with potential
 // crashes deeper in CodeGen.
-class StripUnknownAttributes : public llvm::ModulePass {
-public:
-  static char ID;
-
-  StripUnknownAttributes();
-
-  bool runOnFunction(llvm::Function &F);
-
-  // We have to use a ModulePass, since a FunctionPass only gets run on
-  // defined Functions (and not declared Functions).
-  virtual bool runOnModule(llvm::Module &M);
-};
-
-llvm::ModulePass * createStripUnknownAttributesPass();
+//
+// Similarly, older LLVM versions don't support argmemonly as a function
+// attribute, and so it can trigger an llvm_unreachable assertion when
+// we attempt to write out bitcode.
+bool stripUnknownAttributes(llvm::Function &F);
 
 }  // namespace slang
diff --git a/strip_unknown_attributes.cpp b/StripUnkAttr/strip_unknown_attributes_pass.cpp
similarity index 67%
rename from strip_unknown_attributes.cpp
rename to StripUnkAttr/strip_unknown_attributes_pass.cpp
index d41dd8f..31c46f5 100644
--- a/strip_unknown_attributes.cpp
+++ b/StripUnkAttr/strip_unknown_attributes_pass.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "strip_unknown_attributes_pass.h"
 #include "strip_unknown_attributes.h"
 
 namespace slang {
@@ -23,23 +24,7 @@
 
 
 bool StripUnknownAttributes::runOnFunction(llvm::Function &F) {
-  bool changed = false;
-  for (llvm::Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
-       I != E; ++I) {
-    llvm::Argument &A = *I;
-    // Remove any readnone/readonly attributes from function parameters.
-    if (A.onlyReadsMemory()) {
-      llvm::AttrBuilder B;
-      B.addAttribute(llvm::Attribute::ReadNone);
-      B.addAttribute(llvm::Attribute::ReadOnly);
-      llvm::AttributeSet ToStrip = llvm::AttributeSet::get(F.getContext(),
-          A.getArgNo() + 1, B);
-      A.removeAttr(ToStrip);
-      changed = true;
-    }
-  }
-  F.removeFnAttr(llvm::Attribute::ArgMemOnly);
-  return changed;
+  return stripUnknownAttributes(F);
 }
 
 
diff --git a/strip_unknown_attributes.h b/StripUnkAttr/strip_unknown_attributes_pass.h
similarity index 84%
rename from strip_unknown_attributes.h
rename to StripUnkAttr/strip_unknown_attributes_pass.h
index 8610cd5..95d99cd 100644
--- a/strip_unknown_attributes.h
+++ b/StripUnkAttr/strip_unknown_attributes_pass.h
@@ -19,11 +19,17 @@
 
 namespace slang {
 
-// Remove any readnone/readonly attributes from function parameters.
+// Remove any readnone/readonly attributes from function parameters,
+// and remove any argmemonly attributes from functions.
+//
 // Jellybean's LLVM version didn't support readnone/readonly as anything
 // other than function attributes, so it will fail verification otherwise.
 // Since we never ran the verifier in Jellybean, it ends up with potential
 // crashes deeper in CodeGen.
+//
+// Similarly, older LLVM versions don't support argmemonly as a function
+// attribute, and so it can trigger an llvm_unreachable assertion when
+// we attempt to write out bitcode.
 class StripUnknownAttributes : public llvm::ModulePass {
 public:
   static char ID;
diff --git a/llvm-rs-as.cpp b/llvm-rs-as.cpp
index 95f19ee..d64061e 100644
--- a/llvm-rs-as.cpp
+++ b/llvm-rs-as.cpp
@@ -32,6 +32,8 @@
 #include "slang_bitcode_gen.h"
 #include "slang_version.h"
 
+#include "StripUnkAttr/strip_unknown_attributes.h"
+
 #include <memory>
 using namespace llvm;
 
@@ -60,6 +62,10 @@
 DisableVerify("disable-verify", cl::Hidden,
               cl::desc("Do not run verifier on input LLVM (dangerous!)"));
 
+static void stripUnknownAttributes(llvm::Module *M) {
+  for (llvm::Function &F : *M)
+    slang::stripUnknownAttributes(F);
+}
 
 static void WriteOutputFile(const Module *M, uint32_t ModuleTargetAPI) {
   // Infer the output filename if needed.
@@ -140,6 +146,8 @@
     }
   }
 
+  stripUnknownAttributes(M.get());
+
   if (DumpAsm) errs() << "Here's the assembly:\n" << *M.get();
 
   if (!DisableOutput)
diff --git a/slang_backend.cpp b/slang_backend.cpp
index 73c370d..370719d 100644
--- a/slang_backend.cpp
+++ b/slang_backend.cpp
@@ -76,7 +76,7 @@
 
 #include "rs_cc_options.h"
 
-#include "strip_unknown_attributes.h"
+#include "StripUnkAttr/strip_unknown_attributes_pass.h"
 
 namespace {
 class VersionInfoPass : public llvm::ModulePass {