Skip to content

Commit 9b8e058

Browse files
committed
SimdJsType spec initial commit
SIMD.js load/store type-spec Lowerer support Fix asm.js load/store failures. Load/store typespec still in progress - Fixed globOpt to consider dataWidth when eliminating bound checks based on range analysis. - Lowerer was not loading from headSegment. Added loading/use of headSegment as baseOpnd. - BoundChecks are not guaranteed to be extracted nor eliminated. Lowerer adds upper bound check if needed. - Further fixes in lowerer: - Inlined bound check subtracts the needed dataWidth from the array length. - Wasn't scaling the array index properly. - GlobOpt fixes: - Remove fall through code if type-spec doesn't happen was asserting on dataUseCount != 0 on x64. Added an if-condition to check before calling DecrementDataUseCount. TypeSpec only happens on non-Virtual, non-Mixed typed arrays. - All unit-tests pass at this point. - Enabled bound-checks on x64 for Virtual and Mixed array ValueTypes. - Several bug fixes in lowerer and GlobOpt - Re-enabled SIMD.js ASM.js unit-tests to run with no-asmjs and with type-spec support (-asmjs-) - Fixed performance issue where we bailed out excessively on BailOnNotBuiltIn. We didn't add Int32x4() to builtIn table Add missing copyright notice CR fixes: - Use PSHUFD for Swizzle_I4. Combine if statments in LowerSwizzle - Load correct lane mask, instead of shifting lane0 mask
1 parent 4376228 commit 9b8e058

34 files changed

Lines changed: 1878 additions & 499 deletions

lib/Backend/GlobOpt.cpp

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ GlobOpt::MergePredBlocksValueMaps(BasicBlock *block)
11871187
BVSparse<JitArenaAllocator> tempBv2(this->tempAlloc);
11881188

11891189
// For syms we made alive in loop header because of hoisting, use-before-def, or def in Loop body, set their valueInfo to definite.
1190-
// Made live on header AND in one of forceSimd128* or likelySimd128* vectors.
1190+
// Make live on header AND in one of forceSimd128* or likelySimd128* vectors.
11911191
tempBv->Or(loop->likelySimd128F4SymsUsedBeforeDefined, loop->symsDefInLoop);
11921192
tempBv->Or(loop->likelySimd128I4SymsUsedBeforeDefined);
11931193
tempBv->Or(loop->forceSimd128F4SymsOnEntry);
@@ -6012,12 +6012,17 @@ GlobOpt::CopyProp(IR::Opnd *opnd, IR::Instr *instr, Value *val, IR::IndirOpnd *p
60126012

60136013
// SIMD_JS
60146014
// Don't copy-prop operand of SIMD instr with ExtendedArg operands. Each instr should have its exclusive EA sequence.
6015-
if (Js::IsSimd128Opcode(instr->m_opcode) && instr->GetSrc1() != nullptr && instr->GetSrc2() == nullptr && instr->GetSrc1()->GetStackSym()->IsSingleDef())
6015+
if (
6016+
Js::IsSimd128Opcode(instr->m_opcode) &&
6017+
instr->GetSrc1() != nullptr &&
6018+
instr->GetSrc1()->IsRegOpnd() &&
6019+
instr->GetSrc2() == nullptr
6020+
)
60166021
{
6017-
IR::Instr *defInstr = instr->GetSrc1()->GetStackSym()->GetInstrDef();
6018-
if (defInstr->m_opcode == Js::OpCode::ExtendArg_A)
6022+
StackSym *sym = instr->GetSrc1()->GetStackSym();
6023+
if (sym && sym->IsSingleDef() && sym->GetInstrDef()->m_opcode == Js::OpCode::ExtendArg_A)
60196024
{
6020-
return opnd;
6025+
return opnd;
60216026
}
60226027
}
60236028

@@ -15360,6 +15365,15 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1536015365
bool needsHeadSegment, needsHeadSegmentLength, needsLength, needsBoundChecks;
1536115366
switch(instr->m_opcode)
1536215367
{
15368+
// SIMD_JS
15369+
case Js::OpCode::Simd128_LdArr_F4:
15370+
case Js::OpCode::Simd128_LdArr_I4:
15371+
// no type-spec for Asm.js
15372+
if (this->GetIsAsmJSFunc())
15373+
{
15374+
return;
15375+
}
15376+
// fall through
1536315377
case Js::OpCode::LdElemI_A:
1536415378
case Js::OpCode::LdMethodElem:
1536515379
if(!instr->GetSrc1()->IsIndirOpnd())
@@ -15370,10 +15384,19 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1537015384
baseOwnerIndir = instr->GetSrc1()->AsIndirOpnd();
1537115385
baseOpnd = baseOwnerIndir->GetBaseOpnd();
1537215386
isProfilableLdElem = instr->m_opcode == Js::OpCode::LdElemI_A; // LdMethodElem is currently not profiled
15387+
isProfilableLdElem |= Js::IsSimd128Load(instr->m_opcode);
1537315388
needsBoundChecks = needsHeadSegmentLength = needsHeadSegment = isLoad = true;
1537415389
needsLength = isStore = isProfilableStElem = false;
1537515390
break;
1537615391

15392+
// SIMD_JS
15393+
case Js::OpCode::Simd128_StArr_F4:
15394+
case Js::OpCode::Simd128_StArr_I4:
15395+
if (this->GetIsAsmJSFunc())
15396+
{
15397+
return;
15398+
}
15399+
// fall through
1537715400
case Js::OpCode::StElemI_A:
1537815401
case Js::OpCode::StElemI_A_Strict:
1537915402
case Js::OpCode::StElemC:
@@ -15385,6 +15408,7 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1538515408
baseOwnerIndir = instr->GetDst()->AsIndirOpnd();
1538615409
baseOpnd = baseOwnerIndir->GetBaseOpnd();
1538715410
needsBoundChecks = isProfilableStElem = instr->m_opcode != Js::OpCode::StElemC;
15411+
isProfilableStElem |= Js::IsSimd128Store(instr->m_opcode);
1538815412
needsHeadSegmentLength = needsHeadSegment = isStore = true;
1538915413
needsLength = isLoad = isProfilableLdElem = false;
1539015414
break;
@@ -15606,8 +15630,17 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1560615630
StackSym *const newHeadSegmentLengthSym = doHeadSegmentLengthLoad ? StackSym::New(TyUint32, instr->m_func) : nullptr;
1560715631
StackSym *const newLengthSym = doLengthLoad ? StackSym::New(TyUint32, instr->m_func) : nullptr;
1560815632

15609-
bool canBailOutOnArrayAccessHelperCall =
15610-
(isProfilableLdElem || isProfilableStElem) &&
15633+
bool canBailOutOnArrayAccessHelperCall;
15634+
15635+
if (Js::IsSimd128LoadStore(instr->m_opcode))
15636+
{
15637+
// SIMD_JS
15638+
// simd load/store never call helper
15639+
canBailOutOnArrayAccessHelperCall = true;
15640+
}
15641+
else
15642+
{
15643+
canBailOutOnArrayAccessHelperCall = (isProfilableLdElem || isProfilableStElem) &&
1561115644
DoEliminateArrayAccessHelperCall() &&
1561215645
!(
1561315646
instr->IsProfiledInstr() &&
@@ -15617,14 +15650,16 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1561715650
: instr->AsProfiledInstr()->u.stElemInfo->LikelyNeedsHelperCall()
1561815651
)
1561915652
);
15653+
}
1562015654

1562115655
bool doExtractBoundChecks = false, eliminatedLowerBoundCheck = false, eliminatedUpperBoundCheck = false;
1562215656
StackSym *indexVarSym = nullptr;
1562315657
Value *indexValue = nullptr;
1562415658
IntConstantBounds indexConstantBounds;
1562515659
Value *headSegmentLengthValue = nullptr;
1562615660
IntConstantBounds headSegmentLengthConstantBounds;
15627-
if (baseValueType.IsLikelyOptimizedVirtualTypedArray())
15661+
15662+
if (baseValueType.IsLikelyOptimizedVirtualTypedArray() && !Js::IsSimd128LoadStore(instr->m_opcode) /*Always extract bounds for SIMD */)
1562815663
{
1562915664
if (isProfilableStElem ||
1563015665
!instr->IsDstNotAlwaysConvertedToInt32() ||
@@ -15747,13 +15782,15 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1574715782
}
1574815783
AssertVerify(headSegmentLengthValue->GetValueInfo()->TryGetIntConstantBounds(&headSegmentLengthConstantBounds));
1574915784

15750-
if(ValueInfo::IsLessThan(
15785+
if (ValueInfo::IsLessThanOrEqualTo(
1575115786
indexValue,
1575215787
indexConstantBounds.LowerBound(),
1575315788
indexConstantBounds.UpperBound(),
1575415789
headSegmentLengthValue,
1575515790
headSegmentLengthConstantBounds.LowerBound(),
15756-
headSegmentLengthConstantBounds.UpperBound()))
15791+
headSegmentLengthConstantBounds.UpperBound(),
15792+
GetBoundCheckOffsetForSimd(newBaseValueType, instr, -1)
15793+
))
1575715794
{
1575815795
eliminatedUpperBoundCheck = true;
1575915796
if(eliminatedLowerBoundCheck)
@@ -16196,7 +16233,7 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1619616233
Assert(!baseOwnerIndir->GetIndexOpnd() || baseOwnerIndir->GetIndexOpnd()->m_sym->IsTypeSpec());
1619716234
Assert(doHeadSegmentLengthLoad || headSegmentLengthIsAvailable);
1619816235
Assert(canBailOutOnArrayAccessHelperCall);
16199-
Assert(!isStore || instr->m_opcode == Js::OpCode::StElemI_A || instr->m_opcode == Js::OpCode::StElemI_A_Strict);
16236+
Assert(!isStore || instr->m_opcode == Js::OpCode::StElemI_A || instr->m_opcode == Js::OpCode::StElemI_A_Strict || Js::IsSimd128LoadStore(instr->m_opcode));
1620016237

1620116238
StackSym *const headSegmentLengthSym =
1620216239
headSegmentLengthIsAvailable ? baseArrayValueInfo->HeadSegmentLengthSym() : newHeadSegmentLengthSym;
@@ -16240,6 +16277,9 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1624016277
hoistHeadSegmentLengthLoadOutOfLoop,
1624116278
failedToUpdateCompatibleLowerBoundCheck,
1624216279
failedToUpdateCompatibleUpperBoundCheck);
16280+
16281+
// SIMD_JS
16282+
UpdateBoundCheckHoistInfoForSimd(upperBoundCheckHoistInfo, newBaseValueType, instr);
1624316283
}
1624416284

1624516285
if(!eliminatedLowerBoundCheck)
@@ -16745,7 +16785,7 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
1674516785
lowerBound->SetIsJITOptimizedReg(true);
1674616786
IR::Opnd* upperBound = IR::RegOpnd::New(headSegmentLengthSym, headSegmentLengthSym->GetType(), instr->m_func);
1674716787
upperBound->SetIsJITOptimizedReg(true);
16748-
const int offset = -1;
16788+
const int offset = GetBoundCheckOffsetForSimd(newBaseValueType, instr, -1);
1674916789
IR::Instr *boundCheck;
1675016790

1675116791
// index <= headSegmentLength - 1 (src1 <= src2 + dst)
@@ -19390,7 +19430,10 @@ GlobOpt::RemoveCodeAfterNoFallthroughInstr(IR::Instr *instr)
1939019430
FOREACH_SUCCESSOR_BLOCK_EDITING(deadBlock, this->currentBlock, iter)
1939119431
{
1939219432
this->currentBlock->RemoveDeadSucc(deadBlock, this->func->m_fg);
19393-
this->currentBlock->DecrementDataUseCount();
19433+
if (this->currentBlock->GetDataUseCount() > 0)
19434+
{
19435+
this->currentBlock->DecrementDataUseCount();
19436+
}
1939419437
} NEXT_SUCCESSOR_BLOCK_EDITING;
1939519438
}
1939619439

lib/Backend/GlobOpt.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,11 +1384,17 @@ class GlobOpt
13841384
// SIMD_JS
13851385
bool TypeSpecializeSimd128(IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val, Value **pDstVal);
13861386
bool Simd128DoTypeSpec(IR::Instr *instr, const Value *src1Val, const Value *src2Val, const Value *dstVal);
1387+
bool Simd128DoTypeSpecLoadStore(IR::Instr *instr, const Value *src1Val, const Value *src2Val, const Value *dstVal, const ThreadContext::SimdFuncSignature *simdFuncSignature);
13871388
bool Simd128CanTypeSpecOpnd(const ValueType opndType, const ValueType expectedType);
1389+
bool Simd128ValidateIfLaneIndex(const IR::Instr * instr, IR::Opnd * opnd, uint argPos);
1390+
13881391
IRType GetIRTypeFromValueType(const ValueType &valueType);
13891392
ValueType GetValueTypeFromIRType(const IRType &type);
13901393
IR::BailOutKind GetBailOutKindFromValueType(const ValueType &valueType);
13911394
IR::Instr * GetExtendedArg(IR::Instr *instr);
1395+
void UpdateBoundCheckHoistInfoForSimd(ArrayUpperBoundCheckHoistInfo &upperHoistInfo, ValueType arrValueType, const IR::Instr *instr);
1396+
int GetBoundCheckOffsetForSimd(ValueType arrValueType, const IR::Instr *instr, const int oldOffset = -1);
1397+
void Simd128SetIndirOpndType(IR::IndirOpnd *indirOpnd, Js::OpCode opcode);
13921398

13931399

13941400
IR::Instr * OptNewScObject(IR::Instr** instrPtr, Value* srcVal);

lib/Backend/GlobOptIntBounds.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class LoopCount
9999
Assert(loopCountMinusOneSym);
100100
}
101101

102-
LoopCount(StackSym *const loopCountMinusOneSym, StackSym *const loopCountSym) :
102+
LoopCount(StackSym *const loopCountMinusOneSym, StackSym *const loopCountSym) :
103103
loopCountMinusOneSym(loopCountMinusOneSym),
104104
loopCountSym(loopCountSym),
105105
hasBeenGenerated(true)
@@ -287,6 +287,12 @@ class GlobOpt::ArrayLowerBoundCheckHoistInfo
287287
return offset;
288288
}
289289

290+
void UpdateOffset(int newOffset)
291+
{
292+
Assert(HasAnyInfo());
293+
offset = newOffset;
294+
}
295+
290296
ValueNumber IndexValueNumber() const
291297
{
292298
Assert(HasAnyInfo());
@@ -324,6 +330,7 @@ class GlobOpt::ArrayLowerBoundCheckHoistInfo
324330
return maxMagnitudeChange;
325331
}
326332

333+
327334
public:
328335
void SetCompatibleBoundCheck(BasicBlock *const compatibleBoundCheckBlock, StackSym *const indexSym, const int offset, const ValueNumber indexValueNumber);
329336
void SetLoop(::Loop *const loop, const int indexConstantValue, const bool isLoopCountBasedBound = false);
@@ -347,6 +354,7 @@ class GlobOpt::ArrayUpperBoundCheckHoistInfo : protected ArrayLowerBoundCheckHoi
347354
using Base::Loop;
348355
using Base::IndexSym;
349356
using Base::Offset;
357+
using Base::UpdateOffset;
350358
using Base::IndexValueNumber;
351359
using Base::IndexValue;
352360
using Base::IndexConstantBounds;

0 commit comments

Comments
 (0)