Thu, 12 Jul 2012 14:19:15 -0700
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 +}