1/*
2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JITSubGenerator.h"
28
29#include "ArithProfile.h"
30#include "JITMathIC.h"
31
32#if ENABLE(JIT)
33
34namespace JSC {
35
36JITMathICInlineResult JITSubGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const BinaryArithProfile* arithProfile)
37{
38 // We default to speculating int32.
39 ObservedType lhs = ObservedType().withInt32();
40 ObservedType rhs = ObservedType().withInt32();
41 if (arithProfile) {
42 lhs = arithProfile->lhsObservedType();
43 rhs = arithProfile->rhsObservedType();
44 }
45
46 if (lhs.isOnlyNonNumber() && rhs.isOnlyNonNumber())
47 return JITMathICInlineResult::DontGenerate;
48
49 if (lhs.isOnlyNumber() && rhs.isOnlyNumber()) {
50 if (!jit.supportsFloatingPoint())
51 return JITMathICInlineResult::DontGenerate;
52
53 if (!m_leftOperand.definitelyIsNumber())
54 state.slowPathJumps.append(jit.branchIfNotNumber(m_left, m_scratchGPR));
55 if (!m_rightOperand.definitelyIsNumber())
56 state.slowPathJumps.append(jit.branchIfNotNumber(m_right, m_scratchGPR));
57 state.slowPathJumps.append(jit.branchIfInt32(m_left));
58 state.slowPathJumps.append(jit.branchIfInt32(m_right));
59 jit.unboxDoubleNonDestructive(m_left, m_leftFPR, m_scratchGPR, m_scratchFPR);
60 jit.unboxDoubleNonDestructive(m_right, m_rightFPR, m_scratchGPR, m_scratchFPR);
61 jit.subDouble(m_rightFPR, m_leftFPR);
62 jit.boxDouble(m_leftFPR, m_result);
63
64 return JITMathICInlineResult::GeneratedFastPath;
65 }
66 if (lhs.isOnlyInt32() && rhs.isOnlyInt32()) {
67 ASSERT(!m_leftOperand.isConstInt32() || !m_rightOperand.isConstInt32());
68 state.slowPathJumps.append(jit.branchIfNotInt32(m_left));
69 state.slowPathJumps.append(jit.branchIfNotInt32(m_right));
70
71 jit.move(m_left.payloadGPR(), m_scratchGPR);
72 state.slowPathJumps.append(jit.branchSub32(CCallHelpers::Overflow, m_right.payloadGPR(), m_scratchGPR));
73
74 jit.boxInt32(m_scratchGPR, m_result);
75 return JITMathICInlineResult::GeneratedFastPath;
76 }
77
78 return JITMathICInlineResult::GenerateFullSnippet;
79}
80
81bool JITSubGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const BinaryArithProfile* arithProfile, bool shouldEmitProfiling)
82{
83 ASSERT(m_scratchGPR != InvalidGPRReg);
84 ASSERT(m_scratchGPR != m_left.payloadGPR());
85 ASSERT(m_scratchGPR != m_right.payloadGPR());
86#if USE(JSVALUE32_64)
87 ASSERT(m_scratchGPR != m_left.tagGPR());
88 ASSERT(m_scratchGPR != m_right.tagGPR());
89 ASSERT(m_scratchFPR != InvalidFPRReg);
90#endif
91
92 CCallHelpers::Jump leftNotInt = jit.branchIfNotInt32(m_left);
93 CCallHelpers::Jump rightNotInt = jit.branchIfNotInt32(m_right);
94
95 jit.move(m_left.payloadGPR(), m_scratchGPR);
96 slowPathJumpList.append(jit.branchSub32(CCallHelpers::Overflow, m_right.payloadGPR(), m_scratchGPR));
97
98 jit.boxInt32(m_scratchGPR, m_result);
99
100 endJumpList.append(jit.jump());
101
102 if (!jit.supportsFloatingPoint()) {
103 slowPathJumpList.append(leftNotInt);
104 slowPathJumpList.append(rightNotInt);
105 return true;
106 }
107
108 leftNotInt.link(&jit);
109 if (!m_leftOperand.definitelyIsNumber())
110 slowPathJumpList.append(jit.branchIfNotNumber(m_left, m_scratchGPR));
111 if (!m_rightOperand.definitelyIsNumber())
112 slowPathJumpList.append(jit.branchIfNotNumber(m_right, m_scratchGPR));
113
114 jit.unboxDoubleNonDestructive(m_left, m_leftFPR, m_scratchGPR, m_scratchFPR);
115 CCallHelpers::Jump rightIsDouble = jit.branchIfNotInt32(m_right);
116
117 jit.convertInt32ToDouble(m_right.payloadGPR(), m_rightFPR);
118 CCallHelpers::Jump rightWasInteger = jit.jump();
119
120 rightNotInt.link(&jit);
121 if (!m_rightOperand.definitelyIsNumber())
122 slowPathJumpList.append(jit.branchIfNotNumber(m_right, m_scratchGPR));
123
124 jit.convertInt32ToDouble(m_left.payloadGPR(), m_leftFPR);
125
126 rightIsDouble.link(&jit);
127 jit.unboxDoubleNonDestructive(m_right, m_rightFPR, m_scratchGPR, m_scratchFPR);
128
129 rightWasInteger.link(&jit);
130
131 jit.subDouble(m_rightFPR, m_leftFPR);
132 if (arithProfile && shouldEmitProfiling)
133 arithProfile->emitSetDouble(jit);
134
135 jit.boxDouble(m_leftFPR, m_result);
136
137 return true;
138}
139
140} // namespace JSC
141
142#endif // ENABLE(JIT)
143