Merge

Thu, 12 Jul 2012 14:19:15 -0700

author
kvn
date
Thu, 12 Jul 2012 14:19:15 -0700
changeset 3911
cc787232c4c5
parent 3907
90d5a592ea8f
parent 3910
ae9241bbce4a
child 3912
66b0450071c1
child 3921
e74da3c2b827

Merge

     1.1 --- a/src/share/vm/opto/library_call.cpp	Thu Jul 12 14:26:25 2012 -0400
     1.2 +++ b/src/share/vm/opto/library_call.cpp	Thu Jul 12 14:19:15 2012 -0700
     1.3 @@ -160,6 +160,7 @@
     1.4    bool inline_trans(vmIntrinsics::ID id);
     1.5    bool inline_abs(vmIntrinsics::ID id);
     1.6    bool inline_sqrt(vmIntrinsics::ID id);
     1.7 +  void finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName);
     1.8    bool inline_pow(vmIntrinsics::ID id);
     1.9    bool inline_exp(vmIntrinsics::ID id);
    1.10    bool inline_min_max(vmIntrinsics::ID id);
    1.11 @@ -1535,40 +1536,79 @@
    1.12    return true;
    1.13  }
    1.14  
    1.15 +void LibraryCallKit::finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName) {
    1.16 +  //-------------------
    1.17 +  //result=(result.isNaN())? funcAddr():result;
    1.18 +  // Check: If isNaN() by checking result!=result? then either trap
    1.19 +  // or go to runtime
    1.20 +  Node* cmpisnan = _gvn.transform(new (C, 3) CmpDNode(result,result));
    1.21 +  // Build the boolean node
    1.22 +  Node* bolisnum = _gvn.transform( new (C, 2) BoolNode(cmpisnan, BoolTest::eq) );
    1.23 +
    1.24 +  if (!too_many_traps(Deoptimization::Reason_intrinsic)) {
    1.25 +    {
    1.26 +      BuildCutout unless(this, bolisnum, PROB_STATIC_FREQUENT);
    1.27 +      // End the current control-flow path
    1.28 +      push_pair(x);
    1.29 +      if (y != NULL) {
    1.30 +        push_pair(y);
    1.31 +      }
    1.32 +      // The pow or exp intrinsic returned a NaN, which requires a call
    1.33 +      // to the runtime.  Recompile with the runtime call.
    1.34 +      uncommon_trap(Deoptimization::Reason_intrinsic,
    1.35 +                    Deoptimization::Action_make_not_entrant);
    1.36 +    }
    1.37 +    push_pair(result);
    1.38 +  } else {
    1.39 +    // If this inlining ever returned NaN in the past, we compile a call
    1.40 +    // to the runtime to properly handle corner cases
    1.41 +
    1.42 +    IfNode* iff = create_and_xform_if(control(), bolisnum, PROB_STATIC_FREQUENT, COUNT_UNKNOWN);
    1.43 +    Node* if_slow = _gvn.transform( new (C, 1) IfFalseNode(iff) );
    1.44 +    Node* if_fast = _gvn.transform( new (C, 1) IfTrueNode(iff) );
    1.45 +
    1.46 +    if (!if_slow->is_top()) {
    1.47 +      RegionNode* result_region = new(C, 3) RegionNode(3);
    1.48 +      PhiNode*    result_val = new (C, 3) PhiNode(result_region, Type::DOUBLE);
    1.49 +
    1.50 +      result_region->init_req(1, if_fast);
    1.51 +      result_val->init_req(1, result);
    1.52 +
    1.53 +      set_control(if_slow);
    1.54 +
    1.55 +      const TypePtr* no_memory_effects = NULL;
    1.56 +      Node* rt = make_runtime_call(RC_LEAF, call_type, funcAddr, funcName,
    1.57 +                                   no_memory_effects,
    1.58 +                                   x, top(), y, y ? top() : NULL);
    1.59 +      Node* value = _gvn.transform(new (C, 1) ProjNode(rt, TypeFunc::Parms+0));
    1.60 +#ifdef ASSERT
    1.61 +      Node* value_top = _gvn.transform(new (C, 1) ProjNode(rt, TypeFunc::Parms+1));
    1.62 +      assert(value_top == top(), "second value must be top");
    1.63 +#endif
    1.64 +
    1.65 +      result_region->init_req(2, control());
    1.66 +      result_val->init_req(2, value);
    1.67 +      push_result(result_region, result_val);
    1.68 +    } else {
    1.69 +      push_pair(result);
    1.70 +    }
    1.71 +  }
    1.72 +}
    1.73 +
    1.74  //------------------------------inline_exp-------------------------------------
    1.75  // Inline exp instructions, if possible.  The Intel hardware only misses
    1.76  // really odd corner cases (+/- Infinity).  Just uncommon-trap them.
    1.77  bool LibraryCallKit::inline_exp(vmIntrinsics::ID id) {
    1.78    assert(id == vmIntrinsics::_dexp, "Not exp");
    1.79  
    1.80 -  // If this inlining ever returned NaN in the past, we do not intrinsify it
    1.81 -  // every again.  NaN results requires StrictMath.exp handling.
    1.82 -  if (too_many_traps(Deoptimization::Reason_intrinsic))  return false;
    1.83 -
    1.84    _sp += arg_size();        // restore stack pointer
    1.85    Node *x = pop_math_arg();
    1.86    Node *result = _gvn.transform(new (C, 2) ExpDNode(0,x));
    1.87  
    1.88 -  //-------------------
    1.89 -  //result=(result.isNaN())? StrictMath::exp():result;
    1.90 -  // Check: If isNaN() by checking result!=result? then go to Strict Math
    1.91 -  Node* cmpisnan = _gvn.transform(new (C, 3) CmpDNode(result,result));
    1.92 -  // Build the boolean node
    1.93 -  Node* bolisnum = _gvn.transform( new (C, 2) BoolNode(cmpisnan, BoolTest::eq) );
    1.94 -
    1.95 -  { BuildCutout unless(this, bolisnum, PROB_STATIC_FREQUENT);
    1.96 -    // End the current control-flow path
    1.97 -    push_pair(x);
    1.98 -    // Math.exp intrinsic returned a NaN, which requires StrictMath.exp
    1.99 -    // to handle.  Recompile without intrinsifying Math.exp
   1.100 -    uncommon_trap(Deoptimization::Reason_intrinsic,
   1.101 -                  Deoptimization::Action_make_not_entrant);
   1.102 -  }
   1.103 +  finish_pow_exp(result, x, NULL, OptoRuntime::Math_D_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dexp), "EXP");
   1.104  
   1.105    C->set_has_split_ifs(true); // Has chance for split-if optimization
   1.106  
   1.107 -  push_pair(result);
   1.108 -
   1.109    return true;
   1.110  }
   1.111  
   1.112 @@ -1577,17 +1617,12 @@
   1.113  bool LibraryCallKit::inline_pow(vmIntrinsics::ID id) {
   1.114    assert(id == vmIntrinsics::_dpow, "Not pow");
   1.115  
   1.116 -  // If this inlining ever returned NaN in the past, we do not intrinsify it
   1.117 -  // every again.  NaN results requires StrictMath.pow handling.
   1.118 -  if (too_many_traps(Deoptimization::Reason_intrinsic))  return false;
   1.119 -
   1.120 -  // Do not intrinsify on older platforms which lack cmove.
   1.121 -  if (ConditionalMoveLimit == 0)  return false;
   1.122 -
   1.123    // Pseudocode for pow
   1.124    // if (x <= 0.0) {
   1.125 -  //   if ((double)((int)y)==y) { // if y is int
   1.126 -  //     result = ((1&(int)y)==0)?-DPow(abs(x), y):DPow(abs(x), y)
   1.127 +  //   long longy = (long)y;
   1.128 +  //   if ((double)longy == y) { // if y is long
   1.129 +  //     if (y + 1 == y) longy = 0; // huge number: even
   1.130 +  //     result = ((1&longy) == 0)?-DPow(abs(x), y):DPow(abs(x), y);
   1.131    //   } else {
   1.132    //     result = NaN;
   1.133    //   }
   1.134 @@ -1595,7 +1630,7 @@
   1.135    //   result = DPow(x,y);
   1.136    // }
   1.137    // if (result != result)?  {
   1.138 -  //   uncommon_trap();
   1.139 +  //   result = uncommon_trap() or runtime_call();
   1.140    // }
   1.141    // return result;
   1.142  
   1.143 @@ -1603,15 +1638,14 @@
   1.144    Node* y = pop_math_arg();
   1.145    Node* x = pop_math_arg();
   1.146  
   1.147 -  Node *fast_result = _gvn.transform( new (C, 3) PowDNode(0, x, y) );
   1.148 -
   1.149 -  // Short form: if not top-level (i.e., Math.pow but inlining Math.pow
   1.150 -  // inside of something) then skip the fancy tests and just check for
   1.151 -  // NaN result.
   1.152 -  Node *result = NULL;
   1.153 -  if( jvms()->depth() >= 1 ) {
   1.154 -    result = fast_result;
   1.155 +  Node* result = NULL;
   1.156 +
   1.157 +  if (!too_many_traps(Deoptimization::Reason_intrinsic)) {
   1.158 +    // Short form: skip the fancy tests and just check for NaN result.
   1.159 +    result = _gvn.transform( new (C, 3) PowDNode(0, x, y) );
   1.160    } else {
   1.161 +    // If this inlining ever returned NaN in the past, include all
   1.162 +    // checks + call to the runtime.
   1.163  
   1.164      // Set the merge point for If node with condition of (x <= 0.0)
   1.165      // There are four possible paths to region node and phi node
   1.166 @@ -1627,55 +1661,95 @@
   1.167      Node *bol1 = _gvn.transform( new (C, 2) BoolNode( cmp, BoolTest::le ) );
   1.168      // Branch either way
   1.169      IfNode *if1 = create_and_xform_if(control(),bol1, PROB_STATIC_INFREQUENT, COUNT_UNKNOWN);
   1.170 -    Node *opt_test = _gvn.transform(if1);
   1.171 -    //assert( opt_test->is_If(), "Expect an IfNode");
   1.172 -    IfNode *opt_if1 = (IfNode*)opt_test;
   1.173      // Fast path taken; set region slot 3
   1.174 -    Node *fast_taken = _gvn.transform( new (C, 1) IfFalseNode(opt_if1) );
   1.175 +    Node *fast_taken = _gvn.transform( new (C, 1) IfFalseNode(if1) );
   1.176      r->init_req(3,fast_taken); // Capture fast-control
   1.177  
   1.178      // Fast path not-taken, i.e. slow path
   1.179 -    Node *complex_path = _gvn.transform( new (C, 1) IfTrueNode(opt_if1) );
   1.180 +    Node *complex_path = _gvn.transform( new (C, 1) IfTrueNode(if1) );
   1.181  
   1.182      // Set fast path result
   1.183 -    Node *fast_result = _gvn.transform( new (C, 3) PowDNode(0, y, x) );
   1.184 +    Node *fast_result = _gvn.transform( new (C, 3) PowDNode(0, x, y) );
   1.185      phi->init_req(3, fast_result);
   1.186  
   1.187      // Complex path
   1.188 -    // Build the second if node (if y is int)
   1.189 -    // Node for (int)y
   1.190 -    Node *inty = _gvn.transform( new (C, 2) ConvD2INode(y));
   1.191 -    // Node for (double)((int) y)
   1.192 -    Node *doubleinty= _gvn.transform( new (C, 2) ConvI2DNode(inty));
   1.193 -    // Check (double)((int) y) : y
   1.194 -    Node *cmpinty= _gvn.transform(new (C, 3) CmpDNode(doubleinty, y));
   1.195 -    // Check if (y isn't int) then go to slow path
   1.196 -
   1.197 -    Node *bol2 = _gvn.transform( new (C, 2) BoolNode( cmpinty, BoolTest::ne ) );
   1.198 +    // Build the second if node (if y is long)
   1.199 +    // Node for (long)y
   1.200 +    Node *longy = _gvn.transform( new (C, 2) ConvD2LNode(y));
   1.201 +    // Node for (double)((long) y)
   1.202 +    Node *doublelongy= _gvn.transform( new (C, 2) ConvL2DNode(longy));
   1.203 +    // Check (double)((long) y) : y
   1.204 +    Node *cmplongy= _gvn.transform(new (C, 3) CmpDNode(doublelongy, y));
   1.205 +    // Check if (y isn't long) then go to slow path
   1.206 +
   1.207 +    Node *bol2 = _gvn.transform( new (C, 2) BoolNode( cmplongy, BoolTest::ne ) );
   1.208      // Branch either way
   1.209      IfNode *if2 = create_and_xform_if(complex_path,bol2, PROB_STATIC_INFREQUENT, COUNT_UNKNOWN);
   1.210 -    Node *slow_path = opt_iff(r,if2); // Set region path 2
   1.211 -
   1.212 -    // Calculate DPow(abs(x), y)*(1 & (int)y)
   1.213 +    Node* ylong_path = _gvn.transform( new (C, 1) IfFalseNode(if2));
   1.214 +
   1.215 +    Node *slow_path = _gvn.transform( new (C, 1) IfTrueNode(if2) );
   1.216 +
   1.217 +    // Calculate DPow(abs(x), y)*(1 & (long)y)
   1.218      // Node for constant 1
   1.219 -    Node *conone = intcon(1);
   1.220 -    // 1& (int)y
   1.221 -    Node *signnode= _gvn.transform( new (C, 3) AndINode(conone, inty) );
   1.222 +    Node *conone = longcon(1);
   1.223 +    // 1& (long)y
   1.224 +    Node *signnode= _gvn.transform( new (C, 3) AndLNode(conone, longy) );
   1.225 +
   1.226 +    // A huge number is always even. Detect a huge number by checking
   1.227 +    // if y + 1 == y and set integer to be tested for parity to 0.
   1.228 +    // Required for corner case:
   1.229 +    // (long)9.223372036854776E18 = max_jlong
   1.230 +    // (double)(long)9.223372036854776E18 = 9.223372036854776E18
   1.231 +    // max_jlong is odd but 9.223372036854776E18 is even
   1.232 +    Node* yplus1 = _gvn.transform( new (C, 3) AddDNode(y, makecon(TypeD::make(1))));
   1.233 +    Node *cmpyplus1= _gvn.transform(new (C, 3) CmpDNode(yplus1, y));
   1.234 +    Node *bolyplus1 = _gvn.transform( new (C, 2) BoolNode( cmpyplus1, BoolTest::eq ) );
   1.235 +    Node* correctedsign = NULL;
   1.236 +    if (ConditionalMoveLimit != 0) {
   1.237 +      correctedsign = _gvn.transform( CMoveNode::make(C, NULL, bolyplus1, signnode, longcon(0), TypeLong::LONG));
   1.238 +    } else {
   1.239 +      IfNode *ifyplus1 = create_and_xform_if(ylong_path,bolyplus1, PROB_FAIR, COUNT_UNKNOWN);
   1.240 +      RegionNode *r = new (C, 3) RegionNode(3);
   1.241 +      Node *phi = new (C, 3) PhiNode(r, TypeLong::LONG);
   1.242 +      r->init_req(1, _gvn.transform( new (C, 1) IfFalseNode(ifyplus1)));
   1.243 +      r->init_req(2, _gvn.transform( new (C, 1) IfTrueNode(ifyplus1)));
   1.244 +      phi->init_req(1, signnode);
   1.245 +      phi->init_req(2, longcon(0));
   1.246 +      correctedsign = _gvn.transform(phi);
   1.247 +      ylong_path = _gvn.transform(r);
   1.248 +      record_for_igvn(r);
   1.249 +    }
   1.250 +
   1.251      // zero node
   1.252 -    Node *conzero = intcon(0);
   1.253 -    // Check (1&(int)y)==0?
   1.254 -    Node *cmpeq1 = _gvn.transform(new (C, 3) CmpINode(signnode, conzero));
   1.255 -    // Check if (1&(int)y)!=0?, if so the result is negative
   1.256 +    Node *conzero = longcon(0);
   1.257 +    // Check (1&(long)y)==0?
   1.258 +    Node *cmpeq1 = _gvn.transform(new (C, 3) CmpLNode(correctedsign, conzero));
   1.259 +    // Check if (1&(long)y)!=0?, if so the result is negative
   1.260      Node *bol3 = _gvn.transform( new (C, 2) BoolNode( cmpeq1, BoolTest::ne ) );
   1.261      // abs(x)
   1.262      Node *absx=_gvn.transform( new (C, 2) AbsDNode(x));
   1.263      // abs(x)^y
   1.264 -    Node *absxpowy = _gvn.transform( new (C, 3) PowDNode(0, y, absx) );
   1.265 +    Node *absxpowy = _gvn.transform( new (C, 3) PowDNode(0, absx, y) );
   1.266      // -abs(x)^y
   1.267      Node *negabsxpowy = _gvn.transform(new (C, 2) NegDNode (absxpowy));
   1.268 -    // (1&(int)y)==1?-DPow(abs(x), y):DPow(abs(x), y)
   1.269 -    Node *signresult = _gvn.transform( CMoveNode::make(C, NULL, bol3, absxpowy, negabsxpowy, Type::DOUBLE));
   1.270 +    // (1&(long)y)==1?-DPow(abs(x), y):DPow(abs(x), y)
   1.271 +    Node *signresult = NULL;
   1.272 +    if (ConditionalMoveLimit != 0) {
   1.273 +      signresult = _gvn.transform( CMoveNode::make(C, NULL, bol3, absxpowy, negabsxpowy, Type::DOUBLE));
   1.274 +    } else {
   1.275 +      IfNode *ifyeven = create_and_xform_if(ylong_path,bol3, PROB_FAIR, COUNT_UNKNOWN);
   1.276 +      RegionNode *r = new (C, 3) RegionNode(3);
   1.277 +      Node *phi = new (C, 3) PhiNode(r, Type::DOUBLE);
   1.278 +      r->init_req(1, _gvn.transform( new (C, 1) IfFalseNode(ifyeven)));
   1.279 +      r->init_req(2, _gvn.transform( new (C, 1) IfTrueNode(ifyeven)));
   1.280 +      phi->init_req(1, absxpowy);
   1.281 +      phi->init_req(2, negabsxpowy);
   1.282 +      signresult = _gvn.transform(phi);
   1.283 +      ylong_path = _gvn.transform(r);
   1.284 +      record_for_igvn(r);
   1.285 +    }
   1.286      // Set complex path fast result
   1.287 +    r->init_req(2, ylong_path);
   1.288      phi->init_req(2, signresult);
   1.289  
   1.290      static const jlong nan_bits = CONST64(0x7ff8000000000000);
   1.291 @@ -1689,27 +1763,10 @@
   1.292      result=_gvn.transform(phi);
   1.293    }
   1.294  
   1.295 -  //-------------------
   1.296 -  //result=(result.isNaN())? uncommon_trap():result;
   1.297 -  // Check: If isNaN() by checking result!=result? then go to Strict Math
   1.298 -  Node* cmpisnan = _gvn.transform(new (C, 3) CmpDNode(result,result));
   1.299 -  // Build the boolean node
   1.300 -  Node* bolisnum = _gvn.transform( new (C, 2) BoolNode(cmpisnan, BoolTest::eq) );
   1.301 -
   1.302 -  { BuildCutout unless(this, bolisnum, PROB_STATIC_FREQUENT);
   1.303 -    // End the current control-flow path
   1.304 -    push_pair(x);
   1.305 -    push_pair(y);
   1.306 -    // Math.pow intrinsic returned a NaN, which requires StrictMath.pow
   1.307 -    // to handle.  Recompile without intrinsifying Math.pow.
   1.308 -    uncommon_trap(Deoptimization::Reason_intrinsic,
   1.309 -                  Deoptimization::Action_make_not_entrant);
   1.310 -  }
   1.311 +  finish_pow_exp(result, x, y, OptoRuntime::Math_DD_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dpow), "POW");
   1.312  
   1.313    C->set_has_split_ifs(true); // Has chance for split-if optimization
   1.314  
   1.315 -  push_pair(result);
   1.316 -
   1.317    return true;
   1.318  }
   1.319  
     2.1 --- a/src/share/vm/opto/parse2.cpp	Thu Jul 12 14:26:25 2012 -0400
     2.2 +++ b/src/share/vm/opto/parse2.cpp	Thu Jul 12 14:19:15 2012 -0700
     2.3 @@ -1278,9 +1278,9 @@
     2.4         // or the narrowOop equivalent.
     2.5         const Type* obj_type = _gvn.type(obj);
     2.6         const TypeOopPtr* tboth = obj_type->join(con_type)->isa_oopptr();
     2.7 -       if (tboth != NULL && tboth != obj_type && tboth->higher_equal(obj_type)) {
     2.8 +       if (tboth != NULL && tboth->klass_is_exact() && tboth != obj_type &&
     2.9 +           tboth->higher_equal(obj_type)) {
    2.10            // obj has to be of the exact type Foo if the CmpP succeeds.
    2.11 -          assert(tboth->klass_is_exact(), "klass should be exact");
    2.12            int obj_in_map = map()->find_edge(obj);
    2.13            JVMState* jvms = this->jvms();
    2.14            if (obj_in_map >= 0 &&
     3.1 --- a/src/share/vm/opto/subnode.cpp	Thu Jul 12 14:26:25 2012 -0400
     3.2 +++ b/src/share/vm/opto/subnode.cpp	Thu Jul 12 14:19:15 2012 -0700
     3.3 @@ -554,9 +554,7 @@
     3.4        return TypeInt::CC_GE;
     3.5      } else if (hi0 <= lo1) {
     3.6        // Check for special case in Hashtable::get.  (See below.)
     3.7 -      if ((jint)lo0 >= 0 && (jint)lo1 >= 0 &&
     3.8 -          in(1)->Opcode() == Op_ModI &&
     3.9 -          in(1)->in(2) == in(2) )
    3.10 +      if ((jint)lo0 >= 0 && (jint)lo1 >= 0 && is_index_range_check())
    3.11          return TypeInt::CC_LT;
    3.12        return TypeInt::CC_LE;
    3.13      }
    3.14 @@ -567,13 +565,17 @@
    3.15    // to be positive.
    3.16    // (This is a gross hack, since the sub method never
    3.17    // looks at the structure of the node in any other case.)
    3.18 -  if ((jint)lo0 >= 0 && (jint)lo1 >= 0 &&
    3.19 -      in(1)->Opcode() == Op_ModI &&
    3.20 -      in(1)->in(2)->uncast() == in(2)->uncast())
    3.21 +  if ((jint)lo0 >= 0 && (jint)lo1 >= 0 && is_index_range_check())
    3.22      return TypeInt::CC_LT;
    3.23    return TypeInt::CC;                   // else use worst case results
    3.24  }
    3.25  
    3.26 +bool CmpUNode::is_index_range_check() const {
    3.27 +  // Check for the "(X ModI Y) CmpU Y" shape
    3.28 +  return (in(1)->Opcode() == Op_ModI &&
    3.29 +          in(1)->in(2)->eqv_uncast(in(2)));
    3.30 +}
    3.31 +
    3.32  //------------------------------Idealize---------------------------------------
    3.33  Node *CmpINode::Ideal( PhaseGVN *phase, bool can_reshape ) {
    3.34    if (phase->type(in(2))->higher_equal(TypeInt::ZERO)) {
     4.1 --- a/src/share/vm/opto/subnode.hpp	Thu Jul 12 14:26:25 2012 -0400
     4.2 +++ b/src/share/vm/opto/subnode.hpp	Thu Jul 12 14:19:15 2012 -0700
     4.3 @@ -158,6 +158,7 @@
     4.4    CmpUNode( Node *in1, Node *in2 ) : CmpNode(in1,in2) {}
     4.5    virtual int Opcode() const;
     4.6    virtual const Type *sub( const Type *, const Type * ) const;
     4.7 +  bool is_index_range_check() const;
     4.8  };
     4.9  
    4.10  //------------------------------CmpPNode---------------------------------------
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/compiler/7177917/Test7177917.java	Thu Jul 12 14:19:15 2012 -0700
     5.3 @@ -0,0 +1,142 @@
     5.4 +/*
     5.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + *
    5.26 + */
    5.27 +
    5.28 +/*
    5.29 + * Micro-benchmark for Math.pow() and Math.exp()
    5.30 + */
    5.31 +
    5.32 +import java.util.*;
    5.33 +
    5.34 +public class Test7177917 {
    5.35 +
    5.36 +  static double d;
    5.37 +
    5.38 +  static Random r = new Random(0);
    5.39 +
    5.40 +  static long  m_pow(double[][] values) {
    5.41 +    double res = 0;
    5.42 +    long start = System.nanoTime();
    5.43 +    for (int i = 0; i < values.length; i++) {
    5.44 +      res += Math.pow(values[i][0], values[i][1]);
    5.45 +    }
    5.46 +    long stop = System.nanoTime();
    5.47 +    d = res;
    5.48 +    return (stop - start) / 1000;
    5.49 +  }
    5.50 +
    5.51 +  static long  m_exp(double[] values) {
    5.52 +    double res = 0;
    5.53 +    long start = System.nanoTime();
    5.54 +    for (int i = 0; i < values.length; i++) {
    5.55 +      res += Math.exp(values[i]);
    5.56 +    }
    5.57 +    long stop = System.nanoTime();
    5.58 +    d = res;
    5.59 +    return (stop - start) / 1000;
    5.60 +  }
    5.61 +
    5.62 +  static double[][] pow_values(int nb) {
    5.63 +    double[][] res = new double[nb][2];
    5.64 +    for (int i = 0; i < nb; i++) {
    5.65 +      double ylogx = (1 + (r.nextDouble() * 2045)) - 1023; // 2045 rather than 2046 as a safety margin
    5.66 +      double x = Math.abs(Double.longBitsToDouble(r.nextLong()));
    5.67 +      while (x != x) {
    5.68 +        x = Math.abs(Double.longBitsToDouble(r.nextLong()));
    5.69 +      }
    5.70 +      double logx = Math.log(x) / Math.log(2);
    5.71 +      double y = ylogx / logx;
    5.72 +
    5.73 +      res[i][0] = x;
    5.74 +      res[i][1] = y;
    5.75 +    }
    5.76 +    return res;
    5.77 +  }
    5.78 +
    5.79 +  static double[] exp_values(int nb) {
    5.80 +    double[] res = new double[nb];
    5.81 +    for (int i = 0; i < nb; i++) {
    5.82 +      double ylogx = (1 + (r.nextDouble() * 2045)) - 1023; // 2045 rather than 2046 as a safety margin
    5.83 +      double x = Math.E;
    5.84 +      double logx = Math.log(x) / Math.log(2);
    5.85 +      double y = ylogx / logx;
    5.86 +      res[i] = y;
    5.87 +    }
    5.88 +    return res;
    5.89 +  }
    5.90 +
    5.91 +  static public void main(String[] args) {
    5.92 +    {
    5.93 +      // warmup
    5.94 +      double[][] warmup_values = pow_values(10);
    5.95 +      m_pow(warmup_values);
    5.96 +
    5.97 +      for (int i = 0; i < 20000; i++) {
    5.98 +        m_pow(warmup_values);
    5.99 +      }
   5.100 +      // test pow perf
   5.101 +      double[][] values = pow_values(1000000);
   5.102 +      System.out.println("==> POW " + m_pow(values));
   5.103 +
   5.104 +      // force uncommon trap
   5.105 +      double[][] nan_values = new double[1][2];
   5.106 +      nan_values[0][0] = Double.NaN;
   5.107 +      nan_values[0][1] = Double.NaN;
   5.108 +      m_pow(nan_values);
   5.109 +
   5.110 +      // force recompilation
   5.111 +      for (int i = 0; i < 20000; i++) {
   5.112 +        m_pow(warmup_values);
   5.113 +      }
   5.114 +
   5.115 +      // test pow perf again
   5.116 +      System.out.println("==> POW " + m_pow(values));
   5.117 +    }
   5.118 +    {
   5.119 +      // warmup
   5.120 +      double[] warmup_values = exp_values(10);
   5.121 +      m_exp(warmup_values);
   5.122 +
   5.123 +      for (int i = 0; i < 20000; i++) {
   5.124 +        m_exp(warmup_values);
   5.125 +      }
   5.126 +
   5.127 +      // test pow perf
   5.128 +      double[] values = exp_values(1000000);
   5.129 +      System.out.println("==> EXP " + m_exp(values));
   5.130 +
   5.131 +      // force uncommon trap
   5.132 +      double[] nan_values = new double[1];
   5.133 +      nan_values[0] = Double.NaN;
   5.134 +      m_exp(nan_values);
   5.135 +
   5.136 +      // force recompilation
   5.137 +      for (int i = 0; i < 20000; i++) {
   5.138 +        m_exp(warmup_values);
   5.139 +      }
   5.140 +
   5.141 +      // test pow perf again
   5.142 +      System.out.println("==> EXP " + m_exp(values));
   5.143 +    }
   5.144 +  }
   5.145 +}

mercurial