--- old/src/hotspot/cpu/ppc/assembler_ppc.hpp 2018-11-16 05:31:08.214828022 -0600 +++ new/src/hotspot/cpu/ppc/assembler_ppc.hpp 2018-11-16 05:31:07.624847610 -0600 @@ -299,6 +299,8 @@ CMPI_OPCODE = (11u << OPCODE_SHIFT), CMPL_OPCODE = (31u << OPCODE_SHIFT | 32u << 1), CMPLI_OPCODE = (10u << OPCODE_SHIFT), + CMPRB_OPCODE = (31u << OPCODE_SHIFT | 192u << 1), + CMPEQB_OPCODE = (31u << OPCODE_SHIFT | 224u << 1), ISEL_OPCODE = (31u << OPCODE_SHIFT | 15u << 1), @@ -336,6 +338,7 @@ MTCRF_OPCODE = (31u << OPCODE_SHIFT | 144u << 1), MFCR_OPCODE = (31u << OPCODE_SHIFT | 19u << 1), MCRF_OPCODE = (19u << OPCODE_SHIFT | 0u << 1), + SETB_OPCODE = (31u << OPCODE_SHIFT | 128u << 1), // condition register logic instructions CRAND_OPCODE = (19u << OPCODE_SHIFT | 257u << 1), @@ -1441,6 +1444,9 @@ inline void cmplw( ConditionRegister crx, Register a, Register b); inline void cmpld( ConditionRegister crx, Register a, Register b); + inline void cmprb( ConditionRegister bf, int l, Register a, Register b); + inline void cmpeqb(ConditionRegister bf, Register a, Register b); + inline void isel( Register d, Register a, Register b, int bc); // Convenient version which takes: Condition register, Condition code and invert flag. Omit b to keep old value. inline void isel( Register d, ConditionRegister cr, Condition cc, bool inv, Register a, Register b = noreg); @@ -1636,6 +1642,7 @@ inline void mfcr( Register d); inline void mcrf( ConditionRegister crd, ConditionRegister cra); inline void mtcr( Register s); + inline void setb( Register d, ConditionRegister cra); // Special purpose registers // Exception Register --- old/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp 2018-11-16 05:31:09.334790838 -0600 +++ new/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp 2018-11-16 05:31:08.754810094 -0600 @@ -171,6 +171,8 @@ inline void Assembler::cmp( ConditionRegister f, int l, Register a, Register b) { emit_int32( CMP_OPCODE | bf(f) | l10(l) | ra(a) | rb(b)); } inline void Assembler::cmpli( ConditionRegister f, int l, Register a, int ui16) { emit_int32( CMPLI_OPCODE | bf(f) | l10(l) | ra(a) | uimm(ui16,16)); } inline void Assembler::cmpl( ConditionRegister f, int l, Register a, Register b) { emit_int32( CMPL_OPCODE | bf(f) | l10(l) | ra(a) | rb(b)); } +inline void Assembler::cmprb( ConditionRegister f, int l, Register a, Register b) { emit_int32( CMPRB_OPCODE | bf(f) | l10(l) | ra(a) | rb(b)); } +inline void Assembler::cmpeqb( ConditionRegister f, Register a, Register b) { emit_int32( CMPEQB_OPCODE| bf(f) | ra(a) | rb(b)); } // extended mnemonics of Compare Instructions inline void Assembler::cmpwi( ConditionRegister crx, Register a, int si16) { Assembler::cmpi( crx, 0, a, si16); } @@ -367,6 +369,8 @@ inline void Assembler::mcrf( ConditionRegister crd, ConditionRegister cra) { emit_int32(MCRF_OPCODE | bf(crd) | bfa(cra)); } inline void Assembler::mtcr( Register s) { Assembler::mtcrf(0xff, s); } +inline void Assembler::setb(Register d, ConditionRegister cra) + { emit_int32(SETB_OPCODE | rt(d) | bfa(cra)); } // Special purpose registers // Exception Register --- old/src/hotspot/cpu/ppc/ppc.ad 2018-11-16 05:31:10.414754982 -0600 +++ new/src/hotspot/cpu/ppc/ppc.ad 2018-11-16 05:31:09.824774570 -0600 @@ -2253,6 +2253,11 @@ return SuperwordUseVSX; case Op_PopCountVI: return (SuperwordUseVSX && UsePopCountInstruction); + case Op_DigitC: + case Op_LowerCaseC: + case Op_UpperCaseC: + case Op_WhitespaceC: + return VM_Version::has_darn(); } return true; // Per default match rules are supported. @@ -12396,6 +12401,130 @@ %} %} +// Compare char +instruct cmprb_DigitC_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{ + match(Set dst (DigitC src1)); + effect(TEMP src2, TEMP crx); + ins_cost(3 * DEFAULT_COST); + + format %{ "LI $src2, 0x3930\n\t" + "CMPRB $crx, 0, $src1, $src2\n\t" + "SETB $dst, $crx" %} + size(12); + ins_encode %{ + // 0x30: 0, 0x39: 9 + __ li($src2$$Register, 0x3930); + // compare src1 with ranges 0x30 to 0x39 + __ cmprb($crx$$CondRegister, 0, $src1$$Register, $src2$$Register); + __ setb($dst$$Register, $crx$$CondRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct cmprb_LowerCaseC_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{ + match(Set dst (LowerCaseC src1)); + effect(TEMP src2, TEMP crx); + ins_cost(12 * DEFAULT_COST); + + format %{ "LI $src2, 0x7A61\n\t" + "CMPRB $crx, 0, $src1, $src2\n\t" + "BGT $crx, done\n\t" + "LIS $src2, (signed short)0xF6DF\n\t" + "ORI $src2, $src2, 0xFFF8\n\t" + "CMPRB $crx, 1, $src1, $src2\n\t" + "BGT $crx, done\n\t" + "LIS $src2, (signed short)0xAAB5\n\t" + "ORI $src2, $src2, 0xBABA\n\t" + "INSRDI $src2, $src2, 32, 0\n\t" + "CMPEQB $crx, 1, $src1, $src2\n\t" + "SETB $dst, $crx" %} + + size(48); + ins_encode %{ + Label done; + // 0x61: a, 0x7A: z + __ li($src2$$Register, 0x7A61); + // compare src1 with ranges 0x61 to 0x7A + __ cmprb($crx$$CondRegister, 0, $src1$$Register, $src2$$Register); + __ bgt($crx$$CondRegister, done); + + // 0xDF: sharp s, 0xFF: y with diaeresis, 0xF7 is not the lower case + __ lis($src2$$Register, (signed short)0xF6DF); + __ ori($src2$$Register, $src2$$Register, 0xFFF8); + // compare src1 with ranges 0xDF to 0xF6 and 0xF8 to 0xFF + __ cmprb($crx$$CondRegister, 1, $src1$$Register, $src2$$Register); + __ bgt($crx$$CondRegister, done); + + // 0xAA: feminine ordinal indicator + // 0xB5: micro sign + // 0xBA: masculine ordinal indicator + __ lis($src2$$Register, (signed short)0xAAB5); + __ ori($src2$$Register, $src2$$Register, 0xBABA); + __ insrdi($src2$$Register, $src2$$Register, 32, 0); + // compare src1 with 0xAA, 0xB5, and 0xBA + __ cmpeqb($crx$$CondRegister, $src1$$Register, $src2$$Register); + + __ bind(done); + __ setb($dst$$Register, $crx$$CondRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct cmprb_UpperCaseC_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{ + match(Set dst (UpperCaseC src1)); + effect(TEMP src2, TEMP crx); + ins_cost(7 * DEFAULT_COST); + + format %{ "LI $src2, 0x5A41\n\t" + "CMPRB $crx, 0, $src1, $src2\n\t" + "BGT $crx, done\n\t" + "LIS $src2, (signed short)0xD6C0\n\t" + "ORI $src2, $src2, 0xDED8\n\t" + "CMPRB $crx, 1, $src1, $src2\n\t" + "SETB $dst, $crx" %} + + size(28); + ins_encode %{ + Label done; + // 0x41: A, 0x5A: Z + __ li($src2$$Register, 0x5A41); + // compare src1 with a range 0x41 to 0x5A + __ cmprb($crx$$CondRegister, 0, $src1$$Register, $src2$$Register); + __ bgt($crx$$CondRegister, done); + + // 0xC0: a with grave, 0xDE: thorn, 0xD7 is not the upper case + __ lis($src2$$Register, (signed short)0xD6C0); + __ ori($src2$$Register, $src2$$Register, 0xDED8); + // compare src1 with ranges 0xC0 to 0xD6 and 0xD8 to 0xDE + __ cmprb($crx$$CondRegister, 1, $src1$$Register, $src2$$Register); + + __ bind(done); + __ setb($dst$$Register, $crx$$CondRegister); + %} + ins_pipe(pipe_class_default); +%} + +instruct cmprb_WhitespaceC_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsReg crx) %{ + match(Set dst (WhitespaceC src1)); + effect(TEMP src2, TEMP crx); + ins_cost(4 * DEFAULT_COST); + + format %{ "LI $src2, 0x0D09\n\t" + "ADDIS $src2, 0x201C\n\t" + "CMPRB $crx, 1, $src1, $src2\n\t" + "SETB $dst, $crx" %} + size(16); + ins_encode %{ + // 0x09 to 0x0D, 0x1C to 0x20 + __ li($src2$$Register, 0x0D09); + __ addis($src2$$Register, $src2$$Register, 0x0201C); + // compare src with ranges 0x09 to 0x0D and 0x1C to 0x20 + __ cmprb($crx$$CondRegister, 1, $src1$$Register, $src2$$Register); + __ setb($dst$$Register, $crx$$CondRegister); + %} + ins_pipe(pipe_class_default); +%} + //----------Branches--------------------------------------------------------- // Jump --- old/src/hotspot/share/classfile/vmSymbols.cpp 2018-11-16 05:31:11.864706842 -0600 +++ new/src/hotspot/share/classfile/vmSymbols.cpp 2018-11-16 05:31:11.274726430 -0600 @@ -380,6 +380,11 @@ case vmIntrinsics::_fmaD: case vmIntrinsics::_fmaF: return true; + case vmIntrinsics::_isDigit_c: + case vmIntrinsics::_isLowerCase_c: + case vmIntrinsics::_isUpperCase_c: + case vmIntrinsics::_isWhitespace_c: + return true; default: return false; } --- old/src/hotspot/share/classfile/vmSymbols.hpp 2018-11-16 05:31:12.954670654 -0600 +++ new/src/hotspot/share/classfile/vmSymbols.hpp 2018-11-16 05:31:12.364690242 -0600 @@ -1358,6 +1358,15 @@ do_name( getAndSetReference_name, "getAndSetReference") \ do_signature(getAndSetReference_signature, "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;" ) \ \ + do_intrinsic(_isDigit_c, java_lang_Character, isDigit_name, int_bool_signature, F_S) \ + do_name( isDigit_name, "isDigit") \ + do_intrinsic(_isLowerCase_c, java_lang_Character, isLowerCase_name, int_bool_signature, F_S) \ + do_name( isLowerCase_name, "isLowerCase") \ + do_intrinsic(_isUpperCase_c, java_lang_Character, isUpperCase_name, int_bool_signature, F_S) \ + do_name( isUpperCase_name, "isUpperCase") \ + do_intrinsic(_isWhitespace_c, java_lang_Character, isWhitespace_name, int_bool_signature, F_S) \ + do_name( isWhitespace_name, "isWhitespace") \ + \ /* (2) Bytecode intrinsics */ \ \ do_intrinsic(_park, jdk_internal_misc_Unsafe, park_name, park_signature, F_R) \ @@ -1543,7 +1552,7 @@ #undef VM_INTRINSIC_ENUM ID_LIMIT, - LAST_COMPILER_INLINE = _getAndSetReference, + LAST_COMPILER_INLINE = _isWhitespace_c, FIRST_MH_SIG_POLY = _invokeGeneric, FIRST_MH_STATIC = _linkToVirtual, LAST_MH_SIG_POLY = _linkToInterface, --- old/src/hotspot/share/opto/c2compiler.cpp 2018-11-16 05:31:14.044634466 -0600 +++ new/src/hotspot/share/opto/c2compiler.cpp 2018-11-16 05:31:13.454654054 -0600 @@ -428,6 +428,18 @@ case vmIntrinsics::_fmaF: if (!UseFMA || !Matcher::match_rule_supported(Op_FmaF)) return false; break; + case vmIntrinsics::_isDigit_c: + if (!Matcher::match_rule_supported(Op_DigitC)) return false; + break; + case vmIntrinsics::_isLowerCase_c: + if (!Matcher::match_rule_supported(Op_LowerCaseC)) return false; + break; + case vmIntrinsics::_isUpperCase_c: + if (!Matcher::match_rule_supported(Op_UpperCaseC)) return false; + break; + case vmIntrinsics::_isWhitespace_c: + if (!Matcher::match_rule_supported(Op_WhitespaceC)) return false; + break; case vmIntrinsics::_hashCode: case vmIntrinsics::_identityHashCode: case vmIntrinsics::_getClass: --- old/src/hotspot/share/opto/classes.hpp 2018-11-16 05:31:15.114598942 -0600 +++ new/src/hotspot/share/opto/classes.hpp 2018-11-16 05:31:14.524618530 -0600 @@ -379,3 +379,7 @@ macro(ExtractL) macro(ExtractF) macro(ExtractD) +macro(DigitC) +macro(LowerCaseC) +macro(UpperCaseC) +macro(WhitespaceC) --- old/src/hotspot/share/opto/library_call.cpp 2018-11-16 05:31:16.164564082 -0600 +++ new/src/hotspot/share/opto/library_call.cpp 2018-11-16 05:31:15.574583670 -0600 @@ -324,6 +324,7 @@ bool inline_montgomerySquare(); bool inline_vectorizedMismatch(); bool inline_fma(vmIntrinsics::ID id); + bool inline_character_compare(vmIntrinsics::ID id); bool inline_profileBoolean(); bool inline_isCompileConstant(); @@ -867,6 +868,12 @@ case vmIntrinsics::_fmaF: return inline_fma(intrinsic_id()); + case vmIntrinsics::_isDigit_c: + case vmIntrinsics::_isLowerCase_c: + case vmIntrinsics::_isUpperCase_c: + case vmIntrinsics::_isWhitespace_c: + return inline_character_compare(intrinsic_id()); + default: // If you get here, it may be that someone has added a new intrinsic // to the list in vmSymbols.hpp without implementing it here. @@ -6555,6 +6562,72 @@ return true; } +bool LibraryCallKit::inline_character_compare(vmIntrinsics::ID id) { + Node* codePoint = argument(0); + Node* n = NULL; + switch (id) { + case vmIntrinsics::_isDigit_c : + if (!Matcher::match_rule_supported(Op_DigitC)) { + return false; + } + n = new DigitCNode(control(), codePoint); + break; + case vmIntrinsics::_isLowerCase_c : + if (!Matcher::match_rule_supported(Op_LowerCaseC)) { + return false; + } + n = new LowerCaseCNode(control(), codePoint); + break; + case vmIntrinsics::_isUpperCase_c : + if (!Matcher::match_rule_supported(Op_UpperCaseC)) { + return false; + } + n = new UpperCaseCNode(control(), codePoint); + break; + case vmIntrinsics::_isWhitespace_c : + if (!Matcher::match_rule_supported(Op_WhitespaceC)) { + return false; + } + n = new WhitespaceCNode(control(), codePoint); + break; + default: + fatal_unexpected_iid(id); + break; + } + + enum { _slow_path = 1, _fast_path, PATH_LIMIT }; + RegionNode* result_rgn = new RegionNode(PATH_LIMIT); + PhiNode* result_val = new PhiNode(result_rgn, TypeInt::CHAR); + + RegionNode* slow_region = new RegionNode(1); + record_for_igvn(slow_region); + + Node *ch = _gvn.transform(new URShiftINode(codePoint, intcon(8))); + Node* cmp_bit = _gvn.transform(new CmpINode(ch, intcon(0))); + Node* test = _gvn.transform(new BoolNode(cmp_bit, BoolTest::ne)); + + generate_slow_guard(test, slow_region); + + result_val->init_req(_fast_path, _gvn.transform(n)); + result_rgn->init_req(_fast_path, control()); + + set_control(_gvn.transform(slow_region)); + + if (!stopped()) { + PreserveJVMState pjvms(this); + CallJavaNode* slow_call = generate_method_call_static(id); + Node* slow_val = set_results_for_java_call(slow_call); + result_val->init_req(_slow_path, slow_val); + result_rgn->init_req(_slow_path, control()); + } else { + result_val->init_req(_slow_path, top()); + result_rgn->init_req(_slow_path, top()); + } + set_result(result_rgn, result_val); + + return true; +} + bool LibraryCallKit::inline_profileBoolean() { Node* counts = argument(1); const TypeAryPtr* ary = NULL; --- old/src/hotspot/share/opto/subnode.hpp 2018-11-16 05:31:17.424522250 -0600 +++ new/src/hotspot/share/opto/subnode.hpp 2018-11-16 05:31:16.834541838 -0600 @@ -502,4 +502,40 @@ virtual uint ideal_reg() const { return Op_RegI; } }; +//-------------------------------DigiCNode---------------------------------------- +class DigitCNode : public Node { +public: + DigitCNode(Node* control, Node *in1) : Node(control, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::CHAR; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------LowerCaseCNode------------------------------------ +class LowerCaseCNode : public Node { +public: + LowerCaseCNode(Node* control, Node *in1) : Node(control, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::CHAR; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------UpperCaseCNode------------------------------------ +class UpperCaseCNode : public Node { +public: + UpperCaseCNode(Node* control, Node *in1) : Node(control, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::CHAR; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------WhitespaceCNode----------------------------------- +class WhitespaceCNode : public Node { +public: + WhitespaceCNode(Node* control, Node *in1) : Node(control, in1) {} + virtual int Opcode() const; + const Type* bottom_type() const { return TypeInt::CHAR; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + #endif // SHARE_VM_OPTO_SUBNODE_HPP --- old/src/java.base/share/classes/java/lang/Character.java 2018-11-16 05:31:18.524485730 -0600 +++ new/src/java.base/share/classes/java/lang/Character.java 2018-11-16 05:31:17.934505318 -0600 @@ -8846,6 +8846,7 @@ * @see Character#getType(int) * @since 1.5 */ + @HotSpotIntrinsicCandidate public static boolean isLowerCase(int codePoint) { return getType(codePoint) == Character.LOWERCASE_LETTER || CharacterData.of(codePoint).isOtherLowercase(codePoint); @@ -8912,6 +8913,7 @@ * @see Character#getType(int) * @since 1.5 */ + @HotSpotIntrinsicCandidate public static boolean isUpperCase(int codePoint) { return getType(codePoint) == Character.UPPERCASE_LETTER || CharacterData.of(codePoint).isOtherUppercase(codePoint); @@ -9063,6 +9065,7 @@ * @see Character#getType(int) * @since 1.5 */ + @HotSpotIntrinsicCandidate public static boolean isDigit(int codePoint) { return getType(codePoint) == Character.DECIMAL_DIGIT_NUMBER; } @@ -10192,6 +10195,7 @@ * @see Character#isSpaceChar(int) * @since 1.5 */ + @HotSpotIntrinsicCandidate public static boolean isWhitespace(int codePoint) { return CharacterData.of(codePoint).isWhitespace(codePoint); }