/* * Copyright (c) 2005, 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. *
*/
LinearScan::LinearScan(IR* ir, LIRGenerator* gen, FrameMap* frame_map)
: _compilation(ir->compilation())
, _ir(ir)
, _gen(gen)
, _frame_map(frame_map)
, _cached_blocks(*ir->linear_scan_order())
, _num_virtual_regs(gen->max_virtual_register_number())
, _has_fpu_registers(false)
, _num_calls(-1)
, _max_spills(0)
, _unused_spill_slot(-1)
, _intervals(0) // initialized later with correct length
, _new_intervals_from_allocation(NULL)
, _sorted_intervals(NULL)
, _needs_full_resort(false)
, _lir_ops(0) // initialized later with correct length
, _block_of_op(0) // initialized later with correct length
, _has_info(0)
, _has_call(0)
, _interval_in_loop(0) // initialized later with correct length
, _scope_value_cache(0) // initialized later with correct length #ifdef IA32
, _fpu_stack_allocator(NULL) #endif
{
assert(this->ir() != NULL, "check if valid");
assert(this->compilation() != NULL, "check if valid");
assert(this->gen() != NULL, "check if valid");
assert(this->frame_map() != NULL, "check if valid");
}
// ********** functions for converting LIR-Operands to register numbers // // Emulate a flat register file comprising physical integer registers, // physical floating-point registers and virtual registers, in that order. // Virtual registers already have appropriate numbers, since V0 is // the number of physical registers. // Returns -1 for hi word if opr is a single word operand. // // Note: the inverse operation (calculating an operand for register numbers) // is done in calc_operand_for_interval()
int LinearScan::reg_num(LIR_Opr opr) {
assert(opr->is_register(), "should not call this otherwise");
// compute next unused stack index that can be used for spilling int LinearScan::allocate_spill_slot(bool double_word) { int spill_slot; if (double_word) { if ((_max_spills & 1) == 1) { // alignment of double-word values // the hole because of the alignment is filled with the next single-word value
assert(_unused_spill_slot == -1, "wasting a spill slot");
_unused_spill_slot = _max_spills;
_max_spills++;
}
spill_slot = _max_spills;
_max_spills += 2;
} elseif (_unused_spill_slot != -1) { // re-use hole that was the result of a previous double-word alignment
spill_slot = _unused_spill_slot;
_unused_spill_slot = -1;
int result = spill_slot + LinearScan::nof_regs + frame_map()->argcount();
// if too many slots used, bailout compilation. if (result > 2000) {
bailout("too many stack slots used");
}
return result;
}
void LinearScan::assign_spill_slot(Interval* it) { // assign the canonical spill slot of the parent (if a part of the interval // is already spilled) or allocate a new spill slot if (it->canonical_spill_slot() >= 0) {
it->assign_reg(it->canonical_spill_slot());
} else { int spill = allocate_spill_slot(type2spill_size[it->type()] == 2);
it->set_canonical_spill_slot(spill);
it->assign_reg(spill);
}
}
void LinearScan::propagate_spill_slots() { if (!frame_map()->finalize_frame(max_spills())) {
bailout("frame too large");
}
}
// create a new interval with a predefined reg_num // (only used for parent intervals that are created during the building phase)
Interval* LinearScan::create_interval(int reg_num) {
assert(_intervals.at(reg_num) == NULL, "overwriting existing interval");
Interval* interval = new Interval(reg_num);
_intervals.at_put(reg_num, interval);
// assign register number for precolored intervals if (reg_num < LIR_Opr::vreg_base) {
interval->assign_reg(reg_num);
} return interval;
}
// assign a new reg_num to the interval and append it to the list of intervals // (only used for child intervals that are created during register allocation) void LinearScan::append_interval(Interval* it) {
it->set_reg_num(_intervals.length());
_intervals.append(it);
IntervalList* new_intervals = _new_intervals_from_allocation; if (new_intervals == NULL) {
new_intervals = _new_intervals_from_allocation = new IntervalList();
}
new_intervals->append(it);
}
// copy the vreg-flags if an interval is split void LinearScan::copy_register_flags(Interval* from, Interval* to) { if (gen()->is_vreg_flag_set(from->reg_num(), LIRGenerator::byte_reg)) {
gen()->set_vreg_flag(to->reg_num(), LIRGenerator::byte_reg);
} if (gen()->is_vreg_flag_set(from->reg_num(), LIRGenerator::callee_saved)) {
gen()->set_vreg_flag(to->reg_num(), LIRGenerator::callee_saved);
}
// Note: do not copy the must_start_in_memory flag because it is not necessary for child // intervals (only the very beginning of the interval must be in memory)
}
// ********** spill move optimization // eliminate moves from register to stack if stack slot is known to be correct
// called during building of intervals void LinearScan::change_spill_definition_pos(Interval* interval, int def_pos) {
assert(interval->is_split_parent(), "can only be called for split parents");
switch (interval->spill_state()) { case noDefinitionFound:
assert(interval->spill_definition_pos() == -1, "must no be set before");
interval->set_spill_definition_pos(def_pos);
interval->set_spill_state(oneDefinitionFound); break;
case oneDefinitionFound:
assert(def_pos <= interval->spill_definition_pos(), "positions are processed in reverse order when intervals are created"); if (def_pos < interval->spill_definition_pos() - 2) { // second definition found, so no spill optimization possible for this interval
interval->set_spill_state(noOptimization);
} else { // two consecutive definitions (because of two-operand LIR form)
assert(block_of_op_with_id(def_pos) == block_of_op_with_id(interval->spill_definition_pos()), "block must be equal");
} break;
case noOptimization: // nothing to do break;
default:
assert(false, "other states not allowed at this time");
}
}
// called during register allocation void LinearScan::change_spill_state(Interval* interval, int spill_pos) { switch (interval->spill_state()) { case oneDefinitionFound: { int def_loop_depth = block_of_op_with_id(interval->spill_definition_pos())->loop_depth(); int spill_loop_depth = block_of_op_with_id(spill_pos)->loop_depth();
if (def_loop_depth < spill_loop_depth) { // the loop depth of the spilling position is higher then the loop depth // at the definition of the interval -> move write to memory out of loop // by storing at definitin of the interval
interval->set_spill_state(storeAtDefinition);
} else { // the interval is currently spilled only once, so for now there is no // reason to store the interval at the definition
interval->set_spill_state(oneMoveInserted);
} break;
}
case oneMoveInserted: { // the interval is spilled more then once, so it is better to store it to // memory at the definition
interval->set_spill_state(storeAtDefinition); break;
}
case storeAtDefinition: case startInMemory: case noOptimization: case noDefinitionFound: // nothing to do break;
default:
assert(false, "other states not allowed at this time");
}
}
// called once before assignment of register numbers void LinearScan::eliminate_spill_moves() {
TIME_LINEAR_SCAN(timer_eliminate_spill_moves);
TRACE_LINEAR_SCAN(3, tty->print_cr("***** Eliminating unnecessary spill moves"));
// collect all intervals that must be stored after their definion. // the list is sorted by Interval::spill_definition_pos
Interval* interval;
Interval* temp_list;
create_unhandled_lists(&interval, &temp_list, must_store_at_definition, NULL);
#ifdef ASSERT
Interval* prev = NULL;
Interval* temp = interval; while (temp != Interval::end()) {
assert(temp->spill_definition_pos() > 0, "invalid spill definition pos"); if (prev != NULL) {
assert(temp->from() >= prev->from(), "intervals not sorted");
assert(temp->spill_definition_pos() >= prev->spill_definition_pos(), "when intervals are sorted by from, then they must also be sorted by spill_definition_pos");
}
assert(temp->canonical_spill_slot() >= LinearScan::nof_regs, "interval has no spill slot assigned");
assert(temp->spill_definition_pos() >= temp->from(), "invalid order");
assert(temp->spill_definition_pos() <= temp->from() + 2, "only intervals defined once at their start-pos can be optimized");
TRACE_LINEAR_SCAN(4, tty->print_cr("interval %d (from %d to %d) must be stored at %d", temp->reg_num(), temp->from(), temp->to(), temp->spill_definition_pos()));
temp = temp->next();
} #endif
LIR_InsertionBuffer insertion_buffer; int num_blocks = block_count(); for (int i = 0; i < num_blocks; i++) {
BlockBegin* block = block_at(i);
LIR_OpList* instructions = block->lir()->instructions_list(); int num_inst = instructions->length(); bool has_new = false;
// iterate all instructions of the block. skip the first because it is always a label for (int j = 1; j < num_inst; j++) {
LIR_Op* op = instructions->at(j); int op_id = op->id();
if (op_id == -1) { // remove move from register to stack if the stack slot is guaranteed to be correct. // only moves that have been inserted by LinearScan can be removed.
assert(op->code() == lir_move, "only moves can have a op_id of -1");
assert(op->as_Op1() != NULL, "move must be LIR_Op1");
assert(op->as_Op1()->result_opr()->is_virtual(), "LinearScan inserts only moves to virtual registers");
if (interval->assigned_reg() >= LinearScan::nof_regs && interval->always_in_memory()) { // move target is a stack slot that is always correct, so eliminate instruction
TRACE_LINEAR_SCAN(4, tty->print_cr("eliminating move from interval %d to %d", op1->in_opr()->vreg_number(), op1->result_opr()->vreg_number()));
instructions->at_put(j, NULL); // NULL-instructions are deleted by assign_reg_num
}
} else { // insert move from register to stack just after the beginning of the interval
assert(interval == Interval::end() || interval->spill_definition_pos() >= op_id, "invalid order");
assert(interval == Interval::end() || (interval->is_split_parent() && interval->spill_state() == storeAtDefinition), "invalid interval");
while (interval != Interval::end() && interval->spill_definition_pos() == op_id) { if (!has_new) { // prepare insertion buffer (appended when all instructions of the block are processed)
insertion_buffer.init(block->lir());
has_new = true;
}
LIR_Opr from_opr = operand_for_interval(interval);
LIR_Opr to_opr = canonical_spill_opr(interval);
assert(from_opr->is_fixed_cpu() || from_opr->is_fixed_fpu(), "from operand must be a register");
assert(to_opr->is_stack(), "to operand must be a stack slot");
insertion_buffer.move(j, from_opr, to_opr);
TRACE_LINEAR_SCAN(4, tty->print_cr("inserting move after definition of interval %d to stack slot %d at op_id %d", interval->reg_num(), interval->canonical_spill_slot() - LinearScan::nof_regs, op_id));
interval = interval->next();
}
}
} // end of instruction iteration
if (has_new) {
block->lir()->append(&insertion_buffer);
}
} // end of block iteration
assert(interval == Interval::end(), "missed an interval");
}
// ********** Phase 1: number all instructions in all blocks // Compute depth-first and linear scan block orders, and number LIR_Op nodes for linear scan.
void LinearScan::number_instructions() {
{ // dummy-timer to measure the cost of the timer itself // (this time is then subtracted from all other timers to get the real value)
TIME_LINEAR_SCAN(timer_do_nothing);
}
TIME_LINEAR_SCAN(timer_number_instructions);
// Assign IDs to LIR nodes and build a mapping, lir_ops, from ID to LIR_Op node. int num_blocks = block_count(); int num_instructions = 0; int i; for (i = 0; i < num_blocks; i++) {
num_instructions += block_at(i)->lir()->instructions_list()->length();
}
// check some asumptions about debug information
assert(!value->type()->is_illegal(), "if this local is used by the interpreter it shouldn't be of indeterminate type");
assert(con == NULL || opr->is_virtual() || opr->is_constant() || opr->is_illegal(), "assumption: Constant instructions have only constant operands");
assert(con != NULL || opr->is_virtual(), "assumption: non-Constant instructions have only virtual operands");
if ((con == NULL || con->is_pinned()) && opr->is_register()) {
assert(reg_num(opr) == opr->vreg_number() && !is_valid_reg_num(reg_numHi(opr)), "invalid optimization below"); int reg = opr->vreg_number(); if (!live_kill.at(reg)) {
live_gen.set_bit(reg);
TRACE_LINEAR_SCAN(4, tty->print_cr(" Setting live_gen for value %c%d, LIR op_id %d, register number %d", value->type()->tchar(), value->id(), op->id(), reg));
}
}
}
if (block->is_set(BlockBegin::exception_entry_flag)) { // Phi functions at the begin of an exception handler are // implicitly defined (= killed) at the beginning of the block.
for_each_phi_fun(block, phi, if (!phi->is_illegal()) { live_kill.set_bit(phi->operand()->vreg_number()); }
);
}
LIR_OpList* instructions = block->lir()->instructions_list(); int num_inst = instructions->length();
// iterate all instructions of the block. skip the first because it is always a label
assert(visitor.no_operands(instructions->at(0)), "first operation must always be a label"); for (int j = 1; j < num_inst; j++) {
LIR_Op* op = instructions->at(j);
// visit operation to collect all operands
visitor.visit(op);
if (visitor.has_call()) {
_has_call.set_bit(op->id() >> 1);
local_num_calls++;
} if (visitor.info_count() > 0) {
_has_info.set_bit(op->id() >> 1);
}
// iterate input operands of instruction int k, n, reg;
n = visitor.opr_count(LIR_OpVisitState::inputMode); for (k = 0; k < n; k++) {
LIR_Opr opr = visitor.opr_at(LIR_OpVisitState::inputMode, k);
assert(opr->is_register(), "visitor should only return register operands");
if (opr->is_virtual_register()) {
assert(reg_num(opr) == opr->vreg_number() && !is_valid_reg_num(reg_numHi(opr)), "invalid optimization below");
reg = opr->vreg_number(); if (!live_kill.at(reg)) {
live_gen.set_bit(reg);
TRACE_LINEAR_SCAN(4, tty->print_cr(" Setting live_gen for register %d at instruction %d", reg, op->id()));
} if (block->loop_index() >= 0) {
local_interval_in_loop.set_bit(reg, block->loop_index());
}
local_has_fpu_registers = local_has_fpu_registers || opr->is_virtual_fpu();
}
#ifdef ASSERT // fixed intervals are never live at block boundaries, so // they need not be processed in live sets. // this is checked by these assertions to be sure about it. // the entry block may have incoming values in registers, which is ok. if (!opr->is_virtual_register() && block != ir()->start()) {
reg = reg_num(opr); if (is_processed_reg_num(reg)) {
assert(live_kill.at(reg), "using fixed register that is not defined in this block");
}
reg = reg_numHi(opr); if (is_valid_reg_num(reg) && is_processed_reg_num(reg)) {
assert(live_kill.at(reg), "using fixed register that is not defined in this block");
}
} #endif
}
// Add uses of live locals from interpreter's point of view for proper debug information generation
n = visitor.info_count(); for (k = 0; k < n; k++) {
CodeEmitInfo* info = visitor.info_at(k);
ValueStack* stack = info->stack();
for_each_state_value(stack, value,
set_live_gen_kill(value, op, live_gen, live_kill);
local_has_fpu_registers = local_has_fpu_registers || value->type()->is_float_kind();
);
}
// iterate temp operands of instruction
n = visitor.opr_count(LIR_OpVisitState::tempMode); for (k = 0; k < n; k++) {
LIR_Opr opr = visitor.opr_at(LIR_OpVisitState::tempMode, k);
assert(opr->is_register(), "visitor should only return register operands");
#ifdef ASSERT // fixed intervals are never live at block boundaries, so // they need not be processed in live sets // process them only in debug mode so that this can be checked if (!opr->is_virtual_register()) {
reg = reg_num(opr); if (is_processed_reg_num(reg)) {
live_kill.set_bit(reg_num(opr));
}
reg = reg_numHi(opr); if (is_valid_reg_num(reg) && is_processed_reg_num(reg)) {
live_kill.set_bit(reg);
}
} #endif
}
// iterate output operands of instruction
n = visitor.opr_count(LIR_OpVisitState::outputMode); for (k = 0; k < n; k++) {
LIR_Opr opr = visitor.opr_at(LIR_OpVisitState::outputMode, k);
assert(opr->is_register(), "visitor should only return register operands");
#ifdef ASSERT // fixed intervals are never live at block boundaries, so // they need not be processed in live sets // process them only in debug mode so that this can be checked if (!opr->is_virtual_register()) {
reg = reg_num(opr); if (is_processed_reg_num(reg)) {
live_kill.set_bit(reg_num(opr));
}
reg = reg_numHi(opr); if (is_valid_reg_num(reg) && is_processed_reg_num(reg)) {
live_kill.set_bit(reg);
}
} #endif
}
} // end of instruction iteration
TRACE_LINEAR_SCAN(4, tty->print("live_gen B%d ", block->block_id()); print_bitmap(block->live_gen()));
TRACE_LINEAR_SCAN(4, tty->print("live_kill B%d ", block->block_id()); print_bitmap(block->live_kill()));
} // end of block iteration
// propagate local calculated information into LinearScan object
_has_fpu_registers = local_has_fpu_registers;
compilation()->set_has_fpu_code(local_has_fpu_registers);
int num_blocks = block_count(); bool change_occurred; bool change_occurred_in_block; int iteration_count = 0;
ResourceBitMap live_out(live_set_size()); // scratch set for calculations
// Perform a backward dataflow analysis to compute live_out and live_in for each block. // The loop is executed until a fixpoint is reached (no changes in an iteration) // Exception handlers must be processed because not all live values are // present in the state array, e.g. because of global value numbering do {
change_occurred = false;
// iterate all blocks in reverse order for (int i = num_blocks - 1; i >= 0; i--) {
BlockBegin* block = block_at(i);
change_occurred_in_block = false;
// live_out(block) is the union of live_in(sux), for successors sux of block int n = block->number_of_sux(); int e = block->number_of_exception_handlers(); if (n + e > 0) { // block has successors if (n > 0) {
live_out.set_from(block->sux_at(0)->live_in()); for (int j = 1; j < n; j++) {
live_out.set_union(block->sux_at(j)->live_in());
}
} else {
live_out.clear();
} for (int j = 0; j < e; j++) {
live_out.set_union(block->exception_handler_at(j)->live_in());
}
if (!block->live_out().is_same(live_out)) { // A change occurred. Swap the old and new live out sets to avoid copying.
ResourceBitMap temp = block->live_out();
block->set_live_out(live_out);
live_out = temp;
if (iteration_count == 0 || change_occurred_in_block) { // live_in(block) is the union of live_gen(block) with (live_out(block) & !live_kill(block)) // note: live_in has to be computed only in first iteration or if live_out has changed!
ResourceBitMap live_in = block->live_in();
live_in.set_from(block->live_out());
live_in.set_difference(block->live_kill());
live_in.set_union(block->live_gen());
}
if (change_occurred && iteration_count > 50) {
BAILOUT("too many iterations in compute_global_live_sets");
}
} while (change_occurred);
#ifdef ASSERT // check that fixed intervals are not live at block boundaries // (live set must be empty at fixed intervals) for (int i = 0; i < num_blocks; i++) {
BlockBegin* block = block_at(i); for (int j = 0; j < LIR_Opr::vreg_base; j++) {
assert(block->live_in().at(j) == false, "live_in set of fixed register must be empty");
assert(block->live_out().at(j) == false, "live_out set of fixed register must be empty");
assert(block->live_gen().at(j) == false, "live_gen set of fixed register must be empty");
}
} #endif
// check that the live_in set of the first block is empty
ResourceBitMap live_in_args(ir()->start()->live_in().size()); if (!ir()->start()->live_in().is_same(live_in_args)) { #ifdef ASSERT
tty->print_cr("Error: live_in set of first block must be empty (when this fails, virtual registers are used before they are defined)");
tty->print_cr("affected registers:");
print_bitmap(ir()->start()->live_in());
// print some additional information to simplify debugging for (unsignedint i = 0; i < ir()->start()->live_in().size(); i++) { if (ir()->start()->live_in().at(i)) {
Instruction* instr = gen()->instruction_for_vreg(i);
tty->print_cr("* vreg %d (HIR instruction %c%d)", i, instr == NULL ? ' ' : instr->type()->tchar(), instr == NULL ? 0 : instr->id());
for (int j = 0; j < num_blocks; j++) {
BlockBegin* block = block_at(j); if (block->live_gen().at(i)) {
tty->print_cr(" used in block B%d", block->block_id());
} if (block->live_kill().at(i)) {
tty->print_cr(" defined in block B%d", block->block_id());
}
}
}
}
#endif // when this fails, virtual registers are used before they are defined.
assert(false, "live_in set of first block must be empty"); // bailout of if this occurs in product mode.
bailout("live_in set of first block not empty");
}
}
// ********** Phase 4: build intervals // (fills the list _intervals)
void LinearScan::add_use(Value value, int from, int to, IntervalUseKind use_kind) {
assert(!value->type()->is_illegal(), "if this value is used by the interpreter it shouldn't be of indeterminate type");
LIR_Opr opr = value->operand();
Constant* con = value->as_Constant();
} else { int reg = reg_num(opr); if (is_processed_reg_num(reg)) {
add_def(reg, def_pos, use_kind, opr->type_register());
}
reg = reg_numHi(opr); if (is_valid_reg_num(reg) && is_processed_reg_num(reg)) {
add_def(reg, def_pos, use_kind, opr->type_register());
}
}
}
void LinearScan::add_use(LIR_Opr opr, int from, int to, IntervalUseKind use_kind) {
TRACE_LINEAR_SCAN(2, tty->print(" use "); opr->print(tty); tty->print_cr(" from %d to %d (%d)", from, to, use_kind));
assert(opr->is_register(), "should not be called otherwise");
if (opr->is_virtual_register()) {
assert(reg_num(opr) == opr->vreg_number() && !is_valid_reg_num(reg_numHi(opr)), "invalid optimization below");
add_use(opr->vreg_number(), from, to, use_kind, opr->type_register());
} else { int reg = reg_num(opr); if (is_processed_reg_num(reg)) {
add_use(reg, from, to, use_kind, opr->type_register());
}
reg = reg_numHi(opr); if (is_valid_reg_num(reg) && is_processed_reg_num(reg)) {
add_use(reg, from, to, use_kind, opr->type_register());
}
}
}
void LinearScan::add_temp(LIR_Opr opr, int temp_pos, IntervalUseKind use_kind) {
TRACE_LINEAR_SCAN(2, tty->print(" temp "); opr->print(tty); tty->print_cr(" temp_pos %d (%d)", temp_pos, use_kind));
assert(opr->is_register(), "should not be called otherwise");
if (type != T_ILLEGAL) {
interval->set_type(type);
}
Range* r = interval->first(); if (r->from() <= def_pos) { // Update the starting point (when a range is first created for a use, its // start is the beginning of the current block until a def is encountered.)
r->set_from(def_pos);
interval->add_use_pos(def_pos, use_kind);
} else { // Dead value - make vacuous interval // also add use_kind for dead intervals
interval->add_range(def_pos, def_pos + 1);
interval->add_use_pos(def_pos, use_kind);
TRACE_LINEAR_SCAN(2, tty->print_cr("Warning: def of reg %d at %d occurs without use", reg_num, def_pos));
}
} else { // Dead value - make vacuous interval // also add use_kind for dead intervals
interval = create_interval(reg_num); if (type != T_ILLEGAL) {
interval->set_type(type);
}
interval->add_range(def_pos, def_pos + 1);
interval->add_use_pos(def_pos, use_kind);
TRACE_LINEAR_SCAN(2, tty->print_cr("Warning: dead value %d at %d in live intervals", reg_num, def_pos));
}
change_spill_definition_pos(interval, def_pos); if (use_kind == noUse && interval->spill_state() <= startInMemory) { // detection of method-parameters and roundfp-results // TODO: move this directly to position where use-kind is computed
interval->set_spill_state(startInMemory);
}
}
void LinearScan::add_use(int reg_num, int from, int to, IntervalUseKind use_kind, BasicType type) {
Interval* interval = interval_at(reg_num); if (interval == NULL) {
interval = create_interval(reg_num);
}
assert(interval->reg_num() == reg_num, "wrong interval");
if (type != T_ILLEGAL) {
interval->set_type(type);
}
// the results of this functions are used for optimizing spilling and reloading // if the functions return shouldHaveRegister and the interval is spilled, // it is not reloaded to a register.
IntervalUseKind LinearScan::use_kind_of_output_operand(LIR_Op* op, LIR_Opr opr) { if (op->code() == lir_move) {
assert(op->as_Op1() != NULL, "lir_move must be LIR_Op1");
LIR_Op1* move = (LIR_Op1*)op;
LIR_Opr res = move->result_opr(); bool result_in_memory = res->is_virtual() && gen()->is_vreg_flag_set(res->vreg_number(), LIRGenerator::must_start_in_memory);
if (result_in_memory) { // Begin of an interval with must_start_in_memory set. // This interval will always get a stack slot first, so return noUse. return noUse;
} elseif (move->in_opr()->is_stack()) { // method argument (condition must be equal to handle_method_arguments) return noUse;
} elseif (move->in_opr()->is_register() && move->result_opr()->is_register()) { // Move from register to register if (block_of_op_with_id(op->id())->is_set(BlockBegin::osr_entry_flag)) { // special handling of phi-function moves inside osr-entry blocks // input operand must have a register instead of output operand (leads to better register allocation) return shouldHaveRegister;
}
}
}
if (opr->is_virtual() &&
gen()->is_vreg_flag_set(opr->vreg_number(), LIRGenerator::must_start_in_memory)) { // result is a stack-slot, so prevent immediate reloading return noUse;
}
// all other operands require a register return mustHaveRegister;
}
IntervalUseKind LinearScan::use_kind_of_input_operand(LIR_Op* op, LIR_Opr opr) { if (op->code() == lir_move) {
assert(op->as_Op1() != NULL, "lir_move must be LIR_Op1");
LIR_Op1* move = (LIR_Op1*)op;
LIR_Opr res = move->result_opr(); bool result_in_memory = res->is_virtual() && gen()->is_vreg_flag_set(res->vreg_number(), LIRGenerator::must_start_in_memory);
if (result_in_memory) { // Move to an interval with must_start_in_memory set. // To avoid moves from stack to stack (not allowed) force the input operand to a register return mustHaveRegister;
} elseif (move->in_opr()->is_register() && move->result_opr()->is_register()) { // Move from register to register if (block_of_op_with_id(op->id())->is_set(BlockBegin::osr_entry_flag)) { // special handling of phi-function moves inside osr-entry blocks // input operand must have a register instead of output operand (leads to better register allocation) return mustHaveRegister;
}
// The input operand is not forced to a register (moves from stack to register are allowed), // but it is faster if the input operand is in a register return shouldHaveRegister;
}
}
#ifdefined(X86) || defined(S390) if (op->code() == lir_cmove) { // conditional moves can handle stack operands
assert(op->result_opr()->is_register(), "result must always be in a register"); return shouldHaveRegister;
}
// optimizations for second input operand of arithmehtic operations on Intel // this operand is allowed to be on the stack in some cases
BasicType opr_type = opr->type_register(); if (opr_type == T_FLOAT || opr_type == T_DOUBLE) { if (IA32_ONLY( (UseSSE == 1 && opr_type == T_FLOAT) || UseSSE >= 2 ) NOT_IA32( true )) { // SSE float instruction (T_DOUBLE only supported with SSE2) switch (op->code()) { case lir_cmp: case lir_add: case lir_sub: case lir_mul: case lir_div:
{
assert(op->as_Op2() != NULL, "must be LIR_Op2");
LIR_Op2* op2 = (LIR_Op2*)op; if (op2->in_opr1() != op2->in_opr2() && op2->in_opr2() == opr) {
assert((op2->result_opr()->is_register() || op->code() == lir_cmp) && op2->in_opr1()->is_register(), "cannot mark second operand as stack if others are not in register"); return shouldHaveRegister;
}
} default: break;
}
} else { // FPU stack float instruction switch (op->code()) { case lir_add: case lir_sub: case lir_mul: case lir_div:
{
assert(op->as_Op2() != NULL, "must be LIR_Op2");
LIR_Op2* op2 = (LIR_Op2*)op; if (op2->in_opr1() != op2->in_opr2() && op2->in_opr2() == opr) {
assert((op2->result_opr()->is_register() || op->code() == lir_cmp) && op2->in_opr1()->is_register(), "cannot mark second operand as stack if others are not in register"); return shouldHaveRegister;
}
} default: break;
}
} // We want to sometimes use logical operations on pointers, in particular in GC barriers. // Since 64bit logical operations do not current support operands on stack, we have to make sure // T_OBJECT doesn't get spilled along with T_LONG.
} elseif (opr_type != T_LONG LP64_ONLY(&& opr_type != T_OBJECT)) { // integer instruction (note: long operands must always be in register) switch (op->code()) { case lir_cmp: case lir_add: case lir_sub: case lir_logic_and: case lir_logic_or: case lir_logic_xor:
{
assert(op->as_Op2() != NULL, "must be LIR_Op2");
LIR_Op2* op2 = (LIR_Op2*)op; if (op2->in_opr1() != op2->in_opr2() && op2->in_opr2() == opr) {
assert((op2->result_opr()->is_register() || op->code() == lir_cmp) && op2->in_opr1()->is_register(), "cannot mark second operand as stack if others are not in register"); return shouldHaveRegister;
}
} default: break;
}
} #endif// X86 || S390
// all other operands require a register return mustHaveRegister;
}
void LinearScan::handle_method_arguments(LIR_Op* op) { // special handling for method arguments (moves from stack to virtual register): // the interval gets no register assigned, but the stack slot. // it is split before the first use by the register allocator.
if (op->code() == lir_move) {
assert(op->as_Op1() != NULL, "must be LIR_Op1");
LIR_Op1* move = (LIR_Op1*)op;
if (move->in_opr()->is_stack()) { #ifdef ASSERT int arg_size = compilation()->method()->arg_size();
LIR_Opr o = move->in_opr(); if (o->is_single_stack()) {
assert(o->single_stack_ix() >= 0 && o->single_stack_ix() < arg_size, "out of range");
} elseif (o->is_double_stack()) {
assert(o->double_stack_ix() >= 0 && o->double_stack_ix() < arg_size, "out of range");
} else {
ShouldNotReachHere();
}
assert(move->id() > 0, "invalid id");
assert(block_of_op_with_id(move->id())->number_of_preds() == 0, "move from stack must be in first block");
assert(move->result_opr()->is_virtual(), "result of move must be a virtual register");
TRACE_LINEAR_SCAN(4, tty->print_cr("found move from stack slot %d to vreg %d", o->is_single_stack() ? o->single_stack_ix() : o->double_stack_ix(), reg_num(move->result_opr()))); #endif
void LinearScan::handle_doubleword_moves(LIR_Op* op) { // special handling for doubleword move from memory to register: // in this case the registers of the input address and the result // registers must not overlap -> add a temp range for the input registers if (op->code() == lir_move) {
assert(op->as_Op1() != NULL, "must be LIR_Op1");
LIR_Op1* move = (LIR_Op1*)op;
if (move->result_opr()->is_double_cpu() && move->in_opr()->is_pointer()) {
LIR_Address* address = move->in_opr()->as_address_ptr(); if (address != NULL) { if (address->base()->is_valid()) {
add_temp(address->base(), op->id(), noUse);
} if (address->index()->is_valid()) {
add_temp(address->index(), op->id(), noUse);
}
}
}
}
}
void LinearScan::add_register_hints(LIR_Op* op) { switch (op->code()) { case lir_move: // fall through case lir_convert: {
assert(op->as_Op1() != NULL, "lir_move, lir_convert must be LIR_Op1");
LIR_Op1* move = (LIR_Op1*)op;
if (move_to->is_register() && move_from->is_register()) {
Interval* from = interval_at(reg_num(move_from));
Interval* to = interval_at(reg_num(move_to)); if (from != NULL && to != NULL) {
to->set_register_hint(from);
TRACE_LINEAR_SCAN(4, tty->print_cr("operation at op_id %d: added hint from interval %d to %d", move->id(), from->reg_num(), to->reg_num()));
}
} break;
} case lir_cmove: {
assert(op->as_Op4() != NULL, "lir_cmove must be LIR_Op4");
LIR_Op4* cmove = (LIR_Op4*)op;
// initialize interval list with expected number of intervals // (32 is added to have some space for split children without having to resize the list)
_intervals = IntervalList(num_virtual_regs() + 32); // initialize all slots that are used by build_intervals
_intervals.at_put_grow(num_virtual_regs() - 1, NULL, NULL);
// create a list with all caller-save registers (cpu, fpu, xmm) // when an instruction is a call, a temp range is created for all these registers int num_caller_save_registers = 0; int caller_save_registers[LinearScan::nof_regs];
int i; for (i = 0; i < FrameMap::nof_caller_save_cpu_regs(); i++) {
LIR_Opr opr = FrameMap::caller_save_cpu_reg_at(i);
assert(opr->is_valid() && opr->is_register(), "FrameMap should not return invalid operands");
assert(reg_numHi(opr) == -1, "missing addition of range for hi-register");
caller_save_registers[num_caller_save_registers++] = reg_num(opr);
}
// temp ranges for fpu registers are only created when the method has // virtual fpu operands. Otherwise no allocation for fpu registers is // performed and so the temp ranges would be useless if (has_fpu_registers()) { #ifdef X86 if (UseSSE < 2) { #endif// X86 for (i = 0; i < FrameMap::nof_caller_save_fpu_regs; i++) {
LIR_Opr opr = FrameMap::caller_save_fpu_reg_at(i);
assert(opr->is_valid() && opr->is_register(), "FrameMap should not return invalid operands");
assert(reg_numHi(opr) == -1, "missing addition of range for hi-register");
caller_save_registers[num_caller_save_registers++] = reg_num(opr);
} #ifdef X86
} #endif// X86
#ifdef X86 if (UseSSE > 0) { int num_caller_save_xmm_regs = FrameMap::get_num_caller_save_xmms(); for (i = 0; i < num_caller_save_xmm_regs; i ++) {
LIR_Opr opr = FrameMap::caller_save_xmm_reg_at(i);
assert(opr->is_valid() && opr->is_register(), "FrameMap should not return invalid operands");
assert(reg_numHi(opr) == -1, "missing addition of range for hi-register");
caller_save_registers[num_caller_save_registers++] = reg_num(opr);
}
} #endif// X86
}
assert(num_caller_save_registers <= LinearScan::nof_regs, "out of bounds");
LIR_OpVisitState visitor;
// iterate all blocks in reverse order for (i = block_count() - 1; i >= 0; i--) {
BlockBegin* block = block_at(i);
LIR_OpList* instructions = block->lir()->instructions_list(); int block_from = block->first_lir_instruction_id(); int block_to = block->last_lir_instruction_id();
// Update intervals for registers live at the end of this block;
ResourceBitMap live = block->live_out(); int size = (int)live.size(); for (int number = (int)live.get_next_one_offset(0, size); number < size; number = (int)live.get_next_one_offset(number + 1, size)) {
assert(live.at(number), "should not stop here otherwise");
assert(number >= LIR_Opr::vreg_base, "fixed intervals must not be live on block bounds");
TRACE_LINEAR_SCAN(2, tty->print_cr("live in %d to %d", number, block_to + 2));
// add special use positions for loop-end blocks when the // interval is used anywhere inside this loop. It's possible // that the block was part of a non-natural loop, so it might // have an invalid loop index. if (block->is_set(BlockBegin::linear_scan_loop_end_flag) &&
block->loop_index() != -1 &&
is_interval_in_loop(number, block->loop_index())) {
interval_at(number)->add_use_pos(block_to + 1, loopEndMarker);
}
}
// iterate all instructions of the block in reverse order. // skip the first instruction because it is always a label // definitions of intervals are processed before uses
assert(visitor.no_operands(instructions->at(0)), "first operation must always be a label"); for (int j = instructions->length() - 1; j >= 1; j--) {
LIR_Op* op = instructions->at(j); int op_id = op->id();
// visit operation to collect all operands
visitor.visit(op);
// add a temp range for each register if operation destroys caller-save registers if (visitor.has_call()) { for (int k = 0; k < num_caller_save_registers; k++) {
add_temp(caller_save_registers[k], op_id, noUse, T_ILLEGAL);
}
TRACE_LINEAR_SCAN(4, tty->print_cr("operation destroys all caller-save registers"));
}
// Add any platform dependent temps
pd_add_temps(op);
// visit definitions (output and temp operands) int k, n;
n = visitor.opr_count(LIR_OpVisitState::outputMode); for (k = 0; k < n; k++) {
LIR_Opr opr = visitor.opr_at(LIR_OpVisitState::outputMode, k);
assert(opr->is_register(), "visitor should only return register operands");
add_def(opr, op_id, use_kind_of_output_operand(op, opr));
}
n = visitor.opr_count(LIR_OpVisitState::tempMode); for (k = 0; k < n; k++) {
LIR_Opr opr = visitor.opr_at(LIR_OpVisitState::tempMode, k);
assert(opr->is_register(), "visitor should only return register operands");
add_temp(opr, op_id, mustHaveRegister);
}
// visit uses (input operands)
n = visitor.opr_count(LIR_OpVisitState::inputMode); for (k = 0; k < n; k++) {
LIR_Opr opr = visitor.opr_at(LIR_OpVisitState::inputMode, k);
assert(opr->is_register(), "visitor should only return register operands");
add_use(opr, block_from, op_id, use_kind_of_input_operand(op, opr));
}
// Add uses of live locals from interpreter's point of view for proper // debug information generation // Treat these operands as temp values (if the life range is extended // to a call site, the value would be in a register at the call otherwise)
n = visitor.info_count(); for (k = 0; k < n; k++) {
CodeEmitInfo* info = visitor.info_at(k);
ValueStack* stack = info->stack();
for_each_state_value(stack, value,
add_use(value, block_from, op_id + 1, noUse);
);
}
// special steps for some instructions (especially moves)
handle_method_arguments(op);
handle_doubleword_moves(op);
add_register_hints(op);
} // end of instruction iteration
} // end of block iteration
// add the range [0, 1[ to all fixed intervals // -> the register allocator need not handle unhandled fixed intervals for (int n = 0; n < LinearScan::nof_regs; n++) {
Interval* interval = interval_at(n); if (interval != NULL) {
interval->add_range(0, 1);
}
}
}
// ********** Phase 5: actual register allocation
int LinearScan::interval_cmp(Interval** a, Interval** b) { if (*a != NULL) { if (*b != NULL) { return (*a)->from() - (*b)->from();
} else { return -1;
}
} else { if (*b != NULL) { return 1;
} else { return 0;
}
}
}
// The index we've found using binary search is pointing to an interval // that is defined in the same place as the interval we were looking for. // So now we have to look around that index and find exact interval. for (int i = idx; i >= 0; i--) { if (intervals->at(i) == interval) { returntrue;
} if (intervals->at(i)->from() != from) { break;
}
}
for (int i = idx + 1; i < intervals->length(); i++) { if (intervals->at(i) == interval) { returntrue;
} if (intervals->at(i)->from() != from) { break;
}
}
returnfalse;
}
bool LinearScan::is_sorted(IntervalArray* intervals) { int from = -1; int null_count = 0;
for (int i = 0; i < intervals->length(); i++) {
Interval* it = intervals->at(i); if (it != NULL) {
assert(from <= it->from(), "Intervals are unordered");
from = it->from();
} else {
null_count++;
}
}
assert(null_count == 0, "Sorted intervals should not contain nulls");
null_count = 0;
for (int i = 0; i < interval_count(); i++) {
Interval* interval = interval_at(i); if (interval != NULL) {
assert(find_interval(interval, intervals), "Lists do not contain same intervals");
} else {
null_count++;
}
}
assert(interval_count() - null_count == intervals->length(), "Sorted list should contain the same amount of non-NULL intervals as unsorted list");
if (list1_prev != NULL) list1_prev->set_next(Interval::end()); if (list2_prev != NULL) list2_prev->set_next(Interval::end());
assert(list1_prev == NULL || list1_prev->next() == Interval::end(), "linear list ends not with sentinel");
assert(list2_prev == NULL || list2_prev->next() == Interval::end(), "linear list ends not with sentinel");
}
if (_needs_full_resort) { // There is no known reason why this should occur but just in case...
assert(false, "should never occur"); // Re-sort existing interval list because an Interval::from() has changed
_sorted_intervals->sort(interval_cmp);
_needs_full_resort = false;
}
IntervalList* unsorted_list = &_intervals; int unsorted_len = unsorted_list->length(); int sorted_len = 0; int unsorted_idx; int sorted_idx = 0; int sorted_from_max = -1;
// calc number of items for sorted list (sorted list must not contain NULL values) for (unsorted_idx = 0; unsorted_idx < unsorted_len; unsorted_idx++) { if (unsorted_list->at(unsorted_idx) != NULL) {
sorted_len++;
}
}
IntervalArray* sorted_list = new IntervalArray(sorted_len, sorted_len, NULL);
// special sorting algorithm: the original interval-list is almost sorted, // only some intervals are swapped. So this is much faster than a complete QuickSort for (unsorted_idx = 0; unsorted_idx < unsorted_len; unsorted_idx++) {
Interval* cur_interval = unsorted_list->at(unsorted_idx);
if (cur_interval != NULL) { int cur_from = cur_interval->from();
if (sorted_from_max <= cur_from) {
sorted_list->at_put(sorted_idx++, cur_interval);
sorted_from_max = cur_interval->from();
} else { // the assumption that the intervals are already sorted failed, // so this interval must be sorted in manually int j; for (j = sorted_idx - 1; j >= 0 && cur_from < sorted_list->at(j)->from(); j--) {
sorted_list->at_put(j + 1, sorted_list->at(j));
}
sorted_list->at_put(j + 1, cur_interval);
sorted_idx++;
}
}
}
_sorted_intervals = sorted_list;
assert(is_sorted(_sorted_intervals), "intervals unsorted");
}
if (_needs_full_resort) { // Re-sort existing interval list because an Interval::from() has changed
_sorted_intervals->sort(interval_cmp);
_needs_full_resort = false;
}
if (new_len == 0) { // no intervals have been added during allocation, so sorted list is already up to date
assert(is_sorted(_sorted_intervals), "intervals unsorted"); return;
}
// conventional sort-algorithm for new intervals
new_list->sort(interval_cmp);
// merge old and new list (both already sorted) into one combined list int combined_list_len = old_len + new_len;
IntervalArray* combined_list = new IntervalArray(combined_list_len, combined_list_len, NULL); int old_idx = 0; int new_idx = 0;
// collect cpu intervals
create_unhandled_lists(&precolored_cpu_intervals, ¬_precolored_cpu_intervals,
is_precolored_cpu_interval, is_virtual_cpu_interval);
// collect fpu intervals
create_unhandled_lists(&precolored_fpu_intervals, ¬_precolored_fpu_intervals,
is_precolored_fpu_interval, is_virtual_fpu_interval); // this fpu interval collection cannot be moved down below with the allocation section as // the cpu_lsw.walk() changes interval positions.
if (!has_fpu_registers()) { #ifdef ASSERT
assert(not_precolored_fpu_intervals == Interval::end(), "missed an uncolored fpu interval"); #else if (not_precolored_fpu_intervals != Interval::end()) {
BAILOUT("missed an uncolored fpu interval");
} #endif
}
// allocate cpu registers
LinearScanWalker cpu_lsw(this, precolored_cpu_intervals, not_precolored_cpu_intervals);
cpu_lsw.walk();
cpu_lsw.finish_allocation();
// ********** Phase 6: resolve data flow // (insert moves at edges between blocks if intervals have been split)
// wrapper for Interval::split_child_at_op_id that performs a bailout in product mode // instead of returning NULL
Interval* LinearScan::split_child_at_op_id(Interval* interval, int op_id, LIR_OpVisitState::OprMode mode) {
Interval* result = interval->split_child_at_op_id(op_id, mode); if (result != NULL) { return result;
}
assert(false, "must find an interval, but do a clean bailout in product mode");
result = new Interval(LIR_Opr::vreg_base);
result->assign_reg(0);
result->set_type(T_INT);
BAILOUT_("LinearScan: interval is NULL", result);
}
Interval* LinearScan::interval_at_block_begin(BlockBegin* block, int reg_num) {
assert(LinearScan::nof_regs <= reg_num && reg_num < num_virtual_regs(), "register number out of bounds");
assert(interval_at(reg_num) != NULL, "no interval found");
Interval* LinearScan::interval_at_block_end(BlockBegin* block, int reg_num) {
assert(LinearScan::nof_regs <= reg_num && reg_num < num_virtual_regs(), "register number out of bounds");
assert(interval_at(reg_num) != NULL, "no interval found");
Interval* LinearScan::interval_at_op_id(int reg_num, int op_id) {
assert(LinearScan::nof_regs <= reg_num && reg_num < num_virtual_regs(), "register number out of bounds");
assert(interval_at(reg_num) != NULL, "no interval found");
// visit all registers where the live_at_edge bit is set for (int r = (int)live_at_edge.get_next_one_offset(0, size); r < size; r = (int)live_at_edge.get_next_one_offset(r + 1, size)) {
assert(r < num_virtual_regs(), "live information set for not existing interval");
assert(from_block->live_out().at(r) && to_block->live_in().at(r), "interval not live at this edge");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.