8210497: [PPC64] Vector registers not saved across safepoint
authormdoerr
Wed, 12 Sep 2018 12:54:16 +0200
changeset 51710 355bd23b46e5
parent 51709 a15a61e954c0
child 51711 3aafd7015d87
8210497: [PPC64] Vector registers not saved across safepoint Reviewed-by: goetz, lucy
src/hotspot/cpu/ppc/ppc.ad
src/hotspot/cpu/ppc/register_ppc.cpp
src/hotspot/cpu/ppc/register_ppc.hpp
src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp
--- a/src/hotspot/cpu/ppc/ppc.ad	Wed Sep 12 12:23:58 2018 +0200
+++ b/src/hotspot/cpu/ppc/ppc.ad	Wed Sep 12 12:54:16 2018 +0200
@@ -908,6 +908,7 @@
 // ----------------------------
 
 reg_class vs_reg(
+  // Attention: Only these ones are saved & restored at safepoint by RegisterSaver.
   VSR32,
   VSR33,
   VSR34,
@@ -928,18 +929,7 @@
   VSR49,
   VSR50,
   VSR51
-//  VSR52,     // nv!
-//  VSR53,     // nv!
-//  VSR54,     // nv!
-//  VSR55,     // nv!
-//  VSR56,     // nv!
-//  VSR57,     // nv!
-//  VSR58,     // nv!
-//  VSR59,     // nv!
-//  VSR60,     // nv!
-//  VSR61,     // nv!
-//  VSR62,     // nv!
-//  VSR63      // nv!
+  // VSR52-VSR63 // nv!
 );
 
  %}
--- a/src/hotspot/cpu/ppc/register_ppc.cpp	Wed Sep 12 12:23:58 2018 +0200
+++ b/src/hotspot/cpu/ppc/register_ppc.cpp	Wed Sep 12 12:54:16 2018 +0200
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,6 @@
 #include "precompiled.hpp"
 #include "register_ppc.hpp"
 
-const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers * 2;
-const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr +
-                                          FloatRegisterImpl::number_of_registers * 2;
-const int ConcreteRegisterImpl::max_cnd = ConcreteRegisterImpl::max_fpr +
-                                          ConditionRegisterImpl::number_of_registers;
 
 const char* RegisterImpl::name() const {
   const char* names[number_of_registers] = {
--- a/src/hotspot/cpu/ppc/register_ppc.hpp	Wed Sep 12 12:23:58 2018 +0200
+++ b/src/hotspot/cpu/ppc/register_ppc.hpp	Wed Sep 12 12:54:16 2018 +0200
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -515,6 +515,7 @@
 
   // accessors
   int encoding() const { assert(is_valid(), "invalid register"); return value(); }
+  inline VMReg as_VMReg();
 
   // testers
   bool is_valid() const { return 0 <=  value() &&  value() < number_of_registers; }
@@ -668,21 +669,16 @@
 class ConcreteRegisterImpl : public AbstractRegisterImpl {
  public:
   enum {
+    max_gpr = RegisterImpl::number_of_registers * 2,
+    max_fpr = max_gpr + FloatRegisterImpl::number_of_registers * 2,
+    max_vsr = max_fpr + VectorSRegisterImpl::number_of_registers,
+    max_cnd = max_vsr + ConditionRegisterImpl::number_of_registers,
+    max_spr = max_cnd + SpecialRegisterImpl::number_of_registers,
     // This number must be large enough to cover REG_COUNT (defined by c2) registers.
     // There is no requirement that any ordering here matches any ordering c2 gives
     // it's optoregs.
-    number_of_registers =
-      ( RegisterImpl::number_of_registers +
-        FloatRegisterImpl::number_of_registers )
-      * 2                                          // register halves
-      + ConditionRegisterImpl::number_of_registers // condition code registers
-      + SpecialRegisterImpl::number_of_registers   // special registers
-      + VectorSRegisterImpl::number_of_registers   // VSX registers
+    number_of_registers = max_spr
   };
-
-  static const int max_gpr;
-  static const int max_fpr;
-  static const int max_cnd;
 };
 
 // Common register declarations used in assembler code.
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp	Wed Sep 12 12:23:58 2018 +0200
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp	Wed Sep 12 12:54:16 2018 +0200
@@ -75,10 +75,12 @@
                          int* out_frame_size_in_bytes,
                          bool generate_oop_map,
                          int return_pc_adjustment,
-                         ReturnPCLocation return_pc_location);
+                         ReturnPCLocation return_pc_location,
+                         bool save_vectors = false);
   static void    restore_live_registers_and_pop_frame(MacroAssembler* masm,
                          int frame_size_in_bytes,
-                         bool restore_ctr);
+                         bool restore_ctr,
+                         bool save_vectors = false);
 
   static void push_frame_and_save_argument_registers(MacroAssembler* masm,
                          Register r_temp,
@@ -97,14 +99,16 @@
   // Constants and data structures:
 
   typedef enum {
-    int_reg           = 0,
-    float_reg         = 1,
-    special_reg       = 2
+    int_reg,
+    float_reg,
+    special_reg,
+    vs_reg
   } RegisterType;
 
   typedef enum {
     reg_size          = 8,
     half_reg_size     = reg_size / 2,
+    vs_reg_size       = 16
   } RegisterConstants;
 
   typedef struct {
@@ -115,15 +119,18 @@
 };
 
 
-#define RegisterSaver_LiveSpecialReg(regname) \
-  { RegisterSaver::special_reg, regname->encoding(), regname->as_VMReg() }
-
 #define RegisterSaver_LiveIntReg(regname) \
   { RegisterSaver::int_reg,     regname->encoding(), regname->as_VMReg() }
 
 #define RegisterSaver_LiveFloatReg(regname) \
   { RegisterSaver::float_reg,   regname->encoding(), regname->as_VMReg() }
 
+#define RegisterSaver_LiveSpecialReg(regname) \
+  { RegisterSaver::special_reg, regname->encoding(), regname->as_VMReg() }
+
+#define RegisterSaver_LiveVSReg(regname) \
+  { RegisterSaver::vs_reg,      regname->encoding(), regname->as_VMReg() }
+
 static const RegisterSaver::LiveRegType RegisterSaver_LiveRegs[] = {
   // Live registers which get spilled to the stack. Register
   // positions in this array correspond directly to the stack layout.
@@ -201,14 +208,42 @@
   RegisterSaver_LiveIntReg(   R28 ),
   RegisterSaver_LiveIntReg(   R29 ),
   RegisterSaver_LiveIntReg(   R30 ),
-  RegisterSaver_LiveIntReg(   R31 ), // must be the last register (see save/restore functions below)
+  RegisterSaver_LiveIntReg(   R31 )  // must be the last register (see save/restore functions below)
 };
 
+static const RegisterSaver::LiveRegType RegisterSaver_LiveVSRegs[] = {
+  //
+  // live vector scalar registers (optional, only these ones are used by C2):
+  //
+  RegisterSaver_LiveVSReg( VSR32 ),
+  RegisterSaver_LiveVSReg( VSR33 ),
+  RegisterSaver_LiveVSReg( VSR34 ),
+  RegisterSaver_LiveVSReg( VSR35 ),
+  RegisterSaver_LiveVSReg( VSR36 ),
+  RegisterSaver_LiveVSReg( VSR37 ),
+  RegisterSaver_LiveVSReg( VSR38 ),
+  RegisterSaver_LiveVSReg( VSR39 ),
+  RegisterSaver_LiveVSReg( VSR40 ),
+  RegisterSaver_LiveVSReg( VSR41 ),
+  RegisterSaver_LiveVSReg( VSR42 ),
+  RegisterSaver_LiveVSReg( VSR43 ),
+  RegisterSaver_LiveVSReg( VSR44 ),
+  RegisterSaver_LiveVSReg( VSR45 ),
+  RegisterSaver_LiveVSReg( VSR46 ),
+  RegisterSaver_LiveVSReg( VSR47 ),
+  RegisterSaver_LiveVSReg( VSR48 ),
+  RegisterSaver_LiveVSReg( VSR49 ),
+  RegisterSaver_LiveVSReg( VSR50 ),
+  RegisterSaver_LiveVSReg( VSR51 )
+};
+
+
 OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
                          int* out_frame_size_in_bytes,
                          bool generate_oop_map,
                          int return_pc_adjustment,
-                         ReturnPCLocation return_pc_location) {
+                         ReturnPCLocation return_pc_location,
+                         bool save_vectors) {
   // Push an abi_reg_args-frame and store all registers which may be live.
   // If requested, create an OopMap: Record volatile registers as
   // callee-save values in an OopMap so their save locations will be
@@ -218,15 +253,16 @@
   // If return_pc_adjustment != 0 adjust the return pc by return_pc_adjustment.
   // Updated return pc is returned in R31 (if not return_pc_is_pre_saved).
 
-  int i;
-  int offset;
-
   // calcualte frame size
   const int regstosave_num       = sizeof(RegisterSaver_LiveRegs) /
                                    sizeof(RegisterSaver::LiveRegType);
-  const int register_save_size   = regstosave_num * reg_size;
+  const int vsregstosave_num     = save_vectors ? (sizeof(RegisterSaver_LiveVSRegs) /
+                                                   sizeof(RegisterSaver::LiveRegType))
+                                                : 0;
+  const int register_save_size   = regstosave_num * reg_size + vsregstosave_num * vs_reg_size;
   const int frame_size_in_bytes  = align_up(register_save_size, frame::alignment_in_bytes)
                                    + frame::abi_reg_args_size;
+
   *out_frame_size_in_bytes       = frame_size_in_bytes;
   const int frame_size_in_slots  = frame_size_in_bytes / sizeof(jint);
   const int register_save_offset = frame_size_in_bytes - register_save_size;
@@ -236,17 +272,18 @@
 
   BLOCK_COMMENT("push_frame_reg_args_and_save_live_registers {");
 
-  // Save some registers in the last slots of the not yet pushed frame so that we
-  // can use them as scratch regs.
-  __ std(R31, -  reg_size, R1_SP);
-  __ std(R30, -2*reg_size, R1_SP);
-  assert(-reg_size == register_save_offset - frame_size_in_bytes + ((regstosave_num-1)*reg_size),
-         "consistency check");
+  // push a new frame
+  __ push_frame(frame_size_in_bytes, noreg);
+
+  // Save some registers in the last (non-vector) slots of the new frame so we
+  // can use them as scratch regs or to determine the return pc.
+  __ std(R31, frame_size_in_bytes -   reg_size - vsregstosave_num * vs_reg_size, R1_SP);
+  __ std(R30, frame_size_in_bytes - 2*reg_size - vsregstosave_num * vs_reg_size, R1_SP);
 
   // save the flags
   // Do the save_LR_CR by hand and adjust the return pc if requested.
   __ mfcr(R30);
-  __ std(R30, _abi(cr), R1_SP);
+  __ std(R30, frame_size_in_bytes + _abi(cr), R1_SP);
   switch (return_pc_location) {
     case return_pc_is_lr: __ mflr(R31); break;
     case return_pc_is_pre_saved: assert(return_pc_adjustment == 0, "unsupported"); break;
@@ -257,14 +294,12 @@
     if (return_pc_adjustment != 0) {
       __ addi(R31, R31, return_pc_adjustment);
     }
-    __ std(R31, _abi(lr), R1_SP);
+    __ std(R31, frame_size_in_bytes + _abi(lr), R1_SP);
   }
 
-  // push a new frame
-  __ push_frame(frame_size_in_bytes, R30);
-
   // save all registers (ints and floats)
-  offset = register_save_offset;
+  int offset = register_save_offset;
+
   for (int i = 0; i < regstosave_num; i++) {
     int reg_num  = RegisterSaver_LiveRegs[i].reg_num;
     int reg_type = RegisterSaver_LiveRegs[i].reg_type;
@@ -302,6 +337,22 @@
     offset += reg_size;
   }
 
+  for (int i = 0; i < vsregstosave_num; i++) {
+    int reg_num  = RegisterSaver_LiveVSRegs[i].reg_num;
+    int reg_type = RegisterSaver_LiveVSRegs[i].reg_type;
+
+    __ li(R30, offset);
+    __ stxvd2x(as_VectorSRegister(reg_num), R30, R1_SP);
+
+    if (generate_oop_map) {
+      map->set_callee_saved(VMRegImpl::stack2reg(offset>>2),
+                            RegisterSaver_LiveVSRegs[i].vmreg);
+    }
+    offset += vs_reg_size;
+  }
+
+  assert(offset == frame_size_in_bytes, "consistency check");
+
   BLOCK_COMMENT("} push_frame_reg_args_and_save_live_registers");
 
   // And we're done.
@@ -313,18 +364,22 @@
 // saved.
 void RegisterSaver::restore_live_registers_and_pop_frame(MacroAssembler* masm,
                                                          int frame_size_in_bytes,
-                                                         bool restore_ctr) {
-  int i;
-  int offset;
+                                                         bool restore_ctr,
+                                                         bool save_vectors) {
   const int regstosave_num       = sizeof(RegisterSaver_LiveRegs) /
                                    sizeof(RegisterSaver::LiveRegType);
-  const int register_save_size   = regstosave_num * reg_size;
+  const int vsregstosave_num     = save_vectors ? (sizeof(RegisterSaver_LiveVSRegs) /
+                                                   sizeof(RegisterSaver::LiveRegType))
+                                                : 0;
+  const int register_save_size   = regstosave_num * reg_size + vsregstosave_num * vs_reg_size;
+
   const int register_save_offset = frame_size_in_bytes - register_save_size;
 
   BLOCK_COMMENT("restore_live_registers_and_pop_frame {");
 
   // restore all registers (ints and floats)
-  offset = register_save_offset;
+  int offset = register_save_offset;
+
   for (int i = 0; i < regstosave_num; i++) {
     int reg_num  = RegisterSaver_LiveRegs[i].reg_num;
     int reg_type = RegisterSaver_LiveRegs[i].reg_type;
@@ -356,14 +411,30 @@
     offset += reg_size;
   }
 
-  // pop the frame
-  __ pop_frame();
-
-  // restore the flags
-  __ restore_LR_CR(R31);
+  for (int i = 0; i < vsregstosave_num; i++) {
+    int reg_num  = RegisterSaver_LiveVSRegs[i].reg_num;
+    int reg_type = RegisterSaver_LiveVSRegs[i].reg_type;
+
+    __ li(R31, offset);
+    __ lxvd2x(as_VectorSRegister(reg_num), R31, R1_SP);
+
+    offset += vs_reg_size;
+  }
+
+  assert(offset == frame_size_in_bytes, "consistency check");
+
+  // restore link and the flags
+  __ ld(R31, frame_size_in_bytes + _abi(lr), R1_SP);
+  __ mtlr(R31);
+
+  __ ld(R31, frame_size_in_bytes + _abi(cr), R1_SP);
+  __ mtcr(R31);
 
   // restore scratch register's value
-  __ ld(R31, -reg_size, R1_SP);
+  __ ld(R31, frame_size_in_bytes - reg_size - vsregstosave_num * vs_reg_size, R1_SP);
+
+  // pop the frame
+  __ addi(R1_SP, R1_SP, frame_size_in_bytes);
 
   BLOCK_COMMENT("} restore_live_registers_and_pop_frame");
 }
@@ -447,15 +518,13 @@
 
 // Restore the registers that might be holding a result.
 void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes) {
-  int i;
-  int offset;
   const int regstosave_num       = sizeof(RegisterSaver_LiveRegs) /
                                    sizeof(RegisterSaver::LiveRegType);
-  const int register_save_size   = regstosave_num * reg_size;
+  const int register_save_size   = regstosave_num * reg_size; // VS registers not relevant here.
   const int register_save_offset = frame_size_in_bytes - register_save_size;
 
   // restore all result registers (ints and floats)
-  offset = register_save_offset;
+  int offset = register_save_offset;
   for (int i = 0; i < regstosave_num; i++) {
     int reg_num  = RegisterSaver_LiveRegs[i].reg_num;
     int reg_type = RegisterSaver_LiveRegs[i].reg_type;
@@ -479,6 +548,8 @@
     }
     offset += reg_size;
   }
+
+  assert(offset == frame_size_in_bytes, "consistency check");
 }
 
 // Is vector's size (in bytes) bigger than a size saved by default?
@@ -3109,12 +3180,14 @@
     __ tabort_();
   }
 
+  bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP);
+
   // Save registers, fpu state, and flags. Set R31 = return pc.
   map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
                                                                    &frame_size_in_bytes,
                                                                    /*generate_oop_map=*/ true,
                                                                    /*return_pc_adjustment=*/0,
-                                                                   return_pc_location);
+                                                                   return_pc_location, save_vectors);
 
   // The following is basically a call_VM. However, we need the precise
   // address of the call in order to generate an oopmap. Hence, we do all the
@@ -3148,7 +3221,7 @@
   // Exception pending
   RegisterSaver::restore_live_registers_and_pop_frame(masm,
                                                       frame_size_in_bytes,
-                                                      /*restore_ctr=*/true);
+                                                      /*restore_ctr=*/true, save_vectors);
 
   BLOCK_COMMENT("  Jump to forward_exception_entry.");
   // Jump to forward_exception_entry, with the issuing PC in LR
@@ -3175,7 +3248,7 @@
   // Normal exit, restore registers and exit.
   RegisterSaver::restore_live_registers_and_pop_frame(masm,
                                                       frame_size_in_bytes,
-                                                      /*restore_ctr=*/true);
+                                                      /*restore_ctr=*/true, save_vectors);
 
   __ blr();
 
--- a/src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp	Wed Sep 12 12:23:58 2018 +0200
+++ b/src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp	Wed Sep 12 12:54:16 2018 +0200
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,16 +28,21 @@
 
 inline VMReg RegisterImpl::as_VMReg() {
   if (this == noreg) return VMRegImpl::Bad();
+  // Two halfs, multiply by 2.
   return VMRegImpl::as_VMReg(encoding() << 1);
 }
 
-// Since we don't have two halfs here, don't multiply by 2.
-inline VMReg ConditionRegisterImpl::as_VMReg() {
+inline VMReg FloatRegisterImpl::as_VMReg() {
+  // Two halfs, multiply by 2.
+  return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_gpr);
+}
+
+inline VMReg VectorSRegisterImpl::as_VMReg() {
   return VMRegImpl::as_VMReg((encoding()) + ConcreteRegisterImpl::max_fpr);
 }
 
-inline VMReg FloatRegisterImpl::as_VMReg() {
-  return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_gpr);
+inline VMReg ConditionRegisterImpl::as_VMReg() {
+  return VMRegImpl::as_VMReg((encoding()) + ConcreteRegisterImpl::max_vsr);
 }
 
 inline VMReg SpecialRegisterImpl::as_VMReg() {