void LIRGenerator::do_Convert(Convert* x) { // flags that vary for the different operations and different SSE-settings bool fixed_input, fixed_result, round_result, needs_stub; switch (x->op()) { case Bytecodes::_i2l: // fall through case Bytecodes::_l2i: // fall through case Bytecodes::_i2b: // fall through case Bytecodes::_i2c: // fall through case Bytecodes::_i2s: fixed_input = false; fixed_result = false; round_result = false; needs_stub = false; break; case Bytecodes::_f2d: fixed_input = UseSSE == 1; fixed_result = false; round_result = false; needs_stub = false; break; case Bytecodes::_d2f: fixed_input = false; fixed_result = UseSSE == 1; round_result = UseSSE < 1; needs_stub = false; break; case Bytecodes::_i2f: fixed_input = false; fixed_result = false; round_result = UseSSE < 1; needs_stub = false; break; case Bytecodes::_i2d: fixed_input = false; fixed_result = false; round_result = false; needs_stub = false; break; case Bytecodes::_f2i: fixed_input = false; fixed_result = false; round_result = false; needs_stub = true; break; case Bytecodes::_d2i: fixed_input = false; fixed_result = false; round_result = false; needs_stub = true; break; case Bytecodes::_l2f: fixed_input = false; fixed_result = UseSSE >= 1; round_result = UseSSE < 1; needs_stub = false; break; case Bytecodes::_l2d: fixed_input = false; fixed_result = UseSSE >= 2; round_result = UseSSE < 2; needs_stub = false; break; case Bytecodes::_f2l: fixed_input = true; fixed_result = true; round_result = false; needs_stub = false; break; case Bytecodes::_d2l: fixed_input = true; fixed_result = true; round_result = false; needs_stub = false; break; default: ShouldNotReachHere(); } LIRItem value(x->value(), this); value.load_item(); LIR_Opr input = value.result(); LIR_Opr result = rlock(x); // arguments of lir_convert LIR_Opr conv_input = input; LIR_Opr conv_result = result; ConversionStub* stub = NULL; if (fixed_input) { conv_input = fixed_register_for(input->type()); __ move(input, conv_input); } assert(fixed_result == false || round_result == false, "cannot set both"); if (fixed_result) { conv_result = fixed_register_for(result->type()); } else if (round_result) { result = new_register(result->type()); set_vreg_flag(result, must_start_in_memory); } if (needs_stub) { stub = new ConversionStub(x->op(), conv_input, conv_result); } __ convert(x->op(), conv_input, conv_result, stub); if (result != conv_result) { __ move(conv_result, result); } assert(result->is_virtual(), "result must be virtual register"); set_result(x, result); }
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, BasicType type, bool is_volatile) { if (is_volatile && type == T_LONG) { LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE); LIR_Opr tmp = new_register(T_DOUBLE); LIR_Opr spill = new_register(T_DOUBLE); set_vreg_flag(spill, must_start_in_memory); __ move(data, spill); __ move(spill, tmp); __ move(tmp, addr); } else { LIR_Address* addr = new LIR_Address(src, offset, type); bool is_obj = (type == T_ARRAY || type == T_OBJECT); if (is_obj) { // Do the pre-write barrier, if any. pre_barrier(LIR_OprFact::address(addr), false, NULL); __ move(data, addr); assert(src->is_register(), "must be register"); // Seems to be a precise address post_barrier(LIR_OprFact::address(addr), data); } else { __ move(data, addr); } } }
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, BasicType type, bool is_volatile) { if (is_volatile && type == T_LONG) { LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE); LIR_Opr tmp = new_register(T_DOUBLE); __ load(addr, tmp); LIR_Opr spill = new_register(T_LONG); set_vreg_flag(spill, must_start_in_memory); __ move(tmp, spill); __ move(spill, dst); } else { LIR_Address* addr = new LIR_Address(src, offset, type); __ load(addr, dst); } }
void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, CodeEmitInfo* info) { if (address->type() == T_LONG) { address = new LIR_Address(address->base(), address->index(), address->scale(), address->disp(), T_DOUBLE); // Transfer the value atomically by using FP moves. This means // the value has to be moved between CPU and FPU registers. It // always has to be moved through spill slot since there's no // quick way to pack the value into an SSE register. LIR_Opr temp_double = new_register(T_DOUBLE); LIR_Opr spill = new_register(T_LONG); set_vreg_flag(spill, must_start_in_memory); __ move(value, spill); __ volatile_move(spill, temp_double, T_LONG); __ volatile_move(temp_double, LIR_OprFact::address(address), T_LONG, info); } else { __ store(value, address, info); } }
void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { if (address->type() == T_LONG) { address = new LIR_Address(address->base(), address->index(), address->scale(), address->disp(), T_DOUBLE); // Transfer the value atomically by using FP moves. This means // the value has to be moved between CPU and FPU registers. In // SSE0 and SSE1 mode it has to be moved through spill slot but in // SSE2+ mode it can be moved directly. LIR_Opr temp_double = new_register(T_DOUBLE); __ volatile_move(LIR_OprFact::address(address), temp_double, T_LONG, info); __ volatile_move(temp_double, result, T_LONG); if (UseSSE < 2) { // no spill slot needed in SSE2 mode because xmm->cpu register move is possible set_vreg_flag(result, must_start_in_memory); } } else { __ load(address, result, info); } }
void set_vreg_flag (LIR_Opr opr, VregFlag f) { set_vreg_flag(opr->vreg_number(), f); }
LIR_Opr LIRGenerator::rlock_byte(BasicType type) { LIR_Opr reg = new_register(T_INT); set_vreg_flag(reg, LIRGenerator::byte_reg); return reg; }
// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f // _i2b, _i2c, _i2s void LIRGenerator::do_Convert(Convert* x) { switch (x->op()) { case Bytecodes::_f2l: case Bytecodes::_d2l: case Bytecodes::_d2i: case Bytecodes::_l2f: case Bytecodes::_l2d: { address entry; switch (x->op()) { case Bytecodes::_l2f: entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f); break; case Bytecodes::_l2d: entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2d); break; case Bytecodes::_f2l: entry = CAST_FROM_FN_PTR(address, SharedRuntime::f2l); break; case Bytecodes::_d2l: entry = CAST_FROM_FN_PTR(address, SharedRuntime::d2l); break; case Bytecodes::_d2i: entry = CAST_FROM_FN_PTR(address, SharedRuntime::d2i); break; default: ShouldNotReachHere(); } LIR_Opr result = call_runtime(x->value(), entry, x->type(), NULL); set_result(x, result); break; } case Bytecodes::_i2f: case Bytecodes::_i2d: { LIRItem value(x->value(), this); LIR_Opr reg = rlock_result(x); // To convert an int to double, we need to load the 32-bit int // from memory into a single precision floating point register // (even numbered). Then the sparc fitod instruction takes care // of the conversion. This is a bit ugly, but is the best way to // get the int value in a single precision floating point register value.load_item(); LIR_Opr tmp = force_to_spill(value.result(), T_FLOAT); __ convert(x->op(), tmp, reg); break; } break; case Bytecodes::_i2l: case Bytecodes::_i2b: case Bytecodes::_i2c: case Bytecodes::_i2s: case Bytecodes::_l2i: case Bytecodes::_f2d: case Bytecodes::_d2f: { // inline code LIRItem value(x->value(), this); value.load_item(); LIR_Opr reg = rlock_result(x); __ convert(x->op(), value.result(), reg, false); } break; case Bytecodes::_f2i: { LIRItem value (x->value(), this); value.set_destroys_register(); value.load_item(); LIR_Opr reg = rlock_result(x); set_vreg_flag(reg, must_start_in_memory); __ convert(x->op(), value.result(), reg, false); } break; default: ShouldNotReachHere(); } }
LIR_Opr LIRGenerator::rlock_callee_saved(BasicType type) { LIR_Opr reg = new_register(type); set_vreg_flag(reg, callee_saved); return reg; }