Jelajahi Sumber

Load params from registers when possible

Load ArgIns from registers if the param was passed in registers (x64 only).  Cleanup implicitParams in the process.
Louis Lafreniere 9 tahun lalu
induk
melakukan
ebd1313afa

+ 0 - 1
lib/Backend/LinearScan.h

@@ -104,7 +104,6 @@ public:
         totalOpHelperFullVisitedLength(0), curLoop(NULL), currentBlock(nullptr), currentRegion(nullptr), m_bailOutRecordCount(0),
         globalBailOutRecordTables(nullptr), lastUpdatedRowIndices(nullptr)
     {
-        linearScanMD.Init(this);
     }
 
     void                RegAlloc();

+ 10 - 11
lib/Backend/Lower.cpp

@@ -2937,7 +2937,7 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
             // This is the value the bytecode expects to be in the dst register of the Yield opcode after resumption.
             // Load it here after the bail-in.
 
-            StackSym *resumeYieldDataSym = StackSym::NewParamSlotSym(2, m_func);
+            StackSym *resumeYieldDataSym = StackSym::NewImplicitParamSym(4, m_func);
             m_func->SetArgOffset(resumeYieldDataSym, (LowererMD::GetFormalParamOffset() + 1) * MachPtr);
             IR::SymOpnd * resumeYieldDataOpnd = IR::SymOpnd::New(resumeYieldDataSym, TyMachPtr, m_func);
 
@@ -10007,7 +10007,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
     LowererMD::CreateAssign(opndUndef, opndUndefAddress, labelNormal);
 
 
-    BVSparse<JitArenaAllocator> *formalsBv = JitAnew(this->m_func->m_alloc, BVSparse<JitArenaAllocator>, this->m_func->m_alloc);
+    BVSparse<JitArenaAllocator> *formalsBv = JitAnew(this->m_alloc, BVSparse<JitArenaAllocator>, this->m_alloc);
     
     while (currArgInCount > 0)
     {
@@ -10128,6 +10128,8 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
         this->m_lowererMD.ChangeToAssign(instrArgIn);
     }
 
+	JitAdelete(this->m_alloc, formalsBv);
+
     return instrResume;
 }
 
@@ -10164,11 +10166,12 @@ Lowerer::LoadGeneratorArgsPtr(IR::Instr *instrInsert)
 IR::Instr *
 Lowerer::LoadGeneratorObject(IR::Instr * instrInsert)
 {
-    StackSym * generatorSym = StackSym::NewParamSlotSym(1, instrInsert->m_func);
+    StackSym * generatorSym = StackSym::NewImplicitParamSym(3, instrInsert->m_func);
     instrInsert->m_func->SetArgOffset(generatorSym, LowererMD::GetFormalParamOffset() * MachPtr);
     IR::SymOpnd * generatorSymOpnd = IR::SymOpnd::New(generatorSym, TyMachPtr, instrInsert->m_func);
     IR::RegOpnd * generatorRegOpnd = IR::RegOpnd::New(TyMachPtr, instrInsert->m_func);
-    return LowererMD::CreateAssign(generatorRegOpnd, generatorSymOpnd, instrInsert);
+	instrInsert->m_func->SetHasImplicitParamLoad();
+	return LowererMD::CreateAssign(generatorRegOpnd, generatorSymOpnd, instrInsert);
 }
 
 IR::Instr *
@@ -10844,12 +10847,8 @@ Lowerer::LoadCallInfo(IR::Instr * instrInsert)
     {
         // Generator function arguments and ArgumentsInfo are not on the stack.  Instead they
         // are accessed off the generator object (which is prm1).
-        StackSym * generatorSym = StackSym::NewParamSlotSym(1, func);
-        func->SetArgOffset(generatorSym, LowererMD::GetFormalParamOffset() * MachPtr);
-        IR::SymOpnd * generatorSymOpnd = IR::SymOpnd::New(generatorSym, TyMachPtr, func);
-        IR::RegOpnd * generatorRegOpnd = IR::RegOpnd::New(TyMachPtr, func);
-        LowererMD::CreateAssign(generatorRegOpnd, generatorSymOpnd, instrInsert);
-        func->SetHasImplicitParamLoad();
+		IR::Instr *genLoadInstr = LoadGeneratorObject(instrInsert);
+        IR::RegOpnd * generatorRegOpnd = genLoadInstr->GetDst()->AsRegOpnd();
 
         IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(generatorRegOpnd, Js::JavascriptGenerator::GetCallInfoOffset(), TyMachPtr, func);
         IR::Instr * instr = LowererMD::CreateAssign(IR::RegOpnd::New(TyMachPtr, func), indirOpnd, instrInsert);
@@ -21438,7 +21437,7 @@ void Lowerer::GenerateNullOutGeneratorFrame(IR::Instr* insertInstr)
     // null out frame pointer on generator object to signal completion to JavascriptGenerator::CallGenerator
     // s = MOV prm1
     // s[offset of JavascriptGenerator::frame] = MOV nullptr
-    StackSym *symSrc = StackSym::NewParamSlotSym(1, m_func);
+    StackSym *symSrc = StackSym::NewImplicitParamSym(3, m_func);
     m_func->SetArgOffset(symSrc, LowererMD::GetFormalParamOffset() * MachPtr);
     IR::SymOpnd *srcOpnd = IR::SymOpnd::New(symSrc, TyMachPtr, m_func);
     IR::RegOpnd *dstOpnd = IR::RegOpnd::New(TyMachReg, m_func);

+ 1 - 1
lib/Backend/LowerMDShared.cpp

@@ -7979,7 +7979,7 @@ LowererMD::GetImplicitParamSlotSym(Js::ArgSlot argSlot, Func * func)
     // Stack looks like (EBP chain)+0, (return addr)+4, (function object)+8, (arg count)+12, (this)+16, actual args
     // Pass in the EBP+8 to start at the function object, the start of the implicit param slots
 
-    StackSym * stackSym = StackSym::NewParamSlotSym(argSlot, func);
+    StackSym * stackSym = StackSym::NewImplicitParamSym(argSlot, func);
     func->SetArgOffset(stackSym, (2 + argSlot) * MachPtr);
     func->SetHasImplicitParamLoad();
     return stackSym;

+ 33 - 0
lib/Backend/SccLiveness.cpp

@@ -374,6 +374,39 @@ SCCLiveness::ProcessSrc(IR::Opnd *src, IR::Instr *instr)
             }
         }
     }
+    else if (!this->lastCall && src->IsSymOpnd() && src->AsSymOpnd()->m_sym->AsStackSym()->IsParamSlotSym())
+    {
+		IR::SymOpnd *symOpnd = src->AsSymOpnd();
+		RegNum reg = LinearScanMD::GetParamReg(symOpnd, this->func);
+
+		if (reg != RegNOREG && !PHASE_OFF(Js::LivenessPhase, this->func))
+		{
+			StackSym *stackSym = symOpnd->m_sym->AsStackSym();
+			Lifetime *lifetime = stackSym->scratch.linearScan.lifetime;
+
+			if (lifetime == nullptr)
+			{
+				lifetime = this->InsertLifetime(stackSym, reg, this->func->m_headInstr->m_next);
+				lifetime->region = this->curRegion;
+				lifetime->isFloat = symOpnd->IsFloat();
+				lifetime->isSimd128F4 = symOpnd->IsSimd128F4();
+				lifetime->isSimd128I4 = symOpnd->IsSimd128I4();
+				lifetime->isSimd128I8 = symOpnd->IsSimd128I8();
+				lifetime->isSimd128I16 = symOpnd->IsSimd128I16();
+				lifetime->isSimd128U4 = symOpnd->IsSimd128U4();
+				lifetime->isSimd128U8 = symOpnd->IsSimd128U8();
+				lifetime->isSimd128U16 = symOpnd->IsSimd128U16();
+				lifetime->isSimd128B4 = symOpnd->IsSimd128B4();
+				lifetime->isSimd128B8 = symOpnd->IsSimd128B8();
+				lifetime->isSimd128B16 = symOpnd->IsSimd128B16();
+				lifetime->isSimd128D2 = symOpnd->IsSimd128D2();
+			}
+
+			IR::RegOpnd * newRegOpnd = IR::RegOpnd::New(stackSym, reg, symOpnd->GetType(), this->func);
+			instr->ReplaceSrc(symOpnd, newRegOpnd);
+			this->ProcessRegUse(newRegOpnd, instr);
+		}
+    }
 }
 
 // SCCLiveness::ProcessDst

+ 148 - 123
lib/Backend/Sym.cpp

@@ -45,13 +45,16 @@ StackSym::New(SymID id, IRType type, Js::RegSlot byteCodeRegSlot, Func *func)
     stackSym->m_isStrEmpty = false;
     stackSym->m_allocated = false;
     stackSym->m_isTypeSpec = false;
-    stackSym->m_isArgSlotSym = false;
+	stackSym->m_isArgSlotSym = false;
+	stackSym->m_isArgSlotRegSym = false;
+	stackSym->m_isParamSym = false;
+	stackSym->m_isImplicitParamSym = false;
     stackSym->m_isBailOutReferenced = false;
     stackSym->m_isArgCaptured = false;
     stackSym->m_requiresBailOnNotNumber = false;
     stackSym->m_isCatchObjectSym = false;
     stackSym->m_builtInIndex = Js::BuiltinFunction::None;
-    stackSym->m_paramSlotNum = StackSym::InvalidSlot;
+    stackSym->m_slotNum = StackSym::InvalidSlot;
 
     stackSym->m_type = type;
     stackSym->m_equivNext = stackSym;
@@ -109,20 +112,24 @@ StackSym::New(IRType type, Func *func)
     return StackSym::New(func->m_symTable->NewID(), type, Js::Constants::NoRegister, func);
 }
 
+StackSym *
+StackSym::NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func)
+{
+	return func->m_symTable->GetImplicitParam(paramSlotNum);
+}
 
 StackSym *
 StackSym::NewParamSlotSym(Js::ArgSlot paramSlotNum, Func * func)
 {
-    StackSym * stackSym = StackSym::New(func);
-    stackSym->m_paramSlotNum = paramSlotNum;
-    return stackSym;
+	return NewParamSlotSym(paramSlotNum, func, TyVar);
 }
 
 StackSym *
 StackSym::NewParamSlotSym(Js::ArgSlot paramSlotNum, Func * func, IRType type)
 {
     StackSym * stackSym = StackSym::New(type, func);
-    stackSym->m_paramSlotNum = paramSlotNum;
+	stackSym->m_isParamSym = true;
+    stackSym->m_slotNum = paramSlotNum;
     return stackSym;
 }
 
@@ -131,8 +138,8 @@ StackSym *
 StackSym::NewArgSlotRegSym(Js::ArgSlot argSlotNum, Func * func, IRType type /* = TyVar */)
 {
     StackSym * stackSym = StackSym::New(type, func);
-    stackSym->m_isArgSlotSym = false;
-    stackSym->m_argSlotNum = argSlotNum;
+    stackSym->m_isArgSlotRegSym = true;
+    stackSym->m_slotNum = argSlotNum;
 
 #if defined(_M_X64)
     stackSym->m_argPosition = 0;
@@ -146,7 +153,7 @@ StackSym::NewArgSlotSym(Js::ArgSlot argSlotNum, Func * func, IRType type /* = Ty
 {
     StackSym * stackSym = StackSym::New(type, func);
     stackSym->m_isArgSlotSym = true;
-    stackSym->m_argSlotNum = argSlotNum;
+    stackSym->m_slotNum = argSlotNum;
 
 #if defined(_M_X64)
     stackSym->m_argPosition = 0;
@@ -332,14 +339,14 @@ void
 StackSym::IncrementArgSlotNum()
 {
     Assert(IsArgSlotSym());
-    m_argSlotNum++;
+    m_slotNum++;
 }
 
 void
 StackSym::DecrementArgSlotNum()
 {
     Assert(IsArgSlotSym());
-    m_argSlotNum--;
+    m_slotNum--;
 }
 
 void
@@ -438,16 +445,18 @@ StackSym::CloneDef(Func *func)
         newSym->m_isConst = m_isConst;
         newSym->m_isIntConst = m_isIntConst;
         newSym->m_isTaggableIntConst = m_isTaggableIntConst;
-        newSym->m_isArgSlotSym = m_isArgSlotSym;
+		newSym->m_isArgSlotSym = m_isArgSlotSym;
+		newSym->m_isArgSlotRegSym = m_isArgSlotRegSym;
+		newSym->m_isParamSym = m_isParamSym;
+		newSym->m_isImplicitParamSym = m_isImplicitParamSym;
         newSym->m_isArgCaptured = m_isArgCaptured;
         newSym->m_isBailOutReferenced = m_isBailOutReferenced;
-        newSym->m_argSlotNum = m_argSlotNum;
+        newSym->m_slotNum = m_slotNum;
 
 #if defined(_M_X64)
         newSym->m_argPosition = m_argPosition;
 #endif
 
-        newSym->m_paramSlotNum = m_paramSlotNum;
         newSym->m_offset = m_offset;
         newSym->m_allocated = m_allocated;
         newSym->m_isInlinedArgSlot = m_isInlinedArgSlot;
@@ -987,117 +996,133 @@ Sym::Dump(IRDumpFlags flags, const ValueType valueType)
             Output::Print(_u("param "));
         }
     }
-    else
-    {
-        if (this->IsStackSym() && this->AsStackSym()->IsArgSlotSym())
-        {
-            if (this->AsStackSym()->m_isInlinedArgSlot)
-            {
-                Output::Print(_u("iarg%d"), this->AsStackSym()->GetArgSlotNum());
-            }
-            else
-            {
-                Output::Print(_u("arg%d"), this->AsStackSym()->GetArgSlotNum());
-            }
-            Output::Print(_u("(s%d)"), m_id);
-        }
-        else if (this->IsStackSym() && this->AsStackSym()->IsParamSlotSym())
-        {
-            Output::Print(_u("prm%d"), this->AsStackSym()->GetParamSlotNum());
-        }
-        else
-        {
-            if (!this->IsPropertySym() || !SimpleForm)
-            {
-                Output::Print(_u("s%d"), m_id);
-            }
-            if (this->IsStackSym())
-            {
-                if(Js::Configuration::Global.flags.Debug && this->AsStackSym()->HasByteCodeRegSlot())
-                {
-                    StackSym* sym =  this->AsStackSym();
-                    Js::FunctionBody* functionBody = sym->GetByteCodeFunc()->GetJnFunction();
-                    if(functionBody->GetPropertyIdOnRegSlotsContainer())
-                    {
-                        if(functionBody->IsNonTempLocalVar(sym->GetByteCodeRegSlot()))
-                        {
-                            uint index = sym->GetByteCodeRegSlot() - functionBody->GetConstantCount();
-                            Js::PropertyId propertyId = functionBody->GetPropertyIdOnRegSlotsContainer()->propertyIdsForRegSlots[index];
-                            Output::Print(_u("(%s)"), functionBody->GetScriptContext()->GetPropertyNameLocked(propertyId)->GetBuffer());
-                        }
-                    }
-                }
-                if (this->AsStackSym()->IsVar())
-                {
-                    if (this->AsStackSym()->HasObjectTypeSym() && !SimpleForm)
-                    {
-                        Output::Print(_u("<s%d>"), this->AsStackSym()->GetObjectTypeSym()->m_id);
-                    }
-                }
-                else
-                {
-                    StackSym *varSym = this->AsStackSym()->GetVarEquivSym(nullptr);
-                    if (varSym)
-                    {
-                        Output::Print(_u("(s%d)"), varSym->m_id);
-                    }
-                }
-                if (!SimpleForm)
-                {
-                    if (this->AsStackSym()->m_builtInIndex != Js::BuiltinFunction::None)
-                    {
-                        Output::Print(_u("[ffunc]"));
-                    }
-                }
-            }
-        }
-        if(IsStackSym())
-        {
-            IR::Opnd::DumpValueType(valueType);
-        }
-    }
-
-    if (this->IsPropertySym())
-    {
-        PropertySym *propertySym = this->AsPropertySym();
-
-        if (!SimpleForm)
-        {
-            Output::Print(_u("("));
-        }
-
-        Js::ScriptContext* scriptContext;
-        switch (propertySym->m_fieldKind)
-        {
-        case PropertyKindData:
-        {
-            propertySym->m_stackSym->Dump(flags, valueType);
-            scriptContext = propertySym->m_func->GetScriptContext();
-            Js::PropertyRecord const* fieldName = scriptContext->GetPropertyNameLocked(propertySym->m_propertyId);
-            Output::Print(_u("->%s"), fieldName->GetBuffer());
-            break;
-        }
-        case PropertyKindSlots:
-        case PropertyKindSlotArray:
-            propertySym->m_stackSym->Dump(flags, valueType);
-            Output::Print(_u("[%d]"), propertySym->m_propertyId);
-            break;
-        case PropertyKindLocalSlots:
-            propertySym->m_stackSym->Dump(flags, valueType);
-            Output::Print(_u("l[%d]"), propertySym->m_propertyId);
-            break;
-        default:
-            AssertMsg(0, "Unknown field kind");
-            break;
-        }
-
-        if (!SimpleForm)
-        {
-            Output::Print(_u(")"));
-        }
-    }
+	else if (this->IsStackSym())
+	{
+		StackSym *stackSym = this->AsStackSym();
+
+		if (stackSym->IsArgSlotSym())
+		{
+			if (stackSym->m_isInlinedArgSlot)
+			{
+				Output::Print(_u("iarg%d"), stackSym->GetArgSlotNum());
+			}
+			else
+			{
+				Output::Print(_u("arg%d"), stackSym->GetArgSlotNum());
+			}
+			Output::Print(_u("(s%d)"), m_id);
+		}
+		else if (stackSym->IsParamSlotSym())
+		{
+			if (stackSym->IsImplicitParamSym())
+			{
+				switch (stackSym->GetParamSlotNum())
+				{
+				case 1:
+					Output::Print(_u("callInfo"));
+					break;
+				case 2:
+					Output::Print(_u("funcInfo"));
+					break;
+				case 3:
+					Output::Print(_u("genObj"));
+					break;
+				case 4:
+					Output::Print(_u("genFrame"));
+					break;
+				default:
+					Output::Print(_u("implPrm%d"), stackSym->GetParamSlotNum());
+				}
+			}
+			else
+			{
+				Output::Print(_u("prm%d"), stackSym->GetParamSlotNum());
+			}
+		}
+		else
+		{
+  		    Output::Print(_u("s%d"), m_id);
+
+			if (Js::Configuration::Global.flags.Debug && stackSym->HasByteCodeRegSlot())
+			{
+				Js::FunctionBody* functionBody = stackSym->GetByteCodeFunc()->GetJnFunction();
+				if (functionBody->GetPropertyIdOnRegSlotsContainer())
+				{
+					if (functionBody->IsNonTempLocalVar(stackSym->GetByteCodeRegSlot()))
+					{
+						uint index = stackSym->GetByteCodeRegSlot() - functionBody->GetConstantCount();
+						Js::PropertyId propertyId = functionBody->GetPropertyIdOnRegSlotsContainer()->propertyIdsForRegSlots[index];
+						Output::Print(_u("(%s)"), functionBody->GetScriptContext()->GetPropertyNameLocked(propertyId)->GetBuffer());
+					}
+				}
+			}
+			if (stackSym->IsVar())
+			{
+				if (stackSym->HasObjectTypeSym() && !SimpleForm)
+				{
+					Output::Print(_u("<s%d>"), stackSym->GetObjectTypeSym()->m_id);
+				}
+			}
+			else
+			{
+				StackSym *varSym = stackSym->GetVarEquivSym(nullptr);
+				if (varSym)
+				{
+					Output::Print(_u("(s%d)"), varSym->m_id);
+				}
+			}
+			if (!SimpleForm)
+			{
+				if (stackSym->m_builtInIndex != Js::BuiltinFunction::None)
+				{
+					Output::Print(_u("[ffunc]"));
+				}
+			}
+			IR::Opnd::DumpValueType(valueType);
+		}
+	}
+	else if (this->IsPropertySym())
+	{
+		PropertySym *propertySym = this->AsPropertySym();
+
+		if (!SimpleForm)
+		{
+			Output::Print(_u("s%d("), m_id);
+		}
+
+		Js::ScriptContext* scriptContext;
+		switch (propertySym->m_fieldKind)
+		{
+		case PropertyKindData:
+		{
+			propertySym->m_stackSym->Dump(flags, valueType);
+			scriptContext = propertySym->m_func->GetScriptContext();
+			Js::PropertyRecord const* fieldName = scriptContext->GetPropertyNameLocked(propertySym->m_propertyId);
+			Output::Print(_u("->%s"), fieldName->GetBuffer());
+			break;
+		}
+		case PropertyKindSlots:
+		case PropertyKindSlotArray:
+			propertySym->m_stackSym->Dump(flags, valueType);
+			Output::Print(_u("[%d]"), propertySym->m_propertyId);
+			break;
+		case PropertyKindLocalSlots:
+			propertySym->m_stackSym->Dump(flags, valueType);
+			Output::Print(_u("l[%d]"), propertySym->m_propertyId);
+			break;
+		default:
+			AssertMsg(0, "Unknown field kind");
+			break;
+		}
+
+		if (!SimpleForm)
+		{
+			Output::Print(_u(")"));
+		}
+	}
 }
 
+
 void
 Sym::Dump(const ValueType valueType)
 {

+ 12 - 8
lib/Backend/Sym.h

@@ -91,6 +91,7 @@ public:
     static StackSym * NewArgSlotRegSym(Js::ArgSlot argSlotNum, Func * func, IRType = TyVar);
     static StackSym * NewParamSlotSym(Js::ArgSlot argSlotNum, Func * func);
     static StackSym * NewParamSlotSym(Js::ArgSlot argSlotNum, Func * func, IRType type);
+	static StackSym *NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func);
     static StackSym * New(SymID id, IRType type, Js::RegSlot byteCodeRegSlot, Func *func);
     static StackSym * New(IRType type, Func *func);
     static StackSym * New(Func *func);
@@ -98,7 +99,8 @@ public:
 
     IRType          GetType() const { return this->m_type; }
     bool            IsArgSlotSym() const;
-    bool            IsParamSlotSym() const;
+	bool            IsParamSlotSym() const;
+	bool            IsImplicitParamSym() const { return this->m_isImplicitParamSym; }
     bool            IsAllocated() const;
     int32           GetIntConstValue() const;
     Js::Var         GetFloatConstValueAsVar_PostGlobOpt() const;
@@ -162,11 +164,11 @@ public:
     bool            IsTempReg(Func *const func) const;
     bool            IsFromByteCodeConstantTable() const { return m_isFromByteCodeConstantTable; }
     void            SetIsFromByteCodeConstantTable() { this->m_isFromByteCodeConstantTable = true; }
-    Js::ArgSlot     GetArgSlotNum() const { Assert(HasArgSlotNum()); return m_argSlotNum; }
-    bool            HasArgSlotNum() const { return m_argSlotNum != 0; }
+    Js::ArgSlot     GetArgSlotNum() const { Assert(HasArgSlotNum()); return m_slotNum; }
+    bool            HasArgSlotNum() const { return !!(m_isArgSlotSym | m_isArgSlotRegSym); }
     void            IncrementArgSlotNum();
     void            DecrementArgSlotNum();
-    Js::ArgSlot     GetParamSlotNum() const { Assert(IsParamSlotSym()); return m_paramSlotNum; }
+    Js::ArgSlot     GetParamSlotNum() const { Assert(IsParamSlotSym()); return m_slotNum; }
 
     IR::Instr *     GetInstrDef() const { return this->IsSingleDef() ? this->m_instrDef : nullptr; }
 
@@ -186,11 +188,10 @@ private:
     void            VerifyConstFlags() const;
 #endif
 private:
-    Js::ArgSlot     m_argSlotNum;
-    Js::ArgSlot     m_paramSlotNum;
+    Js::ArgSlot     m_slotNum;
 public:
     uint8           m_isSingleDef:1;            // the symbol only has a single definition in the IR
-    uint8           m_isNotInt:1;
+	uint8           m_isNotInt:1;
     uint8           m_isSafeThis : 1;
     uint8           m_isConst : 1;              // single def and it is a constant
     uint8           m_isIntConst : 1;           // a constant and it's value is an Int32
@@ -209,7 +210,10 @@ public:
     uint8           m_isFromByteCodeConstantTable:1;
     uint8           m_mayNotBeTempLastUse:1;
     uint8           m_isArgSlotSym: 1;        // When set this implies an argument stack slot with no lifetime for register allocation
-    uint8           m_isBailOutReferenced: 1;        // argument sym referenced by bailout
+	uint8           m_isArgSlotRegSym : 1;
+	uint8           m_isParamSym : 1;
+	uint8           m_isImplicitParamSym : 1;
+	uint8           m_isBailOutReferenced: 1;        // argument sym referenced by bailout
     uint8           m_isArgCaptured: 1;       // True if there is a ByteCodeArgOutCapture for this symbol
     uint8           m_nonEscapingArgObjAlias : 1;
     uint8           m_isCatchObjectSym : 1;   // a catch object sym (used while jitting loop bodies)

+ 2 - 2
lib/Backend/Sym.inl

@@ -72,7 +72,7 @@ StackSym::IsArgSlotSym() const
 {
     if(m_isArgSlotSym)
     {
-        Assert(this->m_argSlotNum != 0);
+        Assert(this->m_slotNum != 0);
     }
     return m_isArgSlotSym;
 }
@@ -86,7 +86,7 @@ StackSym::IsArgSlotSym() const
 inline bool
 StackSym::IsParamSlotSym() const
 {
-    return m_paramSlotNum != InvalidSlot;
+	return m_isParamSym;
 }
 
 ///----------------------------------------------------------------------------

+ 17 - 0
lib/Backend/SymTable.cpp

@@ -243,6 +243,23 @@ SymTable::GetArgSlotSym(Js::ArgSlot argSlotNum)
     return argSym;
 }
 
+StackSym *          
+SymTable::GetImplicitParam(Js::ArgSlot paramSlotNum)
+{
+	Assert(paramSlotNum - 1 <= this->k_maxImplicitParamSlot);
+
+	if (this->m_implicitParams[paramSlotNum - 1])
+	{
+		return this->m_implicitParams[paramSlotNum - 1];
+	}
+	StackSym *implicitParamSym = StackSym::NewParamSlotSym(paramSlotNum, this->m_func, TyVar);
+	implicitParamSym->m_isImplicitParamSym = true;
+
+	this->m_implicitParams[paramSlotNum - 1] = implicitParamSym;
+
+	return implicitParamSym;
+}
+
 ///----------------------------------------------------------------------------
 ///
 /// SymTable::GetMaxSymID

+ 11 - 6
lib/Backend/SymTable.h

@@ -9,21 +9,25 @@ class SymTable
     typedef JsUtil::Pair<SymID, Js::PropertyId> SymIdPropIdPair;
     typedef JsUtil::BaseDictionary<SymIdPropIdPair, PropertySym *, JitArenaAllocator, PrimeSizePolicy> PropertyMap;
     typedef JsUtil::BaseDictionary<Js::PropertyId, BVSparse<JitArenaAllocator> *, JitArenaAllocator, PowerOf2SizePolicy> PropertyEquivBvMap;
-public:
-    static const int    k_symTableSize = 8192;
-    Sym *               m_table[k_symTableSize];
-    PropertyMap *       m_propertyMap;
-    PropertyEquivBvMap *m_propertyEquivBvMap;
 
 private:
+	static const int    k_symTableSize = 8192;
+	static const int    k_maxImplicitParamSlot = 4;
+    Sym *               m_table[k_symTableSize];
+	StackSym *          m_implicitParams[k_maxImplicitParamSlot];
+    PropertyMap *       m_propertyMap;
     Func *              m_func;
     SymID               m_currentID;
     SymID               m_IDAdjustment;
 
+public:
+	PropertyEquivBvMap *m_propertyEquivBvMap;
+
 public:
     SymTable() : m_currentID(0), m_func(nullptr), m_IDAdjustment(0)
     {
-        memset(m_table, 0, sizeof(m_table));
+		memset(m_table, 0, sizeof(m_table));
+		memset(m_implicitParams, 0, sizeof(m_implicitParams));
     }
 
 
@@ -37,6 +41,7 @@ public:
     void                IncreaseStartingID(SymID IDIncrease);
     SymID               NewID();
     StackSym *          GetArgSlotSym(Js::ArgSlot argSlotNum);
+	StackSym *          GetImplicitParam(Js::ArgSlot paramSlotNum);
     SymID               GetMaxSymID() const;
     void                ClearStackSymScratch();
     void                SetIDAdjustment() { m_IDAdjustment = m_currentID;}

+ 90 - 0
lib/Backend/amd64/LinearScanMD.cpp

@@ -450,3 +450,93 @@ RegNum LinearScanMD::GetRegisterFromSaveIndex(uint offset)
 {
     return (RegNum)(offset >= RegXMM0 ? (offset - RegXMM0) / (sizeof(SIMDValue) / sizeof(Js::Var)) + RegXMM0 : offset);
 }
+
+RegNum LinearScanMD::GetParamReg(IR::SymOpnd *symOpnd, Func *func)
+{
+	RegNum reg = RegNOREG;
+	StackSym *paramSym = symOpnd->m_sym->AsStackSym();
+
+	if (func->GetJnFunction()->GetIsAsmjsMode() && !func->IsLoopBody())
+	{
+		// Asm.js function only have 1 implicit param as they have no CallInfo, and they have float/SIMD params.
+		// Asm.js loop bodies however are called like normal JS functions.
+		if (IRType_IsFloat(symOpnd->GetType()) || IRType_IsSimd(symOpnd->GetType()))
+		{
+			switch (paramSym->GetParamSlotNum())
+			{
+			case 10000:
+				reg = RegXMM0;
+				break;
+			case 1:
+				reg = RegXMM1;
+				break;
+			case 2:
+				reg = RegXMM2;
+				break;
+			case 3:
+				reg = RegXMM3;
+				break;
+			}
+		}
+		else
+		{
+			if (paramSym->IsImplicitParamSym())
+			{
+				switch (paramSym->GetParamSlotNum())
+				{
+				case 1:
+					reg = RegRCX;
+					break;
+				default:
+					Assert(UNREACHED);
+				}
+			}
+			else
+			{
+				switch (paramSym->GetParamSlotNum())
+				{
+				case 1:
+					reg = RegRDX;
+					break;
+				case 2:
+					reg = RegR8;
+					break;
+				case 3:
+					reg = RegR9;
+					break;
+				}
+			}
+		}
+	}
+	else // Non-Asm.js
+	{
+		Assert(symOpnd->GetType() == TyVar || IRType_IsNativeInt(symOpnd->GetType()));
+
+		if (paramSym->IsImplicitParamSym())
+		{
+			switch (paramSym->GetParamSlotNum())
+			{
+			case 2:
+				reg = RegRCX;
+				break;
+			case 1:
+				reg = RegRDX;
+				break;
+			}
+		}
+		else
+		{
+			switch (paramSym->GetParamSlotNum())
+			{
+			case 1:
+				reg = RegR8;
+				break;
+			case 2:
+				reg = RegR9;
+				break;
+			}
+		}
+	}
+
+	return reg;
+}

+ 1 - 0
lib/Backend/amd64/LinearScanMD.h

@@ -44,6 +44,7 @@ private:
 public:
     static void SaveAllRegistersAndBailOut(BailOutRecord *const bailOutRecord);
     static void SaveAllRegistersAndBranchBailOut(BranchBailOutRecord *const bailOutRecord, const BOOL condition);
+	static RegNum GetParamReg(IR::SymOpnd *symOpnd, Func *func);
 
     static uint GetRegisterSaveSlotCount() {
         return RegisterSaveSlotCount;

+ 6 - 0
lib/Backend/arm/LinearScanMD.cpp

@@ -346,3 +346,9 @@ RegNum LinearScanMD::GetRegisterFromSaveIndex(uint offset)
 {
     return (RegNum)(offset >= RegD0 ? (offset - RegD0) / 2  + RegD0 : offset);
 }
+
+RegNum LinearScanMD::GetParamReg(IR::SymOpnd *symOpnd, Func *func)
+{
+	/* TODO - Add ARM32 support according to register calling convention */
+	return RegNOREG;
+}

+ 1 - 0
lib/Backend/arm/LinearScanMD.h

@@ -45,6 +45,7 @@ private:
 public:
     static void SaveAllRegistersAndBailOut(BailOutRecord *const bailOutRecord);
     static void SaveAllRegistersAndBranchBailOut(BranchBailOutRecord *const bailOutRecord, const BOOL condition);
+	static RegNum GetParamReg(IR::SymOpnd *symOpnd, Func *func);
 
     bool        IsAllocatable(RegNum reg, Func *func) const;
     static uint GetRegisterSaveSlotCount() {

+ 1 - 1
lib/Backend/arm/LowerMD.cpp

@@ -7691,7 +7691,7 @@ LowererMD::GetImplicitParamSlotSym(Js::ArgSlot argSlot, Func * func)
     // For ARM, offset for implicit params always start at 0
     // TODO: Consider not to use the argSlot number for the param slot sym, which can
     // be confused with arg slot number from javascript
-    StackSym * stackSym = StackSym::NewParamSlotSym(argSlot, func);
+    StackSym * stackSym = StackSym::NewImplicitParamSym(argSlot, func);
     func->SetArgOffset(stackSym, argSlot * MachPtr);
     func->SetHasImplicitParamLoad();
     return stackSym;

+ 1 - 0
lib/Backend/arm64/LinearScanMD.h

@@ -38,6 +38,7 @@ public:
 public:
     static void SaveAllRegistersAndBailOut(BailOutRecord *const bailOutRecord) { __debugbreak(); }
     static void SaveAllRegistersAndBranchBailOut(BranchBailOutRecord *const bailOutRecord, const BOOL condition) { __debugbreak(); }
+	static RegNum GetParamReg(IR::SymOpnd *symOpnd, Func *func) { /* TODO */ return RegNOREG; }
 
     bool        IsAllocatable(RegNum reg, Func *func) const { __debugbreak(); return 0; }
     static uint GetRegisterSaveSlotCount() {

+ 5 - 0
lib/Backend/i386/LinearScanMD.cpp

@@ -530,3 +530,8 @@ RegNum LinearScanMD::GetRegisterFromSaveIndex(uint offset)
 {
     return (RegNum)(offset >= RegXMM0 ? (offset - RegXMM0) / (sizeof(SIMDValue) / sizeof(Js::Var)) + RegXMM0 : offset);
 }
+
+RegNum LinearScanMD::GetParamReg(IR::SymOpnd *symOpnd, Func *func)
+{
+	return RegNOREG;
+}

+ 1 - 0
lib/Backend/i386/LinearScanMD.h

@@ -43,6 +43,7 @@ public:
     static void SaveAllRegistersNoSse2AndBailOut(BailOutRecord *const bailOutRecord);
     static void SaveAllRegistersAndBranchBailOut(BranchBailOutRecord *const bailOutRecord, const BOOL condition);
     static void SaveAllRegistersNoSse2AndBranchBailOut(BranchBailOutRecord *const bailOutRecord, const BOOL condition);
+	static RegNum GetParamReg(IR::SymOpnd *symOpnd, Func *func);
 
 public:
     static uint GetRegisterSaveSlotCount() {

+ 3 - 5
lib/Runtime/Library/MathLibrary.cpp

@@ -356,10 +356,9 @@ namespace Js
 #if defined(_M_IX86) || defined(_M_X64)
             if (AutoSystemInfo::Data.SSE4_1Available())
             {
-                __m128d input, output;
+				__m128d input, output;
                 input = _mm_load_sd(&x);
-#pragma prefast(suppress:6001, "Signature of _mm_ceil_sd intrinsic confuses prefast, output in the parameter list is not used, it is the dst of the intrinsic")
-                output = _mm_ceil_sd(output, input);
+                output = _mm_ceil_sd(input, input);
                 int intResult = _mm_cvtsd_si32(output);
 
                 if (TaggedInt::IsOverflow(intResult) || intResult == 0 || intResult == 0x80000000)
@@ -567,8 +566,7 @@ namespace Js
             }
             else
             {
-#pragma prefast(suppress:6001, "Signature of _mm_floor_sd intrinsic confuses prefast, output in the parameter list is not used, it is the dst of the intrinsic")
-                output = _mm_floor_sd(output, input);
+                output = _mm_floor_sd(input, input);
             }
             intResult = _mm_cvttsd_si32(output);