Skip to content
Permalink
Browse files
Sub should be a Math IC
https://bugs.webkit.org/show_bug.cgi?id=160270

Reviewed by Mark Lam.

This makes Sub an IC like Mul and Add. I'm seeing the following
improvements of average Sub size on Unity and JetStream:

           |   JetStream  |  Unity 3D  |
     ------| -------------|--------------
      Old  |   202 bytes  |  205 bytes |
     ------| -------------|--------------
      New  |   134  bytes |  134 bytes |
     ------------------------------------

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::addJITMulIC):
(JSC::CodeBlock::addJITSubIC):
(JSC::CodeBlock::findStubInfo):
(JSC::CodeBlock::dumpMathICStats):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::stubInfoBegin):
(JSC::CodeBlock::stubInfoEnd):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithSub):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArithAddOrSub):
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_sub):
(JSC::JIT::emitSlow_op_sub):
(JSC::JIT::emit_op_pow):
* jit/JITMathIC.h:
* jit/JITMathICForwards.h:
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITSubGenerator.cpp:
(JSC::JITSubGenerator::generateInline):
(JSC::JITSubGenerator::generateFastPath):
* jit/JITSubGenerator.h:
(JSC::JITSubGenerator::JITSubGenerator):
(JSC::JITSubGenerator::isLeftOperandValidConstant):
(JSC::JITSubGenerator::isRightOperandValidConstant):
(JSC::JITSubGenerator::arithProfile):
(JSC::JITSubGenerator::didEmitFastPath): Deleted.
(JSC::JITSubGenerator::endJumpList): Deleted.
(JSC::JITSubGenerator::slowPathJumpList): Deleted.


Canonical link: https://commits.webkit.org/178551@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
saambarati committed Aug 1, 2016
1 parent 47310c8 commit 099532089fae745b85a5b46fd9ed128af089ed6f
Showing 12 changed files with 230 additions and 132 deletions.
@@ -1,3 +1,52 @@
2016-08-01 Saam Barati <sbarati@apple.com>

Sub should be a Math IC
https://bugs.webkit.org/show_bug.cgi?id=160270

Reviewed by Mark Lam.

This makes Sub an IC like Mul and Add. I'm seeing the following
improvements of average Sub size on Unity and JetStream:

| JetStream | Unity 3D |
------| -------------|--------------
Old | 202 bytes | 205 bytes |
------| -------------|--------------
New | 134 bytes | 134 bytes |
------------------------------------

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::addJITMulIC):
(JSC::CodeBlock::addJITSubIC):
(JSC::CodeBlock::findStubInfo):
(JSC::CodeBlock::dumpMathICStats):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::stubInfoBegin):
(JSC::CodeBlock::stubInfoEnd):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithSub):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArithAddOrSub):
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_sub):
(JSC::JIT::emitSlow_op_sub):
(JSC::JIT::emit_op_pow):
* jit/JITMathIC.h:
* jit/JITMathICForwards.h:
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITSubGenerator.cpp:
(JSC::JITSubGenerator::generateInline):
(JSC::JITSubGenerator::generateFastPath):
* jit/JITSubGenerator.h:
(JSC::JITSubGenerator::JITSubGenerator):
(JSC::JITSubGenerator::isLeftOperandValidConstant):
(JSC::JITSubGenerator::isRightOperandValidConstant):
(JSC::JITSubGenerator::arithProfile):
(JSC::JITSubGenerator::didEmitFastPath): Deleted.
(JSC::JITSubGenerator::endJumpList): Deleted.
(JSC::JITSubGenerator::slowPathJumpList): Deleted.

2016-08-01 Keith Miller <keith_miller@apple.com>

We should not keep the JavaScript tests inside the Source/JavaScriptCore/ directory.
@@ -3018,6 +3018,11 @@ JITMulIC* CodeBlock::addJITMulIC()
return m_mulICs.add();
}

JITSubIC* CodeBlock::addJITSubIC()
{
return m_subICs.add();
}

StructureStubInfo* CodeBlock::findStubInfo(CodeOrigin codeOrigin)
{
for (StructureStubInfo* stubInfo : m_stubInfos) {
@@ -4585,6 +4590,8 @@ void CodeBlock::dumpMathICStats()
double totalAddSize = 0.0;
double numMuls = 0.0;
double totalMulSize = 0.0;
double numSubs = 0.0;
double totalSubSize = 0.0;

auto countICs = [&] (CodeBlock* codeBlock) {
for (JITAddIC* addIC : codeBlock->m_addICs) {
@@ -4597,6 +4604,11 @@ void CodeBlock::dumpMathICStats()
totalMulSize += mulIC->codeSize();
}

for (JITSubIC* subIC : codeBlock->m_subICs) {
numSubs++;
totalSubSize += subIC->codeSize();
}

return false;
};
heap()->forEachCodeBlock(countICs);
@@ -4608,6 +4620,10 @@ void CodeBlock::dumpMathICStats()
dataLog("Num Muls: ", numMuls, "\n");
dataLog("Total Mul size in bytes: ", totalMulSize, "\n");
dataLog("Average Mul size: ", totalMulSize / numMuls, "\n");
dataLog("\n");
dataLog("Num Subs: ", numSubs, "\n");
dataLog("Total Sub size in bytes: ", totalSubSize, "\n");
dataLog("Average Sub size: ", totalSubSize / numSubs, "\n");

dataLog("-----------------------\n");
#endif
@@ -253,6 +253,7 @@ class CodeBlock : public JSCell {
StructureStubInfo* addStubInfo(AccessType);
JITAddIC* addJITAddIC();
JITMulIC* addJITMulIC();
JITSubIC* addJITSubIC();
Bag<StructureStubInfo>::iterator stubInfoBegin() { return m_stubInfos.begin(); }
Bag<StructureStubInfo>::iterator stubInfoEnd() { return m_stubInfos.end(); }

@@ -1018,6 +1019,7 @@ class CodeBlock : public JSCell {
Bag<StructureStubInfo> m_stubInfos;
Bag<JITAddIC> m_addICs;
Bag<JITMulIC> m_mulICs;
Bag<JITSubIC> m_subICs;
Bag<ByValInfo> m_byValInfos;
Bag<CallLinkInfo> m_callLinkInfos;
SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo>> m_incomingCalls;
@@ -3923,53 +3923,19 @@ void SpeculativeJIT::compileArithSub(Node* node)
}

case UntypedUse: {
Edge& leftChild = node->child1();
Edge& rightChild = node->child2();

JSValueOperand left(this, leftChild);
JSValueOperand right(this, rightChild);

JSValueRegs leftRegs = left.jsValueRegs();
JSValueRegs rightRegs = right.jsValueRegs();

FPRTemporary leftNumber(this);
FPRTemporary rightNumber(this);
FPRReg leftFPR = leftNumber.fpr();
FPRReg rightFPR = rightNumber.fpr();

#if USE(JSVALUE64)
GPRTemporary result(this);
JSValueRegs resultRegs = JSValueRegs(result.gpr());
GPRTemporary scratch(this);
GPRReg scratchGPR = scratch.gpr();
FPRReg scratchFPR = InvalidFPRReg;
bool needsScratchGPRReg = true;
bool needsScratchFPRReg = false;
#else
GPRTemporary resultTag(this);
GPRTemporary resultPayload(this);
JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
GPRReg scratchGPR = resultTag.gpr();
FPRTemporary fprScratch(this);
FPRReg scratchFPR = fprScratch.fpr();
bool needsScratchGPRReg = true;
bool needsScratchFPRReg = true;
#endif

SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());

JITSubGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
leftFPR, rightFPR, scratchGPR, scratchFPR);
gen.generateFastPath(m_jit);

ASSERT(gen.didEmitFastPath());
gen.endJumpList().append(m_jit.jump());

gen.slowPathJumpList().link(&m_jit);
silentSpillAllRegisters(resultRegs);
callOperation(operationValueSub, resultRegs, leftRegs, rightRegs);
silentFillAllRegisters(resultRegs);
m_jit.exceptionCheck();

gen.endJumpList().link(&m_jit);
jsValueResult(resultRegs, node);
JITSubIC* subIC = m_jit.codeBlock()->addJITSubIC();
auto repatchingFunction = operationValueSubOptimize;
auto nonRepatchingFunction = operationValueSub;

compileMathIC(node, subIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
return;
}

@@ -1710,7 +1710,10 @@ class LowerDFGToB3 {
break;
}

emitBinarySnippet<JITSubGenerator>(operationValueSub);
JITSubIC* subIC = codeBlock()->addJITSubIC();
auto repatchingFunction = operationValueSubOptimize;
auto nonRepatchingFunction = operationValueSub;
compileMathIC(subIC, repatchingFunction, nonRepatchingFunction);
break;
}

@@ -926,71 +926,16 @@ void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>

void JIT::emit_op_sub(Instruction* currentInstruction)
{
int result = currentInstruction[1].u.operand;
int op1 = currentInstruction[2].u.operand;
int op2 = currentInstruction[3].u.operand;

#if USE(JSVALUE64)
OperandTypes types = getOperandTypes(copiedInstruction(currentInstruction));
JSValueRegs leftRegs = JSValueRegs(regT0);
JSValueRegs rightRegs = JSValueRegs(regT1);
JSValueRegs resultRegs = leftRegs;
GPRReg scratchGPR = regT2;
FPRReg scratchFPR = InvalidFPRReg;
#else
OperandTypes types = getOperandTypes(currentInstruction);
JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
JSValueRegs rightRegs = JSValueRegs(regT3, regT2);
JSValueRegs resultRegs = leftRegs;
GPRReg scratchGPR = regT4;
FPRReg scratchFPR = fpRegT2;
#endif

ArithProfile* arithProfile = nullptr;
if (shouldEmitProfiling())
arithProfile = &m_codeBlock->arithProfileForPC(currentInstruction);

SnippetOperand leftOperand(types.first());
SnippetOperand rightOperand(types.second());

emitGetVirtualRegister(op1, leftRegs);
emitGetVirtualRegister(op2, rightRegs);

JITSubGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
fpRegT0, fpRegT1, scratchGPR, scratchFPR, arithProfile);

gen.generateFastPath(*this);

ASSERT(gen.didEmitFastPath());
gen.endJumpList().link(this);
emitPutVirtualRegister(result, resultRegs);

addSlowCase(gen.slowPathJumpList());
JITSubIC* subIC = m_codeBlock->addJITSubIC();
m_instructionToMathIC.add(currentInstruction, subIC);
emitMathICFast(subIC, currentInstruction, operationValueSubProfiled, operationValueSub);
}

void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkAllSlowCasesForBytecodeOffset(m_slowCases, iter, m_bytecodeOffset);

int result = currentInstruction[1].u.operand;
#if USE(JSVALUE64)
JSValueRegs leftRegs = JSValueRegs(regT0);
JSValueRegs rightRegs = JSValueRegs(regT1);
JSValueRegs resultRegs = leftRegs;
#else
JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
JSValueRegs rightRegs = JSValueRegs(regT3, regT2);
JSValueRegs resultRegs = leftRegs;
#endif

if (shouldEmitProfiling()) {
ArithProfile& arithProfile = m_codeBlock->arithProfileForPC(currentInstruction);
callOperation(operationValueSubProfiled, resultRegs, leftRegs, rightRegs, &arithProfile);
emitPutVirtualRegister(result, resultRegs);
} else {
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_sub);
slowPathCall.call();
}
JITSubIC* subIC = bitwise_cast<JITSubIC*>(m_instructionToMathIC.get(currentInstruction));
emitMathICSlow(subIC, currentInstruction, operationValueSubProfiledOptimize, operationValueSubProfiled, operationValueSubOptimize);
}

void JIT::emit_op_pow(Instruction* currentInstruction)
@@ -32,6 +32,7 @@
#include "JITAddGenerator.h"
#include "JITMathICInlineResult.h"
#include "JITMulGenerator.h"
#include "JITSubGenerator.h"
#include "LinkBuffer.h"
#include "Repatch.h"
#include "SnippetOperand.h"
@@ -240,6 +241,7 @@ class JITMathIC {

typedef JITMathIC<JITAddGenerator> JITAddIC;
typedef JITMathIC<JITMulGenerator> JITMulIC;
typedef JITMathIC<JITSubGenerator> JITSubIC;

} // namespace JSC

@@ -32,9 +32,11 @@ namespace JSC {
template <typename Generator> class JITMathIC;
class JITAddGenerator;
class JITMulGenerator;
class JITSubGenerator;

typedef JITMathIC<JITAddGenerator> JITAddIC;
typedef JITMathIC<JITMulGenerator> JITMulIC;
typedef JITMathIC<JITSubGenerator> JITSubIC;

} // namespace JSC

@@ -2447,11 +2447,8 @@ EncodedJSValue JIT_OPERATION operationValueMulProfiledNoOptimize(ExecState* exec
return profiledMul(exec, encodedOp1, encodedOp2, arithProfile);
}

EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
ALWAYS_INLINE static EncodedJSValue unprofiledSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

JSValue op1 = JSValue::decode(encodedOp1);
JSValue op2 = JSValue::decode(encodedOp2);

@@ -2460,14 +2457,14 @@ EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue e
return JSValue::encode(jsNumber(a - b));
}

EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
ALWAYS_INLINE static EncodedJSValue profiledSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile, bool shouldObserveLHSAndRHSTypes = true)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

JSValue op1 = JSValue::decode(encodedOp1);
JSValue op2 = JSValue::decode(encodedOp2);

if (shouldObserveLHSAndRHSTypes)
arithProfile->observeLHSAndRHS(op1, op2);

double a = op1.toNumber(exec);
double b = op2.toNumber(exec);

@@ -2476,6 +2473,70 @@ EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJ
return JSValue::encode(result);
}

EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
return unprofiledSub(exec, encodedOp1, encodedOp2);
}

EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

return profiledSub(exec, encodedOp1, encodedOp2, arithProfile);
}

EncodedJSValue JIT_OPERATION operationValueSubOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

auto nonOptimizeVariant = operationValueSubNoOptimize;
if (ArithProfile* arithProfile = subIC->m_generator.arithProfile())
arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
subIC->generateOutOfLine(*vm, exec->codeBlock(), nonOptimizeVariant);

#if ENABLE(MATH_IC_STATS)
exec->codeBlock()->dumpMathICStats();
#endif

return unprofiledSub(exec, encodedOp1, encodedOp2);
}

EncodedJSValue JIT_OPERATION operationValueSubNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC*)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

return unprofiledSub(exec, encodedOp1, encodedOp2);
}

EncodedJSValue JIT_OPERATION operationValueSubProfiledOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile, JITSubIC* subIC)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
auto nonOptimizeVariant = operationValueSubProfiledNoOptimize;
subIC->generateOutOfLine(*vm, exec->codeBlock(), nonOptimizeVariant);

#if ENABLE(MATH_IC_STATS)
exec->codeBlock()->dumpMathICStats();
#endif

return profiledSub(exec, encodedOp1, encodedOp2, arithProfile, false);
}

EncodedJSValue JIT_OPERATION operationValueSubProfiledNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile, JITSubIC*)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);

return profiledSub(exec, encodedOp1, encodedOp2, arithProfile);
}

void JIT_OPERATION operationProcessTypeProfilerLog(ExecState* exec)
{
VM& vm = exec->vm();

0 comments on commit 0995320

Please sign in to comment.