op_add/ValueAdd should be an IC in all JIT tiers
[WebKit.git] / Source / JavaScriptCore / jit / JITAddGenerator.cpp
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 "JITAddGenerator.h"
28
29 #include "ArithProfile.h"
30 #include "JITMathIC.h"
31 #include "LinkBuffer.h"
32
33 #if ENABLE(JIT)
34
35 namespace JSC {
36
37 JITMathICInlineResult JITAddGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state)
38 {
39     // We default to speculating int32.
40     ObservedType lhs = ObservedType().withInt32();
41     ObservedType rhs = ObservedType().withInt32();
42     if (m_arithProfile) {
43         lhs = m_arithProfile->lhsObservedType();
44         rhs = m_arithProfile->rhsObservedType();
45         if (lhs.isEmpty() || rhs.isEmpty()) {
46             lhs = ObservedType().withInt32();
47             rhs = ObservedType().withInt32();
48         }
49     }
50
51     if (lhs.isOnlyNonNumber() && rhs.isOnlyNonNumber())
52         return JITMathICInlineResult::DontGenerate;
53
54     if ((lhs.isOnlyInt32() || m_leftOperand.isConstInt32()) && (rhs.isOnlyInt32() || m_rightOperand.isConstInt32())) {
55         ASSERT(!m_leftOperand.isConstInt32() || !m_rightOperand.isConstInt32());
56         if (!m_leftOperand.isConstInt32())
57             state.slowPathJumps.append(jit.branchIfNotInt32(m_left));
58         if (!m_rightOperand.isConstInt32())
59             state.slowPathJumps.append(jit.branchIfNotInt32(m_right));
60
61         if (m_leftOperand.isConstInt32() || m_rightOperand.isConstInt32()) {
62             JSValueRegs var = m_leftOperand.isConstInt32() ? m_right : m_left;
63             int32_t constValue = m_leftOperand.isConstInt32() ? m_leftOperand.asConstInt32() : m_rightOperand.asConstInt32();
64             state.slowPathJumps.append(jit.branchAdd32(CCallHelpers::Overflow, var.payloadGPR(), CCallHelpers::Imm32(constValue), m_scratchGPR));
65         } else
66             state.slowPathJumps.append(jit.branchAdd32(CCallHelpers::Overflow, m_right.payloadGPR(), m_left.payloadGPR(), m_scratchGPR));
67         jit.boxInt32(m_scratchGPR, m_result);
68         return JITMathICInlineResult::GeneratedFastPath;
69     }
70
71     return JITMathICInlineResult::GenerateFullSnippet;
72 }
73
74 bool JITAddGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList)
75 {
76     ASSERT(m_scratchGPR != InvalidGPRReg);
77     ASSERT(m_scratchGPR != m_left.payloadGPR());
78     ASSERT(m_scratchGPR != m_right.payloadGPR());
79 #if USE(JSVALUE32_64)
80     ASSERT(m_scratchGPR != m_left.tagGPR());
81     ASSERT(m_scratchGPR != m_right.tagGPR());
82     ASSERT(m_scratchFPR != InvalidFPRReg);
83 #endif
84
85     ASSERT(!m_leftOperand.isConstInt32() || !m_rightOperand.isConstInt32());
86     
87     if (!m_leftOperand.mightBeNumber() || !m_rightOperand.mightBeNumber())
88         return false;
89
90     if (m_leftOperand.isConstInt32() || m_rightOperand.isConstInt32()) {
91         JSValueRegs var = m_leftOperand.isConstInt32() ? m_right : m_left;
92         SnippetOperand& varOpr = m_leftOperand.isConstInt32() ? m_rightOperand : m_leftOperand;
93         SnippetOperand& constOpr = m_leftOperand.isConstInt32() ? m_leftOperand : m_rightOperand;
94
95         // Try to do intVar + intConstant.
96         CCallHelpers::Jump notInt32 = jit.branchIfNotInt32(var);
97
98         slowPathJumpList.append(jit.branchAdd32(CCallHelpers::Overflow, var.payloadGPR(), CCallHelpers::Imm32(constOpr.asConstInt32()), m_scratchGPR));
99
100         jit.boxInt32(m_scratchGPR, m_result);
101         endJumpList.append(jit.jump());
102
103         if (!jit.supportsFloatingPoint()) {
104             slowPathJumpList.append(notInt32);
105             return true;
106         }
107
108         // Try to do doubleVar + double(intConstant).
109         notInt32.link(&jit);
110         if (!varOpr.definitelyIsNumber())
111             slowPathJumpList.append(jit.branchIfNotNumber(var, m_scratchGPR));
112
113         jit.unboxDoubleNonDestructive(var, m_leftFPR, m_scratchGPR, m_scratchFPR);
114
115         jit.move(CCallHelpers::Imm32(constOpr.asConstInt32()), m_scratchGPR);
116         jit.convertInt32ToDouble(m_scratchGPR, m_rightFPR);
117
118         // Fall thru to doubleVar + doubleVar.
119
120     } else {
121         ASSERT(!m_leftOperand.isConstInt32() && !m_rightOperand.isConstInt32());
122         CCallHelpers::Jump leftNotInt;
123         CCallHelpers::Jump rightNotInt;
124
125         // Try to do intVar + intVar.
126         leftNotInt = jit.branchIfNotInt32(m_left);
127         rightNotInt = jit.branchIfNotInt32(m_right);
128
129         slowPathJumpList.append(jit.branchAdd32(CCallHelpers::Overflow, m_right.payloadGPR(), m_left.payloadGPR(), m_scratchGPR));
130
131         jit.boxInt32(m_scratchGPR, m_result);
132         endJumpList.append(jit.jump());
133
134
135         if (!jit.supportsFloatingPoint()) {
136             slowPathJumpList.append(leftNotInt);
137             slowPathJumpList.append(rightNotInt);
138             return true;
139         }
140
141         leftNotInt.link(&jit);
142         if (!m_leftOperand.definitelyIsNumber())
143             slowPathJumpList.append(jit.branchIfNotNumber(m_left, m_scratchGPR));
144         if (!m_rightOperand.definitelyIsNumber())
145             slowPathJumpList.append(jit.branchIfNotNumber(m_right, m_scratchGPR));
146
147         jit.unboxDoubleNonDestructive(m_left, m_leftFPR, m_scratchGPR, m_scratchFPR);
148         CCallHelpers::Jump rightIsDouble = jit.branchIfNotInt32(m_right);
149
150         jit.convertInt32ToDouble(m_right.payloadGPR(), m_rightFPR);
151         CCallHelpers::Jump rightWasInteger = jit.jump();
152
153         rightNotInt.link(&jit);
154         if (!m_rightOperand.definitelyIsNumber())
155             slowPathJumpList.append(jit.branchIfNotNumber(m_right, m_scratchGPR));
156
157         jit.convertInt32ToDouble(m_left.payloadGPR(), m_leftFPR);
158
159         rightIsDouble.link(&jit);
160         jit.unboxDoubleNonDestructive(m_right, m_rightFPR, m_scratchGPR, m_scratchFPR);
161
162         rightWasInteger.link(&jit);
163
164         // Fall thru to doubleVar + doubleVar.
165     }
166
167     // Do doubleVar + doubleVar.
168     jit.addDouble(m_rightFPR, m_leftFPR);
169     if (m_arithProfile)
170         m_arithProfile->emitSetDouble(jit);
171         
172     jit.boxDouble(m_leftFPR, m_result);
173
174     return true;
175 }
176
177 } // namespace JSC
178
179 #endif // ENABLE(JIT)