8286182: [BACKOUT] x86: Handle integral division overflow during parsing
8287035: [BACKOUT] PPC64: Handle integral division overflow during parsing Reviewed-by: mdoerr, thartmann
This commit is contained in:
parent
7b19226be2
commit
079312c835
src/hotspot
cpu
aarch64
arm
ppc
riscv
s390
x86
share
test
hotspot/jtreg/compiler
micro/org/openjdk/bench/java/lang
@ -2790,10 +2790,6 @@ bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Parse::do_one_bytecode_targeted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#define MOV_VOLATILE(REG, BASE, INDEX, SCALE, DISP, SCRATCH, INSN) \
|
||||
C2_MacroAssembler _masm(&cbuf); \
|
||||
{ \
|
||||
|
@ -1159,10 +1159,6 @@ bool maybe_far_call(const MachCallNode *n) {
|
||||
return !MacroAssembler::_reachable_from_cache(n->as_MachCall()->entry_point());
|
||||
}
|
||||
|
||||
bool Parse::do_one_bytecode_targeted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
//----------ENCODING BLOCK-----------------------------------------------------
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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"
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
#include "opto/parse.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
|
||||
bool Parse::do_one_bytecode_targeted() {
|
||||
switch (bc()) {
|
||||
case Bytecodes::_idiv: // fallthrough
|
||||
case Bytecodes::_irem: // fallthrough
|
||||
#ifdef _LP64
|
||||
case Bytecodes::_ldiv: // fallthrough
|
||||
case Bytecodes::_lrem:
|
||||
#endif
|
||||
do_divmod_fixup();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
@ -8848,10 +8848,26 @@ instruct mulL_reg_imm16(iRegLdst dst, iRegLsrc src1, immL16 src2) %{
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Integer Division, but not min_jint / -1
|
||||
instruct noOvfDivI_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
match(Set dst (NoOvfDivI src1 src2));
|
||||
ins_cost(3*DEFAULT_COST);
|
||||
// Integer Division with Immediate -1: Negate.
|
||||
instruct divI_reg_immIvalueMinus1(iRegIdst dst, iRegIsrc src1, immI_minus1 src2) %{
|
||||
match(Set dst (DivI src1 src2));
|
||||
ins_cost(DEFAULT_COST);
|
||||
|
||||
format %{ "NEG $dst, $src1 \t// /-1" %}
|
||||
size(4);
|
||||
ins_encode %{
|
||||
__ neg($dst$$Register, $src1$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Integer Division with constant, but not -1.
|
||||
// We should be able to improve this by checking the type of src2.
|
||||
// It might well be that src2 is known to be positive.
|
||||
instruct divI_reg_regnotMinus1(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
match(Set dst (DivI src1 src2));
|
||||
predicate(n->in(2)->find_int_con(-1) != -1); // src2 is a constant, but not -1
|
||||
ins_cost(2*DEFAULT_COST);
|
||||
|
||||
format %{ "DIVW $dst, $src1, $src2 \t// /not-1" %}
|
||||
size(4);
|
||||
@ -8861,10 +8877,56 @@ instruct noOvfDivI_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Long Division, but not min_jlong / -1
|
||||
instruct noOvfDivL_reg_reg(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
||||
match(Set dst (NoOvfDivL src1 src2));
|
||||
ins_cost(3*DEFAULT_COST);
|
||||
instruct cmovI_bne_negI_reg(iRegIdst dst, flagsRegSrc crx, iRegIsrc src1) %{
|
||||
effect(USE_DEF dst, USE src1, USE crx);
|
||||
predicate(false);
|
||||
|
||||
ins_variable_size_depending_on_alignment(true);
|
||||
|
||||
format %{ "CMOVE $dst, neg($src1), $crx" %}
|
||||
// Worst case is branch + move + stop, no stop without scheduler.
|
||||
size(8);
|
||||
ins_encode %{
|
||||
Label done;
|
||||
__ bne($crx$$CondRegister, done);
|
||||
__ neg($dst$$Register, $src1$$Register);
|
||||
__ bind(done);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Integer Division with Registers not containing constants.
|
||||
instruct divI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
match(Set dst (DivI src1 src2));
|
||||
ins_cost(10*DEFAULT_COST);
|
||||
|
||||
expand %{
|
||||
immI16 imm %{ (int)-1 %}
|
||||
flagsReg tmp1;
|
||||
cmpI_reg_imm16(tmp1, src2, imm); // check src2 == -1
|
||||
divI_reg_regnotMinus1(dst, src1, src2); // dst = src1 / src2
|
||||
cmovI_bne_negI_reg(dst, tmp1, src1); // cmove dst = neg(src1) if src2 == -1
|
||||
%}
|
||||
%}
|
||||
|
||||
// Long Division with Immediate -1: Negate.
|
||||
instruct divL_reg_immLvalueMinus1(iRegLdst dst, iRegLsrc src1, immL_minus1 src2) %{
|
||||
match(Set dst (DivL src1 src2));
|
||||
ins_cost(DEFAULT_COST);
|
||||
|
||||
format %{ "NEG $dst, $src1 \t// /-1, long" %}
|
||||
size(4);
|
||||
ins_encode %{
|
||||
__ neg($dst$$Register, $src1$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Long Division with constant, but not -1.
|
||||
instruct divL_reg_regnotMinus1(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
||||
match(Set dst (DivL src1 src2));
|
||||
predicate(n->in(2)->find_long_con(-1L) != -1L); // Src2 is a constant, but not -1.
|
||||
ins_cost(2*DEFAULT_COST);
|
||||
|
||||
format %{ "DIVD $dst, $src1, $src2 \t// /not-1, long" %}
|
||||
size(4);
|
||||
@ -8874,31 +8936,71 @@ instruct noOvfDivL_reg_reg(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Integer Remainder with registers.
|
||||
instruct modI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
match(Set dst (NoOvfModI src1 src2));
|
||||
ins_cost(5*DEFAULT_COST);
|
||||
instruct cmovL_bne_negL_reg(iRegLdst dst, flagsRegSrc crx, iRegLsrc src1) %{
|
||||
effect(USE_DEF dst, USE src1, USE crx);
|
||||
predicate(false);
|
||||
|
||||
ins_variable_size_depending_on_alignment(true);
|
||||
|
||||
format %{ "CMOVE $dst, neg($src1), $crx" %}
|
||||
// Worst case is branch + move + stop, no stop without scheduler.
|
||||
size(8);
|
||||
ins_encode %{
|
||||
Label done;
|
||||
__ bne($crx$$CondRegister, done);
|
||||
__ neg($dst$$Register, $src1$$Register);
|
||||
__ bind(done);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
// Long Division with Registers not containing constants.
|
||||
instruct divL_reg_reg_Ex(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
||||
match(Set dst (DivL src1 src2));
|
||||
ins_cost(10*DEFAULT_COST);
|
||||
|
||||
expand %{
|
||||
iRegIdst tmp1;
|
||||
immL16 imm %{ (int)-1 %}
|
||||
flagsReg tmp1;
|
||||
cmpL_reg_imm16(tmp1, src2, imm); // check src2 == -1
|
||||
divL_reg_regnotMinus1(dst, src1, src2); // dst = src1 / src2
|
||||
cmovL_bne_negL_reg(dst, tmp1, src1); // cmove dst = neg(src1) if src2 == -1
|
||||
%}
|
||||
%}
|
||||
|
||||
// Integer Remainder with registers.
|
||||
instruct modI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
||||
match(Set dst (ModI src1 src2));
|
||||
ins_cost(10*DEFAULT_COST);
|
||||
|
||||
expand %{
|
||||
immI16 imm %{ (int)-1 %}
|
||||
flagsReg tmp1;
|
||||
iRegIdst tmp2;
|
||||
noOvfDivI_reg_reg(tmp1, src1, src2);
|
||||
mulI_reg_reg(tmp2, src2, tmp1);
|
||||
subI_reg_reg(dst, src1, tmp2);
|
||||
iRegIdst tmp3;
|
||||
cmpI_reg_imm16(tmp1, src2, imm); // check src2 == -1
|
||||
divI_reg_regnotMinus1(tmp2, src1, src2); // tmp2 = src1 / src2
|
||||
cmovI_bne_negI_reg(tmp2, tmp1, src1); // cmove tmp2 = neg(src1) if src2 == -1
|
||||
mulI_reg_reg(tmp3, src2, tmp2); // tmp3 = src2 * tmp2
|
||||
subI_reg_reg(dst, src1, tmp3); // dst = src1 - tmp3
|
||||
%}
|
||||
%}
|
||||
|
||||
// Long Remainder with registers
|
||||
instruct modL_reg_reg_Ex(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
||||
match(Set dst (NoOvfModL src1 src2));
|
||||
ins_cost(5*DEFAULT_COST);
|
||||
match(Set dst (ModL src1 src2));
|
||||
ins_cost(10*DEFAULT_COST);
|
||||
|
||||
expand %{
|
||||
iRegLdst tmp1;
|
||||
immL16 imm %{ (int)-1 %}
|
||||
flagsReg tmp1;
|
||||
iRegLdst tmp2;
|
||||
noOvfDivL_reg_reg(tmp1, src1, src2);
|
||||
mulL_reg_reg(tmp2, src2, tmp1);
|
||||
subL_reg_reg(dst, src1, tmp2);
|
||||
iRegLdst tmp3;
|
||||
cmpL_reg_imm16(tmp1, src2, imm); // check src2 == -1
|
||||
divL_reg_regnotMinus1(tmp2, src1, src2); // tmp2 = src1 / src2
|
||||
cmovL_bne_negL_reg(tmp2, tmp1, src1); // cmove tmp2 = neg(src1) if src2 == -1
|
||||
mulL_reg_reg(tmp3, src2, tmp2); // tmp3 = src2 * tmp2
|
||||
subL_reg_reg(dst, src1, tmp3); // dst = src1 - tmp3
|
||||
%}
|
||||
%}
|
||||
|
||||
|
@ -2039,10 +2039,6 @@ bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack,
|
||||
return clone_base_plus_offset_address(m, mstack, address_visited);
|
||||
}
|
||||
|
||||
bool Parse::do_one_bytecode_targeted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
|
||||
|
@ -1693,10 +1693,6 @@ bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack,
|
||||
return clone_base_plus_offset_address(m, mstack, address_visited);
|
||||
}
|
||||
|
||||
bool Parse::do_one_bytecode_targeted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
%} // source
|
||||
|
||||
//----------ENCODING BLOCK-----------------------------------------------------
|
||||
|
@ -2235,13 +2235,6 @@ void Assembler::idivl(Register src) {
|
||||
emit_int16((unsigned char)0xF7, (0xF8 | encode));
|
||||
}
|
||||
|
||||
void Assembler::idivl(Address src) {
|
||||
InstructionMark im(this);
|
||||
prefix(src);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
emit_operand(as_Register(7), src);
|
||||
}
|
||||
|
||||
void Assembler::divl(Register src) { // Unsigned
|
||||
int encode = prefix_and_encode(src->encoding());
|
||||
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
||||
@ -12331,13 +12324,6 @@ void Assembler::idivq(Register src) {
|
||||
emit_int16((unsigned char)0xF7, (0xF8 | encode));
|
||||
}
|
||||
|
||||
void Assembler::idivq(Address src) {
|
||||
InstructionMark im(this);
|
||||
prefixq(src);
|
||||
emit_int8((unsigned char)0xF7);
|
||||
emit_operand(as_Register(7), src);
|
||||
}
|
||||
|
||||
void Assembler::divq(Register src) {
|
||||
int encode = prefixq_and_encode(src->encoding());
|
||||
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
||||
|
@ -1198,9 +1198,6 @@ private:
|
||||
void vpabsd(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void evpabsq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
|
||||
void divl(Register src);
|
||||
void divq(Register src);
|
||||
|
||||
// Divide Scalar Double-Precision Floating-Point Values
|
||||
void divsd(XMMRegister dst, Address src);
|
||||
void divsd(XMMRegister dst, XMMRegister src);
|
||||
@ -1369,9 +1366,12 @@ private:
|
||||
void hlt();
|
||||
|
||||
void idivl(Register src);
|
||||
void idivl(Address src);
|
||||
void divl(Register src); // Unsigned division
|
||||
|
||||
#ifdef _LP64
|
||||
void idivq(Register src);
|
||||
void idivq(Address src);
|
||||
void divq(Register src); // Unsigned division
|
||||
#endif
|
||||
|
||||
void imull(Register src);
|
||||
void imull(Register dst, Register src);
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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"
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
#include "opto/parse.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
|
||||
bool Parse::do_one_bytecode_targeted() {
|
||||
switch (bc()) {
|
||||
case Bytecodes::_idiv: // fallthrough
|
||||
case Bytecodes::_irem: // fallthrough
|
||||
#ifdef _LP64
|
||||
case Bytecodes::_ldiv: // fallthrough
|
||||
case Bytecodes::_lrem:
|
||||
#endif
|
||||
do_divmod_fixup();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
@ -1551,6 +1551,47 @@ encode %{
|
||||
emit_d32 ( cbuf, 0x0 ); // imm32==0x0
|
||||
%}
|
||||
|
||||
enc_class cdq_enc %{
|
||||
// Full implementation of Java idiv and irem; checks for
|
||||
// special case as described in JVM spec., p.243 & p.271.
|
||||
//
|
||||
// normal case special case
|
||||
//
|
||||
// input : rax,: dividend min_int
|
||||
// reg: divisor -1
|
||||
//
|
||||
// output: rax,: quotient (= rax, idiv reg) min_int
|
||||
// rdx: remainder (= rax, irem reg) 0
|
||||
//
|
||||
// Code sequnce:
|
||||
//
|
||||
// 81 F8 00 00 00 80 cmp rax,80000000h
|
||||
// 0F 85 0B 00 00 00 jne normal_case
|
||||
// 33 D2 xor rdx,edx
|
||||
// 83 F9 FF cmp rcx,0FFh
|
||||
// 0F 84 03 00 00 00 je done
|
||||
// normal_case:
|
||||
// 99 cdq
|
||||
// F7 F9 idiv rax,ecx
|
||||
// done:
|
||||
//
|
||||
emit_opcode(cbuf,0x81); emit_d8(cbuf,0xF8);
|
||||
emit_opcode(cbuf,0x00); emit_d8(cbuf,0x00);
|
||||
emit_opcode(cbuf,0x00); emit_d8(cbuf,0x80); // cmp rax,80000000h
|
||||
emit_opcode(cbuf,0x0F); emit_d8(cbuf,0x85);
|
||||
emit_opcode(cbuf,0x0B); emit_d8(cbuf,0x00);
|
||||
emit_opcode(cbuf,0x00); emit_d8(cbuf,0x00); // jne normal_case
|
||||
emit_opcode(cbuf,0x33); emit_d8(cbuf,0xD2); // xor rdx,edx
|
||||
emit_opcode(cbuf,0x83); emit_d8(cbuf,0xF9); emit_d8(cbuf,0xFF); // cmp rcx,0FFh
|
||||
emit_opcode(cbuf,0x0F); emit_d8(cbuf,0x84);
|
||||
emit_opcode(cbuf,0x03); emit_d8(cbuf,0x00);
|
||||
emit_opcode(cbuf,0x00); emit_d8(cbuf,0x00); // je done
|
||||
// normal_case:
|
||||
emit_opcode(cbuf,0x99); // cdq
|
||||
// idiv (note: must be emitted by the user of this rule)
|
||||
// normal:
|
||||
%}
|
||||
|
||||
// Dense encoding for older common ops
|
||||
enc_class Opc_plus(immI opcode, rRegI reg) %{
|
||||
emit_opcode(cbuf, $opcode$$constant + $reg$$reg);
|
||||
@ -7768,17 +7809,21 @@ instruct mulL_eReg_con(eADXRegL dst, immL_127 src, rRegI tmp, eFlagsReg cr) %{
|
||||
|
||||
// Integer DIV with Register
|
||||
instruct divI_eReg(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
|
||||
match(Set rax (NoOvfDivI rax div));
|
||||
match(Set rax (DivI rax div));
|
||||
effect(KILL rdx, KILL cr);
|
||||
size(3);
|
||||
ins_cost(500);
|
||||
format %{ "CDQ\n\t"
|
||||
"IDIV $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Register);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
size(26);
|
||||
ins_cost(30*100+10*100);
|
||||
format %{ "CMP EAX,0x80000000\n\t"
|
||||
"JNE,s normal\n\t"
|
||||
"XOR EDX,EDX\n\t"
|
||||
"CMP ECX,-1\n\t"
|
||||
"JE,s done\n"
|
||||
"normal: CDQ\n\t"
|
||||
"IDIV $div\n\t"
|
||||
"done:" %}
|
||||
opcode(0xF7, 0x7); /* Opcode F7 /7 */
|
||||
ins_encode( cdq_enc, OpcP, RegOpc(div) );
|
||||
ins_pipe( ialu_reg_reg_alu0 );
|
||||
%}
|
||||
|
||||
// Divide Register Long
|
||||
@ -7798,33 +7843,35 @@ instruct divL_eReg(eADXRegL dst, eRegL src1, eRegL src2) %{
|
||||
|
||||
// Integer DIVMOD with Register, both quotient and mod results
|
||||
instruct divModI_eReg_divmod(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
|
||||
match(NoOvfDivModI rax div);
|
||||
match(DivModI rax div);
|
||||
effect(KILL cr);
|
||||
size(3);
|
||||
ins_cost(500);
|
||||
format %{ "CDQ\n\t"
|
||||
"IDIV $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Register);
|
||||
%}
|
||||
size(26);
|
||||
ins_cost(30*100+10*100);
|
||||
format %{ "CMP EAX,0x80000000\n\t"
|
||||
"JNE,s normal\n\t"
|
||||
"XOR EDX,EDX\n\t"
|
||||
"CMP ECX,-1\n\t"
|
||||
"JE,s done\n"
|
||||
"normal: CDQ\n\t"
|
||||
"IDIV $div\n\t"
|
||||
"done:" %}
|
||||
opcode(0xF7, 0x7); /* Opcode F7 /7 */
|
||||
ins_encode( cdq_enc, OpcP, RegOpc(div) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
// Integer MOD with Register
|
||||
instruct modI_eReg(eDXRegI rdx, eAXRegI rax, eCXRegI div, eFlagsReg cr) %{
|
||||
match(Set rdx (NoOvfModI rax div));
|
||||
match(Set rdx (ModI rax div));
|
||||
effect(KILL rax, KILL cr);
|
||||
|
||||
size(3);
|
||||
ins_cost(500);
|
||||
size(26);
|
||||
ins_cost(300);
|
||||
format %{ "CDQ\n\t"
|
||||
"IDIV $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Register);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
opcode(0xF7, 0x7); /* Opcode F7 /7 */
|
||||
ins_encode( cdq_enc, OpcP, RegOpc(div) );
|
||||
ins_pipe( ialu_reg_reg_alu0 );
|
||||
%}
|
||||
|
||||
// Remainder Register Long
|
||||
|
@ -338,19 +338,11 @@ extern RegMask _FLOAT_REG_mask;
|
||||
|
||||
extern RegMask _STACK_OR_PTR_REG_mask;
|
||||
extern RegMask _STACK_OR_LONG_REG_mask;
|
||||
extern RegMask _STACK_OR_LONG_NO_RAX_RDX_REG_mask;
|
||||
extern RegMask _STACK_OR_INT_REG_mask;
|
||||
extern RegMask _STACK_OR_INT_NO_RAX_RDX_REG_mask;
|
||||
|
||||
inline const RegMask& STACK_OR_PTR_REG_mask() { return _STACK_OR_PTR_REG_mask; }
|
||||
inline const RegMask& STACK_OR_LONG_REG_mask() { return _STACK_OR_LONG_REG_mask; }
|
||||
inline const RegMask& STACK_OR_LONG_NO_RAX_RDX_REG_mask() {
|
||||
return _STACK_OR_LONG_NO_RAX_RDX_REG_mask;
|
||||
}
|
||||
inline const RegMask& STACK_OR_INT_REG_mask() { return _STACK_OR_INT_REG_mask; }
|
||||
inline const RegMask& STACK_OR_INT_NO_RAX_RDX_REG_mask() {
|
||||
return _STACK_OR_INT_NO_RAX_RDX_REG_mask;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@ -376,9 +368,7 @@ RegMask _INT_NO_RBP_R13_REG_mask;
|
||||
RegMask _FLOAT_REG_mask;
|
||||
RegMask _STACK_OR_PTR_REG_mask;
|
||||
RegMask _STACK_OR_LONG_REG_mask;
|
||||
RegMask _STACK_OR_LONG_NO_RAX_RDX_REG_mask;
|
||||
RegMask _STACK_OR_INT_REG_mask;
|
||||
RegMask _STACK_OR_INT_NO_RAX_RDX_REG_mask;
|
||||
|
||||
static bool need_r12_heapbase() {
|
||||
return UseCompressedOops;
|
||||
@ -439,9 +429,6 @@ void reg_mask_init() {
|
||||
_LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()));
|
||||
_LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()->next()));
|
||||
|
||||
_STACK_OR_LONG_NO_RAX_RDX_REG_mask = _LONG_NO_RAX_RDX_REG_mask;
|
||||
_STACK_OR_LONG_NO_RAX_RDX_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
|
||||
|
||||
_INT_REG_mask = _ALL_INT_REG_mask;
|
||||
if (PreserveFramePointer) {
|
||||
_INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
|
||||
@ -464,9 +451,6 @@ void reg_mask_init() {
|
||||
_INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
|
||||
_INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()));
|
||||
|
||||
_STACK_OR_INT_NO_RAX_RDX_REG_mask = _INT_NO_RAX_RDX_REG_mask;
|
||||
_STACK_OR_INT_NO_RAX_RDX_REG_mask.OR(STACK_OR_STACK_SLOTS_mask());
|
||||
|
||||
// _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc
|
||||
// from the float_reg_legacy/float_reg_evex register class.
|
||||
_FLOAT_REG_mask = VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask;
|
||||
@ -1917,6 +1901,123 @@ encode %{
|
||||
emit_rm(cbuf, 0x3, $dst$$reg & 7, $src$$reg & 7);
|
||||
%}
|
||||
|
||||
enc_class cdql_enc(no_rax_rdx_RegI div)
|
||||
%{
|
||||
// Full implementation of Java idiv and irem; checks for
|
||||
// special case as described in JVM spec., p.243 & p.271.
|
||||
//
|
||||
// normal case special case
|
||||
//
|
||||
// input : rax: dividend min_int
|
||||
// reg: divisor -1
|
||||
//
|
||||
// output: rax: quotient (= rax idiv reg) min_int
|
||||
// rdx: remainder (= rax irem reg) 0
|
||||
//
|
||||
// Code sequnce:
|
||||
//
|
||||
// 0: 3d 00 00 00 80 cmp $0x80000000,%eax
|
||||
// 5: 75 07/08 jne e <normal>
|
||||
// 7: 33 d2 xor %edx,%edx
|
||||
// [div >= 8 -> offset + 1]
|
||||
// [REX_B]
|
||||
// 9: 83 f9 ff cmp $0xffffffffffffffff,$div
|
||||
// c: 74 03/04 je 11 <done>
|
||||
// 000000000000000e <normal>:
|
||||
// e: 99 cltd
|
||||
// [div >= 8 -> offset + 1]
|
||||
// [REX_B]
|
||||
// f: f7 f9 idiv $div
|
||||
// 0000000000000011 <done>:
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Label normal;
|
||||
Label done;
|
||||
|
||||
// cmp $0x80000000,%eax
|
||||
__ cmpl(as_Register(RAX_enc), 0x80000000);
|
||||
|
||||
// jne e <normal>
|
||||
__ jccb(Assembler::notEqual, normal);
|
||||
|
||||
// xor %edx,%edx
|
||||
__ xorl(as_Register(RDX_enc), as_Register(RDX_enc));
|
||||
|
||||
// cmp $0xffffffffffffffff,%ecx
|
||||
__ cmpl($div$$Register, -1);
|
||||
|
||||
// je 11 <done>
|
||||
__ jccb(Assembler::equal, done);
|
||||
|
||||
// <normal>
|
||||
// cltd
|
||||
__ bind(normal);
|
||||
__ cdql();
|
||||
|
||||
// idivl
|
||||
// <done>
|
||||
__ idivl($div$$Register);
|
||||
__ bind(done);
|
||||
%}
|
||||
|
||||
enc_class cdqq_enc(no_rax_rdx_RegL div)
|
||||
%{
|
||||
// Full implementation of Java ldiv and lrem; checks for
|
||||
// special case as described in JVM spec., p.243 & p.271.
|
||||
//
|
||||
// normal case special case
|
||||
//
|
||||
// input : rax: dividend min_long
|
||||
// reg: divisor -1
|
||||
//
|
||||
// output: rax: quotient (= rax idiv reg) min_long
|
||||
// rdx: remainder (= rax irem reg) 0
|
||||
//
|
||||
// Code sequnce:
|
||||
//
|
||||
// 0: 48 ba 00 00 00 00 00 mov $0x8000000000000000,%rdx
|
||||
// 7: 00 00 80
|
||||
// a: 48 39 d0 cmp %rdx,%rax
|
||||
// d: 75 08 jne 17 <normal>
|
||||
// f: 33 d2 xor %edx,%edx
|
||||
// 11: 48 83 f9 ff cmp $0xffffffffffffffff,$div
|
||||
// 15: 74 05 je 1c <done>
|
||||
// 0000000000000017 <normal>:
|
||||
// 17: 48 99 cqto
|
||||
// 19: 48 f7 f9 idiv $div
|
||||
// 000000000000001c <done>:
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Label normal;
|
||||
Label done;
|
||||
|
||||
// mov $0x8000000000000000,%rdx
|
||||
__ mov64(as_Register(RDX_enc), 0x8000000000000000);
|
||||
|
||||
// cmp %rdx,%rax
|
||||
__ cmpq(as_Register(RAX_enc), as_Register(RDX_enc));
|
||||
|
||||
// jne 17 <normal>
|
||||
__ jccb(Assembler::notEqual, normal);
|
||||
|
||||
// xor %edx,%edx
|
||||
__ xorl(as_Register(RDX_enc), as_Register(RDX_enc));
|
||||
|
||||
// cmp $0xffffffffffffffff,$div
|
||||
__ cmpq($div$$Register, -1);
|
||||
|
||||
// je 1e <done>
|
||||
__ jccb(Assembler::equal, done);
|
||||
|
||||
// <normal>
|
||||
// cqto
|
||||
__ bind(normal);
|
||||
__ cdqq();
|
||||
|
||||
// idivq (note: must be emitted by the user of this rule)
|
||||
// <done>
|
||||
__ idivq($div$$Register);
|
||||
__ bind(done);
|
||||
%}
|
||||
|
||||
// Opcde enc_class for 8/32 bit immediate instructions with sign-extension
|
||||
enc_class OpcSE(immI imm)
|
||||
%{
|
||||
@ -8517,65 +8618,40 @@ instruct umulHiL_rReg(rdx_RegL dst, no_rax_RegL src, rax_RegL rax, rFlagsReg cr)
|
||||
instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rax (NoOvfDivI rax div));
|
||||
match(Set rax (DivI rax div));
|
||||
effect(KILL rdx, KILL cr);
|
||||
|
||||
ins_cost(500);
|
||||
format %{ "cdql\n\t"
|
||||
"idivl $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct divI_mem(rax_RegI rax, rdx_RegI rdx, memory div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rax (NoOvfDivI rax (LoadI div)));
|
||||
effect(KILL rdx, KILL cr);
|
||||
|
||||
ins_cost(575);
|
||||
format %{ "cdql\n\t"
|
||||
"idivl $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Address);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
ins_cost(30*100+10*100); // XXX
|
||||
format %{ "cmpl rax, 0x80000000\t# idiv\n\t"
|
||||
"jne,s normal\n\t"
|
||||
"xorl rdx, rdx\n\t"
|
||||
"cmpl $div, -1\n\t"
|
||||
"je,s done\n"
|
||||
"normal: cdql\n\t"
|
||||
"idivl $div\n"
|
||||
"done:" %}
|
||||
ins_encode(cdql_enc(div));
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct divL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rax (NoOvfDivL rax div));
|
||||
match(Set rax (DivL rax div));
|
||||
effect(KILL rdx, KILL cr);
|
||||
|
||||
ins_cost(500);
|
||||
format %{ "cdqq\n\t"
|
||||
"idivq $div" %}
|
||||
ins_encode %{
|
||||
__ cdqq();
|
||||
__ idivq($div$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct divL_mem(rax_RegL rax, rdx_RegL rdx, memory div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rax (NoOvfDivL rax (LoadL div)));
|
||||
effect(KILL rdx, KILL cr);
|
||||
|
||||
ins_cost(575);
|
||||
format %{ "cdqq\n\t"
|
||||
"idivq $div" %}
|
||||
ins_encode %{
|
||||
__ cdqq();
|
||||
__ idivq($div$$Address);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
ins_cost(30*100+10*100); // XXX
|
||||
format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t"
|
||||
"cmpq rax, rdx\n\t"
|
||||
"jne,s normal\n\t"
|
||||
"xorl rdx, rdx\n\t"
|
||||
"cmpq $div, -1\n\t"
|
||||
"je,s done\n"
|
||||
"normal: cdqq\n\t"
|
||||
"idivq $div\n"
|
||||
"done:" %}
|
||||
ins_encode(cdqq_enc(div));
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct udivI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, rFlagsReg cr)
|
||||
@ -8608,16 +8684,19 @@ instruct udivL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, rFlagsReg c
|
||||
instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(NoOvfDivModI rax div);
|
||||
match(DivModI rax div);
|
||||
effect(KILL cr);
|
||||
|
||||
ins_cost(500);
|
||||
format %{ "cdql\n\t"
|
||||
"idivl $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Register);
|
||||
%}
|
||||
ins_cost(30*100+10*100); // XXX
|
||||
format %{ "cmpl rax, 0x80000000\t# idiv\n\t"
|
||||
"jne,s normal\n\t"
|
||||
"xorl rdx, rdx\n\t"
|
||||
"cmpl $div, -1\n\t"
|
||||
"je,s done\n"
|
||||
"normal: cdql\n\t"
|
||||
"idivl $div\n"
|
||||
"done:" %}
|
||||
ins_encode(cdql_enc(div));
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -8625,16 +8704,20 @@ instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||
instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(NoOvfDivModL rax div);
|
||||
match(DivModL rax div);
|
||||
effect(KILL cr);
|
||||
|
||||
ins_cost(500);
|
||||
format %{ "cdqq\n\t"
|
||||
"idivq $div" %}
|
||||
ins_encode %{
|
||||
__ cdqq();
|
||||
__ idivq($div$$Register);
|
||||
%}
|
||||
ins_cost(30*100+10*100); // XXX
|
||||
format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t"
|
||||
"cmpq rax, rdx\n\t"
|
||||
"jne,s normal\n\t"
|
||||
"xorl rdx, rdx\n\t"
|
||||
"cmpq $div, -1\n\t"
|
||||
"je,s done\n"
|
||||
"normal: cdqq\n\t"
|
||||
"idivq $div\n"
|
||||
"done:" %}
|
||||
ins_encode(cdqq_enc(div));
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -8672,68 +8755,108 @@ instruct udivModL_rReg_divmod(rax_RegL rax, no_rax_rdx_RegL tmp, rdx_RegL rdx,
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
|
||||
//----------- DivL-By-Constant-Expansions--------------------------------------
|
||||
// DivI cases are handled by the compiler
|
||||
|
||||
// Magic constant, reciprocal of 10
|
||||
instruct loadConL_0x6666666666666667(rRegL dst)
|
||||
%{
|
||||
effect(DEF dst);
|
||||
|
||||
format %{ "movq $dst, #0x666666666666667\t# Used in div-by-10" %}
|
||||
ins_encode(load_immL(dst, 0x6666666666666667));
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct mul_hi(rdx_RegL dst, no_rax_RegL src, rax_RegL rax, rFlagsReg cr)
|
||||
%{
|
||||
effect(DEF dst, USE src, USE_KILL rax, KILL cr);
|
||||
|
||||
format %{ "imulq rdx:rax, rax, $src\t# Used in div-by-10" %}
|
||||
ins_encode %{
|
||||
__ imulq($src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct sarL_rReg_63(rRegL dst, rFlagsReg cr)
|
||||
%{
|
||||
effect(USE_DEF dst, KILL cr);
|
||||
|
||||
format %{ "sarq $dst, #63\t# Used in div-by-10" %}
|
||||
ins_encode %{
|
||||
__ sarq($dst$$Register, 63);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct sarL_rReg_2(rRegL dst, rFlagsReg cr)
|
||||
%{
|
||||
effect(USE_DEF dst, KILL cr);
|
||||
|
||||
format %{ "sarq $dst, #2\t# Used in div-by-10" %}
|
||||
ins_encode %{
|
||||
__ sarq($dst$$Register, 2);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct divL_10(rdx_RegL dst, no_rax_RegL src, immL10 div)
|
||||
%{
|
||||
match(Set dst (DivL src div));
|
||||
|
||||
ins_cost((5+8)*100);
|
||||
expand %{
|
||||
rax_RegL rax; // Killed temp
|
||||
rFlagsReg cr; // Killed
|
||||
loadConL_0x6666666666666667(rax); // movq rax, 0x6666666666666667
|
||||
mul_hi(dst, src, rax, cr); // mulq rdx:rax <= rax * $src
|
||||
sarL_rReg_63(src, cr); // sarq src, 63
|
||||
sarL_rReg_2(dst, cr); // sarq rdx, 2
|
||||
subL_rReg(dst, src, cr); // subl rdx, src
|
||||
%}
|
||||
%}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
instruct modI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rdx (NoOvfModI rax div));
|
||||
match(Set rdx (ModI rax div));
|
||||
effect(KILL rax, KILL cr);
|
||||
|
||||
ins_cost(500);
|
||||
format %{ "cdql\n\t"
|
||||
"idivl $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct modI_mem(rdx_RegI rdx, rax_RegI rax, memory div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rdx (NoOvfModI rax (LoadI div)));
|
||||
effect(KILL rax, KILL cr);
|
||||
|
||||
ins_cost(575);
|
||||
format %{ "cdql\n\t"
|
||||
"idivl $div" %}
|
||||
ins_encode %{
|
||||
__ cdql();
|
||||
__ idivl($div$$Address);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
ins_cost(300); // XXX
|
||||
format %{ "cmpl rax, 0x80000000\t# irem\n\t"
|
||||
"jne,s normal\n\t"
|
||||
"xorl rdx, rdx\n\t"
|
||||
"cmpl $div, -1\n\t"
|
||||
"je,s done\n"
|
||||
"normal: cdql\n\t"
|
||||
"idivl $div\n"
|
||||
"done:" %}
|
||||
ins_encode(cdql_enc(div));
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct modL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rdx (NoOvfModL rax div));
|
||||
match(Set rdx (ModL rax div));
|
||||
effect(KILL rax, KILL cr);
|
||||
|
||||
ins_cost(500);
|
||||
format %{ "cdqq\n\t"
|
||||
"idivq $div" %}
|
||||
ins_encode %{
|
||||
__ cdqq();
|
||||
__ idivq($div$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct modL_mem(rdx_RegL rdx, rax_RegL rax, memory div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
match(Set rdx (NoOvfModL rax (LoadL div)));
|
||||
effect(KILL rax, KILL cr);
|
||||
|
||||
ins_cost(575);
|
||||
format %{ "cdqq\n\t"
|
||||
"idivq $div" %}
|
||||
ins_encode %{
|
||||
__ cdqq();
|
||||
__ idivq($div$$Address);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
ins_cost(300); // XXX
|
||||
format %{ "movq rdx, 0x8000000000000000\t# lrem\n\t"
|
||||
"cmpq rax, rdx\n\t"
|
||||
"jne,s normal\n\t"
|
||||
"xorl rdx, rdx\n\t"
|
||||
"cmpq $div, -1\n\t"
|
||||
"je,s done\n"
|
||||
"normal: cdqq\n\t"
|
||||
"idivq $div\n"
|
||||
"done:" %}
|
||||
ins_encode(cdqq_enc(div));
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct umodI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, rFlagsReg cr)
|
||||
|
@ -226,7 +226,6 @@ int main(int argc, char *argv[])
|
||||
AD.addInclude(AD._CPP_file, "opto/intrinsicnode.hpp");
|
||||
AD.addInclude(AD._CPP_file, "opto/locknode.hpp");
|
||||
AD.addInclude(AD._CPP_file, "opto/opcodes.hpp");
|
||||
AD.addInclude(AD._CPP_file, "opto/parse.hpp");
|
||||
AD.addInclude(AD._CPP_file, "opto/regalloc.hpp");
|
||||
AD.addInclude(AD._CPP_file, "opto/regmask.hpp");
|
||||
AD.addInclude(AD._CPP_file, "opto/runtime.hpp");
|
||||
|
@ -161,15 +161,11 @@ macro(DivD)
|
||||
macro(DivF)
|
||||
macro(DivI)
|
||||
macro(DivL)
|
||||
macro(NoOvfDivI)
|
||||
macro(NoOvfDivL)
|
||||
macro(UDivI)
|
||||
macro(UDivL)
|
||||
macro(DivMod)
|
||||
macro(DivModI)
|
||||
macro(DivModL)
|
||||
macro(NoOvfDivModI)
|
||||
macro(NoOvfDivModL)
|
||||
macro(UDivModI)
|
||||
macro(UDivModL)
|
||||
macro(EncodeISOArray)
|
||||
@ -238,8 +234,6 @@ macro(ModD)
|
||||
macro(ModF)
|
||||
macro(ModI)
|
||||
macro(ModL)
|
||||
macro(NoOvfModI)
|
||||
macro(NoOvfModL)
|
||||
macro(UModI)
|
||||
macro(UModL)
|
||||
macro(MoveI2F)
|
||||
|
@ -3565,46 +3565,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_NoOvfModI:
|
||||
if (UseDivMod) {
|
||||
// Check if a%b and a/b both exist
|
||||
Node* d = n->find_similar(Op_NoOvfDivI);
|
||||
if (d) {
|
||||
// Replace them with a fused divmod if supported
|
||||
if (Matcher::has_match_rule(Op_NoOvfDivModI)) {
|
||||
NoOvfDivModINode* divmod = NoOvfDivModINode::make(n);
|
||||
d->subsume_by(divmod->div_proj(), this);
|
||||
n->subsume_by(divmod->mod_proj(), this);
|
||||
} else {
|
||||
// replace a%b with a-((a/b)*b)
|
||||
Node* mult = new MulINode(d, d->in(2));
|
||||
Node* sub = new SubINode(d->in(1), mult);
|
||||
n->subsume_by(sub, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_NoOvfModL:
|
||||
if (UseDivMod) {
|
||||
// Check if a%b and a/b both exist
|
||||
Node* d = n->find_similar(Op_NoOvfDivL);
|
||||
if (d) {
|
||||
// Replace them with a fused divmod if supported
|
||||
if (Matcher::has_match_rule(Op_NoOvfDivModL)) {
|
||||
NoOvfDivModLNode* divmod = NoOvfDivModLNode::make(n);
|
||||
d->subsume_by(divmod->div_proj(), this);
|
||||
n->subsume_by(divmod->mod_proj(), this);
|
||||
} else {
|
||||
// replace a%b with a-((a/b)*b)
|
||||
Node* mult = new MulLNode(d, d->in(2));
|
||||
Node* sub = new SubLNode(d->in(1), mult);
|
||||
n->subsume_by(sub, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_LoadVector:
|
||||
case Op_StoreVector:
|
||||
case Op_LoadVectorGather:
|
||||
|
@ -1466,27 +1466,3 @@ Node* UDivModLNode::match( const ProjNode *proj, const Matcher *match ) {
|
||||
}
|
||||
return new MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||
}
|
||||
|
||||
//------------------------------make------------------------------------------
|
||||
NoOvfDivModINode* NoOvfDivModINode::make(Node* div_or_mod) {
|
||||
Node* n = div_or_mod;
|
||||
assert(n->Opcode() == Op_NoOvfDivI || n->Opcode() == Op_NoOvfModI,
|
||||
"only div or mod input pattern accepted");
|
||||
|
||||
NoOvfDivModINode* divmod = new NoOvfDivModINode(n->in(0), n->in(1), n->in(2));
|
||||
Node* dproj = new ProjNode(divmod, DivModNode::div_proj_num);
|
||||
Node* mproj = new ProjNode(divmod, DivModNode::mod_proj_num);
|
||||
return divmod;
|
||||
}
|
||||
|
||||
//------------------------------make------------------------------------------
|
||||
NoOvfDivModLNode* NoOvfDivModLNode::make(Node* div_or_mod) {
|
||||
Node* n = div_or_mod;
|
||||
assert(n->Opcode() == Op_NoOvfDivL || n->Opcode() == Op_NoOvfModL,
|
||||
"only div or mod input pattern accepted");
|
||||
|
||||
NoOvfDivModLNode* divmod = new NoOvfDivModLNode(n->in(0), n->in(1), n->in(2));
|
||||
Node* dproj = new ProjNode(divmod, DivModNode::div_proj_num);
|
||||
Node* mproj = new ProjNode(divmod, DivModNode::mod_proj_num);
|
||||
return divmod;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
|
||||
//------------------------------UDivLNode--------------------------------------
|
||||
//------------------------------UDivLNode---------------------------------------
|
||||
// Unsigned long division
|
||||
class UDivLNode : public Node {
|
||||
public:
|
||||
@ -116,24 +116,6 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
|
||||
//---------------------------NoOvfDivINode-------------------------------------
|
||||
// Non-overflow integer division, UB when dividend == min_jint and divisor == -1
|
||||
// so user has to ensure this combination does not appear
|
||||
class NoOvfDivINode : public DivINode {
|
||||
public:
|
||||
NoOvfDivINode( Node *c, Node *dividend, Node *divisor ) : DivINode(c, dividend, divisor ) {}
|
||||
virtual int Opcode() const;
|
||||
};
|
||||
|
||||
//---------------------------NoOvfDivLNode-------------------------------------
|
||||
// Non-overflow long division, UB when dividend == min_jlong and divisor == -1
|
||||
// so user has to ensure this combination does not appear
|
||||
class NoOvfDivLNode : public DivLNode {
|
||||
public:
|
||||
NoOvfDivLNode( Node *c, Node *dividend, Node *divisor ) : DivLNode(c, dividend, divisor ) {}
|
||||
virtual int Opcode() const;
|
||||
};
|
||||
|
||||
//------------------------------ModINode---------------------------------------
|
||||
// Integer modulus
|
||||
class ModINode : public Node {
|
||||
@ -180,7 +162,7 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
};
|
||||
|
||||
//------------------------------UModINode--------------------------------------
|
||||
//------------------------------UModINode---------------------------------------
|
||||
// Unsigned integer modulus
|
||||
class UModINode : public Node {
|
||||
public:
|
||||
@ -191,7 +173,7 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
|
||||
//------------------------------UModLNode--------------------------------------
|
||||
//------------------------------UModLNode---------------------------------------
|
||||
// Unsigned long modulus
|
||||
class UModLNode : public Node {
|
||||
public:
|
||||
@ -202,25 +184,7 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegL; }
|
||||
};
|
||||
|
||||
//---------------------------NoOvfModINode-------------------------------------
|
||||
// Non-overflow integer modulus, UB when dividend == min_jint and divisor == -1
|
||||
// so user has to ensure this combination does not appear
|
||||
class NoOvfModINode : public ModINode {
|
||||
public:
|
||||
NoOvfModINode( Node *c, Node *dividend, Node *divisor ) : ModINode(c, dividend, divisor ) {}
|
||||
virtual int Opcode() const;
|
||||
};
|
||||
|
||||
//---------------------------NoOvfModLNode-------------------------------------
|
||||
// Non-overflow long modulus, UB when dividend == min_jlong and divisor == -1
|
||||
// so user has to ensure this combination does not appear
|
||||
class NoOvfModLNode : public ModLNode {
|
||||
public:
|
||||
NoOvfModLNode( Node *c, Node *dividend, Node *divisor ) : ModLNode(c, dividend, divisor ) {}
|
||||
virtual int Opcode() const;
|
||||
};
|
||||
|
||||
//-----------------------------DivModNode--------------------------------------
|
||||
//------------------------------DivModNode---------------------------------------
|
||||
// Division with remainder result.
|
||||
class DivModNode : public MultiNode {
|
||||
protected:
|
||||
@ -242,7 +206,7 @@ public:
|
||||
ProjNode* mod_proj() { return proj_out_or_null(mod_proj_num); }
|
||||
};
|
||||
|
||||
//-----------------------------DivModINode-------------------------------------
|
||||
//------------------------------DivModINode---------------------------------------
|
||||
// Integer division with remainder result.
|
||||
class DivModINode : public DivModNode {
|
||||
public:
|
||||
@ -255,7 +219,7 @@ public:
|
||||
static DivModINode* make(Node* div_or_mod);
|
||||
};
|
||||
|
||||
//-----------------------------DivModLNode-------------------------------------
|
||||
//------------------------------DivModLNode---------------------------------------
|
||||
// Long division with remainder result.
|
||||
class DivModLNode : public DivModNode {
|
||||
public:
|
||||
@ -269,7 +233,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
//----------------------------UDivModINode-------------------------------------
|
||||
//------------------------------UDivModINode---------------------------------------
|
||||
// Unsigend integer division with remainder result.
|
||||
class UDivModINode : public DivModNode {
|
||||
public:
|
||||
@ -282,7 +246,7 @@ public:
|
||||
static UDivModINode* make(Node* div_or_mod);
|
||||
};
|
||||
|
||||
//----------------------------UDivModLNode-------------------------------------
|
||||
//------------------------------UDivModLNode---------------------------------------
|
||||
// Unsigned long division with remainder result.
|
||||
class UDivModLNode : public DivModNode {
|
||||
public:
|
||||
@ -295,28 +259,4 @@ public:
|
||||
static UDivModLNode* make(Node* div_or_mod);
|
||||
};
|
||||
|
||||
//---------------------------NoOvfDivModINode----------------------------------
|
||||
// Non-overflow integer division with remainder result, UB when dividend == min_jint
|
||||
// and divisor == -1 so user has to ensure this combination does not appear
|
||||
class NoOvfDivModINode : public DivModINode {
|
||||
public:
|
||||
NoOvfDivModINode( Node *c, Node *dividend, Node *divisor ) : DivModINode(c, dividend, divisor) {}
|
||||
virtual int Opcode() const;
|
||||
|
||||
// Make a divmod and associated projections from a div or mod.
|
||||
static NoOvfDivModINode* make(Node* div_or_mod);
|
||||
};
|
||||
|
||||
//---------------------------NoOvfDivModLNode----------------------------------
|
||||
// Non-overflow long division with remainder result, UB when dividend == min_jlong
|
||||
// and divisor == -1 so user has to ensure this combination does not appear
|
||||
class NoOvfDivModLNode : public DivModLNode {
|
||||
public:
|
||||
NoOvfDivModLNode( Node *c, Node *dividend, Node *divisor ) : DivModLNode(c, dividend, divisor) {}
|
||||
virtual int Opcode() const;
|
||||
|
||||
// Make a divmod and associated projections from a div or mod.
|
||||
static NoOvfDivModLNode* make(Node* div_or_mod);
|
||||
};
|
||||
|
||||
#endif // SHARE_OPTO_DIVNODE_HPP
|
||||
|
@ -462,8 +462,7 @@ class Parse : public GraphKit {
|
||||
void merge_memory_edges(MergeMemNode* n, int pnum, bool nophi);
|
||||
|
||||
// Parse this bytecode, and alter the Parsers JVM->Node mapping
|
||||
void do_one_bytecode_common();
|
||||
bool do_one_bytecode_targeted();
|
||||
void do_one_bytecode();
|
||||
|
||||
// helper function to generate array store check
|
||||
void array_store_check();
|
||||
@ -535,10 +534,6 @@ class Parse : public GraphKit {
|
||||
void do_jsr();
|
||||
void do_ret();
|
||||
|
||||
// implementation of div/rem bytecodes for handling of special case
|
||||
// min_jint / -1
|
||||
void do_divmod_fixup();
|
||||
|
||||
float dynamic_branch_prediction(float &cnt, BoolTest::mask btest, Node* test);
|
||||
float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci, Node* test);
|
||||
bool seems_never_taken(float prob) const;
|
||||
|
@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm_io.h"
|
||||
#include "compiler/compileLog.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -1557,22 +1556,7 @@ void Parse::do_one_block() {
|
||||
assert(!have_se || pre_bc_sp >= inputs, "have enough stack to execute this BC: pre_bc_sp=%d, inputs=%d", pre_bc_sp, inputs);
|
||||
#endif //ASSERT
|
||||
|
||||
// Try parsing machine-dependently, then if it is not needed then parse
|
||||
// the bytecode in a machine independent manner
|
||||
if (!do_one_bytecode_targeted()) {
|
||||
do_one_bytecode_common();
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
if (C->should_print_igv(1)) {
|
||||
IdealGraphPrinter* printer = C->igv_printer();
|
||||
char buffer[256];
|
||||
jio_snprintf(buffer, sizeof(buffer), "Bytecode %d: %s", bci(), Bytecodes::name(bc()));
|
||||
bool old = printer->traverse_outs();
|
||||
printer->set_traverse_outs(true);
|
||||
printer->print_method(buffer, 4);
|
||||
printer->set_traverse_outs(old);
|
||||
}
|
||||
#endif
|
||||
do_one_bytecode();
|
||||
|
||||
assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth,
|
||||
"incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth);
|
||||
|
@ -1803,7 +1803,7 @@ Node* Parse::optimize_cmp_with_klass(Node* c) {
|
||||
|
||||
//------------------------------do_one_bytecode--------------------------------
|
||||
// Parse this bytecode, and alter the Parsers JVM->Node mapping
|
||||
void Parse::do_one_bytecode_common() {
|
||||
void Parse::do_one_bytecode() {
|
||||
Node *a, *b, *c, *d; // Handy temps
|
||||
BoolTest::mask btest;
|
||||
int i;
|
||||
@ -2751,4 +2751,16 @@ void Parse::do_one_bytecode_common() {
|
||||
tty->print("\nUnhandled bytecode %s\n", Bytecodes::name(bc()) );
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (C->should_print_igv(1)) {
|
||||
IdealGraphPrinter* printer = C->igv_printer();
|
||||
char buffer[256];
|
||||
jio_snprintf(buffer, sizeof(buffer), "Bytecode %d: %s", bci(), Bytecodes::name(bc()));
|
||||
bool old = printer->traverse_outs();
|
||||
printer->set_traverse_outs(true);
|
||||
printer->print_method(buffer, 4);
|
||||
printer->set_traverse_outs(old);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2019, 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
|
||||
@ -433,77 +433,3 @@ void Parse::do_multianewarray() {
|
||||
// - Make a fast path for small multi-arrays. (W/ implicit init. loops.)
|
||||
// - Issue CastII against length[*] values, to TypeInt::POS.
|
||||
}
|
||||
|
||||
// On some architectures, a division cannot be done immediately due to
|
||||
// the special case with min_jint / -1. As a result, we need to have
|
||||
// special handling for this case
|
||||
void Parse::do_divmod_fixup() {
|
||||
Bytecodes::Code bc = this->bc();
|
||||
BasicType bt = (bc == Bytecodes::_idiv || bc == Bytecodes::_irem) ? T_INT : T_LONG;
|
||||
// Operands need to stay in the stack during zero check
|
||||
if (bt == T_INT) {
|
||||
zero_check_int(peek(0));
|
||||
} else {
|
||||
zero_check_long(peek(1));
|
||||
}
|
||||
// Compile-time detection of arithmetic exception
|
||||
if (stopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node* in2 = (bt == T_INT) ? pop() : pop_pair();
|
||||
Node* in1 = (bt == T_INT) ? pop() : pop_pair();
|
||||
|
||||
auto generate_division = [](PhaseGVN& gvn, Node* control, Node* in1, Node* in2,
|
||||
Bytecodes::Code bc) {
|
||||
switch (bc) {
|
||||
case Bytecodes::_idiv: return gvn.transform(new NoOvfDivINode(control, in1, in2));
|
||||
case Bytecodes::_ldiv: return gvn.transform(new NoOvfDivLNode(control, in1, in2));
|
||||
case Bytecodes::_irem: return gvn.transform(new NoOvfModINode(control, in1, in2));
|
||||
case Bytecodes::_lrem: return gvn.transform(new NoOvfModLNode(control, in1, in2));
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return static_cast<Node*>(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
auto push_result = [](Parse& parser, Node* res, BasicType bt) {
|
||||
if (bt == T_INT) {
|
||||
parser.push(res);
|
||||
} else {
|
||||
parser.push_pair(res);
|
||||
}
|
||||
};
|
||||
|
||||
// No overflow possibility here
|
||||
if ((in1 == in2) ||
|
||||
(bt == T_INT && !TypeInt::MIN->higher_equal(_gvn.type(in1))) ||
|
||||
(bt == T_LONG && !TypeLong::MIN->higher_equal(_gvn.type(in1)))) {
|
||||
Node* res = generate_division(_gvn, control(), in1, in2, bc);
|
||||
push_result(*this, res, bt);
|
||||
return;
|
||||
}
|
||||
|
||||
// The generated graph is equivalent to (in2 == -1) ? -in1 : (in1 / in2)
|
||||
// we need to have a separate branch for in2 == -1 due to the special
|
||||
// case of min_jint / -1
|
||||
Node* cmp = _gvn.transform(CmpNode::make(in2, _gvn.integercon(-1, bt), bt));
|
||||
Node* bol = Bool(cmp, BoolTest::eq);
|
||||
IfNode* iff = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN);
|
||||
Node* iff_true = IfTrue(iff);
|
||||
Node* iff_false = IfFalse(iff);
|
||||
Node* res_fast = (bc == Bytecodes::_idiv || bc == Bytecodes::_ldiv)
|
||||
? _gvn.transform(SubNode::make(_gvn.zerocon(bt), in1, bt))
|
||||
: _gvn.zerocon(bt);
|
||||
Node* res_slow = generate_division(_gvn, iff_false, in1, in2, bc);
|
||||
Node* merge = new RegionNode(3);
|
||||
merge->init_req(1, iff_true);
|
||||
merge->init_req(2, iff_false);
|
||||
record_for_igvn(merge);
|
||||
set_control(_gvn.transform(merge));
|
||||
Node* res = new PhiNode(merge, Type::get_const_basic_type(bt));
|
||||
res->init_req(1, res_fast);
|
||||
res->init_req(2, res_slow);
|
||||
res = _gvn.transform(res);
|
||||
push_result(*this, res, bt);
|
||||
}
|
||||
|
@ -1587,23 +1587,17 @@
|
||||
declare_c2_type(DivDNode, Node) \
|
||||
declare_c2_type(UDivINode, Node) \
|
||||
declare_c2_type(UDivLNode, Node) \
|
||||
declare_c2_type(NoOvfDivINode, DivINode) \
|
||||
declare_c2_type(NoOvfDivLNode, DivLNode) \
|
||||
declare_c2_type(ModINode, Node) \
|
||||
declare_c2_type(ModLNode, Node) \
|
||||
declare_c2_type(ModFNode, Node) \
|
||||
declare_c2_type(ModDNode, Node) \
|
||||
declare_c2_type(UModINode, Node) \
|
||||
declare_c2_type(UModLNode, Node) \
|
||||
declare_c2_type(NoOvfModINode, ModINode) \
|
||||
declare_c2_type(NoOvfModLNode, ModLNode) \
|
||||
declare_c2_type(DivModNode, MultiNode) \
|
||||
declare_c2_type(DivModINode, DivModNode) \
|
||||
declare_c2_type(DivModLNode, DivModNode) \
|
||||
declare_c2_type(UDivModINode, DivModNode) \
|
||||
declare_c2_type(UDivModLNode, DivModNode) \
|
||||
declare_c2_type(NoOvfDivModINode, DivModINode) \
|
||||
declare_c2_type(NoOvfDivModLNode, DivModLNode) \
|
||||
declare_c2_type(BoxLockNode, Node) \
|
||||
declare_c2_type(LoopNode, RegionNode) \
|
||||
declare_c2_type(CountedLoopNode, LoopNode) \
|
||||
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
package compiler.integerArithmetic;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
/*
|
||||
* @test TestDivision
|
||||
* @bug 8284742
|
||||
* @summary Tests to verify compiled code correctly handles integral divisions.
|
||||
* @library /test/lib
|
||||
*
|
||||
* @run main/othervm -Xcomp -XX:-TieredCompilation
|
||||
* -XX:CompileCommand=compileonly,*.TestDivision::divide
|
||||
* -XX:CompileCommand=compileonly,*.TestDivision::remainder
|
||||
* compiler.integerArithmetic.TestDivision
|
||||
*/
|
||||
public class TestDivision {
|
||||
public static void main(String[] args) {
|
||||
Asserts.assertEquals(divide(19, 7), 19 / 7);
|
||||
Asserts.assertEquals(remainder(19, 7), 19 % 7);
|
||||
Asserts.assertEquals(divide(19L, 7L), 19L / 7L);
|
||||
Asserts.assertEquals(remainder(19L, 7L), 19L % 7L);
|
||||
|
||||
Asserts.assertEquals(divide(19, -7), 19 / -7);
|
||||
Asserts.assertEquals(remainder(19, -7), 19 % -7);
|
||||
Asserts.assertEquals(divide(19L, -7L), 19L / -7L);
|
||||
Asserts.assertEquals(remainder(19L, -7L), 19L % -7L);
|
||||
|
||||
Asserts.assertEquals(divide(-19, 7), -19 / 7);
|
||||
Asserts.assertEquals(remainder(-19, 7), -19 % 7);
|
||||
Asserts.assertEquals(divide(-19L, 7L), -19L / 7L);
|
||||
Asserts.assertEquals(remainder(-19L, 7L), -19L % 7L);
|
||||
|
||||
Asserts.assertEquals(divide(-19, -7), -19 / -7);
|
||||
Asserts.assertEquals(remainder(-19, -7), -19 % -7);
|
||||
Asserts.assertEquals(divide(-19L, -7L), -19L / -7L);
|
||||
Asserts.assertEquals(remainder(-19L, -7L), -19L % -7L);
|
||||
|
||||
Asserts.assertEquals(divide(Integer.MIN_VALUE, -1), Integer.MIN_VALUE / -1);
|
||||
Asserts.assertEquals(remainder(Integer.MIN_VALUE, -1), Integer.MIN_VALUE % -1);
|
||||
Asserts.assertEquals(divide(Long.MIN_VALUE, -1), Long.MIN_VALUE / -1L);
|
||||
Asserts.assertEquals(remainder(Long.MIN_VALUE, -1), Long.MIN_VALUE % -1L);
|
||||
|
||||
try {
|
||||
divide(19, 0);
|
||||
Asserts.fail();
|
||||
} catch (ArithmeticException e) {}
|
||||
try {
|
||||
remainder(19, 0);
|
||||
Asserts.fail();
|
||||
} catch (ArithmeticException e) {}
|
||||
try {
|
||||
divide(19L, 0L);
|
||||
Asserts.fail();
|
||||
} catch (ArithmeticException e) {}
|
||||
try {
|
||||
remainder(19L, 0L);
|
||||
Asserts.fail();
|
||||
} catch (ArithmeticException e) {}
|
||||
}
|
||||
|
||||
static int divide(int x, int y) {
|
||||
return x / y;
|
||||
}
|
||||
|
||||
static int remainder(int x, int y) {
|
||||
return x % y;
|
||||
}
|
||||
|
||||
static long divide(long x, long y) {
|
||||
return x / y;
|
||||
}
|
||||
|
||||
static long remainder(long x, long y) {
|
||||
return x % y;
|
||||
}
|
||||
}
|
@ -172,8 +172,8 @@ public class IRNode {
|
||||
public static final String MUL_I = START + "MulI" + MID + END;
|
||||
public static final String MUL_L = START + "MulL" + MID + END;
|
||||
public static final String MUL_F = START + "MulF" + MID + END;
|
||||
public static final String DIV = START + "(NoOvf)?Div(I|L|F|D)" + MID + END;
|
||||
public static final String DIV_L = START + "(NoOvf)?DivL" + MID + END;
|
||||
public static final String DIV = START + "Div(I|L|F|D)" + MID + END;
|
||||
public static final String DIV_L = START + "DivL" + MID + END;
|
||||
public static final String CON_I = START + "ConI" + MID + END;
|
||||
public static final String CON_L = START + "ConL" + MID + END;
|
||||
public static final String CONV_I2L = START + "ConvI2L" + MID + END;
|
||||
|
@ -24,7 +24,6 @@ package org.openjdk.bench.java.lang;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
@ -35,10 +34,12 @@ import java.util.random.RandomGenerator;
|
||||
import java.util.random.RandomGeneratorFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Tests unsigned division and modulus methods in java.lang.Integer
|
||||
*/
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Thread)
|
||||
@Fork(1)
|
||||
public class IntegerDivMod {
|
||||
|
||||
RandomGenerator randomGenerator;
|
||||
@ -59,37 +60,12 @@ public class IntegerDivMod {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
dividends[i] = rng.nextInt();
|
||||
int divisor = rng.nextInt();
|
||||
if (divisorType.equals("positive")) {
|
||||
divisor = Math.abs(divisor);
|
||||
} else if (divisorType.equals("negative")) {
|
||||
divisor = -Math.abs(divisor);
|
||||
}
|
||||
if (divisorType.equals("positive")) divisor = Math.abs(divisor);
|
||||
else if (divisorType.equals("negative")) divisor = -Math.abs(divisor);
|
||||
divisors[i] = divisor;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivide() {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
quotients[i] = dividends[i] / divisors[i];
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivideKnownPositive() {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
quotients[i] = dividends[i] / Math.max(1, divisors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivideHoistedDivisor() {
|
||||
int x = divisors[0];
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
quotients[i] = dividends[i] / x;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivideUnsigned() {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
@ -115,4 +91,8 @@ public class IntegerDivMod {
|
||||
quotients[i] = Integer.divideUnsigned(dividend, divisor);
|
||||
remainders[i] = Integer.remainderUnsigned(dividend, divisor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -24,7 +24,6 @@ package org.openjdk.bench.java.lang;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
@ -35,10 +34,12 @@ import java.util.random.RandomGenerator;
|
||||
import java.util.random.RandomGeneratorFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Tests unsigned division and modulus methods in java.lang.Long
|
||||
*/
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Thread)
|
||||
@Fork(1)
|
||||
public class LongDivMod {
|
||||
|
||||
RandomGenerator randomGenerator;
|
||||
@ -59,37 +60,12 @@ public class LongDivMod {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
dividends[i] = rng.nextLong();
|
||||
long divisor = rng.nextLong();
|
||||
if (divisorType.equals("positive")) {
|
||||
divisor = Math.abs(divisor);
|
||||
} else if (divisorType.equals("negative")) {
|
||||
divisor = -Math.abs(divisor);
|
||||
}
|
||||
if (divisorType.equals("positive")) divisor = Math.abs(divisor);
|
||||
else if (divisorType.equals("negative")) divisor = -Math.abs(divisor);
|
||||
divisors[i] = divisor;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivide() {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
quotients[i] = dividends[i] / divisors[i];
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivideKnownPositive() {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
quotients[i] = dividends[i] / Math.max(1, divisors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivideHoistedDivisor() {
|
||||
long x = divisors[0];
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
quotients[i] = dividends[i] / x;
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void testDivideUnsigned() {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
@ -115,4 +91,8 @@ public class LongDivMod {
|
||||
quotients[i] = Long.divideUnsigned(dividend, divisor);
|
||||
remainders[i] = Long.remainderUnsigned(dividend, divisor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user