blob: 757237ed6ea4ac0501815dad98fb003569bfb21e [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"
IR::Instr *
SimpleLayout::MoveHelperBlock(IR::Instr * lastOpHelperLabel, uint32 lastOpHelperStatementIndex, Func* lastOpHelperFunc, IR::LabelInstr * nextLabel,
IR::Instr * instrAfter)
{
// Add pragma instructions around the moved code to track source mapping
Func* pragmatInstrFunc = lastOpHelperFunc ? lastOpHelperFunc : this->func;
if (instrAfter->IsPragmaInstr() && instrAfter->m_opcode == Js::OpCode::StatementBoundary)
{
IR::PragmaInstr* pragmaInstr = instrAfter->AsPragmaInstr();
pragmaInstr->m_statementIndex = lastOpHelperStatementIndex;
pragmaInstr->m_func = pragmatInstrFunc;
}
else
{
IR::PragmaInstr* pragmaInstr = IR::PragmaInstr::New(Js::OpCode::StatementBoundary, lastOpHelperStatementIndex, pragmatInstrFunc);
instrAfter->InsertAfter(pragmaInstr);
instrAfter = pragmaInstr;
}
// Move all the instruction between lastOpHelperLabel to lastOpHelperInstr
// to the end of the function
IR::Instr * lastOpHelperInstr = nextLabel->GetPrevRealInstrOrLabel();
IR::Instr::MoveRangeAfter(lastOpHelperLabel, lastOpHelperInstr, instrAfter);
instrAfter = lastOpHelperInstr;
// Add the jmp back if the lastOpHelperInstr has fall through
if (instrAfter->HasFallThrough())
{
IR::BranchInstr * branchInstr = IR::BranchInstr::New(
LowererMD::MDUncondBranchOpcode, nextLabel, this->func);
instrAfter->InsertAfter(branchInstr);
instrAfter = branchInstr;
}
// Add pragma terminating this source mapping range
IR::PragmaInstr* pragmaInstr = IR::PragmaInstr::New(Js::OpCode::StatementBoundary, Js::Constants::NoStatementIndex, this->func);
instrAfter->InsertAfter(pragmaInstr);
instrAfter = pragmaInstr;
return instrAfter;
}
void
SimpleLayout::Layout()
{
if (PHASE_OFF(Js::LayoutPhase, this->func) || CONFIG_ISENABLED(Js::DebugFlag))
{
return;
}
// Do simple layout of helper block. Push them to after FunctionExit.
IR::Instr * lastInstr = func->m_tailInstr;
IR::LabelInstr * lastOpHelperLabel = NULL;
uint32 lastOpHelperStatementIndex = Js::Constants::NoStatementIndex;
Func* lastOpHelperFunc = nullptr;
FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, func->m_headInstr, func->m_tailInstr->m_prev)
{
if (instr->IsPragmaInstr() && instr->m_opcode == Js::OpCode::StatementBoundary)
{
currentStatement = instr->AsPragmaInstr();
}
else if (instr->IsLabelInstr())
{
IR::LabelInstr * labelInstr = instr->AsLabelInstr();
if (labelInstr->isOpHelper)
{
if (lastOpHelperLabel == NULL)
{
lastOpHelperLabel = labelInstr;
lastOpHelperStatementIndex = currentStatement ? currentStatement->m_statementIndex : Js::Constants::NoStatementIndex;
lastOpHelperFunc = currentStatement ? currentStatement->m_func : nullptr;
}
}
else if (lastOpHelperLabel != NULL)
{
IR::Instr * prevInstr = lastOpHelperLabel->GetPrevRealInstrOrLabel();
if (prevInstr->IsBranchInstr())
{
// If the previous instruction is to jump around this helper block
// Then we move the helper block to the end of the function to
// avoid the jmp in the fast path.
// jxx $label <== prevInstr
// $helper: <== lastOpHelperLabel
// ...
// ... <== lastOpHelperInstr
// $label: <== labelInstr
IR::BranchInstr * prevBranchInstr = prevInstr->AsBranchInstr();
if (prevBranchInstr->GetTarget() == labelInstr)
{
lastInstr = this->MoveHelperBlock(lastOpHelperLabel, lastOpHelperStatementIndex, lastOpHelperFunc, labelInstr, lastInstr);
if (prevBranchInstr->IsUnconditional())
{
// Remove the branch to next after the helper block is moved.
prevBranchInstr->Remove();
}
else
{
// Reverse the condition
LowererMD::InvertBranch(prevBranchInstr);
prevBranchInstr->SetTarget(lastOpHelperLabel);
}
}
else if (prevBranchInstr->IsUnconditional())
{
IR::Instr * prevPrevInstr = prevInstr->GetPrevRealInstrOrLabel();
if (prevPrevInstr->IsBranchInstr()
&& prevPrevInstr->AsBranchInstr()->IsConditional()
&& prevPrevInstr->AsBranchInstr()->GetTarget() == labelInstr)
{
// jcc $label <== prevPrevInstr
// jmp $blah <== prevInstr
// $helper: <== lastOpHelperLabel
// ...
// ... <== lastOpHelperInstr
// $label: <== labelInstr
// Transform to
// jncc $blah <== prevPrevInstr
// $label: <== labelInstr
// $helper: <== lastOpHelperLabel
// ...
// ... <== lastOpHelperInstr
// jmp $label: <== labelInstr
lastInstr = this->MoveHelperBlock(lastOpHelperLabel, lastOpHelperStatementIndex, lastOpHelperFunc, labelInstr, lastInstr);
LowererMD::InvertBranch(prevPrevInstr->AsBranchInstr());
prevPrevInstr->AsBranchInstr()->SetTarget(prevBranchInstr->GetTarget());
prevBranchInstr->Remove();
}
else
{
IR::Instr *lastOpHelperInstr = labelInstr->GetPrevRealInstr();
if (lastOpHelperInstr->IsBranchInstr())
{
IR::BranchInstr *lastOpHelperBranchInstr = lastOpHelperInstr->AsBranchInstr();
// jmp $target <== prevInstr //this is unconditional jump
// $helper: <== lastOpHelperLabel
// ...
// jmp $labeln <== lastOpHelperInstr //Conditional/Unconditional jump
// $label: <== labelInstr
lastInstr = this->MoveHelperBlock(lastOpHelperLabel, lastOpHelperStatementIndex, lastOpHelperFunc, labelInstr, lastInstr);
//Compensation code if its not unconditional jump
if (!lastOpHelperBranchInstr->IsUnconditional())
{
IR::BranchInstr *branchInstr = IR::BranchInstr::New(LowererMD::MDUncondBranchOpcode, labelInstr, this->func);
lastOpHelperBranchInstr->InsertAfter(branchInstr);
}
}
}
}
}
lastOpHelperLabel = NULL;
}
}
}
NEXT_INSTR_EDITING_IN_RANGE;
func->m_tailInstr = lastInstr;
}