Skip to content

Commit

Permalink
VM: Support phis with pair representations.
Browse files Browse the repository at this point in the history
This enables unboxed int64 values in phis on 32-bit platforms (ia32, ARM, MIPS).

On ia32 I measured SHA256 +14%, SHA1 +6%, MD5 +2%.

BUG=
R=johnmccutchan@google.com, regis@google.com

Review URL: https://codereview.chromium.org//1377113004 .
  • Loading branch information
fsc8000 committed Oct 8, 2015
1 parent 9f8da95 commit 8adefa8
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 43 deletions.
2 changes: 1 addition & 1 deletion runtime/vm/flow_graph.cc
Expand Up @@ -921,7 +921,7 @@ void FlowGraph::RenameRecursive(BlockEntryInstr* block_entry,
PhiInstr* phi = (*join->phis())[i];
if (phi != NULL) {
(*env)[i] = phi;
phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
AllocateSSAIndexes(phi); // New SSA temp.
if (block_entry->InsideTryBlock() && !phi->is_alive()) {
// This is a safe approximation. Inside try{} all locals are
// used at every call implicitly, so we mark all phis as live
Expand Down
104 changes: 76 additions & 28 deletions runtime/vm/flow_graph_allocator.cc
Expand Up @@ -222,11 +222,14 @@ void SSALivenessAnalysis::ComputeInitialSets() {
if (block->IsJoinEntry()) {
JoinEntryInstr* join = block->AsJoinEntry();
for (PhiIterator it(join); !it.Done(); it.Advance()) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
ASSERT(phi != NULL);
kill->Add(phi->ssa_temp_index());
live_in->Remove(phi->ssa_temp_index());
if (phi->HasPairRepresentation()) {
kill->Add(ToSecondPairVreg(phi->ssa_temp_index()));
live_in->Remove(ToSecondPairVreg(phi->ssa_temp_index()));
}

// If a phi input is not defined by the corresponding predecessor it
// must be marked live-in for that predecessor.
Expand All @@ -239,6 +242,12 @@ void SSALivenessAnalysis::ComputeInitialSets() {
if (!kill_[pred->postorder_number()]->Contains(use)) {
live_in_[pred->postorder_number()]->Add(use);
}
if (phi->HasPairRepresentation()) {
const intptr_t second_use = ToSecondPairVreg(use);
if (!kill_[pred->postorder_number()]->Contains(second_use)) {
live_in_[pred->postorder_number()]->Add(second_use);
}
}
}
}
} else if (block->IsCatchBlockEntry()) {
Expand Down Expand Up @@ -774,20 +783,18 @@ Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(

// Search for the index of the current block in the predecessors of
// the join.
const intptr_t pred_idx = join->IndexOfPredecessor(block);
const intptr_t pred_index = join->IndexOfPredecessor(block);

// Record the corresponding phi input use for each phi.
intptr_t move_idx = 0;
intptr_t move_index = 0;
for (PhiIterator it(join); !it.Done(); it.Advance()) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
Value* val = phi->InputAt(pred_idx);
MoveOperands* move = parallel_move->MoveOperandsAt(move_idx);
Value* val = phi->InputAt(pred_index);
MoveOperands* move = parallel_move->MoveOperandsAt(move_index++);

ConstantInstr* constant = val->definition()->AsConstant();
if (constant != NULL) {
move->set_src(Location::Constant(constant));
move_idx++;
continue;
}

Expand All @@ -796,8 +803,7 @@ Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(
// g g'
// value --*
//

const intptr_t vreg = val->definition()->ssa_temp_index();
intptr_t vreg = val->definition()->ssa_temp_index();
LiveRange* range = GetLiveRange(vreg);
if (interfere_at_backedge != NULL) interfere_at_backedge->Add(vreg);

Expand All @@ -806,9 +812,23 @@ Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(
pos,
move->src_slot(),
GetLiveRange(phi->ssa_temp_index())->assigned_location_slot());

move->set_src(Location::PrefersRegister());
move_idx++;

if (val->definition()->HasPairRepresentation()) {
move = parallel_move->MoveOperandsAt(move_index++);
vreg = ToSecondPairVreg(vreg);
range = GetLiveRange(vreg);
if (interfere_at_backedge != NULL) {
interfere_at_backedge->Add(vreg);
}
range->AddUseInterval(block->start_pos(), pos);
range->AddHintedUse(
pos,
move->src_slot(),
GetLiveRange(ToSecondPairVreg(
phi->ssa_temp_index()))->assigned_location_slot());
move->set_src(Location::PrefersRegister());
}
}

// Begin backward iteration with the instruction before the parallel
Expand All @@ -826,11 +846,11 @@ void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) {
const bool is_loop_header = BlockInfoAt(join->start_pos())->is_loop_header();
intptr_t move_idx = 0;
for (PhiIterator it(join); !it.Done(); it.Advance()) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
ASSERT(phi != NULL);
const intptr_t vreg = phi->ssa_temp_index();
ASSERT(vreg >= 0);
const bool is_pair_phi = phi->HasPairRepresentation();

// Expected shape of live range:
//
Expand All @@ -839,9 +859,14 @@ void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) {
//
LiveRange* range = GetLiveRange(vreg);
range->DefineAt(pos); // Shorten live range.

if (is_loop_header) range->mark_loop_phi();

if (is_pair_phi) {
LiveRange* second_range = GetLiveRange(ToSecondPairVreg(vreg));
second_range->DefineAt(pos); // Shorten live range.
if (is_loop_header) second_range->mark_loop_phi();
}

for (intptr_t pred_idx = 0; pred_idx < phi->InputCount(); pred_idx++) {
BlockEntryInstr* pred = join->PredecessorAt(pred_idx);
GotoInstr* goto_instr = pred->last_instruction()->AsGoto();
Expand All @@ -850,15 +875,26 @@ void FlowGraphAllocator::ConnectIncomingPhiMoves(JoinEntryInstr* join) {
goto_instr->parallel_move()->MoveOperandsAt(move_idx);
move->set_dest(Location::PrefersRegister());
range->AddUse(pos, move->dest_slot());
if (is_pair_phi) {
LiveRange* second_range = GetLiveRange(ToSecondPairVreg(vreg));
MoveOperands* second_move =
goto_instr->parallel_move()->MoveOperandsAt(move_idx + 1);
second_move->set_dest(Location::PrefersRegister());
second_range->AddUse(pos, second_move->dest_slot());
}
}

// All phi resolution moves are connected. Phi's live range is
// complete.
AssignSafepoints(phi, range);

CompleteRange(range, RegisterKindForResult(phi));
if (is_pair_phi) {
LiveRange* second_range = GetLiveRange(ToSecondPairVreg(vreg));
AssignSafepoints(phi, second_range);
CompleteRange(second_range, RegisterKindForResult(phi));
}

move_idx++;
move_idx += is_pair_phi ? 2 : 1;
}
}

Expand Down Expand Up @@ -1499,10 +1535,11 @@ void FlowGraphAllocator::NumberInstructions() {
// For join entry predecessors create phi resolution moves if
// necessary. They will be populated by the register allocator.
JoinEntryInstr* join = block->AsJoinEntry();
if ((join != NULL) &&
(join->phis() != NULL) &&
!join->phis()->is_empty()) {
const intptr_t phi_count = join->phis()->length();
if (join != NULL) {
intptr_t move_count = 0;
for (PhiIterator it(join); !it.Done(); it.Advance()) {
move_count += it.Current()->HasPairRepresentation() ? 2 : 1;
}
for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
// Insert the move between the last two instructions of the
// predecessor block (all such blocks have at least two instructions:
Expand All @@ -1513,7 +1550,7 @@ void FlowGraphAllocator::NumberInstructions() {
ParallelMoveInstr* move = last->AsGoto()->GetParallelMove();

// Populate the ParallelMove with empty moves.
for (intptr_t j = 0; j < phi_count; j++) {
for (intptr_t j = 0; j < move_count; j++) {
move->AddMove(Location::NoLocation(), Location::NoLocation());
}
}
Expand Down Expand Up @@ -2023,7 +2060,6 @@ intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated(


void ReachingDefs::AddPhi(PhiInstr* phi) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
if (phi->reaching_defs() == NULL) {
Zone* zone = flow_graph_.zone();
phi->set_reaching_defs(new(zone) BitVector(
Expand All @@ -2037,6 +2073,9 @@ void ReachingDefs::AddPhi(PhiInstr* phi) {
depends_on_phi = true;
}
phi->reaching_defs()->Add(input->ssa_temp_index());
if (phi->HasPairRepresentation()) {
phi->reaching_defs()->Add(ToSecondPairVreg(input->ssa_temp_index()));
}
}

// If this phi depends on another phi then we need fix point iteration.
Expand All @@ -2048,7 +2087,6 @@ void ReachingDefs::AddPhi(PhiInstr* phi) {
void ReachingDefs::Compute() {
// Transitively collect all phis that are used by the given phi.
for (intptr_t i = 0; i < phis_.length(); i++) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = phis_[i];

// Add all phis that affect this phi to the list.
Expand Down Expand Up @@ -2153,18 +2191,27 @@ bool FlowGraphAllocator::AllocateFreeRegister(LiveRange* unallocated) {
for (PhiIterator it(loop_header->entry()->AsJoinEntry());
!it.Done();
it.Advance()) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
ASSERT(phi->is_alive());
const intptr_t phi_vreg = phi->ssa_temp_index();
LiveRange* range = GetLiveRange(phi_vreg);
if (range->assigned_location().kind() == register_kind_) {
const intptr_t reg = range->assigned_location().register_code();

if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) {
used_on_backedge[reg] = true;
}
}
if (phi->HasPairRepresentation()) {
const intptr_t second_phi_vreg = ToSecondPairVreg(phi_vreg);
LiveRange* second_range = GetLiveRange(second_phi_vreg);
if (second_range->assigned_location().kind() == register_kind_) {
const intptr_t reg =
second_range->assigned_location().register_code();
if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) {
used_on_backedge[reg] = true;
}
}
}
}

if (used_on_backedge[candidate]) {
Expand Down Expand Up @@ -2877,11 +2924,12 @@ void FlowGraphAllocator::CollectRepresentations() {
if (block->IsJoinEntry()) {
JoinEntryInstr* join = block->AsJoinEntry();
for (PhiIterator it(join); !it.Done(); it.Advance()) {
// TODO(johnmccutchan): Fix handling of PhiInstr with PairLocation.
PhiInstr* phi = it.Current();
if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) {
ASSERT(!phi->HasPairRepresentation());
value_representations_[phi->ssa_temp_index()] =
ASSERT(phi != NULL && phi->ssa_temp_index() >= 0);
value_representations_[phi->ssa_temp_index()] =
RepresentationForRange(phi->representation());
if (phi->HasPairRepresentation()) {
value_representations_[ToSecondPairVreg(phi->ssa_temp_index())] =
RepresentationForRange(phi->representation());
}
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/vm/flow_graph_builder.cc
Expand Up @@ -489,7 +489,7 @@ Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block,
if (call_->HasUses()) {
// Add a phi of the return values.
PhiInstr* phi = new(Z) PhiInstr(join, num_exits);
phi->set_ssa_temp_index(caller_graph_->alloc_ssa_temp_index());
caller_graph_->AllocateSSAIndexes(phi);
phi->mark_alive();
for (intptr_t i = 0; i < num_exits; ++i) {
ReturnAt(i)->RemoveEnvironment();
Expand Down
14 changes: 8 additions & 6 deletions runtime/vm/flow_graph_optimizer.cc
Expand Up @@ -626,7 +626,7 @@ static void EnsureSSATempIndex(FlowGraph* graph,
Definition* replacement) {
if ((replacement->ssa_temp_index() == -1) &&
(defn->ssa_temp_index() != -1)) {
replacement->set_ssa_temp_index(graph->alloc_ssa_temp_index());
graph->AllocateSSAIndexes(replacement);
}
}

Expand Down Expand Up @@ -838,10 +838,10 @@ static void UnboxPhi(PhiInstr* phi) {
if ((kSmiBits < 32) &&
(unboxed == kTagged) &&
phi->Type()->IsInt() &&
RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)) {
RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt64)) {
// On 32-bit platforms conservatively unbox phis that:
// - are proven to be of type Int;
// - fit into 32bits range;
// - fit into 64bits range;
// - have either constants or Box() operations as inputs;
// - have at least one Box() operation as an input;
// - are used in at least 1 Unbox() operation.
Expand All @@ -850,7 +850,7 @@ static void UnboxPhi(PhiInstr* phi) {
Definition* input = phi->InputAt(i)->definition();
if (input->IsBox() &&
RangeUtils::Fits(input->range(),
RangeBoundary::kRangeBoundaryInt32)) {
RangeBoundary::kRangeBoundaryInt64)) {
should_unbox = true;
} else if (!input->IsConstant()) {
should_unbox = false;
Expand Down Expand Up @@ -882,7 +882,9 @@ static void UnboxPhi(PhiInstr* phi) {
}

if (should_unbox) {
unboxed = kUnboxedInt32;
unboxed =
RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
? kUnboxedInt32 : kUnboxedMint;
}
}

Expand Down Expand Up @@ -7073,7 +7075,7 @@ class LoadOptimizer : public ValueObject {
replacement->AddInputUse(input);
}

phi->set_ssa_temp_index(graph_->alloc_ssa_temp_index());
graph_->AllocateSSAIndexes(phi);
phis_.Add(phi); // Postpone phi insertion until after load forwarding.

if (FLAG_trace_load_optimization) {
Expand Down
7 changes: 6 additions & 1 deletion runtime/vm/il_printer.cc
Expand Up @@ -1050,7 +1050,12 @@ static const char *RepresentationToCString(Representation rep) {


void PhiInstr::PrintTo(BufferFormatter* f) const {
f->Print("v%" Pd " <- phi(", ssa_temp_index());
if (HasPairRepresentation()) {
f->Print("(v%" Pd ", v%" Pd ") <- phi(",
ssa_temp_index(), ssa_temp_index() + 1);
} else {
f->Print("v%" Pd " <- phi(", ssa_temp_index());
}
for (intptr_t i = 0; i < inputs_.length(); ++i) {
if (inputs_[i] != NULL) inputs_[i]->PrintTo(f);
if (i < inputs_.length() - 1) f->Print(", ");
Expand Down
5 changes: 4 additions & 1 deletion runtime/vm/intermediate_language_arm.cc
Expand Up @@ -6221,14 +6221,17 @@ void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
} else {
if (shift == 32) {
__ mov(out_lo, Operand(left_hi));
} else {
} else if (shift < 64) {
__ Asr(out_lo, left_hi, Operand(shift - 32));
} else {
__ Asr(out_lo, left_hi, Operand(31));
}
__ Asr(out_hi, left_hi, Operand(31));
}
break;
}
case Token::kSHL: {
ASSERT(shift < 64);
if (shift < 32) {
__ Lsr(out_hi, left_lo, Operand(32 - shift));
__ orr(out_hi, out_hi, Operand(left_hi, LSL, shift));
Expand Down
3 changes: 2 additions & 1 deletion runtime/vm/intermediate_language_ia32.cc
Expand Up @@ -6088,7 +6088,7 @@ void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ movl(left_lo, left_hi); // Shift by 32.
__ sarl(left_hi, Immediate(31)); // Sign extend left hi.
if (shift > 32) {
__ sarl(left_lo, Immediate(shift - 32));
__ sarl(left_lo, Immediate(shift > 63 ? 31 : shift - 32));
}
} else {
__ shrdl(left_lo, left_hi, Immediate(shift));
Expand All @@ -6097,6 +6097,7 @@ void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
break;
}
case Token::kSHL: {
ASSERT(shift < 64);
if (can_overflow()) {
Register temp1 = locs()->temp(0).reg();
Register temp2 = locs()->temp(1).reg();
Expand Down
9 changes: 8 additions & 1 deletion runtime/vm/intermediate_language_mips.cc
Expand Up @@ -4931,12 +4931,19 @@ void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ or_(out_lo, out_lo, TMP);
__ sra(out_hi, left_hi, shift);
} else {
__ sra(out_lo, left_hi, shift - 32);
if (shift == 32) {
__ mov(out_lo, left_hi);
} else if (shift < 64) {
__ sra(out_lo, left_hi, shift - 32);
} else {
__ sra(out_lo, left_hi, 31);
}
__ sra(out_hi, left_hi, 31);
}
break;
}
case Token::kSHL: {
ASSERT(shift < 64);
if (shift < 32) {
__ srl(out_hi, left_lo, 32 - shift);
__ sll(TMP, left_hi, shift);
Expand Down

0 comments on commit 8adefa8

Please sign in to comment.