1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jit_arm_Architecture_arm_h
8 #define jit_arm_Architecture_arm_h
9 
10 #include "mozilla/MathAlgorithms.h"
11 
12 #include <limits.h>
13 #include <stdint.h>
14 
15 #include "js/Utility.h"
16 
17 // GCC versions 4.6 and above define __ARM_PCS_VFP to denote a hard-float
18 // ABI target. The iOS toolchain doesn't define anything specific here,
19 // but iOS always supports VFP.
20 #if defined(__ARM_PCS_VFP) || defined(XP_IOS)
21 #define JS_CODEGEN_ARM_HARDFP
22 #endif
23 
24 namespace js {
25 namespace jit {
26 
27 // In bytes: slots needed for potential memory->memory move spills.
28 //   +8 for cycles
29 //   +4 for gpr spills
30 //   +8 for double spills
31 static const uint32_t ION_FRAME_SLACK_SIZE   = 20;
32 
33 // These offsets are specific to nunboxing, and capture offsets into the
34 // components of a js::Value.
35 static const int32_t NUNBOX32_TYPE_OFFSET    = 4;
36 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
37 
38 static const uint32_t ShadowStackSpace = 0;
39 ////
40 // These offsets are related to bailouts.
41 ////
42 
43 // Size of each bailout table entry. On arm, this is presently a single call
44 // (which is wrong!). The call clobbers lr.
45 // For now, I've dealt with this by ensuring that we never allocate to lr. It
46 // should probably be 8 bytes, a mov of an immediate into r12 (not allocated
47 // presently, or ever) followed by a branch to the apropriate code.
48 static const uint32_t BAILOUT_TABLE_ENTRY_SIZE    = 4;
49 
50 class Registers
51 {
52   public:
53     enum RegisterID {
54         r0 = 0,
55         r1,
56         r2,
57         r3,
58         S0 = r3,
59         r4,
60         r5,
61         r6,
62         r7,
63         r8,
64         S1 = r8,
65         r9,
66         r10,
67         r11,
68         r12,
69         ip = r12,
70         r13,
71         sp = r13,
72         r14,
73         lr = r14,
74         r15,
75         pc = r15,
76         invalid_reg
77     };
78     typedef uint8_t Code;
79     typedef RegisterID Encoding;
80 
81     // Content spilled during bailouts.
82     union RegisterContent {
83         uintptr_t r;
84     };
85 
GetName(Code code)86     static const char* GetName(Code code) {
87         MOZ_ASSERT(code < Total);
88         static const char * const Names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
89                                               "r8", "r9", "r10", "r11", "r12", "sp", "r14", "pc"};
90         return Names[code];
91     }
GetName(Encoding i)92     static const char* GetName(Encoding i) {
93         return GetName(Code(i));
94     }
95 
96     static Code FromName(const char* name);
97 
98     static const Encoding StackPointer = sp;
99     static const Encoding Invalid = invalid_reg;
100 
101     static const uint32_t Total = 16;
102     static const uint32_t Allocatable = 13;
103 
104     typedef uint32_t SetType;
105 
106     static const SetType AllMask = (1 << Total) - 1;
107     static const SetType ArgRegMask = (1 << r0) | (1 << r1) | (1 << r2) | (1 << r3);
108 
109     static const SetType VolatileMask =
110         (1 << r0) |
111         (1 << r1) |
112         (1 << Registers::r2) |
113         (1 << Registers::r3)
114 #if defined(XP_IOS)
115         // per https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW4
116         | (1 << Registers::r9)
117 #endif
118               ;
119 
120     static const SetType NonVolatileMask =
121         (1 << Registers::r4) |
122         (1 << Registers::r5) |
123         (1 << Registers::r6) |
124         (1 << Registers::r7) |
125         (1 << Registers::r8) |
126 #if !defined(XP_IOS)
127         (1 << Registers::r9) |
128 #endif
129         (1 << Registers::r10) |
130         (1 << Registers::r11) |
131         (1 << Registers::r12) |
132         (1 << Registers::r14);
133 
134     static const SetType WrapperMask =
135         VolatileMask |         // = arguments
136         (1 << Registers::r4) | // = outReg
137         (1 << Registers::r5);  // = argBase
138 
139     static const SetType SingleByteRegs =
140         VolatileMask | NonVolatileMask;
141 
142     static const SetType NonAllocatableMask =
143         (1 << Registers::sp) |
144         (1 << Registers::r12) | // r12 = ip = scratch
145         (1 << Registers::lr) |
146         (1 << Registers::pc);
147 
148     // Registers that can be allocated without being saved, generally.
149     static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
150 
151     // Registers returned from a JS -> JS call.
152     static const SetType JSCallMask =
153         (1 << Registers::r2) |
154         (1 << Registers::r3);
155 
156     // Registers returned from a JS -> C call.
157     static const SetType CallMask =
158         (1 << Registers::r0) |
159         (1 << Registers::r1);  // Used for double-size returns.
160 
161     static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
162 
SetSize(SetType x)163     static uint32_t SetSize(SetType x) {
164         static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
165         return mozilla::CountPopulation32(x);
166     }
FirstBit(SetType x)167     static uint32_t FirstBit(SetType x) {
168         return mozilla::CountTrailingZeroes32(x);
169     }
LastBit(SetType x)170     static uint32_t LastBit(SetType x) {
171         return 31 - mozilla::CountLeadingZeroes32(x);
172     }
173 };
174 
175 // Smallest integer type that can hold a register bitmask.
176 typedef uint16_t PackedRegisterMask;
177 typedef uint16_t PackedRegisterMask;
178 
179 class FloatRegisters
180 {
181   public:
182     enum FPRegisterID {
183         s0,
184         s1,
185         s2,
186         s3,
187         s4,
188         s5,
189         s6,
190         s7,
191         s8,
192         s9,
193         s10,
194         s11,
195         s12,
196         s13,
197         s14,
198         s15,
199         s16,
200         s17,
201         s18,
202         s19,
203         s20,
204         s21,
205         s22,
206         s23,
207         s24,
208         s25,
209         s26,
210         s27,
211         s28,
212         s29,
213         s30,
214         s31,
215         d0,
216         d1,
217         d2,
218         d3,
219         d4,
220         d5,
221         d6,
222         d7,
223         d8,
224         d9,
225         d10,
226         d11,
227         d12,
228         d13,
229         d14,
230         d15,
231         d16,
232         d17,
233         d18,
234         d19,
235         d20,
236         d21,
237         d22,
238         d23,
239         d24,
240         d25,
241         d26,
242         d27,
243         d28,
244         d29,
245         d30,
246         d31,
247         invalid_freg
248     };
249 
250     typedef uint32_t Code;
251     typedef FPRegisterID Encoding;
252 
253     // Content spilled during bailouts.
254     union RegisterContent {
255         double d;
256     };
257 
GetDoubleName(Encoding code)258     static const char* GetDoubleName(Encoding code) {
259         static const char * const Names[] = { "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
260                                               "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
261                                               "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
262                                               "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
263         return Names[code];
264     }
GetSingleName(Encoding code)265     static const char* GetSingleName(Encoding code) {
266         static const char * const Names[] = { "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
267                                               "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
268                                               "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
269                                               "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};
270         return Names[code];
271     }
272 
GetName(uint32_t i)273     static const char* GetName(uint32_t i) {
274         MOZ_ASSERT(i < Total);
275         return GetName(Encoding(i));
276     }
277 
278     static Code FromName(const char* name);
279 
280     static const Encoding Invalid = invalid_freg;
281     static const uint32_t Total = 48;
282     static const uint32_t TotalDouble = 16;
283     static const uint32_t TotalSingle = 32;
284     static const uint32_t Allocatable = 45;
285     // There are only 32 places that we can put values.
286     static const uint32_t TotalPhys = 32;
287     static uint32_t ActualTotalPhys();
288 
289     typedef uint64_t SetType;
290     static const SetType AllDoubleMask = ((1ull << 16) - 1) << 32;
291     static const SetType AllMask = ((1ull << 48) - 1);
292 
293     // d15 is the ScratchFloatReg.
294     static const SetType NonVolatileDoubleMask =
295          ((1ULL << d8) |
296           (1ULL << d9) |
297           (1ULL << d10) |
298           (1ULL << d11) |
299           (1ULL << d12) |
300           (1ULL << d13) |
301           (1ULL << d14));
302     // s30 and s31 alias d15.
303     static const SetType NonVolatileMask =
304         (NonVolatileDoubleMask |
305          ((1 << s16) |
306           (1 << s17) |
307           (1 << s18) |
308           (1 << s19) |
309           (1 << s20) |
310           (1 << s21) |
311           (1 << s22) |
312           (1 << s23) |
313           (1 << s24) |
314           (1 << s25) |
315           (1 << s26) |
316           (1 << s27) |
317           (1 << s28) |
318           (1 << s29) |
319           (1 << s30)));
320 
321     static const SetType VolatileMask = AllMask & ~NonVolatileMask;
322     static const SetType VolatileDoubleMask = AllDoubleMask & ~NonVolatileDoubleMask;
323 
324     static const SetType WrapperMask = VolatileMask;
325 
326     // d15 is the ARM scratch float register.
327     // s30 and s31 alias d15.
328     static const SetType NonAllocatableMask = ((1ULL << d15)) |
329                                                (1ULL << s30) |
330                                                (1ULL << s31);
331 
332     // Registers that can be allocated without being saved, generally.
333     static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
334 
335     static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
336 };
337 
338 template <typename T>
339 class TypedRegisterSet;
340 
341 class VFPRegister
342 {
343   public:
344     // What type of data is being stored in this register? UInt / Int are
345     // specifically for vcvt, where we need to know how the data is supposed to
346     // be converted.
347     enum RegType {
348         Single = 0x0,
349         Double = 0x1,
350         UInt   = 0x2,
351         Int    = 0x3
352     };
353 
354     typedef FloatRegisters Codes;
355     typedef Codes::Code Code;
356     typedef Codes::Encoding Encoding;
357 
358   protected:
359     RegType kind : 2;
360     // ARM doesn't have more than 32 registers. Don't take more bits than we'll
361     // need. Presently, we don't have plans to address the upper and lower
362     // halves of the double registers seprately, so 5 bits should suffice. If we
363     // do decide to address them seprately (vmov, I'm looking at you), we will
364     // likely specify it as a separate field.
365   public:
366     uint32_t code_ : 5;
367   protected:
368     bool _isInvalid : 1;
369     bool _isMissing : 1;
370 
371   public:
VFPRegister(uint32_t r,RegType k)372     MOZ_CONSTEXPR VFPRegister(uint32_t r, RegType k)
373       : kind(k), code_ (Code(r)), _isInvalid(false), _isMissing(false)
374     { }
VFPRegister()375     MOZ_CONSTEXPR VFPRegister()
376       : kind(Double), code_(Code(0)), _isInvalid(true), _isMissing(false)
377     { }
378 
VFPRegister(RegType k,uint32_t id,bool invalid,bool missing)379     MOZ_CONSTEXPR VFPRegister(RegType k, uint32_t id, bool invalid, bool missing) :
380         kind(k), code_(Code(id)), _isInvalid(invalid), _isMissing(missing) {
381     }
382 
VFPRegister(Code id)383     explicit MOZ_CONSTEXPR VFPRegister(Code id)
384       : kind(Double), code_(id), _isInvalid(false), _isMissing(false)
385     { }
386     bool operator==(const VFPRegister& other) const {
387         MOZ_ASSERT(!isInvalid());
388         MOZ_ASSERT(!other.isInvalid());
389         return kind == other.kind && code_ == other.code_;
390     }
391 
isSingle()392     bool isSingle() const { return kind == Single; }
isDouble()393     bool isDouble() const { return kind == Double; }
isSimd128()394     bool isSimd128() const { return false; }
isFloat()395     bool isFloat() const { return (kind == Double) || (kind == Single); }
isInt()396     bool isInt() const { return (kind == UInt) || (kind == Int); }
isSInt()397     bool isSInt() const { return kind == Int; }
isUInt()398     bool isUInt() const { return kind == UInt; }
equiv(const VFPRegister & other)399     bool equiv(const VFPRegister& other) const { return other.kind == kind; }
size()400     size_t size() const { return (kind == Double) ? 8 : 4; }
401     bool isInvalid() const;
402     bool isMissing() const;
403 
404     VFPRegister doubleOverlay(unsigned int which = 0) const;
405     VFPRegister singleOverlay(unsigned int which = 0) const;
406     VFPRegister sintOverlay(unsigned int which = 0) const;
407     VFPRegister uintOverlay(unsigned int which = 0) const;
408 
asSingle()409     VFPRegister asSingle() const { return singleOverlay(); }
asDouble()410     VFPRegister asDouble() const { return doubleOverlay(); }
asSimd128()411     VFPRegister asSimd128() const { MOZ_CRASH("NYI"); }
412 
413     struct VFPRegIndexSplit;
414     VFPRegIndexSplit encode();
415 
416     // For serializing values.
417     struct VFPRegIndexSplit {
418         const uint32_t block : 4;
419         const uint32_t bit : 1;
420 
421       private:
422         friend VFPRegIndexSplit js::jit::VFPRegister::encode();
423 
VFPRegIndexSplitVFPRegIndexSplit424         VFPRegIndexSplit(uint32_t block_, uint32_t bit_)
425           : block(block_), bit(bit_)
426         {
427             MOZ_ASSERT(block == block_);
428             MOZ_ASSERT(bit == bit_);
429         }
430     };
431 
code()432     Code code() const {
433         MOZ_ASSERT(!_isInvalid && !_isMissing);
434         // This should only be used in areas where we only have doubles and
435         // singles.
436         MOZ_ASSERT(isFloat());
437         return Code(code_ | (kind << 5));
438     }
encoding()439     Encoding encoding() const {
440         MOZ_ASSERT(!_isInvalid && !_isMissing);
441         return Encoding(code_);
442     }
id()443     uint32_t id() const {
444         return code_;
445     }
FromCode(uint32_t i)446     static VFPRegister FromCode(uint32_t i) {
447         uint32_t code = i & 31;
448         uint32_t kind = i >> 5;
449         return VFPRegister(code, RegType(kind));
450     }
volatile_()451     bool volatile_() const {
452         if (isDouble())
453             return !!((1 << (code_ >> 1)) & FloatRegisters::VolatileMask);
454         return !!((1 << code_) & FloatRegisters::VolatileMask);
455     }
name()456     const char* name() const {
457         if (isDouble())
458             return FloatRegisters::GetDoubleName(Encoding(code_));
459         return FloatRegisters::GetSingleName(Encoding(code_));
460     }
461     bool operator != (const VFPRegister& other) const {
462         return other.kind != kind || code_ != other.code_;
463     }
aliases(const VFPRegister & other)464     bool aliases(const VFPRegister& other) {
465         if (kind == other.kind)
466             return code_ == other.code_;
467         return doubleOverlay() == other.doubleOverlay();
468     }
469     static const int NumAliasedDoubles = 16;
numAliased()470     uint32_t numAliased() const {
471         if (isDouble()) {
472             if (code_ < NumAliasedDoubles)
473                 return 3;
474             return 1;
475         }
476         return 2;
477     }
478 
479     // N.B. FloatRegister is an explicit outparam here because msvc-2010
480     // miscompiled it on win64 when the value was simply returned
aliased(uint32_t aliasIdx,VFPRegister * ret)481     void aliased(uint32_t aliasIdx, VFPRegister* ret) {
482         if (aliasIdx == 0) {
483             *ret = *this;
484             return;
485         }
486         if (isDouble()) {
487             MOZ_ASSERT(code_ < NumAliasedDoubles);
488             MOZ_ASSERT(aliasIdx <= 2);
489             *ret = singleOverlay(aliasIdx - 1);
490             return;
491         }
492         MOZ_ASSERT(aliasIdx == 1);
493         *ret = doubleOverlay(aliasIdx - 1);
494     }
numAlignedAliased()495     uint32_t numAlignedAliased() const {
496         if (isDouble()) {
497             if (code_ < NumAliasedDoubles)
498                 return 2;
499             return 1;
500         }
501         // s1 has 0 other aligned aliases, 1 total.
502         // s0 has 1 other aligned aliase, 2 total.
503         return 2 - (code_ & 1);
504     }
505     // |   d0    |
506     // | s0 | s1 |
507     // If we've stored s0 and s1 in memory, we also want to say that d0 is
508     // stored there, but it is only stored at the location where it is aligned
509     // e.g. at s0, not s1.
alignedAliased(uint32_t aliasIdx,VFPRegister * ret)510     void alignedAliased(uint32_t aliasIdx, VFPRegister* ret) {
511         if (aliasIdx == 0) {
512             *ret = *this;
513             return;
514         }
515         MOZ_ASSERT(aliasIdx == 1);
516         if (isDouble()) {
517             MOZ_ASSERT(code_ < NumAliasedDoubles);
518             *ret = singleOverlay(aliasIdx - 1);
519             return;
520         }
521         MOZ_ASSERT((code_ & 1) == 0);
522         *ret = doubleOverlay(aliasIdx - 1);
523         return;
524     }
525 
526     typedef FloatRegisters::SetType SetType;
527 
528     // This function is used to ensure that Register set can take all Single
529     // registers, even if we are taking a mix of either double or single
530     // registers.
531     //
532     //   s0.alignedOrDominatedAliasedSet() == s0 | d0.
533     //   s1.alignedOrDominatedAliasedSet() == s1.
534     //   d0.alignedOrDominatedAliasedSet() == s0 | s1 | d0.
535     //
536     // This way the Allocator register set does not have to do any arithmetics
537     // to know if a register is available or not, as we have the following
538     // relations:
539     //
540     //   d0.alignedOrDominatedAliasedSet() ==
541     //       s0.alignedOrDominatedAliasedSet() | s1.alignedOrDominatedAliasedSet()
542     //
543     //   s0.alignedOrDominatedAliasedSet() & s1.alignedOrDominatedAliasedSet() == 0
544     //
alignedOrDominatedAliasedSet()545     SetType alignedOrDominatedAliasedSet() const {
546         if (isSingle()) {
547             if (code_ % 2 != 0)
548                 return SetType(1) << code_;
549             return (SetType(1) << code_) | (SetType(1) << (32 + code_ / 2));
550         }
551 
552         MOZ_ASSERT(isDouble());
553         return (SetType(0b11) << (code_ * 2)) | (SetType(1) << (32 + code_));
554     }
555 
SetSize(SetType x)556     static uint32_t SetSize(SetType x) {
557         static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
558         return mozilla::CountPopulation32(x);
559     }
FromName(const char * name)560     static Code FromName(const char* name) {
561         return FloatRegisters::FromName(name);
562     }
563     static TypedRegisterSet<VFPRegister> ReduceSetForPush(const TypedRegisterSet<VFPRegister>& s);
564     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<VFPRegister>& s);
565     uint32_t getRegisterDumpOffsetInBytes();
FirstBit(SetType x)566     static uint32_t FirstBit(SetType x) {
567         return mozilla::CountTrailingZeroes64(x);
568     }
LastBit(SetType x)569     static uint32_t LastBit(SetType x) {
570         return 63 - mozilla::CountLeadingZeroes64(x);
571     }
572 
573 };
574 
575 // The only floating point register set that we work with are the VFP Registers.
576 typedef VFPRegister FloatRegister;
577 
578 uint32_t GetARMFlags();
579 bool HasMOVWT();
580 bool HasLDSTREXBHD();           // {LD,ST}REX{B,H,D}
581 bool HasDMBDSBISB();            // DMB, DSB, and ISB
582 bool HasVFPv3();
583 bool HasVFP();
584 bool Has32DP();
585 bool HasIDIV();
586 
587 extern volatile uint32_t armHwCapFlags;
588 
589 // Not part of the HWCAP flag, but we need to know these and these bits are not
590 // used. Define these here so that their use can be inlined by the simulator.
591 
592 // A bit to flag when the flags are uninitialized, so they can be atomically set.
593 #define HWCAP_UNINITIALIZED (1 << 25)
594 
595 // A bit to flag when alignment faults are enabled and signal.
596 #define HWCAP_ALIGNMENT_FAULT (1 << 26)
597 
598 // A bit to flag the use of the hardfp ABI.
599 #define HWCAP_USE_HARDFP_ABI (1 << 27)
600 
601 // A bit to flag the use of the ARMv7 arch, otherwise ARMv6.
602 #define HWCAP_ARMv7 (1 << 28)
603 
604 // Returns true when cpu alignment faults are enabled and signaled, and thus we
605 // should ensure loads and stores are aligned.
HasAlignmentFault()606 inline bool HasAlignmentFault()
607 {
608     MOZ_ASSERT(armHwCapFlags != HWCAP_UNINITIALIZED);
609     return armHwCapFlags & HWCAP_ALIGNMENT_FAULT;
610 }
611 
612 // Arm/D32 has double registers that can NOT be treated as float32 and this
613 // requires some dances in lowering.
614 inline bool
hasUnaliasedDouble()615 hasUnaliasedDouble()
616 {
617     return Has32DP();
618 }
619 
620 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32 to
621 // a double as a temporary, you need a temporary double register.
622 inline bool
hasMultiAlias()623 hasMultiAlias()
624 {
625     return true;
626 }
627 
628 bool ParseARMHwCapFlags(const char* armHwCap);
629 void InitARMFlags();
630 uint32_t GetARMFlags();
631 
632 // If the simulator is used then the ABI choice is dynamic. Otherwise the ABI is
633 // static and useHardFpABI is inlined so that unused branches can be optimized
634 // away.
635 #ifdef JS_SIMULATOR_ARM
636 bool UseHardFpABI();
637 #else
UseHardFpABI()638 static inline bool UseHardFpABI()
639 {
640 #if defined(JS_CODEGEN_ARM_HARDFP)
641     return true;
642 #else
643     return false;
644 #endif
645 }
646 #endif
647 
648 // In order to handle SoftFp ABI calls, we need to be able to express that we
649 // have ABIArg which are represented by pair of general purpose registers.
650 #define JS_CODEGEN_REGISTER_PAIR 1
651 
652 // See the comments above AsmJSMappedSize in AsmJSValidate.h for more info.
653 // TODO: Implement this for ARM. Note that it requires Codegen to respect the
654 // offset field of AsmJSHeapAccess.
655 static const size_t AsmJSCheckedImmediateRange = 0;
656 static const size_t AsmJSImmediateRange = 0;
657 
658 } // namespace jit
659 } // namespace js
660 
661 #endif /* jit_arm_Architecture_arm_h */
662