ART: Add Mips o32 callee-save registers to SaveAll frame

The floating point registers f20-f31 are callee-save in the Mips
ABI. While the managed code does not touch them, they need to be
saved when throwing an exception, so that they will be correctly
restored and not smashed.

Bug: 21266656
Change-Id: Ia96d52ce7fb41bf604da1797ce4d7a703e292415
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 02c0982..390c606 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -19,7 +19,7 @@
 
 #include "asm_support.h"
 
-#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 48
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 96
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 48
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 64
 
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 89d1449..c00d6cb 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -37,36 +37,44 @@
      * Reserves FRAME_SIZE_SAVE_ALL_CALLEE_SAVE + ARG_SLOT_SIZE bytes on the stack
      */
 .macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    addiu  $sp, $sp, -48
-    .cfi_adjust_cfa_offset 48
+    addiu  $sp, $sp, -96
+    .cfi_adjust_cfa_offset 96
 
      // Ugly compile-time check, but we only have the preprocessor.
-#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 48)
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 96)
 #error "SAVE_ALL_CALLEE_SAVE_FRAME(MIPS) size not as expected."
 #endif
 
-    sw     $ra, 44($sp)
-    .cfi_rel_offset 31, 44
-    sw     $s8, 40($sp)
-    .cfi_rel_offset 30, 40
-    sw     $gp, 36($sp)
-    .cfi_rel_offset 28, 36
-    sw     $s7, 32($sp)
-    .cfi_rel_offset 23, 32
-    sw     $s6, 28($sp)
-    .cfi_rel_offset 22, 28
-    sw     $s5, 24($sp)
-    .cfi_rel_offset 21, 24
-    sw     $s4, 20($sp)
-    .cfi_rel_offset 20, 20
-    sw     $s3, 16($sp)
-    .cfi_rel_offset 19, 16
-    sw     $s2, 12($sp)
-    .cfi_rel_offset 18, 12
-    sw     $s1, 8($sp)
-    .cfi_rel_offset 17, 8
-    sw     $s0, 4($sp)
-    .cfi_rel_offset 16, 4
+    sw     $ra, 92($sp)
+    .cfi_rel_offset 31, 92
+    sw     $s8, 88($sp)
+    .cfi_rel_offset 30, 88
+    sw     $gp, 84($sp)
+    .cfi_rel_offset 28, 84
+    sw     $s7, 80($sp)
+    .cfi_rel_offset 23, 80
+    sw     $s6, 76($sp)
+    .cfi_rel_offset 22, 76
+    sw     $s5, 72($sp)
+    .cfi_rel_offset 21, 72
+    sw     $s4, 68($sp)
+    .cfi_rel_offset 20, 68
+    sw     $s3, 64($sp)
+    .cfi_rel_offset 19, 64
+    sw     $s2, 60($sp)
+    .cfi_rel_offset 18, 60
+    sw     $s1, 56($sp)
+    .cfi_rel_offset 17, 56
+    sw     $s0, 52($sp)
+    .cfi_rel_offset 16, 52
+
+    SDu $f30, $f31, 44, $sp, $t1
+    SDu $f28, $f29, 36, $sp, $t1
+    SDu $f26, $f27, 28, $sp, $t1
+    SDu $f24, $f25, 20, $sp, $t1
+    SDu $f22, $f23, 12, $sp, $t1
+    SDu $f20, $f21, 4,  $sp, $t1
+
     # 1 word for holding Method*
 
     lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
diff --git a/runtime/arch/mips/quick_method_frame_info_mips.h b/runtime/arch/mips/quick_method_frame_info_mips.h
index 97b295f..dd5ac80 100644
--- a/runtime/arch/mips/quick_method_frame_info_mips.h
+++ b/runtime/arch/mips/quick_method_frame_info_mips.h
@@ -32,6 +32,10 @@
     (1 << art::mips::A1) | (1 << art::mips::A2) | (1 << art::mips::A3);
 static constexpr uint32_t kMipsCalleeSaveAllSpills =
     (1 << art::mips::S0) | (1 << art::mips::S1);
+static constexpr uint32_t kMipsCalleeSaveAllFPSpills =
+    (1 << art::mips::F20) | (1 << art::mips::F21) | (1 << art::mips::F22) | (1 << art::mips::F23) |
+    (1 << art::mips::F24) | (1 << art::mips::F25) | (1 << art::mips::F26) | (1 << art::mips::F27) |
+    (1 << art::mips::F28) | (1 << art::mips::F29) | (1 << art::mips::F30) | (1 << art::mips::F31);
 
 constexpr uint32_t MipsCalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
   return kMipsCalleeSaveRefSpills |
@@ -39,15 +43,20 @@
       (type == Runtime::kSaveAll ? kMipsCalleeSaveAllSpills : 0) | (1 << art::mips::RA);
 }
 
+constexpr uint32_t MipsCalleeSaveFPSpills(Runtime::CalleeSaveType type) {
+  return type == Runtime::kSaveAll ? kMipsCalleeSaveAllFPSpills : 0;
+}
+
 constexpr uint32_t MipsCalleeSaveFrameSize(Runtime::CalleeSaveType type) {
   return RoundUp((POPCOUNT(MipsCalleeSaveCoreSpills(type)) /* gprs */ +
+                  POPCOUNT(MipsCalleeSaveFPSpills(type))   /* fprs */ +
                   1 /* Method* */) * kMipsPointerSize, kStackAlignment);
 }
 
 constexpr QuickMethodFrameInfo MipsCalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
   return QuickMethodFrameInfo(MipsCalleeSaveFrameSize(type),
                               MipsCalleeSaveCoreSpills(type),
-                              0u);
+                              MipsCalleeSaveFPSpills(type));
 }
 
 }  // namespace mips