1aaa06c50c0867c15ec1338aecb27877189f0464
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirInstInlines.h
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 #pragma once
27
28 #if ENABLE(B3_JIT)
29
30 #include "AirInst.h"
31 #include "AirOpcodeUtils.h"
32 #include "AirSpecial.h"
33 #include "AirStackSlot.h"
34 #include "B3Value.h"
35
36 namespace JSC { namespace B3 { namespace Air {
37
38 template<typename Thing, typename Functor>
39 void Inst::forEach(const Functor& functor)
40 {
41     forEachArg(
42         [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
43             arg.forEach<Thing>(role, type, width, functor);
44         });
45 }
46
47 inline RegisterSet Inst::extraClobberedRegs()
48 {
49     ASSERT(kind.opcode == Patch);
50     return args[0].special()->extraClobberedRegs(*this);
51 }
52
53 inline RegisterSet Inst::extraEarlyClobberedRegs()
54 {
55     ASSERT(kind.opcode == Patch);
56     return args[0].special()->extraEarlyClobberedRegs(*this);
57 }
58
59 template<typename Thing, typename Functor>
60 inline void Inst::forEachDef(Inst* prevInst, Inst* nextInst, const Functor& functor)
61 {
62     if (prevInst) {
63         prevInst->forEach<Thing>(
64             [&] (Thing& thing, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
65                 if (Arg::isLateDef(role))
66                     functor(thing, role, argType, argWidth);
67             });
68     }
69
70     if (nextInst) {
71         nextInst->forEach<Thing>(
72             [&] (Thing& thing, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
73                 if (Arg::isEarlyDef(role))
74                     functor(thing, role, argType, argWidth);
75             });
76     }
77 }
78
79 template<typename Thing, typename Functor>
80 inline void Inst::forEachDefWithExtraClobberedRegs(
81     Inst* prevInst, Inst* nextInst, const Functor& functor)
82 {
83     forEachDef<Thing>(prevInst, nextInst, functor);
84
85     Arg::Role regDefRole;
86     
87     auto reportReg = [&] (Reg reg) {
88         Arg::Type type = reg.isGPR() ? Arg::GP : Arg::FP;
89         functor(Thing(reg), regDefRole, type, Arg::conservativeWidth(type));
90     };
91
92     if (prevInst && prevInst->kind.opcode == Patch) {
93         regDefRole = Arg::Def;
94         prevInst->extraClobberedRegs().forEach(reportReg);
95     }
96
97     if (nextInst && nextInst->kind.opcode == Patch) {
98         regDefRole = Arg::EarlyDef;
99         nextInst->extraEarlyClobberedRegs().forEach(reportReg);
100     }
101 }
102
103 inline void Inst::reportUsedRegisters(const RegisterSet& usedRegisters)
104 {
105     ASSERT(kind.opcode == Patch);
106     args[0].special()->reportUsedRegisters(*this, usedRegisters);
107 }
108
109 inline bool Inst::admitsStack(Arg& arg)
110 {
111     return admitsStack(&arg - &args[0]);
112 }
113
114 inline Optional<unsigned> Inst::shouldTryAliasingDef()
115 {
116     if (!isX86())
117         return Nullopt;
118
119     switch (kind.opcode) {
120     case Add32:
121     case Add64:
122     case And32:
123     case And64:
124     case Mul32:
125     case Mul64:
126     case Or32:
127     case Or64:
128     case Xor32:
129     case Xor64:
130     case AndFloat:
131     case AndDouble:
132     case XorDouble:
133     case XorFloat:
134         if (args.size() == 3)
135             return 2;
136         break;
137     case AddDouble:
138     case AddFloat:
139     case MulDouble:
140     case MulFloat:
141 #if CPU(X86) || CPU(X86_64)
142         if (MacroAssembler::supportsAVX())
143             return Nullopt;
144 #endif
145         if (args.size() == 3)
146             return 2;
147         break;
148     case BranchAdd32:
149     case BranchAdd64:
150         if (args.size() == 4)
151             return 3;
152         break;
153     case MoveConditionally32:
154     case MoveConditionally64:
155     case MoveConditionallyTest32:
156     case MoveConditionallyTest64:
157     case MoveConditionallyDouble:
158     case MoveConditionallyFloat:
159     case MoveDoubleConditionally32:
160     case MoveDoubleConditionally64:
161     case MoveDoubleConditionallyTest32:
162     case MoveDoubleConditionallyTest64:
163     case MoveDoubleConditionallyDouble:
164     case MoveDoubleConditionallyFloat:
165         if (args.size() == 6)
166             return 5;
167         break;
168         break;
169     case Patch:
170         return PatchCustom::shouldTryAliasingDef(*this);
171     default:
172         break;
173     }
174     return Nullopt;
175 }
176
177 inline bool isShiftValid(const Inst& inst)
178 {
179 #if CPU(X86) || CPU(X86_64)
180     return inst.args[0] == Tmp(X86Registers::ecx);
181 #else
182     UNUSED_PARAM(inst);
183     return true;
184 #endif
185 }
186
187 inline bool isLshift32Valid(const Inst& inst)
188 {
189     return isShiftValid(inst);
190 }
191
192 inline bool isLshift64Valid(const Inst& inst)
193 {
194     return isShiftValid(inst);
195 }
196
197 inline bool isRshift32Valid(const Inst& inst)
198 {
199     return isShiftValid(inst);
200 }
201
202 inline bool isRshift64Valid(const Inst& inst)
203 {
204     return isShiftValid(inst);
205 }
206
207 inline bool isUrshift32Valid(const Inst& inst)
208 {
209     return isShiftValid(inst);
210 }
211
212 inline bool isUrshift64Valid(const Inst& inst)
213 {
214     return isShiftValid(inst);
215 }
216
217 inline bool isRotateRight32Valid(const Inst& inst)
218 {
219     return isShiftValid(inst);
220 }
221
222 inline bool isRotateLeft32Valid(const Inst& inst)
223 {
224     return isShiftValid(inst);
225 }
226
227 inline bool isRotateRight64Valid(const Inst& inst)
228 {
229     return isShiftValid(inst);
230 }
231
232 inline bool isRotateLeft64Valid(const Inst& inst)
233 {
234     return isShiftValid(inst);
235 }
236
237 inline bool isX86DivHelperValid(const Inst& inst)
238 {
239 #if CPU(X86) || CPU(X86_64)
240     return inst.args[0] == Tmp(X86Registers::eax)
241         && inst.args[1] == Tmp(X86Registers::edx);
242 #else
243     UNUSED_PARAM(inst);
244     return false;
245 #endif
246 }
247
248 inline bool isX86ConvertToDoubleWord32Valid(const Inst& inst)
249 {
250     return isX86DivHelperValid(inst);
251 }
252
253 inline bool isX86ConvertToQuadWord64Valid(const Inst& inst)
254 {
255     return isX86DivHelperValid(inst);
256 }
257
258 inline bool isX86Div32Valid(const Inst& inst)
259 {
260     return isX86DivHelperValid(inst);
261 }
262
263 inline bool isX86UDiv32Valid(const Inst& inst)
264 {
265     return isX86DivHelperValid(inst);
266 }
267
268 inline bool isX86Div64Valid(const Inst& inst)
269 {
270     return isX86DivHelperValid(inst);
271 }
272
273 inline bool isX86UDiv64Valid(const Inst& inst)
274 {
275     return isX86DivHelperValid(inst);
276 }
277
278 } } } // namespace JSC::B3::Air
279
280 #endif // ENABLE(B3_JIT)