< prev index next >

src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp

Print this page
rev 12410 : 8171398: s390x: Make interpreter's math entries consistent with C1 and C2 and support FMA
Reviewed-by:

@@ -1295,40 +1295,100 @@
 // Various method entries
 
 // Math function, frame manager must set up an interpreter state, etc.
 address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {
 
-  if (!InlineIntrinsics) { return NULL; } // Generate a vanilla entry.
+  // Decide what to do: Use same platform specific instructions and runtime calls as compilers.
+  bool use_instruction = false;
+  address runtime_entry = NULL;
+  int num_args = 1;
+  bool double_precision = true;
+
+  // s390 specific:
+  switch (kind) {
+    case Interpreter::java_lang_math_sqrt:
+    case Interpreter::java_lang_math_abs:  use_instruction = true; break;
+    case Interpreter::java_lang_math_fmaF:
+    case Interpreter::java_lang_math_fmaD: use_instruction = UseFMA; break;
+    default: break; // Fall back to runtime call.
+  }
 
-  // Only support absolute value and square root.
-  if (kind != Interpreter::java_lang_math_abs && kind != Interpreter::java_lang_math_sqrt) {
-    return NULL;
+  switch (kind) {
+    case Interpreter::java_lang_math_sin  : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);   break;
+    case Interpreter::java_lang_math_cos  : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);   break;
+    case Interpreter::java_lang_math_tan  : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);   break;
+    case Interpreter::java_lang_math_abs  : /* run interpreted */ break;
+    case Interpreter::java_lang_math_sqrt : /* runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); not available */ break;
+    case Interpreter::java_lang_math_log  : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);   break;
+    case Interpreter::java_lang_math_log10: runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); break;
+    case Interpreter::java_lang_math_pow  : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow); num_args = 2; break;
+    case Interpreter::java_lang_math_exp  : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);   break;
+    case Interpreter::java_lang_math_fmaF : /* run interpreted */ num_args = 3; double_precision = false; break;
+    case Interpreter::java_lang_math_fmaD : /* run interpreted */ num_args = 3; break;
+    default: ShouldNotReachHere();
   }
 
-  BLOCK_COMMENT("math_entry {");
+  // Use normal entry if neither instruction nor runtime call is used.
+  if (!use_instruction && runtime_entry == NULL) return NULL;
 
-  address math_entry = __ pc();
+  address entry = __ pc();
 
-  if (kind == Interpreter::java_lang_math_abs) {
+  if (use_instruction) {
+    switch (kind) {
+      case Interpreter::java_lang_math_sqrt:
+        // Can use memory operand directly.
+        __ z_sqdb(Z_FRET, Interpreter::stackElementSize, Z_esp);
+        break;
+      case Interpreter::java_lang_math_abs:
     // Load operand from stack.
     __ mem2freg_opt(Z_FRET, Address(Z_esp, Interpreter::stackElementSize));
     __ z_lpdbr(Z_FRET);
+        break;
+      case Interpreter::java_lang_math_fmaF:
+        __ mem2freg_opt(Z_FRET,  Address(Z_esp,     Interpreter::stackElementSize)); // result reg = arg3
+        __ mem2freg_opt(Z_FARG2, Address(Z_esp, 3 * Interpreter::stackElementSize)); // arg1
+        __ z_maeb(Z_FRET, Z_FARG2, Address(Z_esp, 2 * Interpreter::stackElementSize));
+        break;
+      case Interpreter::java_lang_math_fmaD:
+        __ mem2freg_opt(Z_FRET,  Address(Z_esp,     Interpreter::stackElementSize)); // result reg = arg3
+        __ mem2freg_opt(Z_FARG2, Address(Z_esp, 5 * Interpreter::stackElementSize)); // arg1
+        __ z_madb(Z_FRET, Z_FARG2, Address(Z_esp, 3 * Interpreter::stackElementSize));
+        break;
+      default: ShouldNotReachHere();
+    }
   } else {
-    // sqrt
-    // Can use memory operand directly.
-    __ z_sqdb(Z_FRET, Interpreter::stackElementSize, Z_esp);
+    // Load arguments
+    assert(num_args <= 4, "passed in registers");
+    if (double_precision) {
+      int offset = (2 * num_args - 1) * Interpreter::stackElementSize;
+      for (int i = 0; i < num_args; ++i) {
+        __ mem2freg_opt(as_FloatRegister(Z_FARG1->encoding() + 2 * i), Address(Z_esp, offset));
+        offset -= 2 * Interpreter::stackElementSize;
   }
+    } else {
+      int offset = num_args * Interpreter::stackElementSize;
+      for (int i = 0; i < num_args; ++i) {
+        __ mem2freg_opt(as_FloatRegister(Z_FARG1->encoding() + 2 * i), Address(Z_esp, offset));
+        offset -= Interpreter::stackElementSize;
+      }
+    }
+    // Call runtime
+    __ save_return_pc();       // Save Z_R14.
+    __ push_frame_abi160(0);   // Without new frame the RT call could overwrite the saved Z_R14.
+
+    __ call_VM_leaf(runtime_entry);
 
-  // Restore caller sp for c2i case.
+    __ pop_frame();
+    __ restore_return_pc();    // Restore Z_R14.
+  }
+
+  // Pop c2i arguments (if any) off when we return.
   __ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
 
-  // We are done, return.
   __ z_br(Z_R14);
 
-  BLOCK_COMMENT("} math_entry");
-
-  return math_entry;
+  return entry;
 }
 
 // Interpreter stub for calling a native method. (asm interpreter).
 // This sets up a somewhat different looking stack for calling the
 // native method than the typical interpreter frame setup.
< prev index next >