99c473b64c4ad6ea3fa0ea4a8dce2452d706e341
[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         RELEASE_ASSERT_NOT_REACHED();
126         return false;
127     }
128
129     // Returns true if the Role implies that the Inst will Def the Arg.
130     static bool isDef(Role role)
131     {
132         switch (role) {
133         case Use:
134         case UseAddr:
135             return false;
136         case Def:
137         case UseDef:
138             return true;
139         }
140         RELEASE_ASSERT_NOT_REACHED();
141         return false;
142     }
143
144     static Type typeForB3Type(B3::Type type)
145     {
146         switch (type) {
147         case Void:
148             ASSERT_NOT_REACHED();
149             return GP;
150         case Int32:
151         case Int64:
152             return GP;
153         case Double:
154             return FP;
155         }
156         ASSERT_NOT_REACHED();
157         return GP;
158     }
159
160     Arg()
161         : m_kind(Invalid)
162     {
163     }
164
165     Arg(Air::Tmp tmp)
166         : m_kind(Tmp)
167         , m_base(tmp)
168     {
169     }
170
171     static Arg imm(int32_t value)
172     {
173         Arg result;
174         result.m_kind = Imm;
175         result.m_offset = value;
176         return result;
177     }
178
179     static Arg imm64(intptr_t value)
180     {
181         Arg result;
182         result.m_kind = Imm64;
183         result.m_offset = value;
184         return result;
185     }
186
187     static Arg addr(Air::Tmp base, int32_t offset = 0)
188     {
189         ASSERT(base.isGP());
190         Arg result;
191         result.m_kind = Addr;
192         result.m_base = base;
193         result.m_offset = offset;
194         return result;
195     }
196
197     static Arg stack(StackSlot* value, int32_t offset = 0)
198     {
199         Arg result;
200         result.m_kind = Stack;
201         result.m_offset = bitwise_cast<intptr_t>(value);
202         result.m_scale = offset; // I know, yuck.
203         return result;
204     }
205
206     static Arg callArg(int32_t offset)
207     {
208         Arg result;
209         result.m_kind = CallArg;
210         result.m_offset = offset;
211         return result;
212     }
213
214     static bool isValidScale(unsigned scale)
215     {
216         switch (scale) {
217         case 1:
218         case 2:
219         case 4:
220         case 8:
221             return true;
222         default:
223             return false;
224         }
225     }
226
227     static unsigned logScale(unsigned scale)
228     {
229         switch (scale) {
230         case 1:
231             return 0;
232         case 2:
233             return 1;
234         case 4:
235             return 2;
236         case 8:
237             return 3;
238         default:
239             ASSERT_NOT_REACHED();
240             return 0;
241         }
242     }
243
244     static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1, int32_t offset = 0)
245     {
246         ASSERT(base.isGP());
247         ASSERT(index.isGP());
248         ASSERT(isValidScale(scale));
249         Arg result;
250         result.m_kind = Index;
251         result.m_base = base;
252         result.m_index = index;
253         result.m_scale = static_cast<int32_t>(scale);
254         result.m_offset = offset;
255         return result;
256     }
257
258     static Arg relCond(MacroAssembler::RelationalCondition condition)
259     {
260         Arg result;
261         result.m_kind = RelCond;
262         result.m_offset = condition;
263         return result;
264     }
265
266     static Arg resCond(MacroAssembler::ResultCondition condition)
267     {
268         Arg result;
269         result.m_kind = ResCond;
270         result.m_offset = condition;
271         return result;
272     }
273
274     static Arg doubleCond(MacroAssembler::DoubleCondition condition)
275     {
276         Arg result;
277         result.m_kind = DoubleCond;
278         result.m_offset = condition;
279         return result;
280     }
281
282     static Arg special(Air::Special* special)
283     {
284         Arg result;
285         result.m_kind = Special;
286         result.m_offset = bitwise_cast<intptr_t>(special);
287         return result;
288     }
289
290     bool operator==(const Arg& other) const
291     {
292         return m_offset == other.m_offset
293             && m_kind == other.m_kind
294             && m_base == other.m_base
295             && m_index == other.m_index
296             && m_scale == other.m_scale;
297     }
298
299     bool operator!=(const Arg& other) const
300     {
301         return !(*this == other);
302     }
303
304     explicit operator bool() const { return *this != Arg(); }
305
306     Kind kind() const
307     {
308         return m_kind;
309     }
310
311     bool isTmp() const
312     {
313         return kind() == Tmp;
314     }
315
316     bool isImm() const
317     {
318         return kind() == Imm;
319     }
320
321     bool isImm64() const
322     {
323         return kind() == Imm64;
324     }
325
326     bool isAddr() const
327     {
328         return kind() == Addr;
329     }
330
331     bool isStack() const
332     {
333         return kind() == Stack;
334     }
335
336     bool isCallArg() const
337     {
338         return kind() == CallArg;
339     }
340
341     bool isIndex() const
342     {
343         return kind() == Index;
344     }
345
346     bool isRelCond() const
347     {
348         return kind() == RelCond;
349     }
350
351     bool isResCond() const
352     {
353         return kind() == ResCond;
354     }
355
356     bool isDoubleCond() const
357     {
358         return kind() == DoubleCond;
359     }
360
361     bool isSpecial() const
362     {
363         return kind() == Special;
364     }
365
366     bool isAlive() const
367     {
368         return isTmp() || isStack();
369     }
370
371     Air::Tmp tmp() const
372     {
373         ASSERT(kind() == Tmp);
374         return m_base;
375     }
376
377     int64_t value() const
378     {
379         ASSERT(kind() == Imm || kind() == Imm64);
380         return m_offset;
381     }
382
383     void* pointerValue() const
384     {
385         ASSERT(kind() == Imm64);
386         return bitwise_cast<void*>(static_cast<intptr_t>(m_offset));
387     }
388
389     Air::Tmp base() const
390     {
391         ASSERT(kind() == Addr || kind() == Index);
392         return m_base;
393     }
394
395     bool hasOffset() const
396     {
397         switch (kind()) {
398         case Addr:
399         case Stack:
400         case CallArg:
401         case Index:
402             return true;
403         default:
404             return false;
405         }
406     }
407     
408     int32_t offset() const
409     {
410         if (kind() == Stack)
411             return static_cast<int32_t>(m_scale);
412         ASSERT(kind() == Addr || kind() == CallArg || kind() == Index);
413         return static_cast<int32_t>(m_offset);
414     }
415
416     StackSlot* stackSlot() const
417     {
418         ASSERT(kind() == Stack);
419         return bitwise_cast<StackSlot*>(m_offset);
420     }
421
422     Air::Tmp index() const
423     {
424         ASSERT(kind() == Index);
425         return m_index;
426     }
427
428     unsigned scale() const
429     {
430         ASSERT(kind() == Index);
431         return m_scale;
432     }
433
434     unsigned logScale() const
435     {
436         return logScale(scale());
437     }
438
439     Air::Special* special() const
440     {
441         ASSERT(kind() == Special);
442         return bitwise_cast<Air::Special*>(m_offset);
443     }
444
445     bool isGPTmp() const
446     {
447         return isTmp() && tmp().isGP();
448     }
449
450     bool isFPTmp() const
451     {
452         return isTmp() && tmp().isFP();
453     }
454     
455     // Tells us if this Arg can be used in a position that requires a GP value.
456     bool isGP() const
457     {
458         switch (kind()) {
459         case Imm:
460         case Imm64:
461         case Addr:
462         case Index:
463         case Stack:
464         case CallArg:
465         case RelCond:
466         case ResCond:
467         case DoubleCond:
468         case Special:
469             return true;
470         case Tmp:
471             return isGPTmp();
472         case Invalid:
473             return false;
474         }
475         RELEASE_ASSERT_NOT_REACHED();
476         return false;
477     }
478
479     // Tells us if this Arg can be used in a position that requires a FP value.
480     bool isFP() const
481     {
482         switch (kind()) {
483         case Imm:
484         case RelCond:
485         case ResCond:
486         case DoubleCond:
487         case Special:
488         case Invalid:
489             return false;
490         case Addr:
491         case Index:
492         case Stack:
493         case CallArg:
494         case Imm64: // Yes, we allow Imm64 as a double immediate. We use this for implementing stackmaps.
495             return true;
496         case Tmp:
497             return isFPTmp();
498         }
499         RELEASE_ASSERT_NOT_REACHED();
500         return false;
501     }
502
503     bool hasType() const
504     {
505         switch (kind()) {
506         case Imm:
507         case Special:
508         case Tmp:
509             return true;
510         default:
511             return false;
512         }
513     }
514     
515     // The type is ambiguous for some arg kinds. Call with care.
516     Type type() const
517     {
518         return isGP() ? GP : FP;
519     }
520
521     bool isType(Type type) const
522     {
523         switch (type) {
524         case GP:
525             return isGP();
526         case FP:
527             return isFP();
528         }
529         RELEASE_ASSERT_NOT_REACHED();
530         return false;
531     }
532
533     bool isGPR() const
534     {
535         return isTmp() && tmp().isGPR();
536     }
537
538     GPRReg gpr() const
539     {
540         return tmp().gpr();
541     }
542
543     bool isFPR() const
544     {
545         return isTmp() && tmp().isFPR();
546     }
547
548     FPRReg fpr() const
549     {
550         return tmp().fpr();
551     }
552     
553     bool isReg() const
554     {
555         return isTmp() && tmp().isReg();
556     }
557
558     Reg reg() const
559     {
560         return tmp().reg();
561     }
562
563     unsigned gpTmpIndex() const
564     {
565         return tmp().gpTmpIndex();
566     }
567
568     unsigned fpTmpIndex() const
569     {
570         return tmp().fpTmpIndex();
571     }
572
573     unsigned tmpIndex() const
574     {
575         return tmp().tmpIndex();
576     }
577
578     Arg withOffset(int32_t additionalOffset) const
579     {
580         if (!hasOffset())
581             return Arg();
582         if (sumOverflows<int32_t>(offset(), additionalOffset))
583             return Arg();
584         switch (kind()) {
585         case Addr:
586             return addr(base(), offset() + additionalOffset);
587         case Stack:
588             return stack(stackSlot(), offset() + additionalOffset);
589         case CallArg:
590             return callArg(offset() + additionalOffset);
591         case Index:
592             return index(base(), index(), scale(), offset() + additionalOffset);
593         default:
594             RELEASE_ASSERT_NOT_REACHED();
595             return Arg();
596         }
597     }
598
599     template<typename Functor>
600     void forEachTmpFast(const Functor& functor)
601     {
602         switch (m_kind) {
603         case Tmp:
604         case Addr:
605             functor(m_base);
606             break;
607         case Index:
608             functor(m_base);
609             functor(m_index);
610             break;
611         default:
612             break;
613         }
614     }
615
616     // This is smart enough to know that an address arg in a Def or UseDef rule will use its
617     // tmps and never def them. For example, this:
618     //
619     // mov %rax, (%rcx)
620     //
621     // This defs (%rcx) but uses %rcx.
622     template<typename Functor>
623     void forEachTmp(Role argRole, Type argType, const Functor& functor)
624     {
625         switch (m_kind) {
626         case Tmp:
627             ASSERT(isUse(argRole) || isDef(argRole));
628             functor(m_base, argRole, argType);
629             break;
630         case Addr:
631             functor(m_base, Use, GP);
632             break;
633         case Index:
634             functor(m_base, Use, GP);
635             functor(m_index, Use, GP);
636             break;
637         default:
638             break;
639         }
640     }
641
642     MacroAssembler::TrustedImm32 asTrustedImm32() const
643     {
644         ASSERT(isImm());
645         return MacroAssembler::TrustedImm32(static_cast<int32_t>(m_offset));
646     }
647
648 #if USE(JSVALUE64)
649     MacroAssembler::TrustedImm64 asTrustedImm64() const
650     {
651         ASSERT(isImm64());
652         return MacroAssembler::TrustedImm64(value());
653     }
654 #endif
655
656     MacroAssembler::TrustedImmPtr asTrustedImmPtr() const
657     {
658         if (is64Bit())
659             ASSERT(isImm64());
660         else
661             ASSERT(isImm());
662         return MacroAssembler::TrustedImmPtr(pointerValue());
663     }
664
665     MacroAssembler::Address asAddress() const
666     {
667         ASSERT(isAddr());
668         return MacroAssembler::Address(m_base.gpr(), static_cast<int32_t>(m_offset));
669     }
670
671     MacroAssembler::BaseIndex asBaseIndex() const
672     {
673         ASSERT(isIndex());
674         return MacroAssembler::BaseIndex(
675             m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
676             static_cast<int32_t>(m_offset));
677     }
678
679     MacroAssembler::RelationalCondition asRelationalCondition() const
680     {
681         ASSERT(isRelCond());
682         return static_cast<MacroAssembler::RelationalCondition>(m_offset);
683     }
684
685     MacroAssembler::ResultCondition asResultCondition() const
686     {
687         ASSERT(isResCond());
688         return static_cast<MacroAssembler::ResultCondition>(m_offset);
689     }
690
691     MacroAssembler::DoubleCondition asDoubleCondition() const
692     {
693         ASSERT(isDoubleCond());
694         return static_cast<MacroAssembler::DoubleCondition>(m_offset);
695     }
696
697     void dump(PrintStream&) const;
698
699     Arg(WTF::HashTableDeletedValueType)
700         : m_base(WTF::HashTableDeletedValue)
701     {
702     }
703
704     bool isHashTableDeletedValue() const
705     {
706         return *this == Arg(WTF::HashTableDeletedValue);
707     }
708
709     unsigned hash() const
710     {
711         // This really doesn't have to be that great.
712         return WTF::IntHash<int64_t>::hash(m_offset) + m_kind + m_scale + m_base.hash() +
713             m_index.hash();
714     }
715
716 private:
717     int64_t m_offset { 0 };
718     Kind m_kind { Invalid };
719     int32_t m_scale { 1 };
720     Air::Tmp m_base;
721     Air::Tmp m_index;
722 };
723
724 struct ArgHash {
725     static unsigned hash(const Arg& key) { return key.hash(); }
726     static bool equal(const Arg& a, const Arg& b) { return a == b; }
727     static const bool safeToCompareToEmptyOrDeleted = true;
728 };
729
730 } } } // namespace JSC::B3::Air
731
732 namespace WTF {
733
734 template<typename T> struct DefaultHash;
735 template<> struct DefaultHash<JSC::B3::Air::Arg> {
736     typedef JSC::B3::Air::ArgHash Hash;
737 };
738
739 template<typename T> struct HashTraits;
740 template<> struct HashTraits<JSC::B3::Air::Arg> : SimpleClassHashTraits<JSC::B3::Air::Arg> {
741     // Because m_scale is 1 in the empty value.
742     static const bool emptyValueIsZero = false;
743 };
744
745 } // namespace WTF
746
747 #endif // ENABLE(B3_JIT)
748
749 #endif // AirArg_h
750