MIPS64: Improve method invocation.

Improvements include:
- support for all kinds of method loads and static/direct calls
- 32-bit and 64-bit literals for the above and future work
- shorter instruction sequences for recursive static/direct calls
Also:
- include the MIPS64 dinsu instruction (missed earlier) and minor
  clean-up in the disassembler
- properly prefix constant names with 'k' in relative patcher tests

Test: test-art-host-gtest
Test: booted MIPS64 (with 2nd arch MIPS32R6) in QEMU
Test: "make -j1 ART_TEST_DEFAULT_COMPILER=false ART_TEST_OPTIMIZING=true
       ART_TEST_INTERPRETER=false ART_TEST_JIT=false
       ART_TEST_PIC_TEST=true test-art-target-run-test64"

Change-Id: I19876fa5316b68531af7dfddfce90d2068433116
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 238cb9d..08a55ed 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -17,9 +17,11 @@
 #ifndef ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
 #define ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
 
+#include <deque>
 #include <utility>
 #include <vector>
 
+#include "base/arena_containers.h"
 #include "base/enums.h"
 #include "base/macros.h"
 #include "constants_mips64.h"
@@ -312,6 +314,49 @@
   DISALLOW_COPY_AND_ASSIGN(Mips64Label);
 };
 
+// Assembler literal is a value embedded in code, retrieved using a PC-relative load.
+class Literal {
+ public:
+  static constexpr size_t kMaxSize = 8;
+
+  Literal(uint32_t size, const uint8_t* data)
+      : label_(), size_(size) {
+    DCHECK_LE(size, Literal::kMaxSize);
+    memcpy(data_, data, size);
+  }
+
+  template <typename T>
+  T GetValue() const {
+    DCHECK_EQ(size_, sizeof(T));
+    T value;
+    memcpy(&value, data_, sizeof(T));
+    return value;
+  }
+
+  uint32_t GetSize() const {
+    return size_;
+  }
+
+  const uint8_t* GetData() const {
+    return data_;
+  }
+
+  Mips64Label* GetLabel() {
+    return &label_;
+  }
+
+  const Mips64Label* GetLabel() const {
+    return &label_;
+  }
+
+ private:
+  Mips64Label label_;
+  const uint32_t size_;
+  uint8_t data_[kMaxSize];
+
+  DISALLOW_COPY_AND_ASSIGN(Literal);
+};
+
 // Slowpath entered when Thread::Current()->_exception is non-null.
 class Mips64ExceptionSlowPath {
  public:
@@ -341,6 +386,8 @@
       : Assembler(arena),
         overwriting_(false),
         overwrite_location_(0),
+        literals_(arena->Adapter(kArenaAllocAssembler)),
+        long_literals_(arena->Adapter(kArenaAllocAssembler)),
         last_position_adjustment_(0),
         last_old_position_(0),
         last_branch_id_(0) {
@@ -386,18 +433,18 @@
   void Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt);
 
   void Bitswap(GpuRegister rd, GpuRegister rt);
-  void Dbitswap(GpuRegister rd, GpuRegister rt);
+  void Dbitswap(GpuRegister rd, GpuRegister rt);  // MIPS64
   void Seb(GpuRegister rd, GpuRegister rt);
   void Seh(GpuRegister rd, GpuRegister rt);
-  void Dsbh(GpuRegister rd, GpuRegister rt);
-  void Dshd(GpuRegister rd, GpuRegister rt);
+  void Dsbh(GpuRegister rd, GpuRegister rt);  // MIPS64
+  void Dshd(GpuRegister rd, GpuRegister rt);  // MIPS64
   void Dext(GpuRegister rs, GpuRegister rt, int pos, int size);  // MIPS64
   void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size);  // MIPS64
   void Wsbh(GpuRegister rd, GpuRegister rt);
   void Sc(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
-  void Scd(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
+  void Scd(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);  // MIPS64
   void Ll(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
-  void Lld(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
+  void Lld(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);  // MIPS64
 
   void Sll(GpuRegister rd, GpuRegister rt, int shamt);
   void Srl(GpuRegister rd, GpuRegister rt, int shamt);
@@ -409,7 +456,7 @@
   void Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs);
   void Dsll(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsrl(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
-  void Drotr(GpuRegister rd, GpuRegister rt, int shamt);
+  void Drotr(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsra(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsll32(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
   void Dsrl32(GpuRegister rd, GpuRegister rt, int shamt);  // MIPS64
@@ -427,6 +474,9 @@
   void Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
   void Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
   void Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16);  // MIPS64
+  void Lwpc(GpuRegister rs, uint32_t imm19);
+  void Lwupc(GpuRegister rs, uint32_t imm19);  // MIPS64
+  void Ldpc(GpuRegister rs, uint32_t imm18);  // MIPS64
   void Lui(GpuRegister rt, uint16_t imm16);
   void Dahi(GpuRegister rs, uint16_t imm16);  // MIPS64
   void Dati(GpuRegister rs, uint16_t imm16);  // MIPS64
@@ -445,8 +495,8 @@
   void Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt);
   void Clz(GpuRegister rd, GpuRegister rs);
   void Clo(GpuRegister rd, GpuRegister rs);
-  void Dclz(GpuRegister rd, GpuRegister rs);
-  void Dclo(GpuRegister rd, GpuRegister rs);
+  void Dclz(GpuRegister rd, GpuRegister rs);  // MIPS64
+  void Dclo(GpuRegister rd, GpuRegister rs);  // MIPS64
 
   void Jalr(GpuRegister rd, GpuRegister rs);
   void Jalr(GpuRegister rs);
@@ -454,6 +504,7 @@
   void Auipc(GpuRegister rs, uint16_t imm16);
   void Addiupc(GpuRegister rs, uint32_t imm19);
   void Bc(uint32_t imm26);
+  void Balc(uint32_t imm26);
   void Jic(GpuRegister rt, uint16_t imm16);
   void Jialc(GpuRegister rt, uint16_t imm16);
   void Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16);
@@ -605,8 +656,26 @@
     UNREACHABLE();
   }
 
+  // Create a new literal with a given value.
+  // NOTE: Force the template parameter to be explicitly specified.
+  template <typename T>
+  Literal* NewLiteral(typename Identity<T>::type value) {
+    static_assert(std::is_integral<T>::value, "T must be an integral type.");
+    return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
+  }
+
+  // Load label address using PC-relative loads. To be used with data labels in the literal /
+  // jump table area only and not with regular code labels.
+  void LoadLabelAddress(GpuRegister dest_reg, Mips64Label* label);
+
+  // Create a new literal with the given data.
+  Literal* NewLiteral(size_t size, const uint8_t* data);
+
+  // Load literal using PC-relative loads.
+  void LoadLiteral(GpuRegister dest_reg, LoadOperandType load_type, Literal* literal);
+
   void Bc(Mips64Label* label);
-  void Jialc(Mips64Label* label, GpuRegister indirect_reg);
+  void Balc(Mips64Label* label);
   void Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
   void Bltzc(GpuRegister rt, Mips64Label* label);
   void Bgtzc(GpuRegister rt, Mips64Label* label);
@@ -756,12 +825,15 @@
 
   // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS64,
   // must be used instead of Mips64Label::GetPosition()).
-  uint32_t GetLabelLocation(Mips64Label* label) const;
+  uint32_t GetLabelLocation(const Mips64Label* label) const;
 
   // Get the final position of a label after local fixup based on the old position
   // recorded before FinalizeCode().
   uint32_t GetAdjustedPosition(uint32_t old_position);
 
+  // Note that PC-relative literal loads are handled as pseudo branches because they need very
+  // similar relocation and may similarly expand in size to accomodate for larger offsets relative
+  // to PC.
   enum BranchCondition {
     kCondLT,
     kCondGE,
@@ -791,10 +863,22 @@
       kUncondBranch,
       kCondBranch,
       kCall,
+      // Near label.
+      kLabel,
+      // Near literals.
+      kLiteral,
+      kLiteralUnsigned,
+      kLiteralLong,
       // Long branches.
       kLongUncondBranch,
       kLongCondBranch,
       kLongCall,
+      // Far label.
+      kFarLabel,
+      // Far literals.
+      kFarLiteral,
+      kFarLiteralUnsigned,
+      kFarLiteralLong,
     };
 
     // Bit sizes of offsets defined as enums to minimize chance of typos.
@@ -830,16 +914,16 @@
     };
     static const BranchInfo branch_info_[/* Type */];
 
-    // Unconditional branch.
-    Branch(uint32_t location, uint32_t target);
+    // Unconditional branch or call.
+    Branch(uint32_t location, uint32_t target, bool is_call);
     // Conditional branch.
     Branch(uint32_t location,
            uint32_t target,
            BranchCondition condition,
            GpuRegister lhs_reg,
-           GpuRegister rhs_reg = ZERO);
-    // Call (branch and link) that stores the target address in a given register (i.e. T9).
-    Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg);
+           GpuRegister rhs_reg);
+    // Label address (in literal area) or literal.
+    Branch(uint32_t location, GpuRegister dest_reg, Type label_or_literal_type);
 
     // Some conditional branches with lhs = rhs are effectively NOPs, while some
     // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
@@ -923,7 +1007,7 @@
 
    private:
     // Completes branch construction by determining and recording its type.
-    void InitializeType(bool is_call);
+    void InitializeType(Type initial_type);
     // Helper for the above.
     void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
 
@@ -932,7 +1016,7 @@
     uint32_t target_;            // Offset into assembler buffer in bytes.
 
     GpuRegister lhs_reg_;        // Left-hand side register in conditional branches or
-                                 // indirect call register.
+                                 // destination register in literals.
     GpuRegister rhs_reg_;        // Right-hand side register in conditional branches.
     BranchCondition condition_;  // Condition for conditional branches.
 
@@ -957,12 +1041,13 @@
              BranchCondition condition,
              GpuRegister lhs,
              GpuRegister rhs = ZERO);
-  void Call(Mips64Label* label, GpuRegister indirect_reg);
+  void Call(Mips64Label* label);
   void FinalizeLabeledBranch(Mips64Label* label);
 
   Branch* GetBranch(uint32_t branch_id);
   const Branch* GetBranch(uint32_t branch_id) const;
 
+  void EmitLiterals();
   void PromoteBranches();
   void EmitBranch(Branch* branch);
   void EmitBranches();
@@ -981,6 +1066,11 @@
   // The current overwrite location.
   uint32_t overwrite_location_;
 
+  // Use std::deque<> for literal labels to allow insertions at the end
+  // without invalidating pointers and references to existing elements.
+  ArenaDeque<Literal> literals_;
+  ArenaDeque<Literal> long_literals_;  // 64-bit literals separated for alignment reasons.
+
   // Data for AdjustedPosition(), see the description there.
   uint32_t last_position_adjustment_;
   uint32_t last_old_position_;