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