mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-22 03:17:54 +00:00
8351155: C1/C2: Remove 32-bit x86 specific FP rounding support
Reviewed-by: vlivanov, kvn
This commit is contained in:
parent
1bd0ce1f51
commit
b73663a2b4
@ -32,11 +32,6 @@ enum {
|
||||
pd_hi_word_offset_in_bytes = BytesPerWord
|
||||
};
|
||||
|
||||
// explicit rounding operations are required to implement the strictFP mode
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = false
|
||||
};
|
||||
|
||||
// FIXME: There are no callee-saved
|
||||
|
||||
// registers
|
||||
|
||||
@ -407,7 +407,7 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
|
||||
|
||||
arithmetic_op_fpu(x->op(), reg, left.result(), right.result());
|
||||
|
||||
set_result(x, round_item(reg));
|
||||
set_result(x, reg);
|
||||
}
|
||||
|
||||
// for _ladd, _lmul, _lsub, _ldiv, _lrem
|
||||
|
||||
@ -115,9 +115,6 @@
|
||||
// C code as the Java calling convention forces doubles to be aligned.
|
||||
static const bool misaligned_doubles_ok = true;
|
||||
|
||||
// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
|
||||
static const bool strict_fp_requires_explicit_rounding = false;
|
||||
|
||||
// Are floats converted to double when stored to stack during
|
||||
// deoptimization?
|
||||
static constexpr bool float_in_double() { return false; }
|
||||
|
||||
@ -4510,18 +4510,6 @@ instruct unnecessary_membar_volatile() %{
|
||||
%}
|
||||
|
||||
//----------Register Move Instructions-----------------------------------------
|
||||
// instruct roundDouble_nop(regD dst) %{
|
||||
// match(Set dst (RoundDouble dst));
|
||||
// ins_pipe(empty);
|
||||
// %}
|
||||
|
||||
|
||||
// instruct roundFloat_nop(regF dst) %{
|
||||
// match(Set dst (RoundFloat dst));
|
||||
// ins_pipe(empty);
|
||||
// %}
|
||||
|
||||
|
||||
|
||||
// Cast Index to Pointer for unsafe natives
|
||||
instruct castX2P(iRegX src, iRegP dst) %{
|
||||
|
||||
@ -31,11 +31,6 @@ enum {
|
||||
pd_hi_word_offset_in_bytes = BytesPerWord
|
||||
};
|
||||
|
||||
// explicit rounding operations are required to implement the strictFP mode
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = false
|
||||
};
|
||||
|
||||
#ifdef __SOFTFP__
|
||||
#define SOFT(n) n
|
||||
#define VFP(n)
|
||||
|
||||
@ -101,9 +101,6 @@
|
||||
// Java calling convention forces doubles to be aligned.
|
||||
static const bool misaligned_doubles_ok = false;
|
||||
|
||||
// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
|
||||
static const bool strict_fp_requires_explicit_rounding = false;
|
||||
|
||||
// Are floats converted to double when stored to stack during deoptimization?
|
||||
// ARM does not handle callee-save floats.
|
||||
static constexpr bool float_in_double() {
|
||||
|
||||
@ -38,12 +38,6 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
// Explicit rounding operations are not required to implement the strictFP mode.
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = false
|
||||
};
|
||||
|
||||
|
||||
// registers
|
||||
enum {
|
||||
pd_nof_cpu_regs_frame_map = 32, // Number of registers used during code emission.
|
||||
|
||||
@ -115,9 +115,6 @@
|
||||
// Java calling convention forces doubles to be aligned.
|
||||
static const bool misaligned_doubles_ok = true;
|
||||
|
||||
// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
|
||||
static const bool strict_fp_requires_explicit_rounding = false;
|
||||
|
||||
// Do floats take an entire double register or just half?
|
||||
//
|
||||
// A float occupies a ppc64 double register. For the allocator, a
|
||||
|
||||
@ -9537,28 +9537,6 @@ instruct sqrtF_reg(regF dst, regF src) %{
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct roundDouble_nop(regD dst) %{
|
||||
match(Set dst (RoundDouble dst));
|
||||
ins_cost(0);
|
||||
|
||||
format %{ " -- \t// RoundDouble not needed - empty" %}
|
||||
size(0);
|
||||
// PPC results are already "rounded" (i.e., normal-format IEEE).
|
||||
ins_encode( /*empty*/ );
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
instruct roundFloat_nop(regF dst) %{
|
||||
match(Set dst (RoundFloat dst));
|
||||
ins_cost(0);
|
||||
|
||||
format %{ " -- \t// RoundFloat not needed - empty" %}
|
||||
size(0);
|
||||
// PPC results are already "rounded" (i.e., normal-format IEEE).
|
||||
ins_encode( /*empty*/ );
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
||||
|
||||
// Multiply-Accumulate
|
||||
// src1 * src2 + src3
|
||||
|
||||
@ -32,11 +32,6 @@ enum {
|
||||
pd_hi_word_offset_in_bytes = BytesPerWord
|
||||
};
|
||||
|
||||
// explicit rounding operations are required to implement the strictFP mode
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = false
|
||||
};
|
||||
|
||||
// registers
|
||||
enum {
|
||||
pd_nof_cpu_regs_frame_map = Register::number_of_registers, // number of registers used during code emission
|
||||
|
||||
@ -355,7 +355,7 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
|
||||
LIR_Opr reg = rlock(x);
|
||||
arithmetic_op_fpu(x->op(), reg, left.result(), right.result());
|
||||
|
||||
set_result(x, round_item(reg));
|
||||
set_result(x, reg);
|
||||
}
|
||||
|
||||
// for _ladd, _lmul, _lsub, _ldiv, _lrem
|
||||
|
||||
@ -114,9 +114,6 @@
|
||||
// C code as the Java calling convention forces doubles to be aligned.
|
||||
static const bool misaligned_doubles_ok = true;
|
||||
|
||||
// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
|
||||
static const bool strict_fp_requires_explicit_rounding = false;
|
||||
|
||||
// Are floats converted to double when stored to stack during
|
||||
// deoptimization?
|
||||
static constexpr bool float_in_double() { return false; }
|
||||
|
||||
@ -32,11 +32,6 @@ enum {
|
||||
pd_hi_word_offset_in_bytes = 0
|
||||
};
|
||||
|
||||
// Explicit rounding operations are not required to implement the strictFP mode.
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = false
|
||||
};
|
||||
|
||||
// registers
|
||||
enum {
|
||||
pd_nof_cpu_regs_frame_map = 16, // Number of registers used during code emission.
|
||||
|
||||
@ -108,9 +108,6 @@
|
||||
// Java calling convention forces doubles to be aligned.
|
||||
static const bool misaligned_doubles_ok = true;
|
||||
|
||||
// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
|
||||
static const bool strict_fp_requires_explicit_rounding = false;
|
||||
|
||||
// Do floats take an entire double register or just half?
|
||||
//
|
||||
// A float in resides in a zarch double register. When storing it by
|
||||
|
||||
@ -5317,23 +5317,6 @@ instruct membar_storestore() %{
|
||||
|
||||
|
||||
//----------Register Move Instructions-----------------------------------------
|
||||
instruct roundDouble_nop(regD dst) %{
|
||||
match(Set dst (RoundDouble dst));
|
||||
ins_cost(0);
|
||||
// TODO: s390 port size(FIXED_SIZE);
|
||||
// z/Architecture results are already "rounded" (i.e., normal-format IEEE).
|
||||
ins_encode();
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
||||
instruct roundFloat_nop(regF dst) %{
|
||||
match(Set dst (RoundFloat dst));
|
||||
ins_cost(0);
|
||||
// TODO: s390 port size(FIXED_SIZE);
|
||||
// z/Architecture results are already "rounded" (i.e., normal-format IEEE).
|
||||
ins_encode();
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
||||
// Cast Long to Pointer for unsafe natives.
|
||||
instruct castX2P(iRegP dst, iRegL src) %{
|
||||
|
||||
@ -31,12 +31,6 @@ enum {
|
||||
pd_hi_word_offset_in_bytes = BytesPerWord
|
||||
};
|
||||
|
||||
// explicit rounding operations are required to implement the strictFP mode
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = LP64_ONLY( false ) NOT_LP64 ( true )
|
||||
};
|
||||
|
||||
|
||||
// registers
|
||||
enum {
|
||||
pd_nof_cpu_regs_frame_map = NOT_LP64(8) LP64_ONLY(16), // number of registers used during code emission
|
||||
|
||||
@ -345,7 +345,7 @@ void LIRGenerator::do_NegateOp(NegateOp* x) {
|
||||
|
||||
__ negate(value.result(), reg);
|
||||
|
||||
set_result(x, round_item(reg));
|
||||
set_result(x, reg);
|
||||
}
|
||||
|
||||
// for _fadd, _fmul, _fsub, _fdiv, _frem
|
||||
@ -433,7 +433,7 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
|
||||
__ move(result_reg, result);
|
||||
} else {
|
||||
arithmetic_op_fpu(x->op(), reg, left.result(), right.result(), tmp);
|
||||
set_result(x, round_item(reg));
|
||||
set_result(x, reg);
|
||||
}
|
||||
#else
|
||||
if ((UseSSE >= 1 && x->op() == Bytecodes::_frem) || (UseSSE >= 2 && x->op() == Bytecodes::_drem)) {
|
||||
@ -454,7 +454,7 @@ void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
|
||||
} else {
|
||||
arithmetic_op_fpu(x->op(), reg, left.result(), right.result(), tmp);
|
||||
}
|
||||
set_result(x, round_item(reg));
|
||||
set_result(x, reg);
|
||||
#endif // _LP64
|
||||
}
|
||||
|
||||
|
||||
@ -624,16 +624,6 @@ void FpuStackAllocator::handle_op1(LIR_Op1* op1) {
|
||||
break;
|
||||
}
|
||||
|
||||
case lir_roundfp: {
|
||||
assert(in->is_fpu_register() && !in->is_xmm_register(), "input must be in register");
|
||||
assert(res->is_stack(), "result must be on stack");
|
||||
|
||||
insert_exchange(in);
|
||||
new_in = to_fpu_stack_top(in);
|
||||
pop_if_last_use(op1, in);
|
||||
break;
|
||||
}
|
||||
|
||||
case lir_abs:
|
||||
case lir_sqrt:
|
||||
case lir_neg: {
|
||||
|
||||
@ -121,13 +121,6 @@
|
||||
// Java calling convention forces doubles to be aligned.
|
||||
static const bool misaligned_doubles_ok = true;
|
||||
|
||||
// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode.
|
||||
#ifdef _LP64
|
||||
static const bool strict_fp_requires_explicit_rounding = false;
|
||||
#else
|
||||
static const bool strict_fp_requires_explicit_rounding = true;
|
||||
#endif
|
||||
|
||||
// Are floats converted to double when stored to stack during deoptimization?
|
||||
// On x64 it is stored without conversion so we can use normal access.
|
||||
// On x32 it is stored with conversion only when FPU is used for floats.
|
||||
|
||||
@ -4225,9 +4225,7 @@ int MatchRule::is_expensive() const {
|
||||
strcmp(opType,"FmaD") == 0 ||
|
||||
strcmp(opType,"FmaF") == 0 ||
|
||||
strcmp(opType,"FmaHF") == 0 ||
|
||||
strcmp(opType,"RoundDouble")==0 ||
|
||||
strcmp(opType,"RoundDoubleMode")==0 ||
|
||||
strcmp(opType,"RoundFloat")==0 ||
|
||||
strcmp(opType,"ReverseBytesI")==0 ||
|
||||
strcmp(opType,"ReverseBytesL")==0 ||
|
||||
strcmp(opType,"ReverseBytesUS")==0 ||
|
||||
|
||||
@ -840,7 +840,6 @@ void Canonicalizer::do_Throw (Throw* x) {}
|
||||
void Canonicalizer::do_Base (Base* x) {}
|
||||
void Canonicalizer::do_OsrEntry (OsrEntry* x) {}
|
||||
void Canonicalizer::do_ExceptionObject(ExceptionObject* x) {}
|
||||
void Canonicalizer::do_RoundFP (RoundFP* x) {}
|
||||
void Canonicalizer::do_UnsafeGet (UnsafeGet* x) {}
|
||||
void Canonicalizer::do_UnsafePut (UnsafePut* x) {}
|
||||
void Canonicalizer::do_UnsafeGetAndSet(UnsafeGetAndSet* x) {}
|
||||
|
||||
@ -88,7 +88,6 @@ class Canonicalizer: InstructionVisitor {
|
||||
virtual void do_Base (Base* x);
|
||||
virtual void do_OsrEntry (OsrEntry* x);
|
||||
virtual void do_ExceptionObject(ExceptionObject* x);
|
||||
virtual void do_RoundFP (RoundFP* x);
|
||||
virtual void do_UnsafeGet (UnsafeGet* x);
|
||||
virtual void do_UnsafePut (UnsafePut* x);
|
||||
virtual void do_UnsafeGetAndSet(UnsafeGetAndSet* x);
|
||||
|
||||
@ -44,13 +44,6 @@ enum {
|
||||
hi_word_offset_in_bytes = pd_hi_word_offset_in_bytes
|
||||
};
|
||||
|
||||
|
||||
// the processor may require explicit rounding operations to implement the strictFP mode
|
||||
enum {
|
||||
strict_fp_requires_explicit_rounding = pd_strict_fp_requires_explicit_rounding
|
||||
};
|
||||
|
||||
|
||||
// for debug info: a float value in a register may be saved in double precision by runtime stubs
|
||||
enum {
|
||||
float_saved_as_double = pd_float_saved_as_double
|
||||
|
||||
@ -673,17 +673,6 @@ class MemoryBuffer: public CompilationResourceObj {
|
||||
return load;
|
||||
}
|
||||
|
||||
if (strict_fp_requires_explicit_rounding && load->type()->is_float_kind()) {
|
||||
#ifdef IA32
|
||||
if (UseSSE < 2) {
|
||||
// can't skip load since value might get rounded as a side effect
|
||||
return load;
|
||||
}
|
||||
#else
|
||||
Unimplemented();
|
||||
#endif // IA32
|
||||
}
|
||||
|
||||
ciField* field = load->field();
|
||||
Value object = load->obj();
|
||||
if (field->holder()->is_loaded() && !field->is_volatile()) {
|
||||
@ -1052,7 +1041,7 @@ void GraphBuilder::store_local(ValueStack* state, Value x, int index) {
|
||||
}
|
||||
}
|
||||
|
||||
state->store_local(index, round_fp(x));
|
||||
state->store_local(index, x);
|
||||
}
|
||||
|
||||
|
||||
@ -1204,10 +1193,7 @@ void GraphBuilder::arithmetic_op(ValueType* type, Bytecodes::Code code, ValueSta
|
||||
Value y = pop(type);
|
||||
Value x = pop(type);
|
||||
Value res = new ArithmeticOp(code, x, y, state_before);
|
||||
// Note: currently single-precision floating-point rounding on Intel is handled at the LIRGenerator level
|
||||
res = append(res);
|
||||
res = round_fp(res);
|
||||
push(type, res);
|
||||
push(type, append(res));
|
||||
}
|
||||
|
||||
|
||||
@ -2228,7 +2214,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
append_split(result);
|
||||
|
||||
if (result_type != voidType) {
|
||||
push(result_type, round_fp(result));
|
||||
push(result_type, result);
|
||||
}
|
||||
if (profile_return() && result_type->is_object_kind()) {
|
||||
profile_return_type(result, target);
|
||||
@ -2356,29 +2342,6 @@ void GraphBuilder::throw_op(int bci) {
|
||||
}
|
||||
|
||||
|
||||
Value GraphBuilder::round_fp(Value fp_value) {
|
||||
if (strict_fp_requires_explicit_rounding) {
|
||||
#ifdef IA32
|
||||
// no rounding needed if SSE2 is used
|
||||
if (UseSSE < 2) {
|
||||
// Must currently insert rounding node for doubleword values that
|
||||
// are results of expressions (i.e., not loads from memory or
|
||||
// constants)
|
||||
if (fp_value->type()->tag() == doubleTag &&
|
||||
fp_value->as_Constant() == nullptr &&
|
||||
fp_value->as_Local() == nullptr && // method parameters need no rounding
|
||||
fp_value->as_RoundFP() == nullptr) {
|
||||
return append(new RoundFP(fp_value));
|
||||
}
|
||||
}
|
||||
#else
|
||||
Unimplemented();
|
||||
#endif // IA32
|
||||
}
|
||||
return fp_value;
|
||||
}
|
||||
|
||||
|
||||
Instruction* GraphBuilder::append_with_bci(Instruction* instr, int bci) {
|
||||
Canonicalizer canon(compilation(), instr, bci);
|
||||
Instruction* i1 = canon.canonical();
|
||||
|
||||
@ -266,7 +266,6 @@ class GraphBuilder {
|
||||
void monitorexit(Value x, int bci);
|
||||
void new_multi_array(int dimensions);
|
||||
void throw_op(int bci);
|
||||
Value round_fp(Value fp_value);
|
||||
|
||||
// stack/code manipulation helpers
|
||||
Instruction* append_with_bci(Instruction* instr, int bci);
|
||||
|
||||
@ -91,7 +91,6 @@ class LookupSwitch;
|
||||
class Return;
|
||||
class Throw;
|
||||
class Base;
|
||||
class RoundFP;
|
||||
class UnsafeOp;
|
||||
class UnsafeGet;
|
||||
class UnsafePut;
|
||||
@ -187,7 +186,6 @@ class InstructionVisitor: public StackObj {
|
||||
virtual void do_Base (Base* x) = 0;
|
||||
virtual void do_OsrEntry (OsrEntry* x) = 0;
|
||||
virtual void do_ExceptionObject(ExceptionObject* x) = 0;
|
||||
virtual void do_RoundFP (RoundFP* x) = 0;
|
||||
virtual void do_UnsafeGet (UnsafeGet* x) = 0;
|
||||
virtual void do_UnsafePut (UnsafePut* x) = 0;
|
||||
virtual void do_UnsafeGetAndSet(UnsafeGetAndSet* x) = 0;
|
||||
@ -556,7 +554,6 @@ class Instruction: public CompilationResourceObj {
|
||||
virtual Return* as_Return() { return nullptr; }
|
||||
virtual Throw* as_Throw() { return nullptr; }
|
||||
virtual Base* as_Base() { return nullptr; }
|
||||
virtual RoundFP* as_RoundFP() { return nullptr; }
|
||||
virtual ExceptionObject* as_ExceptionObject() { return nullptr; }
|
||||
virtual UnsafeOp* as_UnsafeOp() { return nullptr; }
|
||||
virtual ProfileInvoke* as_ProfileInvoke() { return nullptr; }
|
||||
@ -2142,30 +2139,6 @@ LEAF(ExceptionObject, Instruction)
|
||||
};
|
||||
|
||||
|
||||
// Models needed rounding for floating-point values on Intel.
|
||||
// Currently only used to represent rounding of double-precision
|
||||
// values stored into local variables, but could be used to model
|
||||
// intermediate rounding of single-precision values as well.
|
||||
LEAF(RoundFP, Instruction)
|
||||
private:
|
||||
Value _input; // floating-point value to be rounded
|
||||
|
||||
public:
|
||||
RoundFP(Value input)
|
||||
: Instruction(input->type()) // Note: should not be used for constants
|
||||
, _input(input)
|
||||
{
|
||||
ASSERT_VALUES
|
||||
}
|
||||
|
||||
// accessors
|
||||
Value input() const { return _input; }
|
||||
|
||||
// generic
|
||||
virtual void input_values_do(ValueVisitor* f) { f->visit(&_input); }
|
||||
};
|
||||
|
||||
|
||||
BASE(UnsafeOp, Instruction)
|
||||
private:
|
||||
Value _object; // Object to be fetched from or mutated
|
||||
|
||||
@ -779,12 +779,6 @@ void InstructionPrinter::do_ExceptionObject(ExceptionObject* x) {
|
||||
output()->print("incoming exception");
|
||||
}
|
||||
|
||||
|
||||
void InstructionPrinter::do_RoundFP(RoundFP* x) {
|
||||
output()->print("round_fp ");
|
||||
print_value(x->input());
|
||||
}
|
||||
|
||||
void InstructionPrinter::do_UnsafeGet(UnsafeGet* x) {
|
||||
print_unsafe_op(x, x->is_raw() ? "UnsafeGet (raw)" : "UnsafeGet");
|
||||
output()->put(')');
|
||||
|
||||
@ -120,7 +120,6 @@ class InstructionPrinter: public InstructionVisitor {
|
||||
virtual void do_Base (Base* x);
|
||||
virtual void do_OsrEntry (OsrEntry* x);
|
||||
virtual void do_ExceptionObject(ExceptionObject* x);
|
||||
virtual void do_RoundFP (RoundFP* x);
|
||||
virtual void do_UnsafeGet (UnsafeGet* x);
|
||||
virtual void do_UnsafePut (UnsafePut* x);
|
||||
virtual void do_UnsafeGetAndSet(UnsafeGetAndSet* x);
|
||||
|
||||
@ -550,20 +550,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
|
||||
}
|
||||
|
||||
|
||||
// LIR_OpRoundFP;
|
||||
case lir_roundfp: {
|
||||
assert(op->as_OpRoundFP() != nullptr, "must be");
|
||||
LIR_OpRoundFP* opRoundFP = (LIR_OpRoundFP*)op;
|
||||
|
||||
assert(op->_info == nullptr, "info not used by this instruction");
|
||||
assert(opRoundFP->_tmp->is_illegal(), "not used");
|
||||
do_input(opRoundFP->_opr);
|
||||
do_output(opRoundFP->_result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// LIR_Op2
|
||||
case lir_cmp:
|
||||
case lir_cmp_l2i:
|
||||
@ -1731,7 +1717,6 @@ const char * LIR_Op::name() const {
|
||||
case lir_branch: s = "branch"; break;
|
||||
case lir_cond_float_branch: s = "flt_cond_br"; break;
|
||||
case lir_move: s = "move"; break;
|
||||
case lir_roundfp: s = "roundfp"; break;
|
||||
case lir_abs: s = "abs"; break;
|
||||
case lir_neg: s = "neg"; break;
|
||||
case lir_sqrt: s = "sqrt"; break;
|
||||
@ -1976,12 +1961,6 @@ void LIR_OpAllocObj::print_instr(outputStream* out) const {
|
||||
out->print("[lbl:" INTPTR_FORMAT "]", p2i(stub()->entry()));
|
||||
}
|
||||
|
||||
void LIR_OpRoundFP::print_instr(outputStream* out) const {
|
||||
_opr->print(out); out->print(" ");
|
||||
tmp()->print(out); out->print(" ");
|
||||
result_opr()->print(out); out->print(" ");
|
||||
}
|
||||
|
||||
// LIR_Op2
|
||||
void LIR_Op2::print_instr(outputStream* out) const {
|
||||
if (code() == lir_cmp || code() == lir_branch || code() == lir_cond_float_branch) {
|
||||
|
||||
@ -884,7 +884,6 @@ class LIR_OpBranch;
|
||||
class LIR_OpConvert;
|
||||
class LIR_OpAllocObj;
|
||||
class LIR_OpReturn;
|
||||
class LIR_OpRoundFP;
|
||||
class LIR_Op2;
|
||||
class LIR_OpDelay;
|
||||
class LIR_Op3;
|
||||
@ -938,7 +937,6 @@ enum LIR_Code {
|
||||
, lir_convert
|
||||
, lir_alloc_object
|
||||
, lir_monaddr
|
||||
, lir_roundfp
|
||||
, lir_sqrt
|
||||
, lir_abs
|
||||
, lir_neg
|
||||
@ -1147,7 +1145,6 @@ class LIR_Op: public CompilationResourceObj {
|
||||
virtual LIR_OpLock* as_OpLock() { return nullptr; }
|
||||
virtual LIR_OpAllocArray* as_OpAllocArray() { return nullptr; }
|
||||
virtual LIR_OpAllocObj* as_OpAllocObj() { return nullptr; }
|
||||
virtual LIR_OpRoundFP* as_OpRoundFP() { return nullptr; }
|
||||
virtual LIR_OpBranch* as_OpBranch() { return nullptr; }
|
||||
virtual LIR_OpReturn* as_OpReturn() { return nullptr; }
|
||||
virtual LIR_OpRTCall* as_OpRTCall() { return nullptr; }
|
||||
@ -1527,23 +1524,6 @@ class LIR_OpAllocObj : public LIR_Op1 {
|
||||
};
|
||||
|
||||
|
||||
// LIR_OpRoundFP
|
||||
class LIR_OpRoundFP : public LIR_Op1 {
|
||||
friend class LIR_OpVisitState;
|
||||
|
||||
private:
|
||||
LIR_Opr _tmp;
|
||||
|
||||
public:
|
||||
LIR_OpRoundFP(LIR_Opr reg, LIR_Opr stack_loc_temp, LIR_Opr result)
|
||||
: LIR_Op1(lir_roundfp, reg, result)
|
||||
, _tmp(stack_loc_temp) {}
|
||||
|
||||
LIR_Opr tmp() const { return _tmp; }
|
||||
virtual LIR_OpRoundFP* as_OpRoundFP() { return this; }
|
||||
void print_instr(outputStream* out) const PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
// LIR_OpTypeCheck
|
||||
class LIR_OpTypeCheck: public LIR_Op {
|
||||
friend class LIR_OpVisitState;
|
||||
@ -2205,7 +2185,6 @@ class LIR_List: public CompilationResourceObj {
|
||||
|
||||
// result is a stack location for old backend and vreg for UseLinearScan
|
||||
// stack_loc_temp is an illegal register for old backend
|
||||
void roundfp(LIR_Opr reg, LIR_Opr stack_loc_temp, LIR_Opr result) { append(new LIR_OpRoundFP(reg, stack_loc_temp, result)); }
|
||||
void move(LIR_Opr src, LIR_Opr dst, CodeEmitInfo* info = nullptr) { append(new LIR_Op1(lir_move, src, dst, dst->type(), lir_patch_none, info)); }
|
||||
void move(LIR_Address* src, LIR_Opr dst, CodeEmitInfo* info = nullptr) { append(new LIR_Op1(lir_move, LIR_OprFact::address(src), dst, src->type(), lir_patch_none, info)); }
|
||||
void move(LIR_Opr src, LIR_Address* dst, CodeEmitInfo* info = nullptr) { append(new LIR_Op1(lir_move, src, LIR_OprFact::address(dst), dst->type(), lir_patch_none, info)); }
|
||||
|
||||
@ -519,12 +519,6 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) {
|
||||
}
|
||||
break;
|
||||
|
||||
case lir_roundfp: {
|
||||
LIR_OpRoundFP* round_op = op->as_OpRoundFP();
|
||||
roundfp_op(round_op->in_opr(), round_op->tmp(), round_op->result_opr(), round_op->pop_fpu_stack());
|
||||
break;
|
||||
}
|
||||
|
||||
case lir_abs:
|
||||
case lir_sqrt:
|
||||
case lir_f2hf:
|
||||
@ -775,16 +769,6 @@ void LIR_Assembler::build_frame() {
|
||||
}
|
||||
|
||||
|
||||
void LIR_Assembler::roundfp_op(LIR_Opr src, LIR_Opr tmp, LIR_Opr dest, bool pop_fpu_stack) {
|
||||
assert(strict_fp_requires_explicit_rounding, "not required");
|
||||
assert((src->is_single_fpu() && dest->is_single_stack()) ||
|
||||
(src->is_double_fpu() && dest->is_double_stack()),
|
||||
"round_fp: rounds register -> stack location");
|
||||
|
||||
reg2stack (src, dest, src->type(), pop_fpu_stack);
|
||||
}
|
||||
|
||||
|
||||
void LIR_Assembler::move_op(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, bool wide) {
|
||||
if (src->is_register()) {
|
||||
if (dest->is_register()) {
|
||||
|
||||
@ -215,7 +215,6 @@ class LIR_Assembler: public CompilationResourceObj {
|
||||
|
||||
void logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest);
|
||||
|
||||
void roundfp_op(LIR_Opr src, LIR_Opr tmp, LIR_Opr dest, bool pop_fpu_stack);
|
||||
void move_op(LIR_Opr src, LIR_Opr result, BasicType type,
|
||||
LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, bool wide);
|
||||
void volatile_move_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info);
|
||||
|
||||
@ -881,27 +881,6 @@ void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** ex
|
||||
}
|
||||
|
||||
|
||||
LIR_Opr LIRGenerator::round_item(LIR_Opr opr) {
|
||||
assert(opr->is_register(), "why spill if item is not register?");
|
||||
|
||||
if (strict_fp_requires_explicit_rounding) {
|
||||
#ifdef IA32
|
||||
if (UseSSE < 1 && opr->is_single_fpu()) {
|
||||
LIR_Opr result = new_register(T_FLOAT);
|
||||
set_vreg_flag(result, must_start_in_memory);
|
||||
assert(opr->is_register(), "only a register can be spilled");
|
||||
assert(opr->value_type()->is_float(), "rounding only for floats available");
|
||||
__ roundfp(opr, LIR_OprFact::illegalOpr, result);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
Unimplemented();
|
||||
#endif // IA32
|
||||
}
|
||||
return opr;
|
||||
}
|
||||
|
||||
|
||||
LIR_Opr LIRGenerator::force_to_spill(LIR_Opr value, BasicType t) {
|
||||
assert(type2size[t] == type2size[value->type()],
|
||||
"size mismatch: t=%s, value->type()=%s", type2name(t), type2name(value->type()));
|
||||
@ -2053,25 +2032,6 @@ void LIRGenerator::do_Throw(Throw* x) {
|
||||
}
|
||||
|
||||
|
||||
void LIRGenerator::do_RoundFP(RoundFP* x) {
|
||||
assert(strict_fp_requires_explicit_rounding, "not required");
|
||||
|
||||
LIRItem input(x->input(), this);
|
||||
input.load_item();
|
||||
LIR_Opr input_opr = input.result();
|
||||
assert(input_opr->is_register(), "why round if value is not in a register?");
|
||||
assert(input_opr->is_single_fpu() || input_opr->is_double_fpu(), "input should be floating-point value");
|
||||
if (input_opr->is_single_fpu()) {
|
||||
set_result(x, round_item(input_opr)); // This code path not currently taken
|
||||
} else {
|
||||
LIR_Opr result = new_register(T_DOUBLE);
|
||||
set_vreg_flag(result, must_start_in_memory);
|
||||
__ roundfp(input_opr, LIR_OprFact::illegalOpr, result);
|
||||
set_result(x, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIRGenerator::do_UnsafeGet(UnsafeGet* x) {
|
||||
BasicType type = x->basic_type();
|
||||
LIRItem src(x->object(), this);
|
||||
|
||||
@ -233,7 +233,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
||||
|
||||
friend class LIRItem;
|
||||
|
||||
LIR_Opr round_item(LIR_Opr opr);
|
||||
LIR_Opr force_to_spill(LIR_Opr value, BasicType t);
|
||||
|
||||
PhiResolverState& resolver_state() { return _resolver_state; }
|
||||
@ -579,7 +578,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
||||
virtual void do_Base (Base* x);
|
||||
virtual void do_OsrEntry (OsrEntry* x);
|
||||
virtual void do_ExceptionObject(ExceptionObject* x);
|
||||
virtual void do_RoundFP (RoundFP* x);
|
||||
virtual void do_UnsafeGet (UnsafeGet* x);
|
||||
virtual void do_UnsafePut (UnsafePut* x);
|
||||
virtual void do_UnsafeGetAndSet(UnsafeGetAndSet* x);
|
||||
|
||||
@ -5888,7 +5888,6 @@ bool LinearScanWalker::activate_current() {
|
||||
|
||||
} else if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::must_start_in_memory)) {
|
||||
// activating an interval that must start in a stack slot, but may get a register later
|
||||
// used for lir_roundfp: rounding is done by store to stack and reload later
|
||||
TRACE_LINEAR_SCAN(4, tty->print_cr(" interval must start in stack slot -> split it before first use"));
|
||||
assert(cur->assigned_reg() == any_reg && cur->assigned_regHi() == any_reg, "register already assigned");
|
||||
|
||||
@ -6770,7 +6769,6 @@ void LinearScanStatistic::collect(LinearScan* allocator) {
|
||||
case lir_push:
|
||||
case lir_pop:
|
||||
case lir_convert:
|
||||
case lir_roundfp:
|
||||
case lir_cmove: inc_counter(counter_misc_inst); break;
|
||||
|
||||
default: inc_counter(counter_other_inst); break;
|
||||
|
||||
@ -577,7 +577,6 @@ public:
|
||||
void do_Base (Base* x);
|
||||
void do_OsrEntry (OsrEntry* x);
|
||||
void do_ExceptionObject(ExceptionObject* x);
|
||||
void do_RoundFP (RoundFP* x);
|
||||
void do_UnsafeGet (UnsafeGet* x);
|
||||
void do_UnsafePut (UnsafePut* x);
|
||||
void do_UnsafeGetAndSet(UnsafeGetAndSet* x);
|
||||
@ -762,7 +761,6 @@ void NullCheckVisitor::do_Throw (Throw* x) { nce()->clear_las
|
||||
void NullCheckVisitor::do_Base (Base* x) {}
|
||||
void NullCheckVisitor::do_OsrEntry (OsrEntry* x) {}
|
||||
void NullCheckVisitor::do_ExceptionObject(ExceptionObject* x) { nce()->handle_ExceptionObject(x); }
|
||||
void NullCheckVisitor::do_RoundFP (RoundFP* x) {}
|
||||
void NullCheckVisitor::do_UnsafeGet (UnsafeGet* x) {}
|
||||
void NullCheckVisitor::do_UnsafePut (UnsafePut* x) {}
|
||||
void NullCheckVisitor::do_UnsafeGetAndSet(UnsafeGetAndSet* x) {}
|
||||
|
||||
@ -154,7 +154,6 @@ public:
|
||||
void do_Base (Base* x) { /* nothing to do */ };
|
||||
void do_OsrEntry (OsrEntry* x) { /* nothing to do */ };
|
||||
void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ };
|
||||
void do_RoundFP (RoundFP* x) { /* nothing to do */ };
|
||||
void do_UnsafePut (UnsafePut* x) { /* nothing to do */ };
|
||||
void do_UnsafeGet (UnsafeGet* x) { /* nothing to do */ };
|
||||
void do_UnsafeGetAndSet(UnsafeGetAndSet* x) { /* nothing to do */ };
|
||||
|
||||
@ -203,7 +203,6 @@ class ValueNumberingVisitor: public InstructionVisitor {
|
||||
void do_Base (Base* x) { /* nothing to do */ }
|
||||
void do_OsrEntry (OsrEntry* x) { /* nothing to do */ }
|
||||
void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }
|
||||
void do_RoundFP (RoundFP* x) { /* nothing to do */ }
|
||||
void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }
|
||||
void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ }
|
||||
void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ };
|
||||
|
||||
@ -149,11 +149,6 @@ Node* BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) cons
|
||||
C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);
|
||||
|
||||
GraphKit* kit = parse_access.kit();
|
||||
if (bt == T_DOUBLE) {
|
||||
Node* new_val = kit->dprecision_rounding(val.node());
|
||||
val.set_node(new_val);
|
||||
}
|
||||
|
||||
store = kit->store_to_memory(kit->control(), access.addr().node(), val.node(), bt,
|
||||
mo, requires_atomic_access, unaligned, mismatched,
|
||||
unsafe, access.barrier_data());
|
||||
|
||||
@ -313,10 +313,8 @@ macro(ReverseI)
|
||||
macro(ReverseL)
|
||||
macro(ReverseV)
|
||||
macro(Root)
|
||||
macro(RoundDouble)
|
||||
macro(RoundDoubleMode)
|
||||
macro(RoundDoubleModeV)
|
||||
macro(RoundFloat)
|
||||
macro(RotateLeft)
|
||||
macro(RotateLeftV)
|
||||
macro(RotateRight)
|
||||
|
||||
@ -181,16 +181,6 @@ const Type* ConvD2INode::Value(PhaseGVN* phase) const {
|
||||
return TypeInt::make( SharedRuntime::d2i( td->getd() ) );
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// If converting to an int type, skip any rounding nodes
|
||||
Node *ConvD2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
if (in(1)->Opcode() == Op_RoundDouble) {
|
||||
set_req(1, in(1)->in(1));
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------Identity---------------------------------------
|
||||
// Int's can be converted to doubles with no loss of bits. Hence
|
||||
// converting an integer to a double and back to an integer is a NOP.
|
||||
@ -217,16 +207,6 @@ Node* ConvD2LNode::Identity(PhaseGVN* phase) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// If converting to an int type, skip any rounding nodes
|
||||
Node *ConvD2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
if (in(1)->Opcode() == Op_RoundDouble) {
|
||||
set_req(1, in(1)->in(1));
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Value------------------------------------------
|
||||
const Type* ConvF2DNode::Value(PhaseGVN* phase) const {
|
||||
@ -300,16 +280,6 @@ Node* ConvF2INode::Identity(PhaseGVN* phase) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// If converting to an int type, skip any rounding nodes
|
||||
Node *ConvF2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
if (in(1)->Opcode() == Op_RoundFloat) {
|
||||
set_req(1, in(1)->in(1));
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Value------------------------------------------
|
||||
const Type* ConvF2LNode::Value(PhaseGVN* phase) const {
|
||||
@ -329,16 +299,6 @@ Node* ConvF2LNode::Identity(PhaseGVN* phase) {
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// If converting to an int type, skip any rounding nodes
|
||||
Node *ConvF2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
if (in(1)->Opcode() == Op_RoundFloat) {
|
||||
set_req(1, in(1)->in(1));
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Value------------------------------------------
|
||||
const Type* ConvHF2FNode::Value(PhaseGVN* phase) const {
|
||||
@ -865,52 +825,6 @@ Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Identity---------------------------------------
|
||||
// Remove redundant roundings
|
||||
Node* RoundFloatNode::Identity(PhaseGVN* phase) {
|
||||
assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel");
|
||||
// Do not round constants
|
||||
if (phase->type(in(1))->base() == Type::FloatCon) return in(1);
|
||||
int op = in(1)->Opcode();
|
||||
// Redundant rounding
|
||||
if( op == Op_RoundFloat ) return in(1);
|
||||
// Already rounded
|
||||
if( op == Op_Parm ) return in(1);
|
||||
if( op == Op_LoadF ) return in(1);
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Value------------------------------------------
|
||||
const Type* RoundFloatNode::Value(PhaseGVN* phase) const {
|
||||
return phase->type( in(1) );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------Identity---------------------------------------
|
||||
// Remove redundant roundings. Incoming arguments are already rounded.
|
||||
Node* RoundDoubleNode::Identity(PhaseGVN* phase) {
|
||||
assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel");
|
||||
// Do not round constants
|
||||
if (phase->type(in(1))->base() == Type::DoubleCon) return in(1);
|
||||
int op = in(1)->Opcode();
|
||||
// Redundant rounding
|
||||
if( op == Op_RoundDouble ) return in(1);
|
||||
// Already rounded
|
||||
if( op == Op_Parm ) return in(1);
|
||||
if( op == Op_LoadD ) return in(1);
|
||||
if( op == Op_ConvF2D ) return in(1);
|
||||
if( op == Op_ConvI2D ) return in(1);
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------Value------------------------------------------
|
||||
const Type* RoundDoubleNode::Value(PhaseGVN* phase) const {
|
||||
return phase->type( in(1) );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
RoundDoubleModeNode* RoundDoubleModeNode::make(PhaseGVN& gvn, Node* arg, RoundDoubleModeNode::RoundingMode rmode) {
|
||||
ConINode* rm = gvn.intcon(rmode);
|
||||
|
||||
@ -79,7 +79,6 @@ class ConvD2INode : public ConvertNode {
|
||||
virtual const Type* in_type() const { return Type::DOUBLE; }
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------ConvD2LNode------------------------------------
|
||||
@ -91,7 +90,6 @@ class ConvD2LNode : public ConvertNode {
|
||||
virtual const Type* in_type() const { return Type::DOUBLE; }
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------ConvF2DNode------------------------------------
|
||||
@ -124,7 +122,6 @@ public:
|
||||
virtual const Type* in_type() const { return TypeInt::FLOAT; }
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------ConvF2LNode------------------------------------
|
||||
@ -136,7 +133,6 @@ public:
|
||||
virtual const Type* in_type() const { return TypeInt::FLOAT; }
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------ConvHF2FNode------------------------------------
|
||||
@ -254,28 +250,6 @@ public:
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
};
|
||||
|
||||
//-----------------------------RoundFloatNode----------------------------------
|
||||
class RoundFloatNode: public Node {
|
||||
public:
|
||||
RoundFloatNode(Node* c, Node *in1): Node(c, in1) {}
|
||||
virtual int Opcode() const;
|
||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||
virtual uint ideal_reg() const { return Op_RegF; }
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------RoundDoubleNode---------------------------------
|
||||
class RoundDoubleNode: public Node {
|
||||
public:
|
||||
RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {}
|
||||
virtual int Opcode() const;
|
||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||
virtual uint ideal_reg() const { return Op_RegD; }
|
||||
virtual Node* Identity(PhaseGVN* phase);
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
};
|
||||
|
||||
//-----------------------------RoundDoubleModeNode-----------------------------
|
||||
class RoundDoubleModeNode: public Node {
|
||||
|
||||
@ -648,8 +648,6 @@ void Parse::do_call() {
|
||||
orig_callee = callee = nullptr;
|
||||
|
||||
// ---------------------
|
||||
// Round double arguments before call
|
||||
round_double_arguments(cg->method());
|
||||
|
||||
// Feed profiling data for arguments to the type system so it can
|
||||
// propagate it as speculative types
|
||||
|
||||
@ -2364,51 +2364,6 @@ void GraphKit::record_profiled_return_for_speculation() {
|
||||
}
|
||||
}
|
||||
|
||||
void GraphKit::round_double_arguments(ciMethod* dest_method) {
|
||||
if (Matcher::strict_fp_requires_explicit_rounding) {
|
||||
// (Note: TypeFunc::make has a cache that makes this fast.)
|
||||
const TypeFunc* tf = TypeFunc::make(dest_method);
|
||||
int nargs = tf->domain()->cnt() - TypeFunc::Parms;
|
||||
for (int j = 0; j < nargs; j++) {
|
||||
const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms);
|
||||
if (targ->basic_type() == T_DOUBLE) {
|
||||
// If any parameters are doubles, they must be rounded before
|
||||
// the call, dprecision_rounding does gvn.transform
|
||||
Node *arg = argument(j);
|
||||
arg = dprecision_rounding(arg);
|
||||
set_argument(j, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rounding for strict float precision conformance
|
||||
Node* GraphKit::precision_rounding(Node* n) {
|
||||
if (Matcher::strict_fp_requires_explicit_rounding) {
|
||||
#ifdef IA32
|
||||
if (UseSSE == 0) {
|
||||
return _gvn.transform(new RoundFloatNode(nullptr, n));
|
||||
}
|
||||
#else
|
||||
Unimplemented();
|
||||
#endif // IA32
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// rounding for strict double precision conformance
|
||||
Node* GraphKit::dprecision_rounding(Node *n) {
|
||||
if (Matcher::strict_fp_requires_explicit_rounding) {
|
||||
#ifdef IA32
|
||||
if (UseSSE < 2) {
|
||||
return _gvn.transform(new RoundDoubleNode(nullptr, n));
|
||||
}
|
||||
#else
|
||||
Unimplemented();
|
||||
#endif // IA32
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Generate a fast path/slow path idiom. Graph looks like:
|
||||
|
||||
@ -752,15 +752,6 @@ class GraphKit : public Phase {
|
||||
void final_sync(IdealKit& ideal);
|
||||
|
||||
public:
|
||||
// Helper function to round double arguments before a call
|
||||
void round_double_arguments(ciMethod* dest_method);
|
||||
|
||||
// rounding for strict float precision conformance
|
||||
Node* precision_rounding(Node* n);
|
||||
|
||||
// rounding for strict double precision conformance
|
||||
Node* dprecision_rounding(Node* n);
|
||||
|
||||
// Helper functions for fast/slow path codes
|
||||
Node* opt_iff(Node* region, Node* iff);
|
||||
Node* make_runtime_call(int flags,
|
||||
|
||||
@ -1721,20 +1721,6 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------round_double_node--------------------------------
|
||||
// Round a double node if necessary.
|
||||
Node* LibraryCallKit::round_double_node(Node* n) {
|
||||
if (Matcher::strict_fp_requires_explicit_rounding) {
|
||||
#ifdef IA32
|
||||
if (UseSSE < 2) {
|
||||
n = _gvn.transform(new RoundDoubleNode(nullptr, n));
|
||||
}
|
||||
#else
|
||||
Unimplemented();
|
||||
#endif // IA32
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
//------------------------------inline_math-----------------------------------
|
||||
// public static double Math.abs(double)
|
||||
@ -1743,7 +1729,7 @@ Node* LibraryCallKit::round_double_node(Node* n) {
|
||||
// public static double Math.log10(double)
|
||||
// public static double Math.round(double)
|
||||
bool LibraryCallKit::inline_double_math(vmIntrinsics::ID id) {
|
||||
Node* arg = round_double_node(argument(0));
|
||||
Node* arg = argument(0);
|
||||
Node* n = nullptr;
|
||||
switch (id) {
|
||||
case vmIntrinsics::_dabs: n = new AbsDNode( arg); break;
|
||||
@ -1754,7 +1740,7 @@ bool LibraryCallKit::inline_double_math(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_floor: n = RoundDoubleModeNode::make(_gvn, arg, RoundDoubleModeNode::rmode_floor); break;
|
||||
case vmIntrinsics::_rint: n = RoundDoubleModeNode::make(_gvn, arg, RoundDoubleModeNode::rmode_rint); break;
|
||||
case vmIntrinsics::_roundD: n = new RoundDNode(arg); break;
|
||||
case vmIntrinsics::_dcopySign: n = CopySignDNode::make(_gvn, arg, round_double_node(argument(2))); break;
|
||||
case vmIntrinsics::_dcopySign: n = CopySignDNode::make(_gvn, arg, argument(2)); break;
|
||||
case vmIntrinsics::_dsignum: n = SignumDNode::make(_gvn, arg); break;
|
||||
default: fatal_unexpected_iid(id); break;
|
||||
}
|
||||
@ -1788,8 +1774,8 @@ bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, c
|
||||
"must be (DD)D or (D)D type");
|
||||
|
||||
// Inputs
|
||||
Node* a = round_double_node(argument(0));
|
||||
Node* b = (call_type == OptoRuntime::Math_DD_D_Type()) ? round_double_node(argument(2)) : nullptr;
|
||||
Node* a = argument(0);
|
||||
Node* b = (call_type == OptoRuntime::Math_DD_D_Type()) ? argument(2) : nullptr;
|
||||
|
||||
const TypePtr* no_memory_effects = nullptr;
|
||||
Node* trig = make_runtime_call(RC_LEAF, call_type, funcAddr, funcName,
|
||||
@ -1807,17 +1793,17 @@ bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, c
|
||||
|
||||
//------------------------------inline_math_pow-----------------------------
|
||||
bool LibraryCallKit::inline_math_pow() {
|
||||
Node* exp = round_double_node(argument(2));
|
||||
Node* exp = argument(2);
|
||||
const TypeD* d = _gvn.type(exp)->isa_double_constant();
|
||||
if (d != nullptr) {
|
||||
if (d->getd() == 2.0) {
|
||||
// Special case: pow(x, 2.0) => x * x
|
||||
Node* base = round_double_node(argument(0));
|
||||
Node* base = argument(0);
|
||||
set_result(_gvn.transform(new MulDNode(base, base)));
|
||||
return true;
|
||||
} else if (d->getd() == 0.5 && Matcher::match_rule_supported(Op_SqrtD)) {
|
||||
// Special case: pow(x, 0.5) => sqrt(x)
|
||||
Node* base = round_double_node(argument(0));
|
||||
Node* base = argument(0);
|
||||
Node* zero = _gvn.zerocon(T_DOUBLE);
|
||||
|
||||
RegionNode* region = new RegionNode(3);
|
||||
@ -1963,8 +1949,8 @@ bool LibraryCallKit::inline_min_max(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_minD_strict:
|
||||
case vmIntrinsics::_maxD_strict:
|
||||
assert(callee()->signature()->size() == 4, "minD/maxD has 2 parameters of size 2 each.");
|
||||
a = round_double_node(argument(0));
|
||||
b = round_double_node(argument(2));
|
||||
a = argument(0);
|
||||
b = argument(2);
|
||||
break;
|
||||
case vmIntrinsics::_minL:
|
||||
case vmIntrinsics::_maxL:
|
||||
@ -8483,9 +8469,9 @@ bool LibraryCallKit::inline_fma(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_fmaD:
|
||||
assert(callee()->signature()->size() == 6, "fma has 3 parameters of size 2 each.");
|
||||
// no receiver since it is static method
|
||||
a = round_double_node(argument(0));
|
||||
b = round_double_node(argument(2));
|
||||
c = round_double_node(argument(4));
|
||||
a = argument(0);
|
||||
b = argument(2);
|
||||
c = argument(4);
|
||||
result = _gvn.transform(new FmaDNode(a, b, c));
|
||||
break;
|
||||
case vmIntrinsics::_fmaF:
|
||||
|
||||
@ -202,7 +202,6 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_string_getCharsU();
|
||||
bool inline_string_copy(bool compress);
|
||||
bool inline_string_char_access(bool is_store);
|
||||
Node* round_double_node(Node* n);
|
||||
bool runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName);
|
||||
bool inline_math_native(vmIntrinsics::ID id);
|
||||
bool inline_math(vmIntrinsics::ID id);
|
||||
|
||||
@ -2062,19 +2062,19 @@ void Parse::do_one_bytecode() {
|
||||
|
||||
// double stores
|
||||
case Bytecodes::_dstore_0:
|
||||
set_pair_local( 0, dprecision_rounding(pop_pair()) );
|
||||
set_pair_local( 0, pop_pair() );
|
||||
break;
|
||||
case Bytecodes::_dstore_1:
|
||||
set_pair_local( 1, dprecision_rounding(pop_pair()) );
|
||||
set_pair_local( 1, pop_pair() );
|
||||
break;
|
||||
case Bytecodes::_dstore_2:
|
||||
set_pair_local( 2, dprecision_rounding(pop_pair()) );
|
||||
set_pair_local( 2, pop_pair() );
|
||||
break;
|
||||
case Bytecodes::_dstore_3:
|
||||
set_pair_local( 3, dprecision_rounding(pop_pair()) );
|
||||
set_pair_local( 3, pop_pair() );
|
||||
break;
|
||||
case Bytecodes::_dstore:
|
||||
set_pair_local( iter().get_index(), dprecision_rounding(pop_pair()) );
|
||||
set_pair_local( iter().get_index(), pop_pair() );
|
||||
break;
|
||||
|
||||
case Bytecodes::_pop: dec_sp(1); break;
|
||||
@ -2256,32 +2256,28 @@ void Parse::do_one_bytecode() {
|
||||
b = pop();
|
||||
a = pop();
|
||||
c = _gvn.transform( new SubFNode(a,b) );
|
||||
d = precision_rounding(c);
|
||||
push( d );
|
||||
push(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_fadd:
|
||||
b = pop();
|
||||
a = pop();
|
||||
c = _gvn.transform( new AddFNode(a,b) );
|
||||
d = precision_rounding(c);
|
||||
push( d );
|
||||
push(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_fmul:
|
||||
b = pop();
|
||||
a = pop();
|
||||
c = _gvn.transform( new MulFNode(a,b) );
|
||||
d = precision_rounding(c);
|
||||
push( d );
|
||||
push(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_fdiv:
|
||||
b = pop();
|
||||
a = pop();
|
||||
c = _gvn.transform( new DivFNode(nullptr,a,b) );
|
||||
d = precision_rounding(c);
|
||||
push( d );
|
||||
push(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_frem:
|
||||
@ -2331,8 +2327,6 @@ void Parse::do_one_bytecode() {
|
||||
case Bytecodes::_d2f:
|
||||
a = pop_pair();
|
||||
b = _gvn.transform( new ConvD2FNode(a));
|
||||
// This breaks _227_mtrt (speed & correctness) and _222_mpegaudio (speed)
|
||||
//b = _gvn.transform(new RoundFloatNode(nullptr, b) );
|
||||
push( b );
|
||||
break;
|
||||
|
||||
@ -2340,11 +2334,6 @@ void Parse::do_one_bytecode() {
|
||||
if (Matcher::convL2FSupported()) {
|
||||
a = pop_pair();
|
||||
b = _gvn.transform( new ConvL2FNode(a));
|
||||
// For x86_32.ad, FILD doesn't restrict precision to 24 or 53 bits.
|
||||
// Rather than storing the result into an FP register then pushing
|
||||
// out to memory to round, the machine instruction that implements
|
||||
// ConvL2D is responsible for rounding.
|
||||
// c = precision_rounding(b);
|
||||
push(b);
|
||||
} else {
|
||||
l2f();
|
||||
@ -2354,8 +2343,6 @@ void Parse::do_one_bytecode() {
|
||||
case Bytecodes::_l2d:
|
||||
a = pop_pair();
|
||||
b = _gvn.transform( new ConvL2DNode(a));
|
||||
// For x86_32.ad, rounding is always necessary (see _l2f above).
|
||||
// c = dprecision_rounding(b);
|
||||
push_pair(b);
|
||||
break;
|
||||
|
||||
@ -2375,32 +2362,28 @@ void Parse::do_one_bytecode() {
|
||||
b = pop_pair();
|
||||
a = pop_pair();
|
||||
c = _gvn.transform( new SubDNode(a,b) );
|
||||
d = dprecision_rounding(c);
|
||||
push_pair( d );
|
||||
push_pair(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_dadd:
|
||||
b = pop_pair();
|
||||
a = pop_pair();
|
||||
c = _gvn.transform( new AddDNode(a,b) );
|
||||
d = dprecision_rounding(c);
|
||||
push_pair( d );
|
||||
push_pair(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_dmul:
|
||||
b = pop_pair();
|
||||
a = pop_pair();
|
||||
c = _gvn.transform( new MulDNode(a,b) );
|
||||
d = dprecision_rounding(c);
|
||||
push_pair( d );
|
||||
push_pair(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_ddiv:
|
||||
b = pop_pair();
|
||||
a = pop_pair();
|
||||
c = _gvn.transform( new DivDNode(nullptr,a,b) );
|
||||
d = dprecision_rounding(c);
|
||||
push_pair( d );
|
||||
push_pair(c);
|
||||
break;
|
||||
|
||||
case Bytecodes::_dneg:
|
||||
@ -2585,8 +2568,7 @@ void Parse::do_one_bytecode() {
|
||||
case Bytecodes::_i2f:
|
||||
a = pop();
|
||||
b = _gvn.transform( new ConvI2FNode(a) ) ;
|
||||
c = precision_rounding(b);
|
||||
push (b);
|
||||
push(b);
|
||||
break;
|
||||
|
||||
case Bytecodes::_i2d:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user