8075052: Autobox elimination hinders loop unrolling
authorvlivanov
Mon, 04 Feb 2019 17:35:36 -0800
changeset 53633 eebdde444bb5
parent 53632 d620a4a1d5ed
child 53634 f57b943a1a22
8075052: Autobox elimination hinders loop unrolling Reviewed-by: kvn
src/hotspot/share/opto/callGenerator.cpp
--- a/src/hotspot/share/opto/callGenerator.cpp	Mon Feb 04 17:35:35 2019 -0800
+++ b/src/hotspot/share/opto/callGenerator.cpp	Mon Feb 04 17:35:36 2019 -0800
@@ -296,16 +296,16 @@
 // Allow inlining decisions to be delayed
 class LateInlineCallGenerator : public DirectCallGenerator {
  private:
-  // unique id for log compilation
-  jlong _unique_id;
+  jlong _unique_id;   // unique id for log compilation
+  bool _is_pure_call; // a hint that the call doesn't have important side effects to care about
 
  protected:
   CallGenerator* _inline_cg;
   virtual bool do_late_inline_check(JVMState* jvms) { return true; }
 
  public:
-  LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
-    DirectCallGenerator(method, true), _unique_id(0), _inline_cg(inline_cg) {}
+  LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg, bool is_pure_call = false) :
+    DirectCallGenerator(method, true), _unique_id(0), _is_pure_call(is_pure_call), _inline_cg(inline_cg) {}
 
   virtual bool is_late_inline() const { return true; }
 
@@ -389,78 +389,86 @@
     C->remove_macro_node(call);
   }
 
-  // Make a clone of the JVMState that appropriate to use for driving a parse
-  JVMState* old_jvms = call->jvms();
-  JVMState* jvms = old_jvms->clone_shallow(C);
-  uint size = call->req();
-  SafePointNode* map = new SafePointNode(size, jvms);
-  for (uint i1 = 0; i1 < size; i1++) {
-    map->init_req(i1, call->in(i1));
-  }
-
-  // Make sure the state is a MergeMem for parsing.
-  if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
-    Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory));
-    C->initial_gvn()->set_type_bottom(mem);
-    map->set_req(TypeFunc::Memory, mem);
-  }
+  bool result_not_used = (callprojs.resproj == NULL || callprojs.resproj->outcnt() == 0);
+  if (_is_pure_call && result_not_used) {
+    // The call is marked as pure (no important side effects), but result isn't used.
+    // It's safe to remove the call.
+    GraphKit kit(call->jvms());
+    kit.replace_call(call, C->top(), true);
+  } else {
+    // Make a clone of the JVMState that appropriate to use for driving a parse
+    JVMState* old_jvms = call->jvms();
+    JVMState* jvms = old_jvms->clone_shallow(C);
+    uint size = call->req();
+    SafePointNode* map = new SafePointNode(size, jvms);
+    for (uint i1 = 0; i1 < size; i1++) {
+      map->init_req(i1, call->in(i1));
+    }
 
-  uint nargs = method()->arg_size();
-  // blow away old call arguments
-  Node* top = C->top();
-  for (uint i1 = 0; i1 < nargs; i1++) {
-    map->set_req(TypeFunc::Parms + i1, top);
-  }
-  jvms->set_map(map);
+    // Make sure the state is a MergeMem for parsing.
+    if (!map->in(TypeFunc::Memory)->is_MergeMem()) {
+      Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory));
+      C->initial_gvn()->set_type_bottom(mem);
+      map->set_req(TypeFunc::Memory, mem);
+    }
 
-  // Make enough space in the expression stack to transfer
-  // the incoming arguments and return value.
-  map->ensure_stack(jvms, jvms->method()->max_stack());
-  for (uint i1 = 0; i1 < nargs; i1++) {
-    map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
-  }
+    uint nargs = method()->arg_size();
+    // blow away old call arguments
+    Node* top = C->top();
+    for (uint i1 = 0; i1 < nargs; i1++) {
+      map->set_req(TypeFunc::Parms + i1, top);
+    }
+    jvms->set_map(map);
 
-  C->print_inlining_assert_ready();
+    // Make enough space in the expression stack to transfer
+    // the incoming arguments and return value.
+    map->ensure_stack(jvms, jvms->method()->max_stack());
+    for (uint i1 = 0; i1 < nargs; i1++) {
+      map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
+    }
 
-  C->print_inlining_move_to(this);
+    C->print_inlining_assert_ready();
 
-  C->log_late_inline(this);
+    C->print_inlining_move_to(this);
+
+    C->log_late_inline(this);
 
-  // This check is done here because for_method_handle_inline() method
-  // needs jvms for inlined state.
-  if (!do_late_inline_check(jvms)) {
-    map->disconnect_inputs(NULL, C);
-    return;
-  }
+    // This check is done here because for_method_handle_inline() method
+    // needs jvms for inlined state.
+    if (!do_late_inline_check(jvms)) {
+      map->disconnect_inputs(NULL, C);
+      return;
+    }
 
-  // Setup default node notes to be picked up by the inlining
-  Node_Notes* old_nn = C->node_notes_at(call->_idx);
-  if (old_nn != NULL) {
-    Node_Notes* entry_nn = old_nn->clone(C);
-    entry_nn->set_jvms(jvms);
-    C->set_default_node_notes(entry_nn);
-  }
+    // Setup default node notes to be picked up by the inlining
+    Node_Notes* old_nn = C->node_notes_at(call->_idx);
+    if (old_nn != NULL) {
+      Node_Notes* entry_nn = old_nn->clone(C);
+      entry_nn->set_jvms(jvms);
+      C->set_default_node_notes(entry_nn);
+    }
 
-  // Now perform the inlining using the synthesized JVMState
-  JVMState* new_jvms = _inline_cg->generate(jvms);
-  if (new_jvms == NULL)  return;  // no change
-  if (C->failing())      return;
+    // Now perform the inlining using the synthesized JVMState
+    JVMState* new_jvms = _inline_cg->generate(jvms);
+    if (new_jvms == NULL)  return;  // no change
+    if (C->failing())      return;
 
-  // Capture any exceptional control flow
-  GraphKit kit(new_jvms);
+    // Capture any exceptional control flow
+    GraphKit kit(new_jvms);
 
-  // Find the result object
-  Node* result = C->top();
-  int   result_size = method()->return_type()->size();
-  if (result_size != 0 && !kit.stopped()) {
-    result = (result_size == 1) ? kit.pop() : kit.pop_pair();
+    // Find the result object
+    Node* result = C->top();
+    int   result_size = method()->return_type()->size();
+    if (result_size != 0 && !kit.stopped()) {
+      result = (result_size == 1) ? kit.pop() : kit.pop_pair();
+    }
+
+    C->set_has_loops(C->has_loops() || _inline_cg->method()->has_loops());
+    C->env()->notice_inlined_method(_inline_cg->method());
+    C->set_inlining_progress(true);
+    C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup
+    kit.replace_call(call, result, true);
   }
-
-  C->set_has_loops(C->has_loops() || _inline_cg->method()->has_loops());
-  C->env()->notice_inlined_method(_inline_cg->method());
-  C->set_inlining_progress(true);
-  C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup
-  kit.replace_call(call, result, true);
 }
 
 
@@ -551,7 +559,7 @@
 
  public:
   LateInlineBoxingCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
-    LateInlineCallGenerator(method, inline_cg) {}
+    LateInlineCallGenerator(method, inline_cg, /*is_pure=*/true) {}
 
   virtual JVMState* generate(JVMState* jvms) {
     Compile *C = Compile::current();