Unreviewed, partially revert r191952.
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirArg.h
1 /*
2  * Copyright (C) 2015 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 #ifndef AirArg_h
27 #define AirArg_h
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirTmp.h"
32 #include "B3Common.h"
33 #include "B3Type.h"
34
35 namespace JSC { namespace B3 { namespace Air {
36
37 class Special;
38 class StackSlot;
39
40 // This class name is also intentionally terse because we will say it a lot. You'll see code like
41 // Inst(..., Arg::imm(5), Arg::addr(thing, blah), ...)
42 class Arg {
43 public:
44     // These enum members are intentionally terse because we have to mention them a lot.
45     enum Kind : int8_t {
46         Invalid,
47
48         // This is either an unassigned temporary or a register. All unassigned temporaries
49         // eventually become registers.
50         Tmp,
51
52         // This is an immediate that the instruction will materialize.
53         Imm,
54         Imm64,
55
56         // These are the addresses. Instructions may load from (Use), store to (Def), or evaluate
57         // (UseAddr) addresses.
58         Addr,
59         Stack,
60         CallArg,
61         Index,
62
63         // Immediate operands that customize the behavior of an operation. You can think of them as
64         // secondary opcodes. They are always "Use"'d.
65         RelCond,
66         ResCond,
67         DoubleCond,
68         Special
69     };
70
71     enum Role : int8_t {
72         // Use means that the Inst will read from this value before doing anything else.
73         //
74         // For Tmp: The Inst will read this Tmp.
75         // For Arg::addr and friends: The Inst will load from this address.
76         // For Arg::imm and friends: The Inst will materialize and use this immediate.
77         // For RelCond/ResCond/Special: This is the only valid role for these kinds.
78         //
79         // Note that Use of an address does not mean escape. It only means that the instruction will
80         // load from the address before doing anything else. This is a bit tricky; for example
81         // Specials could theoretically squirrel away the address and effectively escape it. However,
82         // this is not legal. On the other hand, any address other than Stack is presumed to be
83         // always escaping, and Stack is presumed to be always escaping if it's Locked.
84         Use,
85
86         // Def means that the Inst will write to this value after doing everything else.
87         //
88         // For Tmp: The Inst will write to this Tmp.
89         // For Arg::addr and friends: The Inst will store to this address.
90         // This isn't valid for any other kinds.
91         //
92         // Like Use of address, Def of address does not mean escape.
93         Def,
94
95         // This is a combined Use and Def. It means that both things happen.
96         UseDef,
97
98         // This is a special kind of use that is only valid for addresses. It means that the
99         // instruction will evaluate the address expression and consume the effective address, but it
100         // will neither load nor store. This is an escaping use, because now the address may be
101         // passed along to who-knows-where. Note that this isn't really a Use of the Arg, but it does
102         // imply that we're Use'ing any registers that the Arg contains.
103         UseAddr
104     };
105
106     enum Type : int8_t {
107         GP,
108         FP
109     };
110
111     static const unsigned numTypes = 2;
112
113     // Returns true if the Role implies that the Inst will Use the Arg. It's deliberately false for
114     // UseAddr, since isUse() for an Arg::addr means that we are loading from the address.
115     static bool isUse(Role role)
116     {
117         switch (role) {
118         case Use:
119         case UseDef:
120             return true;
121         case Def:
122         case UseAddr:
123             return false;
124         }
125     }
126
127     // Returns true if the Role implies that the Inst will Def the Arg.
128     static bool isDef(Role role)
129     {
130         switch (role) {
131         case Use:
132         case UseAddr:
133             return false;
134         case Def:
135         case UseDef:
136             return true;
137         }
138     }
139
140     static Type typeForB3Type(B3::Type type)
141     {
142         switch (type) {
143         case Void:
144             ASSERT_NOT_REACHED();
145             return GP;
146         case Int32:
147         case Int64:
148             return GP;
149         case Double:
150             return FP;
151         }
152         ASSERT_NOT_REACHED();
153         return GP;
154     }
155
156     Arg()
157         : m_kind(Invalid)
158     {
159     }
160
161     Arg(Air::Tmp tmp)
162         : m_kind(Tmp)
163         , m_base(tmp)
164     {
165     }
166
167     static Arg imm(int32_t value)
168     {
169         Arg result;
170         result.m_kind = Imm;
171         result.m_offset = value;
172         return result;
173     }
174
175     static Arg imm64(intptr_t value)
176     {
177         Arg result;
178         result.m_kind = Imm64;
179         result.m_offset = value;
180         return result;
181     }
182
183     static Arg addr(Air::Tmp base, int32_t offset = 0)
184     {
185         ASSERT(base.isGP());
186         Arg result;
187         result.m_kind = Addr;
188         result.m_base = base;
189         result.m_offset = offset;
190         return result;
191     }
192
193     static Arg stack(StackSlot* value, int32_t offset = 0)
194     {
195         Arg result;
196         result.m_kind = Stack;
197         result.m_offset = bitwise_cast<intptr_t>(value);
198         result.m_scale = offset; // I know, yuck.
199         return result;
200     }
201
202     static Arg callArg(int32_t offset)
203     {
204         Arg result;
205         result.m_kind = CallArg;
206         result.m_offset = offset;
207         return result;
208     }
209
210     static bool isValidScale(unsigned scale)
211     {
212         switch (scale) {
213         case 1:
214         case 2:
215         case 4:
216         case 8:
217             return true;
218         default:
219             return false;
220         }
221     }
222
223     static unsigned logScale(unsigned scale)
224     {
225         switch (scale) {
226         case 1:
227             return 0;
228         case 2:
229             return 1;
230         case 4:
231             return 2;
232         case 8:
233             return 3;
234         default:
235             ASSERT_NOT_REACHED();
236             return 0;
237         }
238     }
239
240     static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1, int32_t offset = 0)
241     {
242         ASSERT(base.isGP());
243         ASSERT(index.isGP());
244         ASSERT(isValidScale(scale));
245         Arg result;
246         result.m_kind = Index;
247         result.m_base = base;
248         result.m_index = index;
249         result.m_scale = static_cast<int32_t>(scale);
250         result.m_offset = offset;
251         return result;
252     }
253
254     static Arg relCond(MacroAssembler::RelationalCondition condition)
255     {
256         Arg result;
257         result.m_kind = RelCond;
258         result.m_offset = condition;
259         return result;
260     }
261
262     static Arg resCond(MacroAssembler::ResultCondition condition)
263     {
264         Arg result;
265         result.m_kind = ResCond;
266         result.m_offset = condition;
267         return result;
268     }
269
270     static Arg doubleCond(MacroAssembler::DoubleCondition condition)
271     {
272         Arg result;
273         result.m_kind = DoubleCond;
274         result.m_offset = condition;
275         return result;
276     }
277
278     static Arg special(Air::Special* special)
279     {
280         Arg result;
281         result.m_kind = Special;
282         result.m_offset = bitwise_cast<intptr_t>(special);
283         return result;
284     }
285
286     bool operator==(const Arg& other) const
287     {
288         return m_offset == other.m_offset
289             && m_kind == other.m_kind
290             && m_base == other.m_base
291             && m_index == other.m_index
292             && m_scale == other.m_scale;
293     }
294
295     bool operator!=(const Arg& other) const
296     {
297         return !(*this == other);
298     }
299
300     explicit operator bool() const { return *this != Arg(); }
301
302     Kind kind() const
303     {
304         return m_kind;
305     }
306
307     bool isTmp() const
308     {
309         return kind() == Tmp;
310     }
311
312     bool isImm() const
313     {
314         return kind() == Imm;
315     }
316
317     bool isImm64() const
318     {
319         return kind() == Imm64;
320     }
321
322     bool isAddr() const
323     {
324         return kind() == Addr;
325     }
326
327     bool isStack() const
328     {
329         return kind() == Stack;
330     }
331
332     bool isCallArg() const
333     {
334         return kind() == CallArg;
335     }
336
337     bool isIndex() const
338     {
339         return kind() == Index;
340     }
341
342     bool isRelCond() const
343     {
344         return kind() == RelCond;
345     }
346
347     bool isResCond() const
348     {
349         return kind() == ResCond;
350     }
351
352     bool isDoubleCond() const
353     {
354         return kind() == DoubleCond;
355     }
356
357     bool isSpecial() const
358     {
359         return kind() == Special;
360     }
361
362     bool isAlive() const
363     {
364         return isTmp() || isStack();
365     }
366
367     Air::Tmp tmp() const
368     {
369         ASSERT(kind() == Tmp);
370         return m_base;
371     }
372
373     int64_t value() const
374     {
375         ASSERT(kind() == Imm || kind() == Imm64);
376         return m_offset;
377     }
378
379     void* pointerValue() const
380     {
381         ASSERT(kind() == Imm64);
382         return bitwise_cast<void*>(static_cast<intptr_t>(m_offset));
383     }
384
385     Air::Tmp base() const
386     {
387         ASSERT(kind() == Addr || kind() == Index);
388         return m_base;
389     }
390
391     bool hasOffset() const
392     {
393         switch (kind()) {
394         case Addr:
395         case Stack:
396         case CallArg:
397         case Index:
398             return true;
399         default:
400             return false;
401         }
402     }
403     
404     int32_t offset() const
405     {
406         if (kind() == Stack)
407             return static_cast<int32_t>(m_scale);
408         ASSERT(kind() == Addr || kind() == CallArg || kind() == Index);
409         return static_cast<int32_t>(m_offset);
410     }
411
412     StackSlot* stackSlot() const
413     {
414         ASSERT(kind() == Stack);
415         return bitwise_cast<StackSlot*>(m_offset);
416     }
417
418     Air::Tmp index() const
419     {
420         ASSERT(kind() == Index);
421         return m_index;
422     }
423
424     unsigned scale() const
425     {
426         ASSERT(kind() == Index);
427         return m_scale;
428     }
429
430     unsigned logScale() const
431     {
432         return logScale(scale());
433     }
434
435     Air::Special* special() const
436     {
437         ASSERT(kind() == Special);
438         return bitwise_cast<Air::Special*>(m_offset);
439     }
440
441     bool isGPTmp() const
442     {
443         return isTmp() && tmp().isGP();
444     }
445
446     bool isFPTmp() const
447     {
448         return isTmp() && tmp().isFP();
449     }
450     
451     // Tells us if this Arg can be used in a position that requires a GP value.
452     bool isGP() const
453     {
454         switch (kind()) {
455         case Imm:
456         case Imm64:
457         case Addr:
458         case Index:
459         case Stack:
460         case CallArg:
461         case RelCond:
462         case ResCond:
463         case DoubleCond:
464         case Special:
465             return true;
466         case Tmp:
467             return isGPTmp();
468         case Invalid:
469             return false;
470         }
471     }
472
473     // Tells us if this Arg can be used in a position that requires a FP value.
474     bool isFP() const
475     {
476         switch (kind()) {
477         case Imm:
478         case RelCond:
479         case ResCond:
480         case DoubleCond:
481         case Special:
482         case Invalid:
483             return false;
484         case Addr:
485         case Index:
486         case Stack:
487         case CallArg:
488         case Imm64: // Yes, we allow Imm64 as a double immediate. We use this for implementing stackmaps.
489             return true;
490         case Tmp:
491             return isFPTmp();
492         }
493     }
494
495     bool hasType() const
496     {
497         switch (kind()) {
498         case Imm:
499         case Special:
500         case Tmp:
501             return true;
502         default:
503             return false;
504         }
505     }
506     
507     // The type is ambiguous for some arg kinds. Call with care.
508     Type type() const
509     {
510         return isGP() ? GP : FP;
511     }
512
513     bool isType(Type type) const
514     {
515         switch (type) {
516         case GP:
517             return isGP();
518         case FP:
519             return isFP();
520         }
521     }
522
523     bool isGPR() const
524     {
525         return isTmp() && tmp().isGPR();
526     }
527
528     GPRReg gpr() const
529     {
530         return tmp().gpr();
531     }
532
533     bool isFPR() const
534     {
535         return isTmp() && tmp().isFPR();
536     }
537
538     FPRReg fpr() const
539     {
540         return tmp().fpr();
541     }
542     
543     bool isReg() const
544     {
545         return isTmp() && tmp().isReg();
546     }
547
548     Reg reg() const
549     {
550         return tmp().reg();
551     }
552
553     unsigned gpTmpIndex() const
554     {
555         return tmp().gpTmpIndex();
556     }
557
558     unsigned fpTmpIndex() const
559     {
560         return tmp().fpTmpIndex();
561     }
562
563     unsigned tmpIndex() const
564     {
565         return tmp().tmpIndex();
566     }
567
568     Arg withOffset(int32_t additionalOffset) const
569     {
570         if (!hasOffset())
571             return Arg();
572         if (sumOverflows<int32_t>(offset(), additionalOffset))
573             return Arg();
574         switch (kind()) {
575         case Addr:
576             return addr(base(), offset() + additionalOffset);
577         case Stack:
578             return stack(stackSlot(), offset() + additionalOffset);
579         case CallArg:
580             return callArg(offset() + additionalOffset);
581         case Index:
582             return index(base(), index(), scale(), offset() + additionalOffset);
583         default:
584             RELEASE_ASSERT_NOT_REACHED();
585             return Arg();
586         }
587     }
588
589     template<typename Functor>
590     void forEachTmpFast(const Functor& functor)
591     {
592         switch (m_kind) {
593         case Tmp:
594         case Addr:
595             functor(m_base);
596             break;
597         case Index:
598             functor(m_base);
599             functor(m_index);
600             break;
601         default:
602             break;
603         }
604     }
605
606     // This is smart enough to know that an address arg in a Def or UseDef rule will use its
607     // tmps and never def them. For example, this:
608     //
609     // mov %rax, (%rcx)
610     //
611     // This defs (%rcx) but uses %rcx.
612     template<typename Functor>
613     void forEachTmp(Role argRole, Type argType, const Functor& functor)
614     {
615         switch (m_kind) {
616         case Tmp:
617             ASSERT(isUse(argRole) || isDef(argRole));
618             functor(m_base, argRole, argType);
619             break;
620         case Addr:
621             functor(m_base, Use, GP);
622             break;
623         case Index:
624             functor(m_base, Use, GP);
625             functor(m_index, Use, GP);
626             break;
627         default:
628             break;
629         }
630     }
631
632     MacroAssembler::TrustedImm32 asTrustedImm32() const
633     {
634         ASSERT(isImm());
635         return MacroAssembler::TrustedImm32(static_cast<int32_t>(m_offset));
636     }
637
638 #if USE(JSVALUE64)
639     MacroAssembler::TrustedImm64 asTrustedImm64() const
640     {
641         ASSERT(isImm64());
642         return MacroAssembler::TrustedImm64(value());
643     }
644 #endif
645
646     MacroAssembler::TrustedImmPtr asTrustedImmPtr() const
647     {
648         if (is64Bit())
649             ASSERT(isImm64());
650         else
651             ASSERT(isImm());
652         return MacroAssembler::TrustedImmPtr(pointerValue());
653     }
654
655     MacroAssembler::Address asAddress() const
656     {
657         ASSERT(isAddr());
658         return MacroAssembler::Address(m_base.gpr(), static_cast<int32_t>(m_offset));
659     }
660
661     MacroAssembler::BaseIndex asBaseIndex() const
662     {
663         ASSERT(isIndex());
664         return MacroAssembler::BaseIndex(
665             m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
666             static_cast<int32_t>(m_offset));
667     }
668
669     MacroAssembler::RelationalCondition asRelationalCondition() const
670     {
671         ASSERT(isRelCond());
672         return static_cast<MacroAssembler::RelationalCondition>(m_offset);
673     }
674
675     MacroAssembler::ResultCondition asResultCondition() const
676     {
677         ASSERT(isResCond());
678         return static_cast<MacroAssembler::ResultCondition>(m_offset);
679     }
680
681     MacroAssembler::DoubleCondition asDoubleCondition() const
682     {
683         ASSERT(isDoubleCond());
684         return static_cast<MacroAssembler::DoubleCondition>(m_offset);
685     }
686
687     void dump(PrintStream&) const;
688
689     Arg(WTF::HashTableDeletedValueType)
690         : m_base(WTF::HashTableDeletedValue)
691     {
692     }
693
694     bool isHashTableDeletedValue() const
695     {
696         return *this == Arg(WTF::HashTableDeletedValue);
697     }
698
699     unsigned hash() const
700     {
701         // This really doesn't have to be that great.
702         return WTF::IntHash<int64_t>::hash(m_offset) + m_kind + m_scale + m_base.hash() +
703             m_index.hash();
704     }
705
706 private:
707     int64_t m_offset { 0 };
708     Kind m_kind { Invalid };
709     int32_t m_scale { 1 };
710     Air::Tmp m_base;
711     Air::Tmp m_index;
712 };
713
714 struct ArgHash {
715     static unsigned hash(const Arg& key) { return key.hash(); }
716     static bool equal(const Arg& a, const Arg& b) { return a == b; }
717     static const bool safeToCompareToEmptyOrDeleted = true;
718 };
719
720 } } } // namespace JSC::B3::Air
721
722 namespace WTF {
723
724 template<typename T> struct DefaultHash;
725 template<> struct DefaultHash<JSC::B3::Air::Arg> {
726     typedef JSC::B3::Air::ArgHash Hash;
727 };
728
729 template<typename T> struct HashTraits;
730 template<> struct HashTraits<JSC::B3::Air::Arg> : SimpleClassHashTraits<JSC::B3::Air::Arg> {
731     // Because m_scale is 1 in the empty value.
732     static const bool emptyValueIsZero = false;
733 };
734
735 } // namespace WTF
736
737 #endif // ENABLE(B3_JIT)
738
739 #endif // AirArg_h
740