Skip to content

Commit

Permalink
add inlining support for asm.js/wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeHolman committed Sep 7, 2017
1 parent 7bf217a commit 0ec1c7c
Show file tree
Hide file tree
Showing 74 changed files with 1,203 additions and 1,099 deletions.
20 changes: 11 additions & 9 deletions lib/Backend/BackendOpCodeAttrAsmJs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,14 @@
#ifdef ASMJS_PLAT
namespace OpCodeAttrAsmJs
{
// OpSideEffect:
// Opcode has side effect not just to the dst/src on the instruction.
// The opcode cannot be deadstored. (e.g. StFld, LdFld from DOM, call valueOf/toString/getter/setter)
// Doesn't include all "exit" script (e.g. LdThis doesn't have side effect for HostDispatch for exiting script to getting the name space parent)
// OpHasImplicitCall:
// Include all possible exit scripts, call valueOf/toString/getter/setter
// OpSerialized:
// Op is a serialized (indirected) variant of another op code
enum OpCodeAttrEnum
{
None = 0,
OpNoFallThrough = 1 << 0, // Opcode doesn't fallthrough in flow and its always jump to the return from this opcode.
OpHasMultiSizeLayout = 1 << 1,

OpHasProfiled = 1 << 2,
OpProfiled = 1 << 3,
OpByteCodeOnly = 1 << 4
};

static const int OpcodeAttributesAsmJs[] =
Expand Down Expand Up @@ -65,6 +59,14 @@ namespace OpCodeAttrAsmJs
return CheckHasFlag( OpHasMultiSizeLayout );
}

bool HasProfiledOp(Js::OpCodeAsmJs opcode)
{
return ((GetOpCodeAttributes(opcode) & OpHasProfiled) != 0);
}
bool IsProfiledOp(Js::OpCodeAsmJs opcode)
{
return ((GetOpCodeAttributes(opcode) & OpProfiled) != 0);
}

}; // OpCodeAttrAsmJs
#endif
2 changes: 2 additions & 0 deletions lib/Backend/BackendOpCodeAttrAsmJs.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ namespace OpCodeAttrAsmJs
bool HasFallThrough(Js::OpCodeAsmJs opcode);
// True if the opcode has a small/large layout
bool HasMultiSizeLayout(Js::OpCodeAsmJs opcode);
bool HasProfiledOp(Js::OpCodeAsmJs opcode);
bool IsProfiledOp(Js::OpCodeAsmJs opcode);
};
#endif
39 changes: 24 additions & 15 deletions lib/Backend/Func.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
m_canDoInlineArgsOpt(true),
m_doFastPaths(false),
hasBailout(false),
firstIRTemp(0),
hasBailoutInEHRegion(false),
hasInstrNumber(false),
maintainByteCodeOffset(true),
Expand All @@ -78,7 +79,7 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
hasAnyStackNestedFunc(false),
hasMarkTempObjects(false),
postCallByteCodeOffset(postCallByteCodeOffset),
maxInlineeArgOutCount(0),
maxInlineeArgOutSize(0),
returnValueRegSlot(returnValueRegSlot),
firstActualStackOffset(-1),
m_localVarSlotsOffset(Js::Constants::InvalidOffset),
Expand Down Expand Up @@ -744,19 +745,27 @@ void Func::SetFirstArgOffset(IR::Instr* inlineeStart)
int32 lastOffset;

IR::Instr* arg = inlineeStart->GetNextArg();
const auto lastArgOutStackSym = arg->GetDst()->AsSymOpnd()->m_sym->AsStackSym();
lastOffset = lastArgOutStackSym->m_offset;
Assert(lastArgOutStackSym->m_isSingleDef);
const auto secondLastArgOutOpnd = lastArgOutStackSym->m_instrDef->GetSrc2();
if (secondLastArgOutOpnd->IsSymOpnd())
{
const auto secondLastOffset = secondLastArgOutOpnd->AsSymOpnd()->m_sym->AsStackSym()->m_offset;
if (secondLastOffset > lastOffset)
if (arg)
{
const auto lastArgOutStackSym = arg->GetDst()->AsSymOpnd()->m_sym->AsStackSym();
lastOffset = lastArgOutStackSym->m_offset;
Assert(lastArgOutStackSym->m_isSingleDef);
const auto secondLastArgOutOpnd = lastArgOutStackSym->m_instrDef->GetSrc2();
if (secondLastArgOutOpnd->IsSymOpnd())
{
lastOffset = secondLastOffset;
const auto secondLastOffset = secondLastArgOutOpnd->AsSymOpnd()->m_sym->AsStackSym()->m_offset;
if (secondLastOffset > lastOffset)
{
lastOffset = secondLastOffset;
}
}
lastOffset += MachPtr;
}
else
{
Assert(this->GetTopFunc()->GetJITFunctionBody()->IsAsmJsMode());
lastOffset = MachPtr;
}
lastOffset += MachPtr;
int32 firstActualStackOffset = lastOffset - ((this->actualCount + Js::Constants::InlineeMetaArgCount) * MachPtr);
Assert((this->firstActualStackOffset == -1) || (this->firstActualStackOffset == firstActualStackOffset));
this->firstActualStackOffset = firstActualStackOffset;
Expand Down Expand Up @@ -918,7 +927,7 @@ Int64RegPair Func::FindOrCreateInt64Pair(IR::Opnd* opnd)
{
Js::ArgSlot slotNumber = stackSym->GetArgSlotNum();
symPair.low = StackSym::NewArgSlotSym(slotNumber, this, pairType);
symPair.high = StackSym::NewArgSlotSym(slotNumber + 1, this, pairType);
symPair.high = StackSym::NewArgSlotSym(slotNumber, this, pairType);
}
else
{
Expand Down Expand Up @@ -1363,11 +1372,11 @@ Func::EnsureLoopParamSym()
}

void
Func::UpdateMaxInlineeArgOutCount(uint inlineeArgOutCount)
Func::UpdateMaxInlineeArgOutSize(uint inlineeArgOutSize)
{
if (maxInlineeArgOutCount < inlineeArgOutCount)
if (this->maxInlineeArgOutSize < inlineeArgOutSize)
{
maxInlineeArgOutCount = inlineeArgOutCount;
this->maxInlineeArgOutSize = inlineeArgOutSize;
}
}

Expand Down
13 changes: 7 additions & 6 deletions lib/Backend/Func.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
uint32 inlineDepth;
uint32 postCallByteCodeOffset;
Js::RegSlot returnValueRegSlot;
Js::RegSlot firstIRTemp;
Js::ArgSlot actualCount;
int32 firstActualStackOffset;
uint32 tryCatchNestingLevel;
Expand Down Expand Up @@ -760,8 +761,8 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
bool DoMaintainByteCodeOffset() const { return this->HasByteCodeOffset() && this->GetTopFunc()->maintainByteCodeOffset; }
void StopMaintainByteCodeOffset() { this->GetTopFunc()->maintainByteCodeOffset = false; }
Func * GetParentFunc() const { return parentFunc; }
uint GetMaxInlineeArgOutCount() const { return maxInlineeArgOutCount; }
void UpdateMaxInlineeArgOutCount(uint inlineeArgOutCount);
uint GetMaxInlineeArgOutSize() const { return this->maxInlineeArgOutSize; }
void UpdateMaxInlineeArgOutSize(uint inlineeArgOutSize);
#if DBG_DUMP
ptrdiff_t m_codeSize;
#endif
Expand Down Expand Up @@ -983,10 +984,10 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
#if defined(_M_ARM32_OR_ARM64)
int32 GetInlineeArgumentStackSize()
{
int32 count = this->GetMaxInlineeArgOutCount();
if (count)
int32 size = this->GetMaxInlineeArgOutSize();
if (size)
{
return ((count + 1) * MachPtr); // +1 for the dedicated zero out argc slot
return size + MachPtr; // +1 for the dedicated zero out argc slot
}
return 0;
}
Expand Down Expand Up @@ -1014,7 +1015,7 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
#endif
Func * const parentFunc;
StackSym * m_inlineeFrameStartSym;
uint maxInlineeArgOutCount;
uint maxInlineeArgOutSize;
const bool m_isBackgroundJIT;
bool hasInstrNumber;
bool maintainByteCodeOffset;
Expand Down
23 changes: 9 additions & 14 deletions lib/Backend/GlobOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,7 @@ GlobOpt::OptArguments(IR::Instr *instr)

if (instr->HasAnyLoadHeapArgsOpCode())
{
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
if (instr->m_func->IsStackArgsEnabled())
{
if (instr->GetSrc1()->IsRegOpnd() && instr->m_func->GetJITFunctionBody()->GetInParamsCount() > 1)
Expand All @@ -1593,6 +1594,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
}
}
}
#endif

if (instr->m_func->GetJITFunctionBody()->GetInParamsCount() != 1 && !instr->m_func->IsStackArgsEnabled())
{
Expand Down Expand Up @@ -2632,11 +2634,8 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
}

// Track calls after any pre-op bailouts have been inserted before the call, because they will need to restore out params.
// We don't inline in asmjs and hence we don't need to track calls in asmjs too, skipping this step for asmjs.
if (!GetIsAsmJSFunc())
{
this->TrackCalls(instr);
}

this->TrackCalls(instr);

if (instr->GetSrc1())
{
Expand Down Expand Up @@ -6764,17 +6763,13 @@ GlobOpt::OptConstFoldBranch(IR::Instr *instr, Value *src1Val, Value*src2Val, Val
// this path would probably work outside of asm.js, but we should verify that if we ever hit this scenario
Assert(GetIsAsmJSFunc());
constVal = 0;
if (src1Val->GetValueInfo()->TryGetIntConstantValue(&constVal) && constVal != 0)
if (!src1Val->GetValueInfo()->TryGetIntConstantValue(&constVal))
{
instr->FreeSrc1();
if (instr->GetSrc2())
{
instr->FreeSrc2();
}
instr->m_opcode = Js::OpCode::Nop;
return true;
return false;
}
return false;

result = constVal == 0;
break;

default:
return false;
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/GlobOpt.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ class GlobOpt
IR::Instr * GetExtendedArg(IR::Instr *instr);
int GetBoundCheckOffsetForSimd(ValueType arrValueType, const IR::Instr *instr, const int oldOffset = -1);

IR::Instr * OptNewScObject(IR::Instr** instrPtr, Value* srcVal);
void OptNewScObject(IR::Instr** instrPtr, Value* srcVal);
template <typename T>
bool OptConstFoldBinaryWasm(IR::Instr * *pInstr, const Value* src1, const Value* src2, Value **pDstVal);
template <typename T>
Expand Down
27 changes: 18 additions & 9 deletions lib/Backend/GlobOptBailOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ GlobOpt::CaptureArguments(BasicBlock *block, BailOutInfo * bailOutInfo, JitArena
void
GlobOpt::TrackByteCodeSymUsed(IR::Instr * instr, BVSparse<JitArenaAllocator> * instrByteCodeStackSymUsed, PropertySym **pPropertySym)
{
if(instr->m_func->GetJITFunctionBody()->IsAsmJsMode())
{
return;
}
IR::Opnd * src = instr->GetSrc1();
if (src)
{
Expand Down Expand Up @@ -427,7 +431,7 @@ GlobOpt::MarkNonByteCodeUsed(IR::Opnd * opnd)
void
GlobOpt::CaptureByteCodeSymUses(IR::Instr * instr)
{
if (this->byteCodeUses)
if (this->byteCodeUses || this->func->GetJITFunctionBody()->IsAsmJsMode())
{
// We already captured it before.
return;
Expand Down Expand Up @@ -493,7 +497,8 @@ GlobOpt::TrackCalls(IR::Instr * instr)
Assert(stackSym->IsArgSlotSym());
if (stackSym->m_isInlinedArgSlot)
{
this->currentBlock->globOptData.inlinedArgOutCount++;
uint size = TySize[instr->GetDst()->GetType()];
this->currentBlock->globOptData.inlinedArgOutSize += size < MachPtr ? MachPtr : size;
// We want to update the offsets only once: don't do in prepass.
if (!this->IsLoopPrePass() && stackSym->m_offset >= 0)
{
Expand Down Expand Up @@ -523,7 +528,7 @@ GlobOpt::TrackCalls(IR::Instr * instr)
this->currentBlock->globOptData.curFunc = instr->m_func;
this->currentBlock->globOptData.curFunc = instr->m_func;

this->func->UpdateMaxInlineeArgOutCount(this->currentBlock->globOptData.inlinedArgOutCount);
this->func->UpdateMaxInlineeArgOutSize(this->currentBlock->globOptData.inlinedArgOutSize);
this->EndTrackCall(instr);

if (DoInlineArgsOpt(instr->m_func))
Expand Down Expand Up @@ -560,8 +565,8 @@ GlobOpt::TrackCalls(IR::Instr * instr)
}
EndTrackingOfArgObjSymsForInlinee();

Assert(this->currentBlock->globOptData.inlinedArgOutCount >= instr->GetArgOutCount(/*getInterpreterArgOutCount*/ false));
this->currentBlock->globOptData.inlinedArgOutCount -= instr->GetArgOutCount(/*getInterpreterArgOutCount*/ false);
Assert(this->currentBlock->globOptData.inlinedArgOutSize >= instr->GetArgOutSize(/*getInterpreterArgOutCount*/ false));
this->currentBlock->globOptData.inlinedArgOutSize -= instr->GetArgOutSize(/*getInterpreterArgOutCount*/ false);
break;

case Js::OpCode::InlineeMetaArg:
Expand All @@ -578,7 +583,7 @@ GlobOpt::TrackCalls(IR::Instr * instr)
Func * currentFunc = instr->m_func->GetParentFunc();
stackSym->FixupStackOffset(currentFunc);
}
this->currentBlock->globOptData.inlinedArgOutCount++;
this->currentBlock->globOptData.inlinedArgOutSize += MachPtr;
break;
}

Expand Down Expand Up @@ -651,8 +656,8 @@ GlobOpt::TrackCalls(IR::Instr * instr)
this->EndTrackCall(instr);
}

Assert(this->currentBlock->globOptData.inlinedArgOutCount >= instr->GetArgOutCount(/*getInterpreterArgOutCount*/ false));
this->currentBlock->globOptData.inlinedArgOutCount -= instr->GetArgOutCount(/*getInterpreterArgOutCount*/ false);
Assert(this->currentBlock->globOptData.inlinedArgOutSize >= instr->GetArgOutSize(/*getInterpreterArgOutCount*/ false));
this->currentBlock->globOptData.inlinedArgOutSize -= instr->GetArgOutSize(/*getInterpreterArgOutCount*/ false);

this->inInlinedBuiltIn = false;
break;
Expand Down Expand Up @@ -1043,7 +1048,11 @@ IR::ByteCodeUsesInstr *
GlobOpt::InsertByteCodeUses(IR::Instr * instr, bool includeDef)
{
IR::ByteCodeUsesInstr * byteCodeUsesInstr = nullptr;
Assert(this->byteCodeUses);
if (!this->byteCodeUses)
{
Assert(this->isAsmJSFunc);
return nullptr;
}
IR::RegOpnd * dstOpnd = nullptr;
if (includeDef)
{
Expand Down
12 changes: 6 additions & 6 deletions lib/Backend/GlobOptBlockData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ GlobOptBlockData::NullOutBlockData(GlobOpt* globOpt, Func* func)
this->startCallCount = 0;
this->argOutCount = 0;
this->totalOutParamCount = 0;
this->inlinedArgOutCount = 0;
this->inlinedArgOutSize = 0;
this->hasCSECandidates = false;
this->curFunc = func;

Expand Down Expand Up @@ -84,7 +84,7 @@ GlobOptBlockData::InitBlockData(GlobOpt* globOpt, Func* func)
this->startCallCount = 0;
this->argOutCount = 0;
this->totalOutParamCount = 0;
this->inlinedArgOutCount = 0;
this->inlinedArgOutSize = 0;
this->hasCSECandidates = false;
this->curFunc = func;

Expand Down Expand Up @@ -137,7 +137,7 @@ GlobOptBlockData::ReuseBlockData(GlobOptBlockData *fromData)
this->startCallCount = fromData->startCallCount;
this->argOutCount = fromData->argOutCount;
this->totalOutParamCount = fromData->totalOutParamCount;
this->inlinedArgOutCount = fromData->inlinedArgOutCount;
this->inlinedArgOutSize = fromData->inlinedArgOutSize;
this->hasCSECandidates = fromData->hasCSECandidates;

this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap;
Expand Down Expand Up @@ -180,7 +180,7 @@ GlobOptBlockData::CopyBlockData(GlobOptBlockData *fromData)
this->startCallCount = fromData->startCallCount;
this->argOutCount = fromData->argOutCount;
this->totalOutParamCount = fromData->totalOutParamCount;
this->inlinedArgOutCount = fromData->inlinedArgOutCount;
this->inlinedArgOutSize = fromData->inlinedArgOutSize;
this->hasCSECandidates = fromData->hasCSECandidates;

this->changedSyms = fromData->changedSyms;
Expand Down Expand Up @@ -348,7 +348,7 @@ void GlobOptBlockData::CloneBlockData(BasicBlock *const toBlockContext, BasicBlo
this->startCallCount = fromData->startCallCount;
this->argOutCount = fromData->argOutCount;
this->totalOutParamCount = fromData->totalOutParamCount;
this->inlinedArgOutCount = fromData->inlinedArgOutCount;
this->inlinedArgOutSize = fromData->inlinedArgOutSize;
this->hasCSECandidates = fromData->hasCSECandidates;

// Although we don't need the data on loop pre pass, we need to do it for the loop header
Expand Down Expand Up @@ -835,7 +835,7 @@ GlobOptBlockData::MergeBlockData(
Assert(this->startCallCount == fromData->startCallCount);
Assert(this->argOutCount == fromData->argOutCount);
Assert(this->totalOutParamCount == fromData->totalOutParamCount);
Assert(this->inlinedArgOutCount == fromData->inlinedArgOutCount);
Assert(this->inlinedArgOutSize == fromData->inlinedArgOutSize);

// stackLiteralInitFldDataMap is a union of the stack literal from two path.
// Although we don't need the data on loop prepass, we need to do it for the loop header
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/GlobOptBlockData.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class GlobOptBlockData
CapturedValues * capturedValues;
BVSparse<JitArenaAllocator> * changedSyms;

uint inlinedArgOutCount;
uint inlinedArgOutSize;

bool hasCSECandidates;

Expand Down
Loading

0 comments on commit 0ec1c7c

Please sign in to comment.