# HG changeset patch # User rbackman # Date 1380263959 -7200 # Node ID c9ccd7b85f20c1fd728027155ed44d1d7c302277 # Parent 72b7e96c192218045f6eea0334a8a36513a4633c 8024924: Intrinsify java.lang.Math.addExact Reviewed-by: kvn, twisti diff -r 72b7e96c1922 -r c9ccd7b85f20 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Thu Sep 26 12:07:53 2013 -0700 +++ b/src/cpu/sparc/vm/sparc.ad Fri Sep 27 08:39:19 2013 +0200 @@ -2018,6 +2018,15 @@ return L7_REGP_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return G1_REGI_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + + %} @@ -4245,12 +4254,16 @@ greater_equal(0xB); less_equal(0x2); greater(0xA); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, unsigned operand cmpOpU() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "u" %} interface(COND_INTER) %{ @@ -4260,12 +4273,16 @@ greater_equal(0xD); less_equal(0x4); greater(0xC); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, pointer (same as unsigned) operand cmpOpP() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "p" %} interface(COND_INTER) %{ @@ -4275,12 +4292,16 @@ greater_equal(0xD); less_equal(0x4); greater(0xC); + overflow(0x7); + no_overflow(0xF); %} %} // Comparison Op, branch-register encoding operand cmpOp_reg() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ @@ -4290,12 +4311,16 @@ greater_equal(0x7); less_equal (0x2); greater (0x6); + overflow(0x7); // not supported + no_overflow(0xF); // not supported %} %} // Comparison Code, floating, unordered same as less operand cmpOpF() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "fl" %} interface(COND_INTER) %{ @@ -4305,12 +4330,17 @@ greater_equal(0xB); less_equal(0xE); greater(0x6); + + overflow(0x7); // not supported + no_overflow(0xF); // not supported %} %} // Used by long compare operand cmpOp_commute() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ @@ -4320,6 +4350,8 @@ greater_equal(0x2); less_equal(0xB); greater(0x3); + overflow(0x7); + no_overflow(0xF); %} %} diff -r 72b7e96c1922 -r c9ccd7b85f20 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Thu Sep 26 12:07:53 2013 -0700 +++ b/src/cpu/x86/vm/x86_32.ad Fri Sep 27 08:39:19 2013 +0200 @@ -1534,6 +1534,14 @@ return EBP_REG_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return EAX_REG_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + // Returns true if the high 32 bits of the value is known to be zero. bool is_operand_hi32_zero(Node* n) { int opc = n->Opcode(); @@ -4922,6 +4930,8 @@ greater_equal(0xD, "ge"); less_equal(0xE, "le"); greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4939,6 +4949,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4957,6 +4969,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4974,6 +4988,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4981,6 +4997,8 @@ operand cmpOp_fcmov() %{ match(Bool); + predicate(n->as_Bool()->_test._test != BoolTest::overflow && + n->as_Bool()->_test._test != BoolTest::no_overflow); format %{ "" %} interface(COND_INTER) %{ equal (0x0C8); @@ -4989,6 +5007,8 @@ greater_equal(0x1C0); less_equal (0x0D0); greater (0x1D0); + overflow(0x0, "o"); // not really supported by the instruction + no_overflow(0x1, "no"); // not really supported by the instruction %} %} @@ -5004,6 +5024,8 @@ greater_equal(0xE, "le"); less_equal(0xD, "ge"); greater(0xC, "l"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -7496,6 +7518,31 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- + +instruct addExactI_rReg(eAXRegI dst, rRegI src, eFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "ADD $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactI_rReg_imm(eAXRegI dst, immI src, eFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "ADD $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + // Integer Addition Instructions instruct addI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{ match(Set dst (AddI dst src)); diff -r 72b7e96c1922 -r c9ccd7b85f20 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Thu Sep 26 12:07:53 2013 -0700 +++ b/src/cpu/x86/vm/x86_64.ad Fri Sep 27 08:39:19 2013 +0200 @@ -1649,6 +1649,14 @@ return PTR_RBP_REG_mask(); } +const RegMask Matcher::mathExactI_result_proj_mask() { + return INT_RAX_REG_mask(); +} + +const RegMask Matcher::mathExactI_flags_proj_mask() { + return INT_FLAGS_mask(); +} + %} //----------ENCODING BLOCK----------------------------------------------------- @@ -4133,6 +4141,8 @@ greater_equal(0xD, "ge"); less_equal(0xE, "le"); greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4151,6 +4161,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4170,6 +4182,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -4187,6 +4201,8 @@ greater_equal(0x3, "nb"); less_equal(0x6, "be"); greater(0x7, "nbe"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); %} %} @@ -6922,6 +6938,30 @@ //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- +instruct addExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr) +%{ + match(AddExactI dst src); + effect(DEF cr); + + format %{ "addl $dst, $src\t# addExact int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/adlc/adlparse.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -3395,12 +3395,16 @@ char *greater_equal; char *less_equal; char *greater; + char *overflow; + char *no_overflow; const char *equal_format = "eq"; const char *not_equal_format = "ne"; const char *less_format = "lt"; const char *greater_equal_format = "ge"; const char *less_equal_format = "le"; const char *greater_format = "gt"; + const char *overflow_format = "o"; + const char *no_overflow_format = "no"; if (_curchar != '%') { parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); @@ -3437,6 +3441,12 @@ else if ( strcmp(field,"greater") == 0 ) { greater = interface_field_parse(&greater_format); } + else if ( strcmp(field,"overflow") == 0 ) { + overflow = interface_field_parse(&overflow_format); + } + else if ( strcmp(field,"no_overflow") == 0 ) { + no_overflow = interface_field_parse(&no_overflow_format); + } else { parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; @@ -3455,7 +3465,9 @@ less, less_format, greater_equal, greater_equal_format, less_equal, less_equal_format, - greater, greater_format); + greater, greater_format, + overflow, overflow_format, + no_overflow, no_overflow_format); return inter; } diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/adlc/archDesc.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -1192,6 +1192,8 @@ || strcmp(idealName,"CmpF") == 0 || strcmp(idealName,"FastLock") == 0 || strcmp(idealName,"FastUnlock") == 0 + || strcmp(idealName,"AddExactI") == 0 + || strcmp(idealName,"FlagsProj") == 0 || strcmp(idealName,"Bool") == 0 || strcmp(idealName,"Binary") == 0 ) { // Removed ConI from the must_clone list. CPUs that cannot use diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/adlc/formssel.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -2757,14 +2757,18 @@ const char* less, const char* less_format, const char* greater_equal, const char* greater_equal_format, const char* less_equal, const char* less_equal_format, - const char* greater, const char* greater_format) + const char* greater, const char* greater_format, + const char* overflow, const char* overflow_format, + const char* no_overflow, const char* no_overflow_format) : Interface("COND_INTER"), _equal(equal), _equal_format(equal_format), _not_equal(not_equal), _not_equal_format(not_equal_format), _less(less), _less_format(less_format), _greater_equal(greater_equal), _greater_equal_format(greater_equal_format), _less_equal(less_equal), _less_equal_format(less_equal_format), - _greater(greater), _greater_format(greater_format) { + _greater(greater), _greater_format(greater_format), + _overflow(overflow), _overflow_format(overflow_format), + _no_overflow(no_overflow), _no_overflow_format(no_overflow_format) { } CondInterface::~CondInterface() { // not owner of any character arrays @@ -2777,12 +2781,14 @@ // Write info to output files void CondInterface::output(FILE *fp) { Interface::output(fp); - if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal); - if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal); - if ( _less != NULL ) fprintf(fp," less == %s\n", _less); - if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal); - if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal); - if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater); + if ( _equal != NULL ) fprintf(fp," equal == %s\n", _equal); + if ( _not_equal != NULL ) fprintf(fp," not_equal == %s\n", _not_equal); + if ( _less != NULL ) fprintf(fp," less == %s\n", _less); + if ( _greater_equal != NULL ) fprintf(fp," greater_equal == %s\n", _greater_equal); + if ( _less_equal != NULL ) fprintf(fp," less_equal == %s\n", _less_equal); + if ( _greater != NULL ) fprintf(fp," greater == %s\n", _greater); + if ( _overflow != NULL ) fprintf(fp," overflow == %s\n", _overflow); + if ( _no_overflow != NULL ) fprintf(fp," no_overflow == %s\n", _no_overflow); // fprintf(fp,"\n"); } diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/adlc/formssel.hpp --- a/src/share/vm/adlc/formssel.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/adlc/formssel.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -798,12 +798,16 @@ const char *_greater_equal; const char *_less_equal; const char *_greater; + const char *_overflow; + const char *_no_overflow; const char *_equal_format; const char *_not_equal_format; const char *_less_format; const char *_greater_equal_format; const char *_less_equal_format; const char *_greater_format; + const char *_overflow_format; + const char *_no_overflow_format; // Public Methods CondInterface(const char* equal, const char* equal_format, @@ -811,7 +815,9 @@ const char* less, const char* less_format, const char* greater_equal, const char* greater_equal_format, const char* less_equal, const char* less_equal_format, - const char* greater, const char* greater_format); + const char* greater, const char* greater_format, + const char* overflow, const char* overflow_format, + const char* no_overflow, const char* no_overflow_format); ~CondInterface(); void dump(); diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/adlc/output_h.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -388,6 +388,8 @@ fprintf(fp, " else if( _c%d == BoolTest::ge ) st->print(\"%s\");\n",i,cond->_greater_equal_format); fprintf(fp, " else if( _c%d == BoolTest::lt ) st->print(\"%s\");\n",i,cond->_less_format); fprintf(fp, " else if( _c%d == BoolTest::gt ) st->print(\"%s\");\n",i,cond->_greater_format); + fprintf(fp, " else if( _c%d == BoolTest::overflow ) st->print(\"%s\");\n",i,cond->_overflow_format); + fprintf(fp, " else if( _c%d == BoolTest::no_overflow ) st->print(\"%s\");\n",i,cond->_no_overflow_format); } // Output code that dumps constant values, increment "i" if type is constant @@ -1208,6 +1210,8 @@ fprintf(fp," case BoolTest::ne : return not_equal();\n"); fprintf(fp," case BoolTest::le : return less_equal();\n"); fprintf(fp," case BoolTest::ge : return greater_equal();\n"); + fprintf(fp," case BoolTest::overflow : return overflow();\n"); + fprintf(fp," case BoolTest::no_overflow: return no_overflow();\n"); fprintf(fp," default : ShouldNotReachHere(); return 0;\n"); fprintf(fp," }\n"); fprintf(fp," };\n"); @@ -1373,6 +1377,14 @@ if( greater != NULL ) { define_oper_interface(fp, *oper, _globalNames, "greater", greater); } + const char *overflow = cInterface->_overflow; + if( overflow != NULL ) { + define_oper_interface(fp, *oper, _globalNames, "overflow", overflow); + } + const char *no_overflow = cInterface->_no_overflow; + if( no_overflow != NULL ) { + define_oper_interface(fp, *oper, _globalNames, "no_overflow", no_overflow); + } } // end Conditional Interface // Check if it is a Constant Interface else if (oper->_interface->is_ConstInterface() != NULL ) { diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -631,6 +631,10 @@ do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \ do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \ \ + do_name(addExact_name,"addExact") \ + do_name(subtractExact_name,"subtractExact") \ + do_name(multiplyExact_name,"multiplyExact") \ + \ do_intrinsic(_dabs, java_lang_Math, abs_name, double_double_signature, F_S) \ do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \ do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \ @@ -643,6 +647,7 @@ do_intrinsic(_dexp, java_lang_Math, exp_name, double_double_signature, F_S) \ do_intrinsic(_min, java_lang_Math, min_name, int2_int_signature, F_S) \ do_intrinsic(_max, java_lang_Math, max_name, int2_int_signature, F_S) \ + do_intrinsic(_addExact, java_lang_Math, addExact_name, int2_int_signature, F_S) \ \ do_intrinsic(_floatToRawIntBits, java_lang_Float, floatToRawIntBits_name, float_int_signature, F_S) \ do_name( floatToRawIntBits_name, "floatToRawIntBits") \ diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/c2_globals.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -636,7 +636,9 @@ \ diagnostic(bool, OptimizeExpensiveOps, true, \ "Find best control for expensive operations") \ - + \ + product(bool, UseMathExactIntrinsics, true, \ + "Enables intrinsification of various java.lang.Math funcitons") C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/classes.cpp --- a/src/share/vm/opto/classes.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/classes.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -32,6 +32,7 @@ #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/multnode.hpp" #include "opto/node.hpp" diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/classes.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -29,6 +29,7 @@ macro(AbsF) macro(AbsI) macro(AddD) +macro(AddExactI) macro(AddF) macro(AddI) macro(AddL) @@ -133,6 +134,7 @@ macro(ExpD) macro(FastLock) macro(FastUnlock) +macro(FlagsProj) macro(Goto) macro(Halt) macro(If) @@ -167,6 +169,7 @@ macro(LoopLimit) macro(Mach) macro(MachProj) +macro(MathExact) macro(MaxI) macro(MemBarAcquire) macro(MemBarAcquireLock) diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/ifnode.cpp --- a/src/share/vm/opto/ifnode.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/ifnode.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -76,6 +76,7 @@ if( !i1->is_Bool() ) return NULL; BoolNode *b = i1->as_Bool(); Node *cmp = b->in(1); + if( cmp->is_FlagsProj() ) return NULL; if( !cmp->is_Cmp() ) return NULL; i1 = cmp->in(1); if( i1 == NULL || !i1->is_Phi() ) return NULL; diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/lcm.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -472,6 +472,13 @@ break; } + // For nodes that produce a FlagsProj, make the node adjacent to the + // use of the FlagsProj + if (use->is_FlagsProj() && get_block_for_node(use) == block) { + found_machif = true; + break; + } + // More than this instruction pending for successor to be ready, // don't choose this if other opportunities are ready if (ready_cnt.at(use->_idx) > 1) diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/library_call.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -32,6 +32,7 @@ #include "opto/callGenerator.hpp" #include "opto/cfgnode.hpp" #include "opto/idealKit.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" @@ -199,6 +200,8 @@ bool inline_math_native(vmIntrinsics::ID id); bool inline_trig(vmIntrinsics::ID id); bool inline_math(vmIntrinsics::ID id); + bool inline_math_mathExact(Node* math); + bool inline_math_addExact(); bool inline_exp(); bool inline_pow(); void finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); @@ -498,6 +501,15 @@ if (!UseCRC32Intrinsics) return NULL; break; + case vmIntrinsics::_addExact: + if (!Matcher::match_rule_supported(Op_AddExactI)) { + return NULL; + } + if (!UseMathExactIntrinsics) { + return NULL; + } + break; + default: assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); @@ -668,6 +680,8 @@ case vmIntrinsics::_min: case vmIntrinsics::_max: return inline_min_max(intrinsic_id()); + case vmIntrinsics::_addExact: return inline_math_addExact(); + case vmIntrinsics::_arraycopy: return inline_arraycopy(); case vmIntrinsics::_compareTo: return inline_string_compareTo(); @@ -1911,6 +1925,45 @@ return true; } +bool LibraryCallKit::inline_math_mathExact(Node* math) { + Node* result = _gvn.transform( new(C) ProjNode(math, MathExactNode::result_proj_node)); + Node* flags = _gvn.transform( new(C) FlagsProjNode(math, MathExactNode::flags_proj_node)); + + Node* bol = _gvn.transform( new (C) BoolNode(flags, BoolTest::overflow) ); + IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); + Node* fast_path = _gvn.transform( new (C) IfFalseNode(check)); + Node* slow_path = _gvn.transform( new (C) IfTrueNode(check) ); + + { + PreserveJVMState pjvms(this); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + set_control(slow_path); + set_i_o(i_o()); + + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + } + + set_control(fast_path); + set_result(result); + return true; +} + +bool LibraryCallKit::inline_math_addExact() { + Node* arg1 = argument(0); + Node* arg2 = argument(1); + + Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) ); + if (add->Opcode() == Op_AddExactI) { + return inline_math_mathExact(add); + } else { + set_result(add); + } + return true; +} + Node* LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) { // These are the candidate return value: diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/loopTransform.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -776,6 +776,9 @@ continue; // not RC Node *cmp = bol->in(1); + if (cmp->is_FlagsProj()) { + continue; + } Node *rc_exp = cmp->in(1); Node *limit = cmp->in(2); diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/loopopts.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -2355,7 +2355,8 @@ opc == Op_Catch || opc == Op_CatchProj || opc == Op_Jump || - opc == Op_JumpProj) { + opc == Op_JumpProj || + opc == Op_FlagsProj) { #if !defined(PRODUCT) if (TracePartialPeeling) { tty->print_cr("\nExit control too complex: lp: %d", head->_idx); diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/matcher.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -1964,6 +1964,7 @@ case Op_Catch: case Op_CatchProj: case Op_CProj: + case Op_FlagsProj: case Op_JumpProj: case Op_JProj: case Op_NeverBranch: diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/matcher.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -337,6 +337,9 @@ // Register for MODL projection of divmodL static RegMask modL_proj_mask(); + static const RegMask mathExactI_result_proj_mask(); + static const RegMask mathExactI_flags_proj_mask(); + // Use hardware DIV instruction when it is faster than // a code which use multiply for division by constant. static bool use_asm_for_ldiv_by_con( jlong divisor ); diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/mathexactnode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/mathexactnode.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.inline.hpp" +#include "opto/addnode.hpp" +#include "opto/machnode.hpp" +#include "opto/mathexactnode.hpp" +#include "opto/matcher.hpp" +#include "opto/subnode.hpp" + +MathExactNode::MathExactNode(Node* ctrl, Node* n1, Node* n2) : MultiNode(3) { + init_req(0, ctrl); + init_req(1, n1); + init_req(2, n2); +} + +Node* AddExactINode::match(const ProjNode* proj, const Matcher* m) { + uint ideal_reg = proj->ideal_reg(); + RegMask rm; + if (proj->_con == result_proj_node) { + rm = m->mathExactI_result_proj_mask(); + } else { + assert(proj->_con == flags_proj_node, "must be result or flags"); + assert(ideal_reg == Op_RegFlags, "sanity"); + rm = m->mathExactI_flags_proj_mask(); + } + return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg); +} + +// If the MathExactNode won't overflow we have to replace the +// FlagsProjNode and ProjNode that is generated by the MathExactNode +Node* MathExactNode::no_overflow(PhaseGVN *phase, Node* new_result) { + PhaseIterGVN *igvn = phase->is_IterGVN(); + if (igvn) { + ProjNode* result = result_node(); + ProjNode* flags = flags_node(); + + if (result != NULL) { + igvn->replace_node(result, new_result); + } + + if (flags != NULL) { + BoolNode* bolnode = (BoolNode *) flags->unique_out(); + switch (bolnode->_test._test) { + case BoolTest::overflow: + // if the check is for overflow - never taken + igvn->replace_node(bolnode, phase->intcon(0)); + break; + case BoolTest::no_overflow: + // if the check is for no overflow - always taken + igvn->replace_node(bolnode, phase->intcon(1)); + break; + default: + fatal("Unexpected value of BoolTest"); + break; + } + flags->del_req(0); + } + } + return new_result; +} + +Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node *arg1 = in(1); + Node *arg2 = in(2); + + const Type* type1 = phase->type(arg1); + const Type* type2 = phase->type(arg2); + + if (type1 != Type::TOP && type1->singleton() && + type2 != Type::TOP && type2->singleton()) { + jint val1 = arg1->get_int(); + jint val2 = arg2->get_int(); + jint result = val1 + val2; + // Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result + if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) { + Node* con_result = ConINode::make(phase->C, result); + return no_overflow(phase, con_result); + } + return NULL; + } + + if (type1 == TypeInt::ZERO) { // (Add 0 x) == x + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2 == TypeInt::ZERO) { // (Add x 0) == x + Node* add_result = new (phase->C) AddINode(arg1, arg2); + return no_overflow(phase, add_result); + } + + if (type2->singleton()) { + return NULL; // no change - keep constant on the right + } + + if (type1->singleton()) { + // Make it x + Constant - move constant to the right + swap_edges(1, 2); + return this; + } + + if (arg2->is_Load()) { + return NULL; // no change - keep load on the right + } + + if (arg1->is_Load()) { + // Make it x + Load - move load to the right + swap_edges(1, 2); + return this; + } + + if (arg1->_idx > arg2->_idx) { + // Sort the edges + swap_edges(1, 2); + return this; + } + + return NULL; +} + diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/mathexactnode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/mathexactnode.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OPTO_MATHEXACTNODE_HPP +#define SHARE_VM_OPTO_MATHEXACTNODE_HPP + +#include "opto/multnode.hpp" +#include "opto/node.hpp" +#include "opto/type.hpp" + +class Node; + +class PhaseGVN; +class PhaseTransform; + +class MathExactNode : public MultiNode { +public: + MathExactNode(Node* ctrl, Node* in1, Node* in2); + enum { + result_proj_node = 0, + flags_proj_node = 1 + }; + virtual int Opcode() const; + virtual Node* Identity(PhaseTransform* phase) { return this; } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) { return NULL; } + virtual const Type* Value(PhaseTransform* phase) const { return bottom_type(); } + virtual uint hash() const { return Node::hash(); } + virtual bool is_CFG() const { return false; } + virtual uint ideal_reg() const { return NotAMachineReg; } + + ProjNode* result_node() { return proj_out(result_proj_node); } + ProjNode* flags_node() { return proj_out(flags_proj_node); } +protected: + Node* no_overflow(PhaseGVN *phase, Node* new_result); +}; + +class AddExactINode : public MathExactNode { +public: + AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {} + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; } + virtual Node* match(const ProjNode* proj, const Matcher* m); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +class FlagsProjNode : public ProjNode { +public: + FlagsProjNode(Node* src, uint con) : ProjNode(src, con) { + init_class_id(Class_FlagsProj); + } + + virtual int Opcode() const; + virtual bool is_CFG() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::CC; } + virtual uint ideal_reg() const { return Op_RegFlags; } +}; + + +#endif + diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/multnode.cpp --- a/src/share/vm/opto/multnode.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/multnode.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "opto/callnode.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/multnode.hpp" #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" @@ -46,15 +47,21 @@ assert(Opcode() != Op_If || outcnt() == 2, "bad if #1"); for( DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++ ) { Node *p = fast_out(i); - if( !p->is_Proj() ) { + if (p->is_Proj()) { + ProjNode *proj = p->as_Proj(); + if (proj->_con == which_proj) { + assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); + return proj; + } + } else if (p->is_FlagsProj()) { + FlagsProjNode *proj = p->as_FlagsProj(); + if (proj->_con == which_proj) { + return proj; + } + } else { assert(p == this && this->is_Start(), "else must be proj"); continue; } - ProjNode *proj = p->as_Proj(); - if( proj->_con == which_proj ) { - assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); - return proj; - } } return NULL; } diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/node.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -69,6 +69,7 @@ class EncodePKlassNode; class FastLockNode; class FastUnlockNode; +class FlagsProjNode; class IfNode; class IfFalseNode; class IfTrueNode; @@ -623,6 +624,7 @@ DEFINE_CLASS_ID(Cmp, Sub, 0) DEFINE_CLASS_ID(FastLock, Cmp, 0) DEFINE_CLASS_ID(FastUnlock, Cmp, 1) + DEFINE_CLASS_ID(FlagsProj, Cmp, 2) DEFINE_CLASS_ID(MergeMem, Node, 7) DEFINE_CLASS_ID(Bool, Node, 8) @@ -726,6 +728,7 @@ DEFINE_CLASS_QUERY(EncodePKlass) DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) + DEFINE_CLASS_QUERY(FlagsProj) DEFINE_CLASS_QUERY(If) DEFINE_CLASS_QUERY(IfFalse) DEFINE_CLASS_QUERY(IfTrue) diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/subnode.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -1064,7 +1064,7 @@ // Print special per-node info #ifndef PRODUCT void BoolTest::dump_on(outputStream *st) const { - const char *msg[] = {"eq","gt","??","lt","ne","le","??","ge"}; + const char *msg[] = {"eq","gt","of","lt","ne","le","nof","ge"}; st->print(msg[_test]); } #endif @@ -1126,7 +1126,7 @@ Node *cmp = in(1); if( !cmp->is_Sub() ) return NULL; int cop = cmp->Opcode(); - if( cop == Op_FastLock || cop == Op_FastUnlock ) return NULL; + if( cop == Op_FastLock || cop == Op_FastUnlock || cop == Op_FlagsProj) return NULL; Node *cmp1 = cmp->in(1); Node *cmp2 = cmp->in(2); if( !cmp1 ) return NULL; diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/subnode.hpp --- a/src/share/vm/opto/subnode.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/subnode.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -263,16 +263,16 @@ // We pick the values as 3 bits; the low order 2 bits we compare against the // condition codes, the high bit flips the sense of the result. struct BoolTest VALUE_OBJ_CLASS_SPEC { - enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, illegal = 8 }; + enum mask { eq = 0, ne = 4, le = 5, ge = 7, lt = 3, gt = 1, overflow = 2, no_overflow = 6, illegal = 8 }; mask _test; BoolTest( mask btm ) : _test(btm) {} const Type *cc2logical( const Type *CC ) const; // Commute the test. I use a small table lookup. The table is created as // a simple char array where each element is the ASCII version of a 'mask' // enum from above. - mask commute( ) const { return mask("038147858"[_test]-'0'); } + mask commute( ) const { return mask("032147658"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } - bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le); } + bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } #ifndef PRODUCT void dump_on(outputStream *st) const; #endif diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/type.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -430,6 +430,11 @@ longpair[1] = TypeLong::LONG; TypeTuple::LONG_PAIR = TypeTuple::make(2, longpair); + const Type **intccpair = TypeTuple::fields(2); + intccpair[0] = TypeInt::INT; + intccpair[1] = TypeInt::CC; + TypeTuple::INT_CC_PAIR = TypeTuple::make(2, intccpair); + _const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM; _const_basic_type[T_NARROWKLASS] = Type::BOTTOM; _const_basic_type[T_BOOLEAN] = TypeInt::BOOL; @@ -1646,6 +1651,7 @@ const TypeTuple *TypeTuple::START_I2C; const TypeTuple *TypeTuple::INT_PAIR; const TypeTuple *TypeTuple::LONG_PAIR; +const TypeTuple *TypeTuple::INT_CC_PAIR; //------------------------------make------------------------------------------- diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/opto/type.hpp Fri Sep 27 08:39:19 2013 +0200 @@ -584,6 +584,7 @@ static const TypeTuple *START_I2C; static const TypeTuple *INT_PAIR; static const TypeTuple *LONG_PAIR; + static const TypeTuple *INT_CC_PAIR; #ifndef PRODUCT virtual void dump2( Dict &d, uint, outputStream *st ) const; // Specialized per-Type dumping #endif diff -r 72b7e96c1922 -r c9ccd7b85f20 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Sep 26 12:07:53 2013 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Sep 27 08:39:19 2013 +0200 @@ -176,6 +176,7 @@ #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" +#include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/parse.hpp" @@ -1927,6 +1928,9 @@ declare_c2_type(CmpF3Node, CmpFNode) \ declare_c2_type(CmpDNode, CmpNode) \ declare_c2_type(CmpD3Node, CmpDNode) \ + declare_c2_type(MathExactNode, MultiNode) \ + declare_c2_type(AddExactINode, MathExactNode) \ + declare_c2_type(FlagsProjNode, ProjNode) \ declare_c2_type(BoolNode, Node) \ declare_c2_type(AbsNode, Node) \ declare_c2_type(AbsINode, AbsNode) \ diff -r 72b7e96c1922 -r c9ccd7b85f20 test/compiler/intrinsics/mathexact/CondTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/CondTest.java Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile CondTest.java Verify.java + * @run main CondTest + * + */ + +import java.lang.ArithmeticException; + +public class CondTest { + public static int result = 0; + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + runTest(); + } + } + + public static void runTest() { + int i = 7; + while (java.lang.Math.addExact(i, result) < 89361) { + if ((java.lang.Math.addExact(i, i) & 1) == 1) { + i += 3; + } else if ((i & 5) == 4) { + i += 7; + } else if ((i & 0xf) == 6) { + i += 2; + } else { + i += 1; + } + result += 2; + } + } +} diff -r 72b7e96c1922 -r c9ccd7b85f20 test/compiler/intrinsics/mathexact/ConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/ConstantTest.java Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test constant addExact + * @compile ConstantTest.java Verify.java + * @run main ConstantTest + * + */ + +import java.lang.ArithmeticException; + +public class ConstantTest { + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + Verify.verify(5, 7); + Verify.verify(Integer.MAX_VALUE, 1); + Verify.verify(Integer.MIN_VALUE, -1); + Verify.verify(Integer.MAX_VALUE, -1); + Verify.verify(Integer.MIN_VALUE, 1); + Verify.verify(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2); + Verify.verify(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3); + } + } +} diff -r 72b7e96c1922 -r c9ccd7b85f20 test/compiler/intrinsics/mathexact/LoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/LoadTest.java Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile LoadTest.java Verify.java + * @run main LoadTest + * + */ + +import java.lang.ArithmeticException; + +public class LoadTest { + public static java.util.Random rnd = new java.util.Random(); + public static int[] values = new int[256]; + + public static void main(String[] args) { + for (int i = 0; i < values.length; ++i) { + values[i] = rnd.nextInt(); + } + + for (int i = 0; i < 50000; ++i) { + Verify.verify(values[i & 255], values[i & 255] - i); + Verify.verify(values[i & 255] + i, values[i & 255] - i); + Verify.verify(values[i & 255], values[i & 255]); + if ((i & 1) == 1 && i > 5) { + Verify.verify(values[i & 255] + i, values[i & 255] - i); + } else { + Verify.verify(values[i & 255] - i, values[i & 255] + i); + } + } + } +} diff -r 72b7e96c1922 -r c9ccd7b85f20 test/compiler/intrinsics/mathexact/LoopDependentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/LoopDependentTest.java Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile LoopDependentTest.java Verify.java + * @run main LoopDependentTest + * + */ + +import java.lang.ArithmeticException; + +public class LoopDependentTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void main(String[] args) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + for (int i = 0; i < 50000; ++i) { + Verify.verify(rnd1 + i, rnd2 + i); + Verify.verify(rnd1 + i, rnd2 + (i & 0xff)); + Verify.verify(rnd1 - i, rnd2 - (i & 0xff)); + Verify.verify(rnd1 + i + 1, rnd2 + i + 2); + Verify.verify(rnd1 + i * 2, rnd2 + i); + } + } +} diff -r 72b7e96c1922 -r c9ccd7b85f20 test/compiler/intrinsics/mathexact/NonConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/NonConstantTest.java Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8024924 + * @summary Test non constant addExact + * @compile NonConstantTest.java Verify.java + * @run main NonConstantTest + * + */ + +import java.lang.ArithmeticException; + +public class NonConstantTest { + public static java.util.Random rnd = new java.util.Random(); + + public static void main(String[] args) { + for (int i = 0; i < 50000; ++i) { + int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); + Verify.verify(rnd1, rnd2); + Verify.verify(rnd1, rnd2 + 1); + Verify.verify(rnd1 + 1, rnd2); + Verify.verify(rnd1 - 1, rnd2); + Verify.verify(rnd1, rnd2 - 1); + } + } +} diff -r 72b7e96c1922 -r c9ccd7b85f20 test/compiler/intrinsics/mathexact/Verify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/mathexact/Verify.java Fri Sep 27 08:39:19 2013 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class Verify { + public static String throwWord(boolean threw) { + return (threw ? "threw" : "didn't throw"); + } + + public static void verify(int a, int b) { + boolean exception1 = false, exception2 = false; + int result1 = 0, result2 = 0; + try { + result1 = testIntrinsic(a, b); + } catch (ArithmeticException e) { + exception1 = true; + } + try { + result2 = testNonIntrinsic(a, b); + } catch (ArithmeticException e) { + exception2 = true; + } + + if (exception1 != exception2) { + throw new RuntimeException("Intrinsic version " + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); + } + if (result1 != result2) { + throw new RuntimeException("Intrinsic version returned: " + a + " while NonIntrinsic version returned: " + b); + } + } + + public static int testIntrinsic(int a, int b) { + return java.lang.Math.addExact(a, b); + } + + public static int testNonIntrinsic(int a, int b) { + return safeAddExact(a, b); + } + + // Copied java.lang.Math.addExact to avoid intrinsification + public static int safeAddExact(int x, int y) { + int r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } +}