Support hardware divide instruction

Bug: 11299025

Uses sdiv for division and a combo of sdiv, mul and sub for modulus.
Only does this on processors that are capable of the sdiv instruction, as determined
by the build system.

Also provides a command line arg --instruction-set-features= to allow cross compilation.
Makefile adds the --instruction-set-features= arg to build-time dex2oat runs and defaults
it to something obtained from the target architecture.

Provides a GetInstructionSetFeatures() function on CompilerDriver that can be
queried for various features.  The only feature supported right now is hasDivideInstruction().

Also adds a few more instructions to the ARM disassembler

b/11535253 is an addition to this CL to be done later.

Change-Id: Ia8aaf801fd94bc71e476902749cf20f74eba9f68
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 3d275e6..bef4381 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -187,6 +187,7 @@
 	arch/arm/jni_entrypoints_arm.S \
 	arch/arm/portable_entrypoints_arm.S \
 	arch/arm/quick_entrypoints_arm.S \
+	arch/arm/arm_sdiv.S \
 	arch/arm/thread_arm.cc
 else # TARGET_ARCH != arm
 ifeq ($(TARGET_ARCH),x86)
diff --git a/runtime/arch/arm/arm_sdiv.S b/runtime/arch/arm/arm_sdiv.S
new file mode 100644
index 0000000..925e428
--- /dev/null
+++ b/runtime/arch/arm/arm_sdiv.S
@@ -0,0 +1,24 @@
+// This function is used to check for the CPU's support for the sdiv
+// instruction at runtime.  It will either return the value 1 or
+// will cause an invalid instruction trap (SIGILL signal).  The
+// caller must arrange for the signal handler to set the r0
+// register to 0 and move the pc forward by 4 bytes (to skip
+// the invalid instruction).
+
+
+#include "asm_support_arm.S"
+
+.section .text
+ENTRY CheckForARMSDIVInstruction
+  mov r1,#1
+  // depending on the architecture, the assembler will not allow an
+  // sdiv instruction, so we will have to output the bytes directly.
+
+  // sdiv r0,r1,r1 is two words: 0xfb91 0xf1f0.  We need little endian.
+  .byte 0x91,0xfb,0xf1,0xf0
+
+  // if the divide worked, r0 will have the value #1 (result of sdiv).
+  // It will have 0 otherwise (set by the signal handler)
+  // the value is just returned from this function.
+  bx lr
+  END CheckForARMSDIVInstruction
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index d00c64a..00a530a 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -130,6 +130,10 @@
 #define LIKELY(x)       __builtin_expect((x), true)
 #define UNLIKELY(x)     __builtin_expect((x), false)
 
+// Stringify the argument.
+#define QUOTE(x) #x
+#define STRINGIFY(x) QUOTE(x)
+
 #ifndef NDEBUG
 #define ALWAYS_INLINE
 #else
diff --git a/runtime/common_test.h b/runtime/common_test.h
index 673a03b..79fa680 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -22,6 +22,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <fstream>
 
 #include "../../external/icu4c/common/unicode/uvernum.h"
 #include "base/macros.h"
@@ -152,6 +153,113 @@
   UniquePtr<File> file_;
 };
 
+#if defined(__arm__)
+
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+
+
+// A signal handler called when have an illegal instruction.  We record the fact in
+// a global boolean and then increment the PC in the signal context to return to
+// the next instruction.  We know the instruction is an sdiv (4 bytes long).
+static void baddivideinst(int signo, siginfo *si, void *data) {
+  (void)signo;
+  (void)si;
+  struct ucontext *uc = (struct ucontext *)data;
+  struct sigcontext *sc = &uc->uc_mcontext;
+  sc->arm_r0 = 0;     // set R0 to #0 to signal error
+  sc->arm_pc += 4;    // skip offending instruction
+}
+
+// This is in arch/arm/arm_sdiv.S.  It does the following:
+// mov r1,#1
+// sdiv r0,r1,r1
+// bx lr
+//
+// the result will be the value 1 if sdiv is supported.  If it is not supported
+// a SIGILL signal will be raised and the signal handler (baddivideinst) called.
+// The signal handler sets r0 to #0 and then increments pc beyond the failed instruction.
+// Thus if the instruction is not supported, the result of this function will be #0
+
+extern "C" bool CheckForARMSDIVInstruction();
+
+static InstructionSetFeatures GuessInstructionFeatures() {
+  InstructionSetFeatures f;
+
+  // Uncomment this for processing of /proc/cpuinfo.
+  if (false) {
+    // 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.
+    std::ifstream in("/proc/cpuinfo");
+    if (in) {
+      while (!in.eof()) {
+        std::string line;
+        std::getline(in, line);
+        if (!in.eof()) {
+          if (line.find("Features") != std::string::npos) {
+            if (line.find("idivt") != std::string::npos) {
+              f.SetHasDivideInstruction(true);
+            }
+          }
+        }
+        in.close();
+      }
+    } else {
+      LOG(INFO) << "Failed to open /proc/cpuinfo";
+    }
+  }
+
+  // See if have a sdiv instruction.  Register a signal handler and try to execute
+  // an sdiv instruction.  If we get a SIGILL then it's not supported.  We can't use
+  // the /proc/cpuinfo method for this because Krait devices don't always put the idivt
+  // feature in the list.
+  struct sigaction sa, osa;
+  sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+  sa.sa_sigaction = baddivideinst;
+  sigaction(SIGILL, &sa, &osa);
+
+  if (CheckForARMSDIVInstruction()) {
+    f.SetHasDivideInstruction(true);
+  }
+
+  // Restore the signal handler.
+  sigaction(SIGILL, &osa, NULL);
+
+  // Other feature guesses in here.
+  return f;
+}
+
+#endif
+
+// Given a set of instruction features from the build, parse it.  The
+// input 'str' is a comma separated list of feature names.  Parse it and
+// return the InstructionSetFeatures object.
+static InstructionSetFeatures ParseFeatureList(std::string str) {
+  LOG(INFO) << "Parsing features " << str;
+  InstructionSetFeatures result;
+  typedef std::vector<std::string> FeatureList;
+  FeatureList features;
+  Split(str, ',', features);
+  for (FeatureList::iterator i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "default") {
+      // Nothing to do.
+    } else if (feature == "div") {
+      // Supports divide instruction.
+      result.SetHasDivideInstruction(true);
+    } else if (feature == "nodiv") {
+      // Turn off support for divide instruction.
+      result.SetHasDivideInstruction(false);
+    } else {
+      LOG(FATAL) << "Unknown instruction set feature: '" << feature << "'";
+    }
+  }
+  // Others...
+  return result;
+}
+
 class CommonTest : public testing::Test {
  public:
   static void MakeExecutable(const mirror::ByteArray* code_array) {
@@ -314,8 +422,22 @@
       class_linker_ = runtime_->GetClassLinker();
 
       InstructionSet instruction_set = kNone;
+
+      // take the default set of instruction features from the build if present
+      InstructionSetFeatures instruction_set_features =
+#ifdef ART_DEFAULT_INSTRUCTION_SET_FEATURES
+        ParseFeatureList(STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES));
+#else
+        ParseFeatureList("default");
+#endif
+
 #if defined(__arm__)
       instruction_set = kThumb2;
+      InstructionSetFeatures runtime_features = GuessInstructionFeatures();
+
+      // for ARM, do a runtime check to make sure that the features we are passed from
+      // the build match the features we actually determine at runtime.
+      ASSERT_EQ(instruction_set_features, runtime_features);
 #elif defined(__mips__)
       instruction_set = kMips;
 #elif defined(__i386__)
@@ -338,6 +460,7 @@
       }
       class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
       compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set,
+                                                instruction_set_features,
                                                 true, new CompilerDriver::DescriptorSet,
                                                 2, true));
     }
@@ -568,7 +691,6 @@
 #else
 #define TEST_DISABLED_FOR_PORTABLE()
 #endif
-
 }  // namespace art
 
 namespace std {
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
index 2217f7f..aee7447 100644
--- a/runtime/instruction_set.h
+++ b/runtime/instruction_set.h
@@ -18,6 +18,9 @@
 #define ART_RUNTIME_INSTRUCTION_SET_H_
 
 #include <iosfwd>
+#include <string>
+
+#include "base/macros.h"
 
 namespace art {
 
@@ -29,6 +32,53 @@
   kMips
 };
 
+enum InstructionFeatures {
+  kHwDiv = 1                  // Supports hardware divide.
+};
+
+// This is a bitmask of supported features per architecture.
+class PACKED(4) InstructionSetFeatures {
+ public:
+  InstructionSetFeatures() : mask_(0) {}
+  explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
+
+  bool HasDivideInstruction() const {
+      return (mask_ & kHwDiv) != 0;
+  }
+
+  void SetHasDivideInstruction(bool v) {
+    mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
+  }
+
+  std::string GetFeatureString() const {
+    std::string result;
+    if ((mask_ & kHwDiv) != 0) {
+      result += "div";
+    }
+    if (result.size() == 0) {
+      result = "none";
+    }
+    return result;
+  }
+
+  uint32_t get_mask() const {
+    return mask_;
+  }
+
+  // Other features in here.
+
+  bool operator==(const InstructionSetFeatures &peer) const {
+    return mask_ == peer.mask_;
+  }
+
+  bool operator!=(const InstructionSetFeatures &peer) const {
+    return mask_ != peer.mask_;
+  }
+
+ private:
+  uint32_t mask_;
+};
+
 std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
 
 }  // namespace art
diff --git a/runtime/oat.cc b/runtime/oat.cc
index defda6b..9489795 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,13 +22,14 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '0', '9', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '1', '0', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
 }
 
 OatHeader::OatHeader(InstructionSet instruction_set,
+                     const InstructionSetFeatures& instruction_set_features,
                      const std::vector<const DexFile*>* dex_files,
                      uint32_t image_file_location_oat_checksum,
                      uint32_t image_file_location_oat_data_begin,
@@ -42,6 +43,9 @@
   instruction_set_ = instruction_set;
   UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
 
+  instruction_set_features_ = instruction_set_features;
+  UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_));
+
   dex_file_count_ = dex_files->size();
   UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
 
@@ -99,6 +103,11 @@
   return instruction_set_;
 }
 
+const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const {
+  CHECK(IsValid());
+  return instruction_set_features_;
+}
+
 uint32_t OatHeader::GetExecutableOffset() const {
   DCHECK(IsValid());
   DCHECK_ALIGNED(executable_offset_, kPageSize);
diff --git a/runtime/oat.h b/runtime/oat.h
index c864c2c..de840b5 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,6 +32,7 @@
 
   OatHeader();
   OatHeader(InstructionSet instruction_set,
+            const InstructionSetFeatures& instruction_set_features,
             const std::vector<const DexFile*>* dex_files,
             uint32_t image_file_location_oat_checksum,
             uint32_t image_file_location_oat_data_begin,
@@ -80,6 +81,7 @@
   void SetQuickToInterpreterBridgeOffset(uint32_t offset);
 
   InstructionSet GetInstructionSet() const;
+  const InstructionSetFeatures& GetInstructionSetFeatures() const;
   uint32_t GetImageFileLocationOatChecksum() const;
   uint32_t GetImageFileLocationOatDataBegin() const;
   uint32_t GetImageFileLocationSize() const;
@@ -92,6 +94,7 @@
   uint32_t adler32_checksum_;
 
   InstructionSet instruction_set_;
+  InstructionSetFeatures instruction_set_features_;
   uint32_t dex_file_count_;
   uint32_t executable_offset_;
   uint32_t interpreter_to_interpreter_bridge_offset_;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 9796b99..e039581 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -889,6 +889,35 @@
   }
 }
 
+std::string Trim(std::string s) {
+  std::string result;
+  unsigned int start_index = 0;
+  unsigned int end_index = s.size() - 1;
+
+  // Skip initial whitespace.
+  while (start_index < s.size()) {
+    if (!isspace(s[start_index])) {
+      break;
+    }
+    start_index++;
+  }
+
+  // Skip terminating whitespace.
+  while (end_index >= start_index) {
+    if (!isspace(s[end_index])) {
+      break;
+    }
+    end_index--;
+  }
+
+  // All spaces, no beef.
+  if (end_index < start_index) {
+    return "";
+  }
+  // Start_index is the first non-space, end_index is the last one.
+  return s.substr(start_index, end_index - start_index + 1);
+}
+
 template <typename StringT>
 std::string Join(std::vector<StringT>& strings, char separator) {
   if (strings.empty()) {
diff --git a/runtime/utils.h b/runtime/utils.h
index 51035b6..6850e8b 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -252,7 +252,7 @@
 // Get the appropriate unit for a nanosecond duration.
 TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration);
 
-// Get the divisor to convert from a nanoseconds to a time unit
+// Get the divisor to convert from a nanoseconds to a time unit.
 uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit);
 
 // Performs JNI name mangling as described in section 11.3 "Linking Native Methods"
@@ -326,6 +326,9 @@
 // strings. Empty strings will be omitted.
 void Split(const std::string& s, char separator, std::vector<std::string>& result);
 
+// Trims whitespace off both ends of the given string.
+std::string Trim(std::string s);
+
 // Joins a vector of strings into a single string, using the given separator.
 template <typename StringT> std::string Join(std::vector<StringT>& strings, char separator);
 
@@ -354,10 +357,10 @@
 // Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86.
 void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix = "", bool include_count = true);
 
-// Find $ANDROID_ROOT, /system, or abort
+// Find $ANDROID_ROOT, /system, or abort.
 const char* GetAndroidRoot();
 
-// Find $ANDROID_DATA, /data, or abort
+// Find $ANDROID_DATA, /data, or abort.
 const char* GetAndroidData();
 
 // Returns the dalvik-cache location, or dies trying.