MIPS64: Add MSA instruction set feature option

MSA (MIPS SIMD Architecture) is SIMD extension which will be used
for ART Vectorizer implementation on MIPS64.

Test: mma test-art-target in QEMU
Test: mma test-art-host-gtest

Change-Id: Ib8cdbac78f7d91c2929bfe5cc29c8795fee26358
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.cc b/runtime/arch/mips64/instruction_set_features_mips64.cc
index 5757906..08d0bac 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64.cc
+++ b/runtime/arch/mips64/instruction_set_features_mips64.cc
@@ -30,22 +30,52 @@
 
 Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromVariant(
     const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
+  bool msa = true;
   if (variant != "default" && variant != "mips64r6") {
     LOG(WARNING) << "Unexpected CPU variant for Mips64 using defaults: " << variant;
   }
-  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
+  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(msa));
 }
 
-Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromBitmap(uint32_t bitmap ATTRIBUTE_UNUSED) {
-  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
+Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool msa = (bitmap & kMsaBitfield) != 0;
+  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(msa));
 }
 
 Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromCppDefines() {
-  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
+#if defined(_MIPS_ARCH_MIPS64R6)
+  const bool msa = true;
+#else
+  const bool msa = false;
+#endif
+  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(msa));
 }
 
 Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromCpuInfo() {
-  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures());
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool msa = false;
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("ASEs") != std::string::npos) {
+          LOG(INFO) << "found Application Specific Extensions";
+          if (line.find("msa") != std::string::npos) {
+            msa = true;
+          }
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return Mips64FeaturesUniquePtr(new Mips64InstructionSetFeatures(msa));
 }
 
 Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromHwcap() {
@@ -62,28 +92,40 @@
   if (kMips64 != other->GetInstructionSet()) {
     return false;
   }
-  return true;
+  const Mips64InstructionSetFeatures* other_as_mips64 = other->AsMips64InstructionSetFeatures();
+  return msa_ == other_as_mips64->msa_;
 }
 
 uint32_t Mips64InstructionSetFeatures::AsBitmap() const {
-  return 0;
+  return (msa_ ? kMsaBitfield : 0);
 }
 
 std::string Mips64InstructionSetFeatures::GetFeatureString() const {
-  return "default";
+  std::string result;
+  if (msa_) {
+    result += "msa";
+  } else {
+    result += "-msa";
+  }
+  return result;
 }
 
 std::unique_ptr<const InstructionSetFeatures>
 Mips64InstructionSetFeatures::AddFeaturesFromSplitString(
     const std::vector<std::string>& features, std::string* error_msg) const {
-  auto i = features.begin();
-  if (i != features.end()) {
-    // We don't have any features.
+  bool msa = msa_;
+  for (auto i = features.begin(); i != features.end(); i++) {
     std::string feature = android::base::Trim(*i);
-    *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
-    return nullptr;
+    if (feature == "msa") {
+      msa = true;
+    } else if (feature == "-msa") {
+      msa = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
   }
-  return std::unique_ptr<const InstructionSetFeatures>(new Mips64InstructionSetFeatures());
+  return std::unique_ptr<const InstructionSetFeatures>(new Mips64InstructionSetFeatures(msa));
 }
 
 }  // namespace art
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.h b/runtime/arch/mips64/instruction_set_features_mips64.h
index c80c466..d9f30c7 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64.h
+++ b/runtime/arch/mips64/instruction_set_features_mips64.h
@@ -58,6 +58,11 @@
 
   std::string GetFeatureString() const OVERRIDE;
 
+  // Does it have MSA (MIPS SIMD Architecture) support.
+  bool HasMsa() const {
+    return msa_;
+  }
+
   virtual ~Mips64InstructionSetFeatures() {}
 
  protected:
@@ -67,9 +72,16 @@
                                  std::string* error_msg) const OVERRIDE;
 
  private:
-  Mips64InstructionSetFeatures() : InstructionSetFeatures() {
+  explicit Mips64InstructionSetFeatures(bool msa) : InstructionSetFeatures(), msa_(msa) {
   }
 
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kMsaBitfield = 1,
+  };
+
+  const bool msa_;
+
   DISALLOW_COPY_AND_ASSIGN(Mips64InstructionSetFeatures);
 };
 
diff --git a/runtime/arch/mips64/instruction_set_features_mips64_test.cc b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
index 380c4e5..563200f 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64_test.cc
+++ b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
@@ -27,8 +27,8 @@
   ASSERT_TRUE(mips64_features.get() != nullptr) << error_msg;
   EXPECT_EQ(mips64_features->GetInstructionSet(), kMips64);
   EXPECT_TRUE(mips64_features->Equals(mips64_features.get()));
-  EXPECT_STREQ("default", mips64_features->GetFeatureString().c_str());
-  EXPECT_EQ(mips64_features->AsBitmap(), 0U);
+  EXPECT_STREQ("msa", mips64_features->GetFeatureString().c_str());
+  EXPECT_EQ(mips64_features->AsBitmap(), 1U);
 }
 
 }  // namespace art