Add specialized string comparison IR ops
[hiphop-php.git] / hphp / runtime / vm / jit / ir-opcode.cpp
blob432589b740b245dd34a8ee2d4ebc8593d4fcbd2e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/ir-opcode.h"
19 #include "hphp/runtime/base/string-data.h"
20 #include "hphp/runtime/vm/jit/cfg.h"
21 #include "hphp/runtime/vm/jit/extra-data.h"
22 #include "hphp/runtime/vm/jit/ir-instruction.h"
23 #include "hphp/runtime/vm/jit/ir-unit.h"
24 #include "hphp/runtime/vm/jit/ssa-tmp.h"
25 #include "hphp/runtime/vm/jit/print.h"
26 #include "hphp/runtime/vm/jit/type.h"
27 #include "hphp/runtime/vm/runtime.h"
29 #include "hphp/util/trace.h"
31 // Include last to localize effects to this file
32 #include "hphp/util/assert-throw.h"
34 namespace HPHP { namespace jit {
35 ///////////////////////////////////////////////////////////////////////////////
37 TRACE_SET_MOD(hhir);
39 #define NF 0
40 #define Er MayRaiseError
41 #define PRc ProducesRC
42 #define CRc ConsumesRC
43 #define T Terminal
44 #define B Branch
45 #define P Passthrough
46 #define MProp MInstrProp
47 #define MElem MInstrElem
49 #define ND 0
50 #define D(n) HasDest
51 #define DofS(n) HasDest
52 #define DRefineS(n) HasDest
53 #define DParamMayRelax HasDest
54 #define DParam HasDest
55 #define DParamPtr(k) HasDest
56 #define DUnboxPtr HasDest
57 #define DBoxPtr HasDest
58 #define DAllocObj HasDest
59 #define DArrElem HasDest
60 #define DArrPacked HasDest
61 #define DCol HasDest
62 #define DThis HasDest
63 #define DCtx HasDest
64 #define DMulti NaryDest
65 #define DSetElem HasDest
66 #define DPtrToParam HasDest
67 #define DBuiltin HasDest
68 #define DSubtract(n,t) HasDest
69 #define DCns HasDest
71 namespace {
72 template<Opcode op, uint64_t flags>
73 struct op_flags {
74 static constexpr uint64_t value =
75 (OpHasExtraData<op>::value ? HasExtra : 0) | flags;
77 static_assert(!(value & ProducesRC) ||
78 (value & (HasDest | NaryDest)) == HasDest,
79 "ProducesRC instructions must have exactly one dest");
83 OpInfo g_opInfo[] = {
84 #define O(name, dsts, srcs, flags) \
85 { #name, \
86 op_flags<name, dsts | flags>::value \
88 IR_OPCODES
89 #undef O
90 { 0 }
93 #undef NF
94 #undef C
95 #undef E
96 #undef PRc
97 #undef CRc
98 #undef Er
99 #undef T
100 #undef B
101 #undef P
102 #undef K
103 #undef MProp
104 #undef MElem
106 #undef ND
107 #undef D
108 #undef DofS
109 #undef DRefineS
110 #undef DParamMayRelax
111 #undef DParam
112 #undef DParamPtr
113 #undef DUnboxPtr
114 #undef DBoxPtr
115 #undef DArrElem
116 #undef DArrPacked
117 #undef DCol
118 #undef DAllocObj
119 #undef DThis
120 #undef DCtx
121 #undef DMulti
122 #undef DSetElem
123 #undef DPtrToParam
124 #undef DBuiltin
125 #undef DSubtract
126 #undef DCns
128 ///////////////////////////////////////////////////////////////////////////////
130 const StringData* findClassName(SSATmp* cls) {
131 assertx(cls->isA(TCls));
133 if (cls->hasConstVal()) {
134 return cls->clsVal()->preClass()->name();
136 // Try to get the class name from a LdCls
137 IRInstruction* clsInst = cls->inst();
138 if (clsInst->op() == LdCls || clsInst->op() == LdClsCached) {
139 SSATmp* clsName = clsInst->src(0);
140 assertx(clsName->isA(TStr));
141 if (clsName->hasConstVal()) {
142 return clsName->strVal();
145 return nullptr;
148 bool isCallOp(Opcode opc) {
149 // CallBuiltin doesn't count because it is not a php-level call. (It will
150 // call a C++ helper and we can push/pop around it normally.)
151 switch (opc) {
152 case Call:
153 case CallArray:
154 case ContEnter:
155 return true;
156 default:
157 return false;
161 bool isGuardOp(Opcode opc) {
162 switch (opc) {
163 case CheckLoc:
164 case CheckStk:
165 case CheckType:
166 return true;
168 default:
169 return false;
173 bool isQueryOp(Opcode opc) {
174 switch (opc) {
175 case Gt:
176 case Gte:
177 case Lt:
178 case Lte:
179 case Eq:
180 case Neq:
181 case GtInt:
182 case GteInt:
183 case LtInt:
184 case LteInt:
185 case EqInt:
186 case NeqInt:
187 case GtDbl:
188 case GteDbl:
189 case LtDbl:
190 case LteDbl:
191 case EqDbl:
192 case NeqDbl:
193 case GtStr:
194 case GteStr:
195 case LtStr:
196 case LteStr:
197 case EqStr:
198 case NeqStr:
199 case SameStr:
200 case NSameStr:
201 case Same:
202 case NSame:
203 case InstanceOfBitmask:
204 case NInstanceOfBitmask:
205 case IsType:
206 case IsNType:
207 return true;
208 default:
209 return false;
213 bool isIntQueryOp(Opcode opc) {
214 switch (opc) {
215 case GtInt:
216 case GteInt:
217 case LtInt:
218 case LteInt:
219 case EqInt:
220 case NeqInt:
221 return true;
222 default:
223 return false;
227 bool isDblQueryOp(Opcode opc) {
228 switch (opc) {
229 case GtDbl:
230 case GteDbl:
231 case LtDbl:
232 case LteDbl:
233 case EqDbl:
234 case NeqDbl:
235 return true;
236 default:
237 return false;
241 bool isStrQueryOp(Opcode opc) {
242 switch (opc) {
243 case GtStr:
244 case GteStr:
245 case LtStr:
246 case LteStr:
247 case EqStr:
248 case NeqStr:
249 case SameStr:
250 case NSameStr:
251 return true;
252 default:
253 return false;
257 Opcode negateQueryOp(Opcode opc) {
258 assertx(isQueryOp(opc));
259 switch (opc) {
260 case Gt: return Lte;
261 case Gte: return Lt;
262 case Lt: return Gte;
263 case Lte: return Gt;
264 case Eq: return Neq;
265 case Neq: return Eq;
266 case GtInt: return LteInt;
267 case GteInt: return LtInt;
268 case LtInt: return GteInt;
269 case LteInt: return GtInt;
270 case EqInt: return NeqInt;
271 case NeqInt: return EqInt;
272 case EqDbl: return NeqDbl;
273 case NeqDbl: return EqDbl;
274 case GtStr: return LteStr;
275 case GteStr: return LtStr;
276 case LtStr: return GteStr;
277 case LteStr: return GtStr;
278 case EqStr: return NeqStr;
279 case NeqStr: return EqStr;
280 case SameStr: return NSameStr;
281 case NSameStr: return SameStr;
282 case Same: return NSame;
283 case NSame: return Same;
284 case InstanceOfBitmask: return NInstanceOfBitmask;
285 case NInstanceOfBitmask: return InstanceOfBitmask;
286 case IsType: return IsNType;
287 case IsNType: return IsType;
288 case GtDbl:
289 case GteDbl:
290 case LtDbl:
291 case LteDbl:
292 // Negating dbl relational ops probably isn't what you want:
293 // (X < Y) != !(X >= Y) -- when NaN gets involved
294 always_assert(false);
295 default: always_assert(0);
299 Opcode commuteQueryOp(Opcode opc) {
300 assertx(isQueryOp(opc));
301 switch (opc) {
302 case Gt: return Lt;
303 case Gte: return Lte;
304 case Lt: return Gt;
305 case Lte: return Gte;
306 case Eq: return Eq;
307 case Neq: return Neq;
308 case GtInt: return LtInt;
309 case GteInt:return LteInt;
310 case LtInt: return GtInt;
311 case LteInt:return GteInt;
312 case EqInt: return EqInt;
313 case NeqInt:return NeqInt;
314 case GtDbl: return LtDbl;
315 case GteDbl:return LteDbl;
316 case LtDbl: return GtDbl;
317 case LteDbl:return GteDbl;
318 case EqDbl: return EqDbl;
319 case NeqDbl:return NeqDbl;
320 case GtStr: return LtStr;
321 case GteStr:return LteStr;
322 case LtStr: return GtStr;
323 case LteStr:return GteStr;
324 case EqStr:
325 case NeqStr:
326 case SameStr:
327 case NSameStr:
328 return opc;
329 case Same: return Same;
330 case NSame: return NSame;
331 default: always_assert(0);
335 Opcode queryToIntQueryOp(Opcode opc) {
336 assertx(isQueryOp(opc));
337 switch (opc) {
338 case Gt: return GtInt;
339 case Gte: return GteInt;
340 case Lt: return LtInt;
341 case Lte: return LteInt;
342 case Eq: return EqInt;
343 case Neq: return NeqInt;
344 case GtDbl: return GtInt;
345 case GteDbl:return GteInt;
346 case LtDbl: return LtInt;
347 case LteDbl:return LteInt;
348 case EqDbl: return EqInt;
349 case NeqDbl:return NeqInt;
350 default: always_assert(0);
354 Opcode queryToDblQueryOp(Opcode opc) {
355 assertx(isQueryOp(opc));
356 switch (opc) {
357 case Gt: return GtDbl;
358 case Gte: return GteDbl;
359 case Lt: return LtDbl;
360 case Lte: return LteDbl;
361 case Eq: return EqDbl;
362 case Neq: return NeqDbl;
363 case GtInt: return GtDbl;
364 case GteInt:return GteDbl;
365 case LtInt: return LtDbl;
366 case LteInt:return LteDbl;
367 case EqInt: return EqDbl;
368 case NeqInt:return NeqDbl;
369 default: always_assert(0);
373 Opcode queryToStrQueryOp(Opcode opc) {
374 assertx(isQueryOp(opc));
375 switch (opc) {
376 case Gt: return GtStr;
377 case Gte: return GteStr;
378 case Lt: return LtStr;
379 case Lte: return LteStr;
380 case Eq: return EqStr;
381 case Neq: return NeqStr;
382 case Same: return SameStr;
383 case NSame: return NSameStr;
384 default: always_assert(0);
388 ///////////////////////////////////////////////////////////////////////////////