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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parse::do_one_bytecode_targeted() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MOV_VOLATILE(REG, BASE, INDEX, SCALE, DISP, SCRATCH, INSN) \
|
#define MOV_VOLATILE(REG, BASE, INDEX, SCALE, DISP, SCRATCH, INSN) \
|
||||||
C2_MacroAssembler _masm(&cbuf); \
|
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());
|
return !MacroAssembler::_reachable_from_cache(n->as_MachCall()->entry_point());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parse::do_one_bytecode_targeted() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
//----------ENCODING BLOCK-----------------------------------------------------
|
//----------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);
|
ins_pipe(pipe_class_default);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Integer Division, but not min_jint / -1
|
// Integer Division with Immediate -1: Negate.
|
||||||
instruct noOvfDivI_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
instruct divI_reg_immIvalueMinus1(iRegIdst dst, iRegIsrc src1, immI_minus1 src2) %{
|
||||||
match(Set dst (NoOvfDivI src1 src2));
|
match(Set dst (DivI src1 src2));
|
||||||
ins_cost(3*DEFAULT_COST);
|
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" %}
|
format %{ "DIVW $dst, $src1, $src2 \t// /not-1" %}
|
||||||
size(4);
|
size(4);
|
||||||
@ -8861,10 +8877,56 @@ instruct noOvfDivI_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
|||||||
ins_pipe(pipe_class_default);
|
ins_pipe(pipe_class_default);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Long Division, but not min_jlong / -1
|
instruct cmovI_bne_negI_reg(iRegIdst dst, flagsRegSrc crx, iRegIsrc src1) %{
|
||||||
instruct noOvfDivL_reg_reg(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
effect(USE_DEF dst, USE src1, USE crx);
|
||||||
match(Set dst (NoOvfDivL src1 src2));
|
predicate(false);
|
||||||
ins_cost(3*DEFAULT_COST);
|
|
||||||
|
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" %}
|
format %{ "DIVD $dst, $src1, $src2 \t// /not-1, long" %}
|
||||||
size(4);
|
size(4);
|
||||||
@ -8874,31 +8936,71 @@ instruct noOvfDivL_reg_reg(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
|||||||
ins_pipe(pipe_class_default);
|
ins_pipe(pipe_class_default);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Integer Remainder with registers.
|
instruct cmovL_bne_negL_reg(iRegLdst dst, flagsRegSrc crx, iRegLsrc src1) %{
|
||||||
instruct modI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
|
effect(USE_DEF dst, USE src1, USE crx);
|
||||||
match(Set dst (NoOvfModI src1 src2));
|
predicate(false);
|
||||||
ins_cost(5*DEFAULT_COST);
|
|
||||||
|
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 %{
|
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;
|
iRegIdst tmp2;
|
||||||
noOvfDivI_reg_reg(tmp1, src1, src2);
|
iRegIdst tmp3;
|
||||||
mulI_reg_reg(tmp2, src2, tmp1);
|
cmpI_reg_imm16(tmp1, src2, imm); // check src2 == -1
|
||||||
subI_reg_reg(dst, src1, tmp2);
|
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
|
// Long Remainder with registers
|
||||||
instruct modL_reg_reg_Ex(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
instruct modL_reg_reg_Ex(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{
|
||||||
match(Set dst (NoOvfModL src1 src2));
|
match(Set dst (ModL src1 src2));
|
||||||
ins_cost(5*DEFAULT_COST);
|
ins_cost(10*DEFAULT_COST);
|
||||||
|
|
||||||
expand %{
|
expand %{
|
||||||
iRegLdst tmp1;
|
immL16 imm %{ (int)-1 %}
|
||||||
|
flagsReg tmp1;
|
||||||
iRegLdst tmp2;
|
iRegLdst tmp2;
|
||||||
noOvfDivL_reg_reg(tmp1, src1, src2);
|
iRegLdst tmp3;
|
||||||
mulL_reg_reg(tmp2, src2, tmp1);
|
cmpL_reg_imm16(tmp1, src2, imm); // check src2 == -1
|
||||||
subL_reg_reg(dst, src1, tmp2);
|
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);
|
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);
|
return clone_base_plus_offset_address(m, mstack, address_visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parse::do_one_bytecode_targeted() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
%} // source
|
%} // source
|
||||||
|
|
||||||
//----------ENCODING BLOCK-----------------------------------------------------
|
//----------ENCODING BLOCK-----------------------------------------------------
|
||||||
|
@ -2235,13 +2235,6 @@ void Assembler::idivl(Register src) {
|
|||||||
emit_int16((unsigned char)0xF7, (0xF8 | encode));
|
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
|
void Assembler::divl(Register src) { // Unsigned
|
||||||
int encode = prefix_and_encode(src->encoding());
|
int encode = prefix_and_encode(src->encoding());
|
||||||
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
||||||
@ -12331,13 +12324,6 @@ void Assembler::idivq(Register src) {
|
|||||||
emit_int16((unsigned char)0xF7, (0xF8 | encode));
|
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) {
|
void Assembler::divq(Register src) {
|
||||||
int encode = prefixq_and_encode(src->encoding());
|
int encode = prefixq_and_encode(src->encoding());
|
||||||
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
emit_int16((unsigned char)0xF7, (0xF0 | encode));
|
||||||
|
@ -1198,9 +1198,6 @@ private:
|
|||||||
void vpabsd(XMMRegister dst, XMMRegister src, int vector_len);
|
void vpabsd(XMMRegister dst, XMMRegister src, int vector_len);
|
||||||
void evpabsq(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
|
// Divide Scalar Double-Precision Floating-Point Values
|
||||||
void divsd(XMMRegister dst, Address src);
|
void divsd(XMMRegister dst, Address src);
|
||||||
void divsd(XMMRegister dst, XMMRegister src);
|
void divsd(XMMRegister dst, XMMRegister src);
|
||||||
@ -1369,9 +1366,12 @@ private:
|
|||||||
void hlt();
|
void hlt();
|
||||||
|
|
||||||
void idivl(Register src);
|
void idivl(Register src);
|
||||||
void idivl(Address src);
|
void divl(Register src); // Unsigned division
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
void idivq(Register src);
|
void idivq(Register src);
|
||||||
void idivq(Address src);
|
void divq(Register src); // Unsigned division
|
||||||
|
#endif
|
||||||
|
|
||||||
void imull(Register src);
|
void imull(Register src);
|
||||||
void imull(Register dst, 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
|
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
|
// Dense encoding for older common ops
|
||||||
enc_class Opc_plus(immI opcode, rRegI reg) %{
|
enc_class Opc_plus(immI opcode, rRegI reg) %{
|
||||||
emit_opcode(cbuf, $opcode$$constant + $reg$$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
|
// Integer DIV with Register
|
||||||
instruct divI_eReg(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
|
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);
|
effect(KILL rdx, KILL cr);
|
||||||
size(3);
|
size(26);
|
||||||
ins_cost(500);
|
ins_cost(30*100+10*100);
|
||||||
format %{ "CDQ\n\t"
|
format %{ "CMP EAX,0x80000000\n\t"
|
||||||
"IDIV $div" %}
|
"JNE,s normal\n\t"
|
||||||
ins_encode %{
|
"XOR EDX,EDX\n\t"
|
||||||
__ cdql();
|
"CMP ECX,-1\n\t"
|
||||||
__ idivl($div$$Register);
|
"JE,s done\n"
|
||||||
%}
|
"normal: CDQ\n\t"
|
||||||
ins_pipe( pipe_slow );
|
"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
|
// 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
|
// Integer DIVMOD with Register, both quotient and mod results
|
||||||
instruct divModI_eReg_divmod(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
|
instruct divModI_eReg_divmod(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
|
||||||
match(NoOvfDivModI rax div);
|
match(DivModI rax div);
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
size(3);
|
size(26);
|
||||||
ins_cost(500);
|
ins_cost(30*100+10*100);
|
||||||
format %{ "CDQ\n\t"
|
format %{ "CMP EAX,0x80000000\n\t"
|
||||||
"IDIV $div" %}
|
"JNE,s normal\n\t"
|
||||||
ins_encode %{
|
"XOR EDX,EDX\n\t"
|
||||||
__ cdql();
|
"CMP ECX,-1\n\t"
|
||||||
__ idivl($div$$Register);
|
"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 );
|
ins_pipe( pipe_slow );
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Integer MOD with Register
|
// Integer MOD with Register
|
||||||
instruct modI_eReg(eDXRegI rdx, eAXRegI rax, eCXRegI div, eFlagsReg cr) %{
|
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);
|
effect(KILL rax, KILL cr);
|
||||||
|
|
||||||
size(3);
|
size(26);
|
||||||
ins_cost(500);
|
ins_cost(300);
|
||||||
format %{ "CDQ\n\t"
|
format %{ "CDQ\n\t"
|
||||||
"IDIV $div" %}
|
"IDIV $div" %}
|
||||||
ins_encode %{
|
opcode(0xF7, 0x7); /* Opcode F7 /7 */
|
||||||
__ cdql();
|
ins_encode( cdq_enc, OpcP, RegOpc(div) );
|
||||||
__ idivl($div$$Register);
|
ins_pipe( ialu_reg_reg_alu0 );
|
||||||
%}
|
|
||||||
ins_pipe( pipe_slow );
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Remainder Register Long
|
// Remainder Register Long
|
||||||
|
@ -338,19 +338,11 @@ extern RegMask _FLOAT_REG_mask;
|
|||||||
|
|
||||||
extern RegMask _STACK_OR_PTR_REG_mask;
|
extern RegMask _STACK_OR_PTR_REG_mask;
|
||||||
extern RegMask _STACK_OR_LONG_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_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_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_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_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 _FLOAT_REG_mask;
|
||||||
RegMask _STACK_OR_PTR_REG_mask;
|
RegMask _STACK_OR_PTR_REG_mask;
|
||||||
RegMask _STACK_OR_LONG_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_REG_mask;
|
||||||
RegMask _STACK_OR_INT_NO_RAX_RDX_REG_mask;
|
|
||||||
|
|
||||||
static bool need_r12_heapbase() {
|
static bool need_r12_heapbase() {
|
||||||
return UseCompressedOops;
|
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()));
|
||||||
_LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()->next()));
|
_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;
|
_INT_REG_mask = _ALL_INT_REG_mask;
|
||||||
if (PreserveFramePointer) {
|
if (PreserveFramePointer) {
|
||||||
_INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()));
|
_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(rbp->as_VMReg()));
|
||||||
_INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->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
|
// _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc
|
||||||
// from the float_reg_legacy/float_reg_evex register class.
|
// 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;
|
_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);
|
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
|
// Opcde enc_class for 8/32 bit immediate instructions with sign-extension
|
||||||
enc_class OpcSE(immI imm)
|
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,
|
instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
%{
|
%{
|
||||||
match(Set rax (NoOvfDivI rax div));
|
match(Set rax (DivI rax div));
|
||||||
effect(KILL rdx, KILL cr);
|
effect(KILL rdx, KILL cr);
|
||||||
|
|
||||||
ins_cost(500);
|
ins_cost(30*100+10*100); // XXX
|
||||||
format %{ "cdql\n\t"
|
format %{ "cmpl rax, 0x80000000\t# idiv\n\t"
|
||||||
"idivl $div" %}
|
"jne,s normal\n\t"
|
||||||
ins_encode %{
|
"xorl rdx, rdx\n\t"
|
||||||
__ cdql();
|
"cmpl $div, -1\n\t"
|
||||||
__ idivl($div$$Register);
|
"je,s done\n"
|
||||||
%}
|
"normal: cdql\n\t"
|
||||||
ins_pipe(pipe_slow);
|
"idivl $div\n"
|
||||||
%}
|
"done:" %}
|
||||||
|
ins_encode(cdql_enc(div));
|
||||||
instruct divI_mem(rax_RegI rax, rdx_RegI rdx, memory div,
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
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);
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct divL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
instruct divL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
%{
|
%{
|
||||||
match(Set rax (NoOvfDivL rax div));
|
match(Set rax (DivL rax div));
|
||||||
effect(KILL rdx, KILL cr);
|
effect(KILL rdx, KILL cr);
|
||||||
|
|
||||||
ins_cost(500);
|
ins_cost(30*100+10*100); // XXX
|
||||||
format %{ "cdqq\n\t"
|
format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t"
|
||||||
"idivq $div" %}
|
"cmpq rax, rdx\n\t"
|
||||||
ins_encode %{
|
"jne,s normal\n\t"
|
||||||
__ cdqq();
|
"xorl rdx, rdx\n\t"
|
||||||
__ idivq($div$$Register);
|
"cmpq $div, -1\n\t"
|
||||||
%}
|
"je,s done\n"
|
||||||
ins_pipe(pipe_slow);
|
"normal: cdqq\n\t"
|
||||||
%}
|
"idivq $div\n"
|
||||||
|
"done:" %}
|
||||||
instruct divL_mem(rax_RegL rax, rdx_RegL rdx, memory div,
|
ins_encode(cdqq_enc(div));
|
||||||
rFlagsReg cr)
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
%{
|
|
||||||
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);
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct udivI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, rFlagsReg cr)
|
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,
|
instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
%{
|
%{
|
||||||
match(NoOvfDivModI rax div);
|
match(DivModI rax div);
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
|
|
||||||
ins_cost(500);
|
ins_cost(30*100+10*100); // XXX
|
||||||
format %{ "cdql\n\t"
|
format %{ "cmpl rax, 0x80000000\t# idiv\n\t"
|
||||||
"idivl $div" %}
|
"jne,s normal\n\t"
|
||||||
ins_encode %{
|
"xorl rdx, rdx\n\t"
|
||||||
__ cdql();
|
"cmpl $div, -1\n\t"
|
||||||
__ idivl($div$$Register);
|
"je,s done\n"
|
||||||
%}
|
"normal: cdql\n\t"
|
||||||
|
"idivl $div\n"
|
||||||
|
"done:" %}
|
||||||
|
ins_encode(cdql_enc(div));
|
||||||
ins_pipe(pipe_slow);
|
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,
|
instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
%{
|
%{
|
||||||
match(NoOvfDivModL rax div);
|
match(DivModL rax div);
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
|
|
||||||
ins_cost(500);
|
ins_cost(30*100+10*100); // XXX
|
||||||
format %{ "cdqq\n\t"
|
format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t"
|
||||||
"idivq $div" %}
|
"cmpq rax, rdx\n\t"
|
||||||
ins_encode %{
|
"jne,s normal\n\t"
|
||||||
__ cdqq();
|
"xorl rdx, rdx\n\t"
|
||||||
__ idivq($div$$Register);
|
"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);
|
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);
|
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,
|
instruct modI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
%{
|
%{
|
||||||
match(Set rdx (NoOvfModI rax div));
|
match(Set rdx (ModI rax div));
|
||||||
effect(KILL rax, KILL cr);
|
effect(KILL rax, KILL cr);
|
||||||
|
|
||||||
ins_cost(500);
|
ins_cost(300); // XXX
|
||||||
format %{ "cdql\n\t"
|
format %{ "cmpl rax, 0x80000000\t# irem\n\t"
|
||||||
"idivl $div" %}
|
"jne,s normal\n\t"
|
||||||
ins_encode %{
|
"xorl rdx, rdx\n\t"
|
||||||
__ cdql();
|
"cmpl $div, -1\n\t"
|
||||||
__ idivl($div$$Register);
|
"je,s done\n"
|
||||||
%}
|
"normal: cdql\n\t"
|
||||||
ins_pipe(pipe_slow);
|
"idivl $div\n"
|
||||||
%}
|
"done:" %}
|
||||||
|
ins_encode(cdql_enc(div));
|
||||||
instruct modI_mem(rdx_RegI rdx, rax_RegI rax, memory div,
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
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);
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct modL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div,
|
instruct modL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div,
|
||||||
rFlagsReg cr)
|
rFlagsReg cr)
|
||||||
%{
|
%{
|
||||||
match(Set rdx (NoOvfModL rax div));
|
match(Set rdx (ModL rax div));
|
||||||
effect(KILL rax, KILL cr);
|
effect(KILL rax, KILL cr);
|
||||||
|
|
||||||
ins_cost(500);
|
ins_cost(300); // XXX
|
||||||
format %{ "cdqq\n\t"
|
format %{ "movq rdx, 0x8000000000000000\t# lrem\n\t"
|
||||||
"idivq $div" %}
|
"cmpq rax, rdx\n\t"
|
||||||
ins_encode %{
|
"jne,s normal\n\t"
|
||||||
__ cdqq();
|
"xorl rdx, rdx\n\t"
|
||||||
__ idivq($div$$Register);
|
"cmpq $div, -1\n\t"
|
||||||
%}
|
"je,s done\n"
|
||||||
ins_pipe(pipe_slow);
|
"normal: cdqq\n\t"
|
||||||
%}
|
"idivq $div\n"
|
||||||
|
"done:" %}
|
||||||
instruct modL_mem(rdx_RegL rdx, rax_RegL rax, memory div,
|
ins_encode(cdqq_enc(div));
|
||||||
rFlagsReg cr)
|
ins_pipe(ialu_reg_reg_alu0);
|
||||||
%{
|
|
||||||
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);
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct umodI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, rFlagsReg cr)
|
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/intrinsicnode.hpp");
|
||||||
AD.addInclude(AD._CPP_file, "opto/locknode.hpp");
|
AD.addInclude(AD._CPP_file, "opto/locknode.hpp");
|
||||||
AD.addInclude(AD._CPP_file, "opto/opcodes.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/regalloc.hpp");
|
||||||
AD.addInclude(AD._CPP_file, "opto/regmask.hpp");
|
AD.addInclude(AD._CPP_file, "opto/regmask.hpp");
|
||||||
AD.addInclude(AD._CPP_file, "opto/runtime.hpp");
|
AD.addInclude(AD._CPP_file, "opto/runtime.hpp");
|
||||||
|
@ -161,15 +161,11 @@ macro(DivD)
|
|||||||
macro(DivF)
|
macro(DivF)
|
||||||
macro(DivI)
|
macro(DivI)
|
||||||
macro(DivL)
|
macro(DivL)
|
||||||
macro(NoOvfDivI)
|
|
||||||
macro(NoOvfDivL)
|
|
||||||
macro(UDivI)
|
macro(UDivI)
|
||||||
macro(UDivL)
|
macro(UDivL)
|
||||||
macro(DivMod)
|
macro(DivMod)
|
||||||
macro(DivModI)
|
macro(DivModI)
|
||||||
macro(DivModL)
|
macro(DivModL)
|
||||||
macro(NoOvfDivModI)
|
|
||||||
macro(NoOvfDivModL)
|
|
||||||
macro(UDivModI)
|
macro(UDivModI)
|
||||||
macro(UDivModL)
|
macro(UDivModL)
|
||||||
macro(EncodeISOArray)
|
macro(EncodeISOArray)
|
||||||
@ -238,8 +234,6 @@ macro(ModD)
|
|||||||
macro(ModF)
|
macro(ModF)
|
||||||
macro(ModI)
|
macro(ModI)
|
||||||
macro(ModL)
|
macro(ModL)
|
||||||
macro(NoOvfModI)
|
|
||||||
macro(NoOvfModL)
|
|
||||||
macro(UModI)
|
macro(UModI)
|
||||||
macro(UModL)
|
macro(UModL)
|
||||||
macro(MoveI2F)
|
macro(MoveI2F)
|
||||||
|
@ -3565,46 +3565,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
|
|||||||
}
|
}
|
||||||
break;
|
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_LoadVector:
|
||||||
case Op_StoreVector:
|
case Op_StoreVector:
|
||||||
case Op_LoadVectorGather:
|
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);
|
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; }
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------UDivLNode--------------------------------------
|
//------------------------------UDivLNode---------------------------------------
|
||||||
// Unsigned long division
|
// Unsigned long division
|
||||||
class UDivLNode : public Node {
|
class UDivLNode : public Node {
|
||||||
public:
|
public:
|
||||||
@ -116,24 +116,6 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegL; }
|
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---------------------------------------
|
//------------------------------ModINode---------------------------------------
|
||||||
// Integer modulus
|
// Integer modulus
|
||||||
class ModINode : public Node {
|
class ModINode : public Node {
|
||||||
@ -180,7 +162,7 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------UModINode--------------------------------------
|
//------------------------------UModINode---------------------------------------
|
||||||
// Unsigned integer modulus
|
// Unsigned integer modulus
|
||||||
class UModINode : public Node {
|
class UModINode : public Node {
|
||||||
public:
|
public:
|
||||||
@ -191,7 +173,7 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------UModLNode--------------------------------------
|
//------------------------------UModLNode---------------------------------------
|
||||||
// Unsigned long modulus
|
// Unsigned long modulus
|
||||||
class UModLNode : public Node {
|
class UModLNode : public Node {
|
||||||
public:
|
public:
|
||||||
@ -202,25 +184,7 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegL; }
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------NoOvfModINode-------------------------------------
|
//------------------------------DivModNode---------------------------------------
|
||||||
// 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--------------------------------------
|
|
||||||
// Division with remainder result.
|
// Division with remainder result.
|
||||||
class DivModNode : public MultiNode {
|
class DivModNode : public MultiNode {
|
||||||
protected:
|
protected:
|
||||||
@ -242,7 +206,7 @@ public:
|
|||||||
ProjNode* mod_proj() { return proj_out_or_null(mod_proj_num); }
|
ProjNode* mod_proj() { return proj_out_or_null(mod_proj_num); }
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------DivModINode-------------------------------------
|
//------------------------------DivModINode---------------------------------------
|
||||||
// Integer division with remainder result.
|
// Integer division with remainder result.
|
||||||
class DivModINode : public DivModNode {
|
class DivModINode : public DivModNode {
|
||||||
public:
|
public:
|
||||||
@ -255,7 +219,7 @@ public:
|
|||||||
static DivModINode* make(Node* div_or_mod);
|
static DivModINode* make(Node* div_or_mod);
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------DivModLNode-------------------------------------
|
//------------------------------DivModLNode---------------------------------------
|
||||||
// Long division with remainder result.
|
// Long division with remainder result.
|
||||||
class DivModLNode : public DivModNode {
|
class DivModLNode : public DivModNode {
|
||||||
public:
|
public:
|
||||||
@ -269,7 +233,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//----------------------------UDivModINode-------------------------------------
|
//------------------------------UDivModINode---------------------------------------
|
||||||
// Unsigend integer division with remainder result.
|
// Unsigend integer division with remainder result.
|
||||||
class UDivModINode : public DivModNode {
|
class UDivModINode : public DivModNode {
|
||||||
public:
|
public:
|
||||||
@ -282,7 +246,7 @@ public:
|
|||||||
static UDivModINode* make(Node* div_or_mod);
|
static UDivModINode* make(Node* div_or_mod);
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------UDivModLNode-------------------------------------
|
//------------------------------UDivModLNode---------------------------------------
|
||||||
// Unsigned long division with remainder result.
|
// Unsigned long division with remainder result.
|
||||||
class UDivModLNode : public DivModNode {
|
class UDivModLNode : public DivModNode {
|
||||||
public:
|
public:
|
||||||
@ -295,28 +259,4 @@ public:
|
|||||||
static UDivModLNode* make(Node* div_or_mod);
|
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
|
#endif // SHARE_OPTO_DIVNODE_HPP
|
||||||
|
@ -462,8 +462,7 @@ class Parse : public GraphKit {
|
|||||||
void merge_memory_edges(MergeMemNode* n, int pnum, bool nophi);
|
void merge_memory_edges(MergeMemNode* n, int pnum, bool nophi);
|
||||||
|
|
||||||
// Parse this bytecode, and alter the Parsers JVM->Node mapping
|
// Parse this bytecode, and alter the Parsers JVM->Node mapping
|
||||||
void do_one_bytecode_common();
|
void do_one_bytecode();
|
||||||
bool do_one_bytecode_targeted();
|
|
||||||
|
|
||||||
// helper function to generate array store check
|
// helper function to generate array store check
|
||||||
void array_store_check();
|
void array_store_check();
|
||||||
@ -535,10 +534,6 @@ class Parse : public GraphKit {
|
|||||||
void do_jsr();
|
void do_jsr();
|
||||||
void do_ret();
|
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 dynamic_branch_prediction(float &cnt, BoolTest::mask btest, Node* test);
|
||||||
float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci, Node* test);
|
float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci, Node* test);
|
||||||
bool seems_never_taken(float prob) const;
|
bool seems_never_taken(float prob) const;
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm_io.h"
|
|
||||||
#include "compiler/compileLog.hpp"
|
#include "compiler/compileLog.hpp"
|
||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
#include "memory/resourceArea.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);
|
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
|
#endif //ASSERT
|
||||||
|
|
||||||
// Try parsing machine-dependently, then if it is not needed then parse
|
do_one_bytecode();
|
||||||
// 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
|
|
||||||
|
|
||||||
assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth,
|
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);
|
"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--------------------------------
|
//------------------------------do_one_bytecode--------------------------------
|
||||||
// Parse this bytecode, and alter the Parsers JVM->Node mapping
|
// 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
|
Node *a, *b, *c, *d; // Handy temps
|
||||||
BoolTest::mask btest;
|
BoolTest::mask btest;
|
||||||
int i;
|
int i;
|
||||||
@ -2751,4 +2751,16 @@ void Parse::do_one_bytecode_common() {
|
|||||||
tty->print("\nUnhandled bytecode %s\n", Bytecodes::name(bc()) );
|
tty->print("\nUnhandled bytecode %s\n", Bytecodes::name(bc()) );
|
||||||
ShouldNotReachHere();
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.)
|
// - Make a fast path for small multi-arrays. (W/ implicit init. loops.)
|
||||||
// - Issue CastII against length[*] values, to TypeInt::POS.
|
// - 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(DivDNode, Node) \
|
||||||
declare_c2_type(UDivINode, Node) \
|
declare_c2_type(UDivINode, Node) \
|
||||||
declare_c2_type(UDivLNode, Node) \
|
declare_c2_type(UDivLNode, Node) \
|
||||||
declare_c2_type(NoOvfDivINode, DivINode) \
|
|
||||||
declare_c2_type(NoOvfDivLNode, DivLNode) \
|
|
||||||
declare_c2_type(ModINode, Node) \
|
declare_c2_type(ModINode, Node) \
|
||||||
declare_c2_type(ModLNode, Node) \
|
declare_c2_type(ModLNode, Node) \
|
||||||
declare_c2_type(ModFNode, Node) \
|
declare_c2_type(ModFNode, Node) \
|
||||||
declare_c2_type(ModDNode, Node) \
|
declare_c2_type(ModDNode, Node) \
|
||||||
declare_c2_type(UModINode, Node) \
|
declare_c2_type(UModINode, Node) \
|
||||||
declare_c2_type(UModLNode, Node) \
|
declare_c2_type(UModLNode, Node) \
|
||||||
declare_c2_type(NoOvfModINode, ModINode) \
|
|
||||||
declare_c2_type(NoOvfModLNode, ModLNode) \
|
|
||||||
declare_c2_type(DivModNode, MultiNode) \
|
declare_c2_type(DivModNode, MultiNode) \
|
||||||
declare_c2_type(DivModINode, DivModNode) \
|
declare_c2_type(DivModINode, DivModNode) \
|
||||||
declare_c2_type(DivModLNode, DivModNode) \
|
declare_c2_type(DivModLNode, DivModNode) \
|
||||||
declare_c2_type(UDivModINode, DivModNode) \
|
declare_c2_type(UDivModINode, DivModNode) \
|
||||||
declare_c2_type(UDivModLNode, DivModNode) \
|
declare_c2_type(UDivModLNode, DivModNode) \
|
||||||
declare_c2_type(NoOvfDivModINode, DivModINode) \
|
|
||||||
declare_c2_type(NoOvfDivModLNode, DivModLNode) \
|
|
||||||
declare_c2_type(BoxLockNode, Node) \
|
declare_c2_type(BoxLockNode, Node) \
|
||||||
declare_c2_type(LoopNode, RegionNode) \
|
declare_c2_type(LoopNode, RegionNode) \
|
||||||
declare_c2_type(CountedLoopNode, LoopNode) \
|
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_I = START + "MulI" + MID + END;
|
||||||
public static final String MUL_L = START + "MulL" + 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 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 = START + "Div(I|L|F|D)" + MID + END;
|
||||||
public static final String DIV_L = START + "(NoOvf)?DivL" + 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_I = START + "ConI" + MID + END;
|
||||||
public static final String CON_L = START + "ConL" + MID + END;
|
public static final String CON_L = START + "ConL" + MID + END;
|
||||||
public static final String CONV_I2L = START + "ConvI2L" + 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.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
import org.openjdk.jmh.annotations.Fork;
|
|
||||||
import org.openjdk.jmh.annotations.Mode;
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
import org.openjdk.jmh.annotations.Scope;
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
@ -35,10 +34,12 @@ import java.util.random.RandomGenerator;
|
|||||||
import java.util.random.RandomGeneratorFactory;
|
import java.util.random.RandomGeneratorFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unsigned division and modulus methods in java.lang.Integer
|
||||||
|
*/
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
@State(Scope.Thread)
|
@State(Scope.Thread)
|
||||||
@Fork(1)
|
|
||||||
public class IntegerDivMod {
|
public class IntegerDivMod {
|
||||||
|
|
||||||
RandomGenerator randomGenerator;
|
RandomGenerator randomGenerator;
|
||||||
@ -59,37 +60,12 @@ public class IntegerDivMod {
|
|||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
dividends[i] = rng.nextInt();
|
dividends[i] = rng.nextInt();
|
||||||
int divisor = rng.nextInt();
|
int divisor = rng.nextInt();
|
||||||
if (divisorType.equals("positive")) {
|
if (divisorType.equals("positive")) divisor = Math.abs(divisor);
|
||||||
divisor = Math.abs(divisor);
|
else if (divisorType.equals("negative")) divisor = -Math.abs(divisor);
|
||||||
} else if (divisorType.equals("negative")) {
|
|
||||||
divisor = -Math.abs(divisor);
|
|
||||||
}
|
|
||||||
divisors[i] = 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
|
@Benchmark
|
||||||
public void testDivideUnsigned() {
|
public void testDivideUnsigned() {
|
||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
@ -115,4 +91,8 @@ public class IntegerDivMod {
|
|||||||
quotients[i] = Integer.divideUnsigned(dividend, divisor);
|
quotients[i] = Integer.divideUnsigned(dividend, divisor);
|
||||||
remainders[i] = Integer.remainderUnsigned(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.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
import org.openjdk.jmh.annotations.Fork;
|
|
||||||
import org.openjdk.jmh.annotations.Mode;
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
import org.openjdk.jmh.annotations.Scope;
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
@ -35,10 +34,12 @@ import java.util.random.RandomGenerator;
|
|||||||
import java.util.random.RandomGeneratorFactory;
|
import java.util.random.RandomGeneratorFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unsigned division and modulus methods in java.lang.Long
|
||||||
|
*/
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
@State(Scope.Thread)
|
@State(Scope.Thread)
|
||||||
@Fork(1)
|
|
||||||
public class LongDivMod {
|
public class LongDivMod {
|
||||||
|
|
||||||
RandomGenerator randomGenerator;
|
RandomGenerator randomGenerator;
|
||||||
@ -59,37 +60,12 @@ public class LongDivMod {
|
|||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
dividends[i] = rng.nextLong();
|
dividends[i] = rng.nextLong();
|
||||||
long divisor = rng.nextLong();
|
long divisor = rng.nextLong();
|
||||||
if (divisorType.equals("positive")) {
|
if (divisorType.equals("positive")) divisor = Math.abs(divisor);
|
||||||
divisor = Math.abs(divisor);
|
else if (divisorType.equals("negative")) divisor = -Math.abs(divisor);
|
||||||
} else if (divisorType.equals("negative")) {
|
|
||||||
divisor = -Math.abs(divisor);
|
|
||||||
}
|
|
||||||
divisors[i] = 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
|
@Benchmark
|
||||||
public void testDivideUnsigned() {
|
public void testDivideUnsigned() {
|
||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
@ -115,4 +91,8 @@ public class LongDivMod {
|
|||||||
quotients[i] = Long.divideUnsigned(dividend, divisor);
|
quotients[i] = Long.divideUnsigned(dividend, divisor);
|
||||||
remainders[i] = Long.remainderUnsigned(dividend, divisor);
|
remainders[i] = Long.remainderUnsigned(dividend, divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user