/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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"
#include "c1/c1_Instruction.hpp"
#include "c1/c1_LinearScan.hpp"
#include "utilities/bitMap.inline.hpp"
//----------------------------------------------------------------------
// Allocation of FPU stack slots (Intel x86 only)
//----------------------------------------------------------------------
// First compute which FPU registers are live at the start of each basic block
// (To minimize the amount of work we have to do if we have to merge FPU stacks)
if (ComputeExactFPURegisterUsage) {
// ignore memory intervals by overwriting intervals_in_memory
// the dummy interval is needed to enforce the walker to walk until the given id:
// without it, the walker stops when the unhandled-list is empty -> live information
// beyond this point would be incorrect.
for (int i = 0; i < num_blocks; i++) {
BlockBegin* b = block_at(i);
// register usage is only needed for merging stacks -> compute only
// when more than one predecessor.
// the block must not have any spill moves at the beginning (checked by assertions)
// spill moves would use intervals that are marked as handled and so the usage bit
// would been set incorrectly
// NOTE: the check for number_of_preds > 1 is necessary. A block with only one
// predecessor may have spill moves at the begin of the block.
// If an interval ends at the current instruction id, it is not possible
// to decide if the register is live or not at the block begin -> the
// register information would be incorrect.
if (b->number_of_preds() > 1) {
// Only consider FPU values in registers
assert(interval->assigned_regHi() == -1, "must not have hi register (doubles stored in one register)");
#ifndef PRODUCT
if (TraceFPURegisterUsage) {
}
#endif
}
#ifndef PRODUCT
if (TraceFPURegisterUsage) {
tty->print("FPU regs for block %d, LIR instr %d): ", b->block_id(), id); regs.print_on(tty); tty->print_cr("");
}
#endif
}
}
}
}
, _pos(-1)
, _sim(compilation)
{}
for (int i = 0; i < num_blocks; i++) {
// Set up to process block
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
"FPU stack state must be present due to linear-scan order for FPU stack allocation");
// note: exception handler entries always start with an empty fpu stack
// because stack merging would be too complicated
if (fpu_stack_state != NULL) {
} else {
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
}
bool processed_merge = false;
set_pos(0);
// Note: insts->length() may change during loop
_debug_information_computed = false;
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
if (!processed_merge) {
// propagate stack at first branch to a successor
processed_merge = true;
assert(!required_merge || branch->cond() == lir_cond_always, "splitting of critical edges should prevent FPU stack mismatches at cond branches");
}
}
}
// Propagate stack when block does not end with branch
if (!processed_merge) {
}
}
// exception handling
for (int k = 0; k < n; k++) {
}
} else {
}
// compute debug information
int n = visitor.info_count();
assert(n > 0, "should not visit operation otherwise");
for (int j = 0; j < n; j++) {
// Compute debug information
}
}
_debug_information_computed = true;
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
// need entry code to clear FPU stack
}
set_pos(0);
// Note: insts->length() may change during loop
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
case lir_move:
break;
case lir_branch:
// remove all remaining dead registers from FPU stack
break;
default:
// other operations not allowed in exception entry code
}
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
}
}
}
if (opr->is_single_fpu()) {
} else {
}
}
int stack_offset = 0;
if (opr->is_single_fpu()) {
} else {
}
}
}
if (offset > 0) {
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
}
}
// move stack slot to the top of stack and then pop it
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
}
}
}
}
#ifndef PRODUCT
if (TraceFPUStack) {
tty->print("Inserted copy (%d -> %d) New state: ", fpu_num(from), fpu_num(to)); sim()->print(); tty->cr();
}
#endif
}
}
}
if (opr->is_last_use()) {
}
}
}
insert_free(0);
} else {
// move "preserve" to bottom of stack so that all other stack slots can be popped
}
}
}
// Note: this switch is processed for all LIR_Op1, regardless if they have FPU-arguments,
// so checks for is_float_kind() are necessary inside the cases
case lir_return: {
// FPU-Stack must only contain the (optional) fpu return value.
// All remaining dead values are popped from the stack
// If the input operand is a fpu-register, it is exchanged to the bottom of the stack
}
break;
}
case lir_move: {
if (res->is_xmm_register()) {
// move from fpu register to xmm register (necessary for operations that
// are not available in the SSE instruction set)
// move from fpu-register to fpu-register:
// * input and result register equal:
// nothing to do
// * input register is last use:
// rename the input register to result register -> input register
// not present on fpu-stack afterwards
// * input register not last use:
// duplicate input register to result register to preserve input
//
// Note: The LIR-Assembler does not produce any code for fpu register moves,
// so input and result stack index must be equal
// nothing to do
} else if (in->is_last_use()) {
} else {
}
} else {
// move from fpu-register to memory
// input operand must be on top of stack
// create debug information here because afterwards the register may have been popped
}
// result is pushed on the stack
// create debug information before register is pushed
}
break;
}
case lir_neg: {
}
break;
}
case lir_convert: {
switch (bc) {
// this is quite the same as a move from fpu-register to fpu-register
// Note: input and result operands must have different types
// nothing to do
} else if (in->is_last_use()) {
} else {
}
}
break;
if (!res->is_xmm_register()) {
}
break;
if (!in->is_xmm_register()) {
// TODO: update registes of stub
}
break;
if (!in->is_xmm_register()) {
}
break;
// no fpu operands
break;
default:
}
break;
}
case lir_roundfp: {
break;
}
default: {
}
}
}
if (!left->is_float_kind()) {
return;
}
if (left->is_xmm_register()) {
return;
}
assert(!left->is_xmm_register() && !right->is_xmm_register() && !res->is_xmm_register(), "not for xmm registers");
case lir_cmp:
case lir_cmp_fd2i:
case lir_ucmp_fd2i: {
// the left-hand side must be on top of stack.
// the right-hand side is never popped, even if is_last_use is set
break;
}
case lir_mul_strictfp:
case lir_div_strictfp: {
// fall-through: continue with the normal handling of lir_mul and lir_div
}
case lir_add:
case lir_sub:
case lir_mul:
case lir_div: {
// either the left-hand or the right-hand side must be on top of stack
// (if right is not a register, left must be on top)
if (!right->is_fpu_register()) {
} else {
// no exchange necessary if right is alredy on top of stack
if (tos_offset(right) == 0) {
} else {
}
if (right->is_last_use()) {
if (tos_offset(right) == 0) {
} else {
// if left is on top of stack, the result is placed in the stack
// slot of right, so a renaming from right to res is necessary
}
}
}
break;
}
case lir_rem: {
// Must bring both operands to top of stack with following operand ordering:
// * fpu stack before rem: ... right left
// * fpu stack after rem: ... left
insert_exchange(1);
}
break;
}
case lir_abs:
case lir_sqrt: {
// Right argument appears to be unused
break;
}
case lir_log:
case lir_log10: {
// log and log10 need one temporary fpu stack slot, so
// there is one temporary registers stored in temp of the
// operation. the stack allocator must guarantee that the stack
// slots are really free, otherwise there might be a stack
// overflow.
break;
}
case lir_tan:
case lir_sin:
case lir_cos:
case lir_exp: {
// sin, cos and exp need two temporary fpu stack slots, so there are two temporary
// registers (stored in right and temp of the operation).
// the stack allocator must guarantee that the stack slots are really free,
// otherwise there might be a stack overflow.
// assert(left->is_last_use(), "old value gets destroyed");
assert(fpu_num(left) != fpu_num(right) && fpu_num(right) != fpu_num(op2->tmp1_opr()) && fpu_num(op2->tmp1_opr()) != fpu_num(res), "need distinct temp registers");
break;
}
case lir_pow: {
// pow needs two temporary fpu stack slots, so there are two temporary
// registers (stored in tmp1 and tmp2 of the operation).
// the stack allocator must guarantee that the stack slots are really free,
// otherwise there might be a stack overflow.
assert(fpu_num(left) != fpu_num(right) && fpu_num(left) != fpu_num(op2->tmp1_opr()) && fpu_num(left) != fpu_num(op2->tmp2_opr()) && fpu_num(left) != fpu_num(res), "need distinct temp registers");
assert(fpu_num(right) != fpu_num(op2->tmp1_opr()) && fpu_num(right) != fpu_num(op2->tmp2_opr()) && fpu_num(right) != fpu_num(res), "need distinct temp registers");
assert(fpu_num(op2->tmp1_opr()) != fpu_num(op2->tmp2_opr()) && fpu_num(op2->tmp1_opr()) != fpu_num(res), "need distinct temp registers");
// Must bring both operands to top of stack with following operand ordering:
// * fpu stack before pow: ... right left
// * fpu stack after pow: ... left
insert_exchange(1);
}
break;
}
default: {
assert(false, "missed a fpu-operation");
}
}
}
// clear fpu-stack before call
// it may contain dead values that could not have been remved by previous operations
// compute debug information before (possible) fpu result is pushed
}
}
#ifndef PRODUCT
case lir_24bit_FPU:
case lir_reset_FPU:
case lir_ffree:
assert(false, "operations not allowed in lir. If one of these operations is needed, check if they have fpu operands");
break;
case lir_fpop_raw:
case lir_fxch:
case lir_fld:
assert(false, "operations only inserted by FpuStackAllocator");
break;
}
}
#endif
LIR_Op1* move = new LIR_Op1(lir_move, LIR_OprFact::doubleConst(0), LIR_OprFact::double_fpu(reg)->make_fpu_stack_offset());
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
#ifndef PRODUCT
if (TraceFPUStack) {
tty->print("Exchanged register: %d New state: ", cur_sim->get_slot(slot)); cur_sim->print(); tty->cr();
}
#endif
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
bool FpuStackAllocator::merge_rename(FpuStackSim* cur_sim, FpuStackSim* sux_sim, int start_slot, int change_slot) {
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
return true;
}
}
return false;
}
void FpuStackAllocator::merge_fpu_stack(LIR_List* instrs, FpuStackSim* cur_sim, FpuStackSim* sux_sim) {
#ifndef PRODUCT
if (TraceFPUStack) {
}
int slot;
}
}
#endif
// size difference between cur and sux that must be resolved by adding or removing values form the stack
if (!ComputeExactFPURegisterUsage) {
// add slots that are currently free, but used in successor
// When the exact FPU register usage is computed, the stack does
// not contain dead values at merging -> no values must be added
while (size_diff < 0) {
size_diff++;
}
}
sux_slot--;
}
}
// stack merge algorithm:
// 1) as long as the current stack top is not in the right location (that meens
// it should not be on the stack top), exchange it into the right location
// 2) if the stack top is right, but the remaining stack is not ordered correctly,
// the stack top is exchanged away to get another value on top ->
// now step 1) can be continued
// the stack can also contain unused items -> these items are removed from stack
while (finished_slot >= 0 || size_diff > 0) {
while (size_diff > 0 || (cur_sim->stack_size() > 0 && cur_sim->get_slot(0) != sux_sim->get_slot(0))) {
size_diff--;
}
assert(cur_sim->stack_size() == 0 || cur_sim->get_slot(0) != reg, "register must have been changed");
}
while (finished_slot >= 0 && cur_sim->get_slot(finished_slot) == sux_sim->get_slot(finished_slot)) {
}
if (finished_slot >= 0) {
}
}
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
void FpuStackAllocator::merge_cleanup_fpu_stack(LIR_List* instrs, FpuStackSim* cur_sim, BitMap& live_fpu_regs) {
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
int slot = 0;
if (slot != 0) {
}
} else {
slot++;
}
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
// check if fpu stack only contains live registers
for (unsigned int i = 0; i < live_fpu_regs.size(); i++) {
break;
}
}
#endif
}
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
bool changed = false;
// The successor has at least two incoming edges, so a stack merge will be necessary
// If this block is the first predecessor, cleanup the current stack and propagate it
// If this block is not the first predecessor, a stack merge will be necessary
// Merge with a successors that already has a FPU stack state
// the block must only have one successor because critical edges must been split
} else {
// propagate current FPU stack state to successor without state
// clean up stack first so that there are no dead values on the stack
if (ComputeExactFPURegisterUsage) {
}
if (TraceFPUStack) {
}
}
changed = true;
}
} else {
// Propagate unmodified Stack to successors where a stack merge is not necessary
for (int i = 0; i < number_of_sux; i++) {
#ifdef ASSERT
for (int j = 0; j < sux->number_of_preds(); j++) {
}
// check if new state is same
}
}
#endif
#ifndef PRODUCT
if (TraceFPUStack) {
}
#endif
}
}
#ifndef PRODUCT
// assertions that FPU stack state conforms to all successors' states
for (int i = 0; i < number_of_sux; i++) {
}
}
#endif
return changed;
}