1 /*
2  * Copyright (C) 2012, 2014, 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 MacroAssemblerARM64_h
27 #define MacroAssemblerARM64_h
28 
29 #if ENABLE(ASSEMBLER) && CPU(ARM64)
30 
31 #include "ARM64Assembler.h"
32 #include "AbstractMacroAssembler.h"
33 #include <wtf/MathExtras.h>
34 
35 namespace JSC {
36 
37 class MacroAssemblerARM64 : public AbstractMacroAssembler<ARM64Assembler> {
38 #define COPIED_FROM_AbstractAssembler_H 1
39 #ifdef COPIED_FROM_AbstractAssembler_H
40     typedef MacroAssemblerARM64 AbstractMacroAssemblerType;
41     class CachedTempRegister {
42         friend class DataLabelPtr;
43         friend class DataLabel32;
44         friend class DataLabelCompact;
45 //        template <typename> friend class Jump;
46         friend class Label;
47 
48     public:
CachedTempRegister(AbstractMacroAssemblerType * masm,RegisterID registerID)49         CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID)
50             : m_masm(masm)
51             , m_registerID(registerID)
52             , m_value(0)
53             , m_validBit(1 << static_cast<unsigned>(registerID))
54         {
55             ASSERT(static_cast<unsigned>(registerID) < (sizeof(unsigned) * 8));
56         }
57 
registerIDInvalidate()58         ALWAYS_INLINE RegisterID registerIDInvalidate() { invalidate(); return m_registerID; }
59 
registerIDNoInvalidate()60         ALWAYS_INLINE RegisterID registerIDNoInvalidate() { return m_registerID; }
61 
value(intptr_t & value)62         bool value(intptr_t& value)
63         {
64             value = m_value;
65             return m_masm->isTempRegisterValid(m_validBit);
66         }
67 
setValue(intptr_t value)68         void setValue(intptr_t value)
69         {
70             m_value = value;
71             m_masm->setTempRegisterValid(m_validBit);
72         }
73 
invalidate()74         ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); }
75 
76     private:
77         AbstractMacroAssemblerType* m_masm;
78         RegisterID m_registerID;
79         intptr_t m_value;
80         unsigned m_validBit;
81     };
82 
invalidateAllTempRegisters()83     ALWAYS_INLINE void invalidateAllTempRegisters()
84     {
85         m_tempRegistersValidBits = 0;
86     }
87 
isTempRegisterValid(unsigned registerMask)88     ALWAYS_INLINE bool isTempRegisterValid(unsigned registerMask)
89     {
90         return (m_tempRegistersValidBits & registerMask);
91     }
92 
clearTempRegisterValid(unsigned registerMask)93     ALWAYS_INLINE void clearTempRegisterValid(unsigned registerMask)
94     {
95         m_tempRegistersValidBits &=  ~registerMask;
96     }
97 
setTempRegisterValid(unsigned registerMask)98     ALWAYS_INLINE void setTempRegisterValid(unsigned registerMask)
99     {
100         m_tempRegistersValidBits |= registerMask;
101     }
102 
103     friend class AllowMacroScratchRegisterUsage;
104     friend class DisallowMacroScratchRegisterUsage;
105     unsigned m_tempRegistersValidBits;
106 #endif // COPIED_FROM_AbstractAssembler_H
107 public:
108     static const RegisterID dataTempRegister = ARM64Registers::ip0;
109     static const RegisterID memoryTempRegister = ARM64Registers::ip1;
110 
111 #if 0
112     RegisterID scratchRegister()
113     {
114         RELEASE_ASSERT(m_allowScratchRegister);
115         return getCachedDataTempRegisterIDAndInvalidate();
116     }
117 #endif
118 
119 private:
120     static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31;
121     static const ARM64Assembler::SetFlags S = ARM64Assembler::S;
122     static const int64_t maskHalfWord0 = 0xffffl;
123     static const int64_t maskHalfWord1 = 0xffff0000l;
124     static const int64_t maskUpperWord = 0xffffffff00000000l;
125 
126     // 4 instructions - 3 to load the function pointer, + blr.
127     static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16;
128 
129 public:
130     static const int PointerSize = 8;
131 
MacroAssemblerARM64()132     MacroAssemblerARM64()
133         : m_dataMemoryTempRegister(this, dataTempRegister)
134         , m_cachedMemoryTempRegister(this, memoryTempRegister)
135         , m_makeJumpPatchable(false)
136     {
137     }
138 
139     typedef ARM64Assembler::LinkRecord LinkRecord;
140     typedef ARM64Assembler::JumpType JumpType;
141     typedef ARM64Assembler::JumpLinkType JumpLinkType;
142     typedef ARM64Assembler::Condition Condition;
143 
144     static const ARM64Assembler::Condition DefaultCondition = ARM64Assembler::ConditionInvalid;
145     static const ARM64Assembler::JumpType DefaultJump = ARM64Assembler::JumpNoConditionFixedSize;
146 
jumpsToLink()147     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
unlinkedCode()148     void* unlinkedCode() { return m_assembler.unlinkedCode(); }
canCompact(JumpType jumpType)149     static bool canCompact(JumpType jumpType) { return ARM64Assembler::canCompact(jumpType); }
computeJumpType(JumpType jumpType,const uint8_t * from,const uint8_t * to)150     static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARM64Assembler::computeJumpType(jumpType, from, to); }
computeJumpType(LinkRecord & record,const uint8_t * from,const uint8_t * to)151     static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARM64Assembler::computeJumpType(record, from, to); }
jumpSizeDelta(JumpType jumpType,JumpLinkType jumpLinkType)152     static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return ARM64Assembler::jumpSizeDelta(jumpType, jumpLinkType); }
link(LinkRecord & record,uint8_t * from,uint8_t * to)153     static void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return ARM64Assembler::link(record, from, to); }
154 
155     static const Scale ScalePtr = TimesEight;
156 
isCompactPtrAlignedAddressOffset(ptrdiff_t value)157     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
158     {
159         // This is the largest 32-bit access allowed, aligned to 64-bit boundary.
160         return !(value & ~0x3ff8);
161     }
162 
163     enum RelationalCondition {
164         Equal = ARM64Assembler::ConditionEQ,
165         NotEqual = ARM64Assembler::ConditionNE,
166         Above = ARM64Assembler::ConditionHI,
167         AboveOrEqual = ARM64Assembler::ConditionHS,
168         Below = ARM64Assembler::ConditionLO,
169         BelowOrEqual = ARM64Assembler::ConditionLS,
170         GreaterThan = ARM64Assembler::ConditionGT,
171         GreaterThanOrEqual = ARM64Assembler::ConditionGE,
172         LessThan = ARM64Assembler::ConditionLT,
173         LessThanOrEqual = ARM64Assembler::ConditionLE
174     };
175 
176     enum ResultCondition {
177         Overflow = ARM64Assembler::ConditionVS,
178         Signed = ARM64Assembler::ConditionMI,
179         PositiveOrZero = ARM64Assembler::ConditionPL,
180         Zero = ARM64Assembler::ConditionEQ,
181         NonZero = ARM64Assembler::ConditionNE
182     };
183 
184     enum ZeroCondition {
185         IsZero = ARM64Assembler::ConditionEQ,
186         IsNonZero = ARM64Assembler::ConditionNE
187     };
188 
189     enum DoubleCondition {
190         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
191         DoubleEqual = ARM64Assembler::ConditionEQ,
192         DoubleNotEqual = ARM64Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
193         DoubleGreaterThan = ARM64Assembler::ConditionGT,
194         DoubleGreaterThanOrEqual = ARM64Assembler::ConditionGE,
195         DoubleLessThan = ARM64Assembler::ConditionLO,
196         DoubleLessThanOrEqual = ARM64Assembler::ConditionLS,
197         // If either operand is NaN, these conditions always evaluate to true.
198         DoubleEqualOrUnordered = ARM64Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
199         DoubleNotEqualOrUnordered = ARM64Assembler::ConditionNE,
200         DoubleGreaterThanOrUnordered = ARM64Assembler::ConditionHI,
201         DoubleGreaterThanOrEqualOrUnordered = ARM64Assembler::ConditionHS,
202         DoubleLessThanOrUnordered = ARM64Assembler::ConditionLT,
203         DoubleLessThanOrEqualOrUnordered = ARM64Assembler::ConditionLE,
204     };
205 
206     static const RegisterID stackPointerRegister = ARM64Registers::sp;
207     static const RegisterID framePointerRegister = ARM64Registers::fp;
208     static const RegisterID linkRegister = ARM64Registers::lr;
209 
210     // FIXME: Get reasonable implementations for these
shouldBlindForSpecificArch(uint32_t value)211     static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; }
shouldBlindForSpecificArch(uint64_t value)212     static bool shouldBlindForSpecificArch(uint64_t value) { return value >= 0x00ffffff; }
213 
214     // Integer operations:
215 
add32(RegisterID a,RegisterID b,RegisterID dest)216     void add32(RegisterID a, RegisterID b, RegisterID dest)
217     {
218         ASSERT(a != ARM64Registers::sp && b != ARM64Registers::sp);
219         m_assembler.add<32>(dest, a, b);
220     }
221 
add32(RegisterID src,RegisterID dest)222     void add32(RegisterID src, RegisterID dest)
223     {
224         m_assembler.add<32>(dest, dest, src);
225     }
226 
add32(TrustedImm32 imm,RegisterID dest)227     void add32(TrustedImm32 imm, RegisterID dest)
228     {
229         if (!imm.m_value)
230             return;
231 
232         add32(imm, dest, dest);
233     }
234 
add32(TrustedImm32 imm,RegisterID src,RegisterID dest)235     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
236     {
237         if (!imm.m_value) {
238             move(src, dest);
239             return;
240         }
241 
242         if (isUInt12(imm.m_value))
243             m_assembler.add<32>(dest, src, UInt12(imm.m_value));
244         else if (isUInt12(-imm.m_value))
245             m_assembler.sub<32>(dest, src, UInt12(-imm.m_value));
246         else {
247             move(imm, getCachedDataTempRegisterIDAndInvalidate());
248             m_assembler.add<32>(dest, src, dataTempRegister);
249         }
250     }
251 
add32(TrustedImm32 imm,Address address)252     void add32(TrustedImm32 imm, Address address)
253     {
254         if (!imm.m_value)
255             return;
256 
257         load32(address, getCachedDataTempRegisterIDAndInvalidate());
258 
259         if (isUInt12(imm.m_value))
260             m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
261         else if (isUInt12(-imm.m_value))
262             m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
263         else {
264             move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
265             m_assembler.add<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
266         }
267 
268         store32(dataTempRegister, address);
269     }
270 
add32(TrustedImm32 imm,AbsoluteAddress address)271     void add32(TrustedImm32 imm, AbsoluteAddress address)
272     {
273         if (!imm.m_value)
274             return;
275 
276         load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
277 
278         if (isUInt12(imm.m_value)) {
279             m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
280             store32(dataTempRegister, address.m_ptr);
281             return;
282         }
283 
284         if (isUInt12(-imm.m_value)) {
285             m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
286             store32(dataTempRegister, address.m_ptr);
287             return;
288         }
289 
290         move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
291         m_assembler.add<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
292         store32(dataTempRegister, address.m_ptr);
293     }
294 
add32(Address src,RegisterID dest)295     void add32(Address src, RegisterID dest)
296     {
297         load32(src, getCachedDataTempRegisterIDAndInvalidate());
298         add32(dataTempRegister, dest);
299     }
300 
add64(RegisterID a,RegisterID b,RegisterID dest)301     void add64(RegisterID a, RegisterID b, RegisterID dest)
302     {
303         ASSERT(a != ARM64Registers::sp || b != ARM64Registers::sp);
304         if (b == ARM64Registers::sp)
305             std::swap(a, b);
306         m_assembler.add<64>(dest, a, b);
307     }
308 
add64(RegisterID src,RegisterID dest)309     void add64(RegisterID src, RegisterID dest)
310     {
311         if (src == ARM64Registers::sp)
312             m_assembler.add<64>(dest, src, dest);
313         else
314             m_assembler.add<64>(dest, dest, src);
315     }
316 
add64(TrustedImm32 imm,RegisterID dest)317     void add64(TrustedImm32 imm, RegisterID dest)
318     {
319         if (!imm.m_value)
320             return;
321 
322         if (isUInt12(imm.m_value)) {
323             m_assembler.add<64>(dest, dest, UInt12(imm.m_value));
324             return;
325         }
326         if (isUInt12(-imm.m_value)) {
327             m_assembler.sub<64>(dest, dest, UInt12(-imm.m_value));
328             return;
329         }
330 
331         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
332         m_assembler.add<64>(dest, dest, dataTempRegister);
333     }
334 
add64(TrustedImm64 imm,RegisterID dest)335     void add64(TrustedImm64 imm, RegisterID dest)
336     {
337         intptr_t immediate = imm.m_value;
338         if (!immediate)
339             return;
340 
341         if (isUInt12(immediate)) {
342             m_assembler.add<64>(dest, dest, UInt12(static_cast<int32_t>(immediate)));
343             return;
344         }
345         if (isUInt12(-immediate)) {
346             m_assembler.sub<64>(dest, dest, UInt12(static_cast<int32_t>(-immediate)));
347             return;
348         }
349 
350         move(imm, getCachedDataTempRegisterIDAndInvalidate());
351         m_assembler.add<64>(dest, dest, dataTempRegister);
352     }
353 
add64(TrustedImm32 imm,RegisterID src,RegisterID dest)354     void add64(TrustedImm32 imm, RegisterID src, RegisterID dest)
355     {
356         if (!imm.m_value) {
357             move(src, dest);
358             return;
359         }
360 
361         if (isUInt12(imm.m_value)) {
362             m_assembler.add<64>(dest, src, UInt12(imm.m_value));
363             return;
364         }
365         if (isUInt12(-imm.m_value)) {
366             m_assembler.sub<64>(dest, src, UInt12(-imm.m_value));
367             return;
368         }
369 
370         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
371         m_assembler.add<64>(dest, src, dataTempRegister);
372     }
373 
add64(TrustedImm32 imm,Address address)374     void add64(TrustedImm32 imm, Address address)
375     {
376         if (!imm.m_value)
377             return;
378 
379         load64(address, getCachedDataTempRegisterIDAndInvalidate());
380 
381         if (isUInt12(imm.m_value))
382             m_assembler.add<64>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
383         else if (isUInt12(-imm.m_value))
384             m_assembler.sub<64>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
385         else {
386             signExtend32ToPtr(imm, getCachedMemoryTempRegisterIDAndInvalidate());
387             m_assembler.add<64>(dataTempRegister, dataTempRegister, memoryTempRegister);
388         }
389 
390         store64(dataTempRegister, address);
391     }
392 
add64(TrustedImm32 imm,AbsoluteAddress address)393     void add64(TrustedImm32 imm, AbsoluteAddress address)
394     {
395         if (!imm.m_value)
396             return;
397 
398         load64(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
399 
400         if (isUInt12(imm.m_value)) {
401             m_assembler.add<64>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
402             store64(dataTempRegister, address.m_ptr);
403             return;
404         }
405 
406         if (isUInt12(-imm.m_value)) {
407             m_assembler.sub<64>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
408             store64(dataTempRegister, address.m_ptr);
409             return;
410         }
411 
412         signExtend32ToPtr(imm, getCachedMemoryTempRegisterIDAndInvalidate());
413         m_assembler.add<64>(dataTempRegister, dataTempRegister, memoryTempRegister);
414         store64(dataTempRegister, address.m_ptr);
415     }
416 
addPtrNoFlags(TrustedImm32 imm,RegisterID srcDest)417     void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
418     {
419         add64(imm, srcDest);
420     }
421 
add64(Address src,RegisterID dest)422     void add64(Address src, RegisterID dest)
423     {
424         load64(src, getCachedDataTempRegisterIDAndInvalidate());
425         m_assembler.add<64>(dest, dest, dataTempRegister);
426     }
427 
add64(AbsoluteAddress src,RegisterID dest)428     void add64(AbsoluteAddress src, RegisterID dest)
429     {
430         load64(src.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
431         m_assembler.add<64>(dest, dest, dataTempRegister);
432     }
433 
and32(RegisterID src,RegisterID dest)434     void and32(RegisterID src, RegisterID dest)
435     {
436         and32(dest, src, dest);
437     }
438 
and32(RegisterID op1,RegisterID op2,RegisterID dest)439     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
440     {
441         m_assembler.and_<32>(dest, op1, op2);
442     }
443 
and32(TrustedImm32 imm,RegisterID dest)444     void and32(TrustedImm32 imm, RegisterID dest)
445     {
446         and32(imm, dest, dest);
447     }
448 
and32(TrustedImm32 imm,RegisterID src,RegisterID dest)449     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
450     {
451         LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
452 
453         if (logicalImm.isValid()) {
454             m_assembler.and_<32>(dest, src, logicalImm);
455             return;
456         }
457 
458         move(imm, getCachedDataTempRegisterIDAndInvalidate());
459         m_assembler.and_<32>(dest, src, dataTempRegister);
460     }
461 
and32(Address src,RegisterID dest)462     void and32(Address src, RegisterID dest)
463     {
464         load32(src, dataTempRegister);
465         and32(dataTempRegister, dest);
466     }
467 
and64(RegisterID src,RegisterID dest)468     void and64(RegisterID src, RegisterID dest)
469     {
470         m_assembler.and_<64>(dest, dest, src);
471     }
472 
and64(TrustedImm32 imm,RegisterID dest)473     void and64(TrustedImm32 imm, RegisterID dest)
474     {
475         LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
476 
477         if (logicalImm.isValid()) {
478             m_assembler.and_<64>(dest, dest, logicalImm);
479             return;
480         }
481 
482         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
483         m_assembler.and_<64>(dest, dest, dataTempRegister);
484     }
485 
and64(TrustedImmPtr imm,RegisterID dest)486     void and64(TrustedImmPtr imm, RegisterID dest)
487     {
488         LogicalImmediate logicalImm = LogicalImmediate::create64(reinterpret_cast<uint64_t>(imm.m_value));
489 
490         if (logicalImm.isValid()) {
491             m_assembler.and_<64>(dest, dest, logicalImm);
492             return;
493         }
494 
495         move(imm, getCachedDataTempRegisterIDAndInvalidate());
496         m_assembler.and_<64>(dest, dest, dataTempRegister);
497     }
498 
countLeadingZeros32(RegisterID src,RegisterID dest)499     void countLeadingZeros32(RegisterID src, RegisterID dest)
500     {
501         m_assembler.clz<32>(dest, src);
502     }
503 
countLeadingZeros64(RegisterID src,RegisterID dest)504     void countLeadingZeros64(RegisterID src, RegisterID dest)
505     {
506         m_assembler.clz<64>(dest, src);
507     }
508 
lshift32(RegisterID src,RegisterID shiftAmount,RegisterID dest)509     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
510     {
511         m_assembler.lsl<32>(dest, src, shiftAmount);
512     }
513 
lshift32(RegisterID src,TrustedImm32 imm,RegisterID dest)514     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
515     {
516         m_assembler.lsl<32>(dest, src, imm.m_value & 0x1f);
517     }
518 
lshift32(RegisterID shiftAmount,RegisterID dest)519     void lshift32(RegisterID shiftAmount, RegisterID dest)
520     {
521         lshift32(dest, shiftAmount, dest);
522     }
523 
lshift32(TrustedImm32 imm,RegisterID dest)524     void lshift32(TrustedImm32 imm, RegisterID dest)
525     {
526         lshift32(dest, imm, dest);
527     }
528 
lshift64(RegisterID src,RegisterID shiftAmount,RegisterID dest)529     void lshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest)
530     {
531         m_assembler.lsl<64>(dest, src, shiftAmount);
532     }
533 
lshift64(RegisterID src,TrustedImm32 imm,RegisterID dest)534     void lshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
535     {
536         m_assembler.lsl<64>(dest, src, imm.m_value & 0x3f);
537     }
538 
lshift64(RegisterID shiftAmount,RegisterID dest)539     void lshift64(RegisterID shiftAmount, RegisterID dest)
540     {
541         lshift64(dest, shiftAmount, dest);
542     }
543 
lshift64(TrustedImm32 imm,RegisterID dest)544     void lshift64(TrustedImm32 imm, RegisterID dest)
545     {
546         lshift64(dest, imm, dest);
547     }
548 
mul32(RegisterID left,RegisterID right,RegisterID dest)549     void mul32(RegisterID left, RegisterID right, RegisterID dest)
550     {
551         m_assembler.mul<32>(dest, left, right);
552     }
553 
mul32(RegisterID src,RegisterID dest)554     void mul32(RegisterID src, RegisterID dest)
555     {
556         m_assembler.mul<32>(dest, dest, src);
557     }
558 
mul32(TrustedImm32 imm,RegisterID src,RegisterID dest)559     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
560     {
561         move(imm, getCachedDataTempRegisterIDAndInvalidate());
562         m_assembler.mul<32>(dest, src, dataTempRegister);
563     }
564 
mul32(Address src,RegisterID dest)565     void mul32(Address src, RegisterID dest)
566     {
567         load32(src, dataTempRegister);
568         mul32(dataTempRegister, dest);
569     }
570 
mul64(RegisterID src,RegisterID dest)571     void mul64(RegisterID src, RegisterID dest)
572     {
573         m_assembler.mul<64>(dest, dest, src);
574     }
575 
mul64(RegisterID left,RegisterID right,RegisterID dest)576     void mul64(RegisterID left, RegisterID right, RegisterID dest)
577     {
578         m_assembler.mul<64>(dest, left, right);
579     }
580 
div32(RegisterID dividend,RegisterID divisor,RegisterID dest)581     void div32(RegisterID dividend, RegisterID divisor, RegisterID dest)
582     {
583         m_assembler.sdiv<32>(dest, dividend, divisor);
584     }
585 
div64(RegisterID dividend,RegisterID divisor,RegisterID dest)586     void div64(RegisterID dividend, RegisterID divisor, RegisterID dest)
587     {
588         m_assembler.sdiv<64>(dest, dividend, divisor);
589     }
590 
neg32(RegisterID dest)591     void neg32(RegisterID dest)
592     {
593         m_assembler.neg<32>(dest, dest);
594     }
595 
neg64(RegisterID dest)596     void neg64(RegisterID dest)
597     {
598         m_assembler.neg<64>(dest, dest);
599     }
600 
or32(RegisterID src,RegisterID dest)601     void or32(RegisterID src, RegisterID dest)
602     {
603         or32(dest, src, dest);
604     }
605 
or32(Address src,RegisterID dest)606     void or32(Address src, RegisterID dest)
607     {
608         load32(src, dataTempRegister);
609         or32(dataTempRegister, dest);
610     }
611 
or32(RegisterID op1,RegisterID op2,RegisterID dest)612     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
613     {
614         m_assembler.orr<32>(dest, op1, op2);
615     }
616 
or32(TrustedImm32 imm,RegisterID dest)617     void or32(TrustedImm32 imm, RegisterID dest)
618     {
619         or32(imm, dest, dest);
620     }
621 
or32(TrustedImm32 imm,RegisterID src,RegisterID dest)622     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
623     {
624         LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
625 
626         if (logicalImm.isValid()) {
627             m_assembler.orr<32>(dest, src, logicalImm);
628             return;
629         }
630 
631         ASSERT(src != dataTempRegister);
632         move(imm, getCachedDataTempRegisterIDAndInvalidate());
633         m_assembler.orr<32>(dest, src, dataTempRegister);
634     }
635 
or32(RegisterID src,AbsoluteAddress address)636     void or32(RegisterID src, AbsoluteAddress address)
637     {
638         load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
639         m_assembler.orr<32>(dataTempRegister, dataTempRegister, src);
640         store32(dataTempRegister, address.m_ptr);
641     }
642 
or32(TrustedImm32 imm,AbsoluteAddress address)643     void or32(TrustedImm32 imm, AbsoluteAddress address)
644     {
645         LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
646         if (logicalImm.isValid()) {
647             load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
648             m_assembler.orr<32>(dataTempRegister, dataTempRegister, logicalImm);
649             store32(dataTempRegister, address.m_ptr);
650         } else {
651             load32(address.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
652             or32(imm, memoryTempRegister, getCachedDataTempRegisterIDAndInvalidate());
653             store32(dataTempRegister, address.m_ptr);
654         }
655     }
656 
or32(TrustedImm32 imm,Address address)657     void or32(TrustedImm32 imm, Address address)
658     {
659         load32(address, getCachedDataTempRegisterIDAndInvalidate());
660         or32(imm, dataTempRegister, dataTempRegister);
661         store32(dataTempRegister, address);
662     }
663 
or64(RegisterID src,RegisterID dest)664     void or64(RegisterID src, RegisterID dest)
665     {
666         or64(dest, src, dest);
667     }
668 
or64(RegisterID op1,RegisterID op2,RegisterID dest)669     void or64(RegisterID op1, RegisterID op2, RegisterID dest)
670     {
671         m_assembler.orr<64>(dest, op1, op2);
672     }
673 
or64(TrustedImm32 imm,RegisterID dest)674     void or64(TrustedImm32 imm, RegisterID dest)
675     {
676         or64(imm, dest, dest);
677     }
678 
or64(TrustedImm32 imm,RegisterID src,RegisterID dest)679     void or64(TrustedImm32 imm, RegisterID src, RegisterID dest)
680     {
681         LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
682 
683         if (logicalImm.isValid()) {
684             m_assembler.orr<64>(dest, src, logicalImm);
685             return;
686         }
687 
688         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
689         m_assembler.orr<64>(dest, src, dataTempRegister);
690     }
691 
or64(TrustedImm64 imm,RegisterID dest)692     void or64(TrustedImm64 imm, RegisterID dest)
693     {
694         or64(imm, dest, dest);
695     }
696 
or64(TrustedImm64 imm,RegisterID src,RegisterID dest)697     void or64(TrustedImm64 imm, RegisterID src, RegisterID dest)
698     {
699         LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
700 
701         if (logicalImm.isValid()) {
702             m_assembler.orr<64>(dest, src, logicalImm);
703             return;
704         }
705 
706         move(imm, getCachedDataTempRegisterIDAndInvalidate());
707         m_assembler.orr<64>(dest, src, dataTempRegister);
708     }
709 
rotateRight64(TrustedImm32 imm,RegisterID srcDst)710     void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
711     {
712         m_assembler.ror<64>(srcDst, srcDst, imm.m_value & 63);
713     }
714 
rshift32(RegisterID src,RegisterID shiftAmount,RegisterID dest)715     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
716     {
717         m_assembler.asr<32>(dest, src, shiftAmount);
718     }
719 
rshift32(RegisterID src,TrustedImm32 imm,RegisterID dest)720     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
721     {
722         m_assembler.asr<32>(dest, src, imm.m_value & 0x1f);
723     }
724 
rshift32(RegisterID shiftAmount,RegisterID dest)725     void rshift32(RegisterID shiftAmount, RegisterID dest)
726     {
727         rshift32(dest, shiftAmount, dest);
728     }
729 
rshift32(TrustedImm32 imm,RegisterID dest)730     void rshift32(TrustedImm32 imm, RegisterID dest)
731     {
732         rshift32(dest, imm, dest);
733     }
734 
rshift64(RegisterID src,RegisterID shiftAmount,RegisterID dest)735     void rshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest)
736     {
737         m_assembler.asr<64>(dest, src, shiftAmount);
738     }
739 
rshift64(RegisterID src,TrustedImm32 imm,RegisterID dest)740     void rshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
741     {
742         m_assembler.asr<64>(dest, src, imm.m_value & 0x3f);
743     }
744 
rshift64(RegisterID shiftAmount,RegisterID dest)745     void rshift64(RegisterID shiftAmount, RegisterID dest)
746     {
747         rshift64(dest, shiftAmount, dest);
748     }
749 
rshift64(TrustedImm32 imm,RegisterID dest)750     void rshift64(TrustedImm32 imm, RegisterID dest)
751     {
752         rshift64(dest, imm, dest);
753     }
754 
sub32(RegisterID src,RegisterID dest)755     void sub32(RegisterID src, RegisterID dest)
756     {
757         m_assembler.sub<32>(dest, dest, src);
758     }
759 
sub32(TrustedImm32 imm,RegisterID dest)760     void sub32(TrustedImm32 imm, RegisterID dest)
761     {
762         if (isUInt12(imm.m_value)) {
763             m_assembler.sub<32>(dest, dest, UInt12(imm.m_value));
764             return;
765         }
766         if (isUInt12(-imm.m_value)) {
767             m_assembler.add<32>(dest, dest, UInt12(-imm.m_value));
768             return;
769         }
770 
771         move(imm, getCachedDataTempRegisterIDAndInvalidate());
772         m_assembler.sub<32>(dest, dest, dataTempRegister);
773     }
774 
sub32(TrustedImm32 imm,Address address)775     void sub32(TrustedImm32 imm, Address address)
776     {
777         load32(address, getCachedDataTempRegisterIDAndInvalidate());
778 
779         if (isUInt12(imm.m_value))
780             m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
781         else if (isUInt12(-imm.m_value))
782             m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
783         else {
784             move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
785             m_assembler.sub<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
786         }
787 
788         store32(dataTempRegister, address);
789     }
790 
sub32(TrustedImm32 imm,AbsoluteAddress address)791     void sub32(TrustedImm32 imm, AbsoluteAddress address)
792     {
793         load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
794 
795         if (isUInt12(imm.m_value)) {
796             m_assembler.sub<32>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
797             store32(dataTempRegister, address.m_ptr);
798             return;
799         }
800 
801         if (isUInt12(-imm.m_value)) {
802             m_assembler.add<32>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
803             store32(dataTempRegister, address.m_ptr);
804             return;
805         }
806 
807         move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
808         m_assembler.sub<32>(dataTempRegister, dataTempRegister, memoryTempRegister);
809         store32(dataTempRegister, address.m_ptr);
810     }
811 
sub32(Address src,RegisterID dest)812     void sub32(Address src, RegisterID dest)
813     {
814         load32(src, getCachedDataTempRegisterIDAndInvalidate());
815         sub32(dataTempRegister, dest);
816     }
817 
sub64(RegisterID src,RegisterID dest)818     void sub64(RegisterID src, RegisterID dest)
819     {
820         m_assembler.sub<64>(dest, dest, src);
821     }
822 
sub64(TrustedImm32 imm,RegisterID dest)823     void sub64(TrustedImm32 imm, RegisterID dest)
824     {
825         if (isUInt12(imm.m_value)) {
826             m_assembler.sub<64>(dest, dest, UInt12(imm.m_value));
827             return;
828         }
829         if (isUInt12(-imm.m_value)) {
830             m_assembler.add<64>(dest, dest, UInt12(-imm.m_value));
831             return;
832         }
833 
834         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
835         m_assembler.sub<64>(dest, dest, dataTempRegister);
836     }
837 
sub64(TrustedImm64 imm,RegisterID dest)838     void sub64(TrustedImm64 imm, RegisterID dest)
839     {
840         intptr_t immediate = imm.m_value;
841 
842         if (isUInt12(immediate)) {
843             m_assembler.sub<64>(dest, dest, UInt12(static_cast<int32_t>(immediate)));
844             return;
845         }
846         if (isUInt12(-immediate)) {
847             m_assembler.add<64>(dest, dest, UInt12(static_cast<int32_t>(-immediate)));
848             return;
849         }
850 
851         move(imm, getCachedDataTempRegisterIDAndInvalidate());
852         m_assembler.sub<64>(dest, dest, dataTempRegister);
853     }
854 
urshift32(RegisterID src,RegisterID shiftAmount,RegisterID dest)855     void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
856     {
857         m_assembler.lsr<32>(dest, src, shiftAmount);
858     }
859 
urshift32(RegisterID src,TrustedImm32 imm,RegisterID dest)860     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
861     {
862         m_assembler.lsr<32>(dest, src, imm.m_value & 0x1f);
863     }
864 
urshift32(RegisterID shiftAmount,RegisterID dest)865     void urshift32(RegisterID shiftAmount, RegisterID dest)
866     {
867         urshift32(dest, shiftAmount, dest);
868     }
869 
urshift32(TrustedImm32 imm,RegisterID dest)870     void urshift32(TrustedImm32 imm, RegisterID dest)
871     {
872         urshift32(dest, imm, dest);
873     }
874 
urshift64(RegisterID src,RegisterID shiftAmount,RegisterID dest)875     void urshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest)
876     {
877         m_assembler.lsr<64>(dest, src, shiftAmount);
878     }
879 
urshift64(RegisterID src,TrustedImm32 imm,RegisterID dest)880     void urshift64(RegisterID src, TrustedImm32 imm, RegisterID dest)
881     {
882         m_assembler.lsr<64>(dest, src, imm.m_value & 0x3f);
883     }
884 
urshift64(RegisterID shiftAmount,RegisterID dest)885     void urshift64(RegisterID shiftAmount, RegisterID dest)
886     {
887         urshift64(dest, shiftAmount, dest);
888     }
889 
urshift64(TrustedImm32 imm,RegisterID dest)890     void urshift64(TrustedImm32 imm, RegisterID dest)
891     {
892         urshift64(dest, imm, dest);
893     }
894 
xor32(Address src,RegisterID dest)895     void xor32(Address src, RegisterID dest)
896     {
897         load32(src, dataTempRegister);
898         xor32(dataTempRegister, dest);
899     }
900 
xor32(RegisterID src,RegisterID dest)901     void xor32(RegisterID src, RegisterID dest)
902     {
903         xor32(dest, src, dest);
904     }
905 
xor32(RegisterID op1,RegisterID op2,RegisterID dest)906     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
907     {
908         m_assembler.eor<32>(dest, op1, op2);
909     }
910 
xor32(TrustedImm32 imm,RegisterID dest)911     void xor32(TrustedImm32 imm, RegisterID dest)
912     {
913         xor32(imm, dest, dest);
914     }
915 
xor32(TrustedImm32 imm,RegisterID src,RegisterID dest)916     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
917     {
918         if (imm.m_value == -1)
919             m_assembler.mvn<32>(dest, src);
920         else {
921             LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value);
922 
923             if (logicalImm.isValid()) {
924                 m_assembler.eor<32>(dest, src, logicalImm);
925                 return;
926             }
927 
928             move(imm, getCachedDataTempRegisterIDAndInvalidate());
929             m_assembler.eor<32>(dest, src, dataTempRegister);
930         }
931     }
932 
xor64(RegisterID src,Address address)933     void xor64(RegisterID src, Address address)
934     {
935         load64(address, getCachedDataTempRegisterIDAndInvalidate());
936         m_assembler.eor<64>(dataTempRegister, dataTempRegister, src);
937         store64(dataTempRegister, address);
938     }
939 
xor64(RegisterID src,RegisterID dest)940     void xor64(RegisterID src, RegisterID dest)
941     {
942         xor64(dest, src, dest);
943     }
944 
xor64(RegisterID op1,RegisterID op2,RegisterID dest)945     void xor64(RegisterID op1, RegisterID op2, RegisterID dest)
946     {
947         m_assembler.eor<64>(dest, op1, op2);
948     }
949 
xor64(TrustedImm32 imm,RegisterID dest)950     void xor64(TrustedImm32 imm, RegisterID dest)
951     {
952         xor64(imm, dest, dest);
953     }
954 
xor64(TrustedImm32 imm,RegisterID src,RegisterID dest)955     void xor64(TrustedImm32 imm, RegisterID src, RegisterID dest)
956     {
957         if (imm.m_value == -1)
958             m_assembler.mvn<64>(dest, src);
959         else {
960             LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast<intptr_t>(static_cast<int64_t>(imm.m_value)));
961 
962             if (logicalImm.isValid()) {
963                 m_assembler.eor<64>(dest, src, logicalImm);
964                 return;
965             }
966 
967             signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
968             m_assembler.eor<64>(dest, src, dataTempRegister);
969         }
970     }
971 
not32(RegisterID src,RegisterID dest)972     void not32(RegisterID src, RegisterID dest)
973     {
974         m_assembler.mvn<32>(dest, src);
975     }
976 
not64(RegisterID src,RegisterID dest)977     void not64(RegisterID src, RegisterID dest)
978     {
979         m_assembler.mvn<64>(dest, src);
980     }
981 
982     // Memory access operations:
983 
load64(ImplicitAddress address,RegisterID dest)984     void load64(ImplicitAddress address, RegisterID dest)
985     {
986         if (tryLoadWithOffset<64>(dest, address.base, address.offset))
987             return;
988 
989         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
990         m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
991     }
992 
load64(BaseIndex address,RegisterID dest)993     void load64(BaseIndex address, RegisterID dest)
994     {
995         if (!address.offset && (!address.scale || address.scale == 3)) {
996             m_assembler.ldr<64>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
997             return;
998         }
999 
1000         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1001         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1002         m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
1003     }
1004 
load64(const void * address,RegisterID dest)1005     void load64(const void* address, RegisterID dest)
1006     {
1007         load<64>(address, dest);
1008     }
1009 
load64WithAddressOffsetPatch(Address address,RegisterID dest)1010     DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID dest)
1011     {
1012         DataLabel32 label(this);
1013         signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
1014         m_assembler.ldr<64>(dest, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
1015         return label;
1016     }
1017 
load64WithCompactAddressOffsetPatch(Address address,RegisterID dest)1018     DataLabelCompact load64WithCompactAddressOffsetPatch(Address address, RegisterID dest)
1019     {
1020         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
1021         DataLabelCompact label(this);
1022         m_assembler.ldr<64>(dest, address.base, address.offset);
1023         return label;
1024     }
1025 
convertibleLoadPtr(Address address,RegisterID dest)1026     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
1027     {
1028         ConvertibleLoadLabel result(this);
1029         ASSERT(!(address.offset & ~0xff8));
1030         m_assembler.ldr<64>(dest, address.base, address.offset);
1031         return result;
1032     }
1033 
load32(ImplicitAddress address,RegisterID dest)1034     void load32(ImplicitAddress address, RegisterID dest)
1035     {
1036         if (tryLoadWithOffset<32>(dest, address.base, address.offset))
1037             return;
1038 
1039         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1040         m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
1041     }
1042 
load32(BaseIndex address,RegisterID dest)1043     void load32(BaseIndex address, RegisterID dest)
1044     {
1045         if (!address.offset && (!address.scale || address.scale == 2)) {
1046             m_assembler.ldr<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1047             return;
1048         }
1049 
1050         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1051         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1052         m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
1053     }
1054 
load32(const void * address,RegisterID dest)1055     void load32(const void* address, RegisterID dest)
1056     {
1057         load<32>(address, dest);
1058     }
1059 
load32WithAddressOffsetPatch(Address address,RegisterID dest)1060     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
1061     {
1062         DataLabel32 label(this);
1063         signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
1064         m_assembler.ldr<32>(dest, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
1065         return label;
1066     }
1067 
load32WithCompactAddressOffsetPatch(Address address,RegisterID dest)1068     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
1069     {
1070         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
1071         DataLabelCompact label(this);
1072         m_assembler.ldr<32>(dest, address.base, address.offset);
1073         return label;
1074     }
1075 
load32WithUnalignedHalfWords(BaseIndex address,RegisterID dest)1076     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
1077     {
1078         load32(address, dest);
1079     }
1080 
load16(ImplicitAddress address,RegisterID dest)1081     void load16(ImplicitAddress address, RegisterID dest)
1082     {
1083         if (tryLoadWithOffset<16>(dest, address.base, address.offset))
1084             return;
1085 
1086         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1087         m_assembler.ldrh(dest, address.base, memoryTempRegister);
1088     }
1089 
load16(BaseIndex address,RegisterID dest)1090     void load16(BaseIndex address, RegisterID dest)
1091     {
1092         if (!address.offset && (!address.scale || address.scale == 1)) {
1093             m_assembler.ldrh(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1094             return;
1095         }
1096 
1097         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1098         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1099         m_assembler.ldrh(dest, address.base, memoryTempRegister);
1100     }
1101 
load16(ExtendedAddress address,RegisterID dest)1102     void load16(ExtendedAddress address, RegisterID dest)
1103     {
1104         moveToCachedReg(TrustedImmPtr(reinterpret_cast<void*>(address.offset)), m_cachedMemoryTempRegister);
1105         m_assembler.ldrh(dest, memoryTempRegister, address.base, ARM64Assembler::UXTX, 1);
1106         if (dest == memoryTempRegister)
1107             m_cachedMemoryTempRegister.invalidate();
1108     }
1109 
load16Unaligned(ImplicitAddress address,RegisterID dest)1110     void load16Unaligned(ImplicitAddress address, RegisterID dest)
1111     {
1112         load16(address, dest);
1113     }
1114 
load16Unaligned(BaseIndex address,RegisterID dest)1115     void load16Unaligned(BaseIndex address, RegisterID dest)
1116     {
1117         load16(address, dest);
1118     }
1119 
load16SignedExtendTo32(ImplicitAddress address,RegisterID dest)1120     void load16SignedExtendTo32(ImplicitAddress address, RegisterID dest)
1121     {
1122         if (tryLoadSignedWithOffset<16>(dest, address.base, address.offset))
1123             return;
1124 
1125         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1126         m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister);
1127     }
1128 
load16SignedExtendTo32(BaseIndex address,RegisterID dest)1129     void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
1130     {
1131         if (!address.offset && (!address.scale || address.scale == 1)) {
1132             m_assembler.ldrsh<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1133             return;
1134         }
1135 
1136         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1137         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1138         m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister);
1139     }
1140 
zeroExtend16To32(RegisterID src,RegisterID dest)1141     void zeroExtend16To32(RegisterID src, RegisterID dest)
1142     {
1143         m_assembler.uxth<64>(dest, src);
1144     }
1145 
signExtend16To32(RegisterID src,RegisterID dest)1146     void signExtend16To32(RegisterID src, RegisterID dest)
1147     {
1148         m_assembler.sxth<64>(dest, src);
1149     }
1150 
load8(ImplicitAddress address,RegisterID dest)1151     void load8(ImplicitAddress address, RegisterID dest)
1152     {
1153         if (tryLoadWithOffset<8>(dest, address.base, address.offset))
1154             return;
1155 
1156         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1157         m_assembler.ldrb(dest, address.base, memoryTempRegister);
1158     }
1159 
load8(BaseIndex address,RegisterID dest)1160     void load8(BaseIndex address, RegisterID dest)
1161     {
1162         if (!address.offset && !address.scale) {
1163             m_assembler.ldrb(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1164             return;
1165         }
1166 
1167         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1168         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1169         m_assembler.ldrb(dest, address.base, memoryTempRegister);
1170     }
1171 
load8(const void * address,RegisterID dest)1172     void load8(const void* address, RegisterID dest)
1173     {
1174         moveToCachedReg(TrustedImmPtr(address), m_cachedMemoryTempRegister);
1175         m_assembler.ldrb(dest, memoryTempRegister, ARM64Registers::zr);
1176         if (dest == memoryTempRegister)
1177             m_cachedMemoryTempRegister.invalidate();
1178     }
1179 
load8SignedExtendTo32(ImplicitAddress address,RegisterID dest)1180     void load8SignedExtendTo32(ImplicitAddress address, RegisterID dest)
1181     {
1182         if (tryLoadSignedWithOffset<8>(dest, address.base, address.offset))
1183             return;
1184 
1185         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1186         m_assembler.ldrsb<32>(dest, address.base, memoryTempRegister);
1187     }
1188 
load8SignedExtendTo32(BaseIndex address,RegisterID dest)1189     void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
1190     {
1191         if (!address.offset && !address.scale) {
1192             m_assembler.ldrsb<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1193             return;
1194         }
1195 
1196         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1197         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1198         m_assembler.ldrsb<32>(dest, address.base, memoryTempRegister);
1199     }
1200 
zeroExtend8To32(RegisterID src,RegisterID dest)1201     void zeroExtend8To32(RegisterID src, RegisterID dest)
1202     {
1203         m_assembler.uxtb<64>(dest, src);
1204     }
1205 
signExtend8To32(RegisterID src,RegisterID dest)1206     void signExtend8To32(RegisterID src, RegisterID dest)
1207     {
1208         m_assembler.sxtb<64>(dest, src);
1209     }
1210 
store64(RegisterID src,ImplicitAddress address)1211     void store64(RegisterID src, ImplicitAddress address)
1212     {
1213         if (tryStoreWithOffset<64>(src, address.base, address.offset))
1214             return;
1215 
1216         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1217         m_assembler.str<64>(src, address.base, memoryTempRegister);
1218     }
1219 
store64(RegisterID src,BaseIndex address)1220     void store64(RegisterID src, BaseIndex address)
1221     {
1222         if (!address.offset && (!address.scale || address.scale == 3)) {
1223             m_assembler.str<64>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1224             return;
1225         }
1226 
1227         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1228         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1229         m_assembler.str<64>(src, address.base, memoryTempRegister);
1230     }
1231 
store64(RegisterID src,const void * address)1232     void store64(RegisterID src, const void* address)
1233     {
1234         store<64>(src, address);
1235     }
1236 
store64(TrustedImm32 imm,ImplicitAddress address)1237     void store64(TrustedImm32 imm, ImplicitAddress address)
1238     {
1239         store64(TrustedImm64(imm.m_value), address);
1240     }
1241 
store64(TrustedImm64 imm,ImplicitAddress address)1242     void store64(TrustedImm64 imm, ImplicitAddress address)
1243     {
1244         if (!imm.m_value) {
1245             store64(ARM64Registers::zr, address);
1246             return;
1247         }
1248 
1249         moveToCachedReg(imm, m_dataMemoryTempRegister);
1250         store64(dataTempRegister, address);
1251     }
1252 
store64(TrustedImm64 imm,BaseIndex address)1253     void store64(TrustedImm64 imm, BaseIndex address)
1254     {
1255         if (!imm.m_value) {
1256             store64(ARM64Registers::zr, address);
1257             return;
1258         }
1259 
1260         moveToCachedReg(imm, m_dataMemoryTempRegister);
1261         store64(dataTempRegister, address);
1262     }
1263 
store64WithAddressOffsetPatch(RegisterID src,Address address)1264     DataLabel32 store64WithAddressOffsetPatch(RegisterID src, Address address)
1265     {
1266         DataLabel32 label(this);
1267         signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
1268         m_assembler.str<64>(src, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
1269         return label;
1270     }
1271 
storePair64(RegisterID src1,RegisterID src2,RegisterID dest)1272     void storePair64(RegisterID src1, RegisterID src2, RegisterID dest)
1273     {
1274         storePair64(src1, src2, dest, TrustedImm32(0));
1275     }
1276 
storePair64(RegisterID src1,RegisterID src2,RegisterID dest,TrustedImm32 offset)1277     void storePair64(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
1278     {
1279         m_assembler.stp<64>(src1, src2, dest, offset.m_value);
1280     }
1281 
store32(RegisterID src,ImplicitAddress address)1282     void store32(RegisterID src, ImplicitAddress address)
1283     {
1284         if (tryStoreWithOffset<32>(src, address.base, address.offset))
1285             return;
1286 
1287         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1288         m_assembler.str<32>(src, address.base, memoryTempRegister);
1289     }
1290 
store32(RegisterID src,BaseIndex address)1291     void store32(RegisterID src, BaseIndex address)
1292     {
1293         if (!address.offset && (!address.scale || address.scale == 2)) {
1294             m_assembler.str<32>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1295             return;
1296         }
1297 
1298         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1299         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1300         m_assembler.str<32>(src, address.base, memoryTempRegister);
1301     }
1302 
store32(RegisterID src,const void * address)1303     void store32(RegisterID src, const void* address)
1304     {
1305         store<32>(src, address);
1306     }
1307 
store32(TrustedImm32 imm,ImplicitAddress address)1308     void store32(TrustedImm32 imm, ImplicitAddress address)
1309     {
1310         if (!imm.m_value) {
1311             store32(ARM64Registers::zr, address);
1312             return;
1313         }
1314 
1315         moveToCachedReg(imm, m_dataMemoryTempRegister);
1316         store32(dataTempRegister, address);
1317     }
1318 
store32(TrustedImm32 imm,BaseIndex address)1319     void store32(TrustedImm32 imm, BaseIndex address)
1320     {
1321         if (!imm.m_value) {
1322             store32(ARM64Registers::zr, address);
1323             return;
1324         }
1325 
1326         moveToCachedReg(imm, m_dataMemoryTempRegister);
1327         store32(dataTempRegister, address);
1328     }
1329 
store32(TrustedImm32 imm,const void * address)1330     void store32(TrustedImm32 imm, const void* address)
1331     {
1332         if (!imm.m_value) {
1333             store32(ARM64Registers::zr, address);
1334             return;
1335         }
1336 
1337         moveToCachedReg(imm, m_dataMemoryTempRegister);
1338         store32(dataTempRegister, address);
1339     }
1340 
store32WithAddressOffsetPatch(RegisterID src,Address address)1341     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
1342     {
1343         DataLabel32 label(this);
1344         signExtend32ToPtrWithFixedWidth(address.offset, getCachedMemoryTempRegisterIDAndInvalidate());
1345         m_assembler.str<32>(src, address.base, memoryTempRegister, ARM64Assembler::SXTW, 0);
1346         return label;
1347     }
1348 
store16(RegisterID src,ImplicitAddress address)1349     void store16(RegisterID src, ImplicitAddress address)
1350     {
1351         if (tryStoreWithOffset<16>(src, address.base, address.offset))
1352             return;
1353 
1354         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1355         m_assembler.str<16>(src, address.base, memoryTempRegister);
1356     }
1357 
store16(RegisterID src,BaseIndex address)1358     void store16(RegisterID src, BaseIndex address)
1359     {
1360         if (!address.offset && (!address.scale || address.scale == 1)) {
1361             m_assembler.strh(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1362             return;
1363         }
1364 
1365         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1366         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1367         m_assembler.strh(src, address.base, memoryTempRegister);
1368     }
1369 
store8(RegisterID src,BaseIndex address)1370     void store8(RegisterID src, BaseIndex address)
1371     {
1372         if (!address.offset && !address.scale) {
1373             m_assembler.strb(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1374             return;
1375         }
1376 
1377         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1378         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1379         m_assembler.strb(src, address.base, memoryTempRegister);
1380     }
1381 
store8(RegisterID src,void * address)1382     void store8(RegisterID src, void* address)
1383     {
1384         move(TrustedImmPtr(address), getCachedMemoryTempRegisterIDAndInvalidate());
1385         m_assembler.strb(src, memoryTempRegister, 0);
1386     }
1387 
store8(RegisterID src,ImplicitAddress address)1388     void store8(RegisterID src, ImplicitAddress address)
1389     {
1390         if (tryStoreWithOffset<8>(src, address.base, address.offset))
1391             return;
1392 
1393         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1394         m_assembler.str<8>(src, address.base, memoryTempRegister);
1395     }
1396 
store8(TrustedImm32 imm,void * address)1397     void store8(TrustedImm32 imm, void* address)
1398     {
1399         if (!imm.m_value) {
1400             store8(ARM64Registers::zr, address);
1401             return;
1402         }
1403 
1404         move(imm, getCachedDataTempRegisterIDAndInvalidate());
1405         store8(dataTempRegister, address);
1406     }
1407 
store8(TrustedImm32 imm,ImplicitAddress address)1408     void store8(TrustedImm32 imm, ImplicitAddress address)
1409     {
1410         if (!imm.m_value) {
1411             store8(ARM64Registers::zr, address);
1412             return;
1413         }
1414 
1415         move(imm, getCachedDataTempRegisterIDAndInvalidate());
1416         store8(dataTempRegister, address);
1417     }
1418 
getEffectiveAddress(BaseIndex address,RegisterID dest)1419     void getEffectiveAddress(BaseIndex address, RegisterID dest)
1420     {
1421         m_assembler.add<64>(dest, address.base, address.index, ARM64Assembler::LSL, address.scale);
1422         if (address.offset)
1423             add64(TrustedImm32(address.offset), dest);
1424     }
1425 
1426 
1427     // Floating-point operations:
1428 
supportsFloatingPoint()1429     static bool supportsFloatingPoint() { return true; }
supportsFloatingPointTruncate()1430     static bool supportsFloatingPointTruncate() { return true; }
supportsFloatingPointSqrt()1431     static bool supportsFloatingPointSqrt() { return true; }
supportsFloatingPointAbs()1432     static bool supportsFloatingPointAbs() { return true; }
supportsFloatingPointCeil()1433     static bool supportsFloatingPointCeil() { return true; }
1434 
1435     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1436 
absDouble(FPRegisterID src,FPRegisterID dest)1437     void absDouble(FPRegisterID src, FPRegisterID dest)
1438     {
1439         m_assembler.fabs<64>(dest, src);
1440     }
1441 
absFloat(FPRegisterID src,FPRegisterID dest)1442     void absFloat(FPRegisterID src, FPRegisterID dest)
1443     {
1444         m_assembler.fabs<32>(dest, src);
1445     }
1446 
addDouble(FPRegisterID src,FPRegisterID dest)1447     void addDouble(FPRegisterID src, FPRegisterID dest)
1448     {
1449         addDouble(dest, src, dest);
1450     }
1451 
addDouble(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1452     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1453     {
1454         m_assembler.fadd<64>(dest, op1, op2);
1455     }
1456 
addDouble(Address src,FPRegisterID dest)1457     void addDouble(Address src, FPRegisterID dest)
1458     {
1459         loadDouble(src, fpTempRegister);
1460         addDouble(fpTempRegister, dest);
1461     }
1462 
addDouble(AbsoluteAddress address,FPRegisterID dest)1463     void addDouble(AbsoluteAddress address, FPRegisterID dest)
1464     {
1465         loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister);
1466         addDouble(fpTempRegister, dest);
1467     }
1468 
addFloat(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1469     void addFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1470     {
1471         m_assembler.fadd<32>(dest, op1, op2);
1472     }
1473 
ceilDouble(FPRegisterID src,FPRegisterID dest)1474     void ceilDouble(FPRegisterID src, FPRegisterID dest)
1475     {
1476         m_assembler.frintp<64>(dest, src);
1477     }
1478 
ceilFloat(FPRegisterID src,FPRegisterID dest)1479     void ceilFloat(FPRegisterID src, FPRegisterID dest)
1480     {
1481         m_assembler.frintp<32>(dest, src);
1482     }
1483 
floorDouble(FPRegisterID src,FPRegisterID dest)1484     void floorDouble(FPRegisterID src, FPRegisterID dest)
1485     {
1486         m_assembler.frintm<64>(dest, src);
1487     }
1488 
1489     // Convert 'src' to an integer, and places the resulting 'dest'.
1490     // If the result is not representable as a 32 bit value, branch.
1491     // May also branch for some values that are representable in 32 bits
1492     // (specifically, in this case, 0).
1493     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1494     {
1495         m_assembler.fcvtns<32, 64>(dest, src);
1496 
1497         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1498         m_assembler.scvtf<64, 32>(fpTempRegister, dest);
1499         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1500 
1501         // Test for negative zero.
1502         if (negZeroCheck) {
1503             Jump valueIsNonZero = branchTest32(NonZero, dest);
1504             RegisterID scratch = getCachedMemoryTempRegisterIDAndInvalidate();
1505             m_assembler.fmov<64>(scratch, src);
1506             failureCases.append(makeTestBitAndBranch(scratch, 63, IsNonZero));
1507             valueIsNonZero.link(this);
1508         }
1509     }
1510 
branchDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right)1511     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1512     {
1513         m_assembler.fcmp<64>(left, right);
1514         return jumpAfterFloatingPointCompare(cond);
1515     }
1516 
branchFloat(DoubleCondition cond,FPRegisterID left,FPRegisterID right)1517     Jump branchFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1518     {
1519         m_assembler.fcmp<32>(left, right);
1520         return jumpAfterFloatingPointCompare(cond);
1521     }
1522 
branchDoubleNonZero(FPRegisterID reg,FPRegisterID)1523     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1524     {
1525         m_assembler.fcmp_0<64>(reg);
1526         Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
1527         Jump result = makeBranch(ARM64Assembler::ConditionNE);
1528         unordered.link(this);
1529         return result;
1530     }
1531 
branchDoubleZeroOrNaN(FPRegisterID reg,FPRegisterID)1532     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1533     {
1534         m_assembler.fcmp_0<64>(reg);
1535         Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
1536         Jump notEqual = makeBranch(ARM64Assembler::ConditionNE);
1537         unordered.link(this);
1538         // We get here if either unordered or equal.
1539         Jump result = jump();
1540         notEqual.link(this);
1541         return result;
1542     }
1543 
1544     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1545     {
1546         // Truncate to a 64-bit integer in dataTempRegister, copy the low 32-bit to dest.
1547         m_assembler.fcvtzs<64, 64>(getCachedDataTempRegisterIDAndInvalidate(), src);
1548         zeroExtend32ToPtr(dataTempRegister, dest);
1549         // Check thlow 32-bits sign extend to be equal to the full value.
1550         m_assembler.cmp<64>(dataTempRegister, dataTempRegister, ARM64Assembler::SXTW, 0);
1551         return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
1552     }
1553 
1554     Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1555     {
1556         // Truncate to a 64-bit unsigned integer in dataTempRegister, copy the low 32-bit to dest.
1557         m_assembler.fcvtzu<64, 64>(getCachedDataTempRegisterIDAndInvalidate(), src);
1558         zeroExtend32ToPtr(dataTempRegister, dest);
1559         // Check thlow 32-bits sign extend to be equal to the full value.
1560         m_assembler.cmp<64>(dataTempRegister, dataTempRegister, ARM64Assembler::SXTW, 0);
1561         return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual));
1562     }
1563 
convertDoubleToFloat(FPRegisterID src,FPRegisterID dest)1564     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest)
1565     {
1566         m_assembler.fcvt<32, 64>(dest, src);
1567     }
1568 
convertFloatToDouble(FPRegisterID src,FPRegisterID dest)1569     void convertFloatToDouble(FPRegisterID src, FPRegisterID dest)
1570     {
1571         m_assembler.fcvt<64, 32>(dest, src);
1572     }
1573 
convertInt32ToDouble(TrustedImm32 imm,FPRegisterID dest)1574     void convertInt32ToDouble(TrustedImm32 imm, FPRegisterID dest)
1575     {
1576         move(imm, getCachedDataTempRegisterIDAndInvalidate());
1577         convertInt32ToDouble(dataTempRegister, dest);
1578     }
1579 
convertUInt32ToDouble(RegisterID src,FPRegisterID dest,RegisterID)1580     void convertUInt32ToDouble(RegisterID src, FPRegisterID dest, RegisterID /*scratch*/)
1581     {
1582         m_assembler.ucvtf<64, 32>(dest, src);
1583     }
1584 
convertInt32ToDouble(RegisterID src,FPRegisterID dest)1585     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1586     {
1587         m_assembler.scvtf<64, 32>(dest, src);
1588     }
1589 
convertInt32ToDouble(Address address,FPRegisterID dest)1590     void convertInt32ToDouble(Address address, FPRegisterID dest)
1591     {
1592         load32(address, getCachedDataTempRegisterIDAndInvalidate());
1593         convertInt32ToDouble(dataTempRegister, dest);
1594     }
1595 
convertInt32ToDouble(AbsoluteAddress address,FPRegisterID dest)1596     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1597     {
1598         load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
1599         convertInt32ToDouble(dataTempRegister, dest);
1600     }
1601 
convertInt64ToDouble(RegisterID src,FPRegisterID dest)1602     void convertInt64ToDouble(RegisterID src, FPRegisterID dest)
1603     {
1604         m_assembler.scvtf<64, 64>(dest, src);
1605     }
1606 
divDouble(FPRegisterID src,FPRegisterID dest)1607     void divDouble(FPRegisterID src, FPRegisterID dest)
1608     {
1609         divDouble(dest, src, dest);
1610     }
1611 
divDouble(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1612     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1613     {
1614         m_assembler.fdiv<64>(dest, op1, op2);
1615     }
1616 
divFloat(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1617     void divFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1618     {
1619         m_assembler.fdiv<32>(dest, op1, op2);
1620     }
1621 
loadDouble(ImplicitAddress address,FPRegisterID dest)1622     void loadDouble(ImplicitAddress address, FPRegisterID dest)
1623     {
1624         if (tryLoadWithOffset<64>(dest, address.base, address.offset))
1625             return;
1626 
1627         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1628         m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
1629     }
1630 
loadDouble(BaseIndex address,FPRegisterID dest)1631     void loadDouble(BaseIndex address, FPRegisterID dest)
1632     {
1633         if (!address.offset && (!address.scale || address.scale == 3)) {
1634             m_assembler.ldr<64>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1635             return;
1636         }
1637 
1638         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1639         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1640         m_assembler.ldr<64>(dest, address.base, memoryTempRegister);
1641     }
1642 
loadDouble(TrustedImmPtr address,FPRegisterID dest)1643     void loadDouble(TrustedImmPtr address, FPRegisterID dest)
1644     {
1645         moveToCachedReg(address, m_cachedMemoryTempRegister);
1646         m_assembler.ldr<64>(dest, memoryTempRegister, ARM64Registers::zr);
1647     }
1648 
loadFloat(ImplicitAddress address,FPRegisterID dest)1649     void loadFloat(ImplicitAddress address, FPRegisterID dest)
1650     {
1651         if (tryLoadWithOffset<32>(dest, address.base, address.offset))
1652             return;
1653 
1654         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1655         m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
1656     }
1657 
loadFloat(BaseIndex address,FPRegisterID dest)1658     void loadFloat(BaseIndex address, FPRegisterID dest)
1659     {
1660         if (!address.offset && (!address.scale || address.scale == 2)) {
1661             m_assembler.ldr<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1662             return;
1663         }
1664 
1665         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1666         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1667         m_assembler.ldr<32>(dest, address.base, memoryTempRegister);
1668     }
1669 
moveDouble(FPRegisterID src,FPRegisterID dest)1670     void moveDouble(FPRegisterID src, FPRegisterID dest)
1671     {
1672         m_assembler.fmov<64>(dest, src);
1673     }
1674 
moveZeroToDouble(FPRegisterID reg)1675     void moveZeroToDouble(FPRegisterID reg)
1676     {
1677         m_assembler.fmov<64>(reg, ARM64Registers::zr);
1678     }
1679 
moveDoubleTo64(FPRegisterID src,RegisterID dest)1680     void moveDoubleTo64(FPRegisterID src, RegisterID dest)
1681     {
1682         m_assembler.fmov<64>(dest, src);
1683     }
1684 
moveFloatTo32(FPRegisterID src,RegisterID dest)1685     void moveFloatTo32(FPRegisterID src, RegisterID dest)
1686     {
1687         m_assembler.fmov<32>(dest, src);
1688     }
1689 
move64ToDouble(RegisterID src,FPRegisterID dest)1690     void move64ToDouble(RegisterID src, FPRegisterID dest)
1691     {
1692         m_assembler.fmov<64>(dest, src);
1693     }
1694 
move32ToFloat(RegisterID src,FPRegisterID dest)1695     void move32ToFloat(RegisterID src, FPRegisterID dest)
1696     {
1697         m_assembler.fmov<32>(dest, src);
1698     }
1699 
moveConditionallyDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right,RegisterID src,RegisterID dest)1700     void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
1701     {
1702         m_assembler.fcmp<64>(left, right);
1703         moveConditionallyAfterFloatingPointCompare<64>(cond, src, dest);
1704     }
1705 
moveConditionallyFloat(DoubleCondition cond,FPRegisterID left,FPRegisterID right,RegisterID src,RegisterID dest)1706     void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
1707     {
1708         m_assembler.fcmp<32>(left, right);
1709         moveConditionallyAfterFloatingPointCompare<64>(cond, src, dest);
1710     }
1711 
1712     template<int datasize>
moveConditionallyAfterFloatingPointCompare(DoubleCondition cond,RegisterID src,RegisterID dest)1713     void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, RegisterID src, RegisterID dest)
1714     {
1715         if (cond == DoubleNotEqual) {
1716             Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
1717             m_assembler.csel<datasize>(dest, src, dest, ARM64Assembler::ConditionNE);
1718             unordered.link(this);
1719             return;
1720         }
1721         if (cond == DoubleEqualOrUnordered) {
1722             // If the compare is unordered, src is copied to dest and the
1723             // next csel has all arguments equal to src.
1724             // If the compare is ordered, dest is unchanged and EQ decides
1725             // what value to set.
1726             m_assembler.csel<datasize>(dest, src, dest, ARM64Assembler::ConditionVS);
1727             m_assembler.csel<datasize>(dest, src, dest, ARM64Assembler::ConditionEQ);
1728             return;
1729         }
1730         m_assembler.csel<datasize>(dest, src, dest, ARM64Condition(cond));
1731     }
1732 
mulDouble(FPRegisterID src,FPRegisterID dest)1733     void mulDouble(FPRegisterID src, FPRegisterID dest)
1734     {
1735         mulDouble(dest, src, dest);
1736     }
1737 
mulDouble(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1738     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1739     {
1740         m_assembler.fmul<64>(dest, op1, op2);
1741     }
1742 
mulDouble(Address src,FPRegisterID dest)1743     void mulDouble(Address src, FPRegisterID dest)
1744     {
1745         loadDouble(src, fpTempRegister);
1746         mulDouble(fpTempRegister, dest);
1747     }
1748 
mulFloat(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1749     void mulFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1750     {
1751         m_assembler.fmul<32>(dest, op1, op2);
1752     }
1753 
andDouble(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1754     void andDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1755     {
1756         m_assembler.vand<64>(dest, op1, op2);
1757     }
1758 
andFloat(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1759     void andFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1760     {
1761         andDouble(op1, op2, dest);
1762     }
1763 
negateDouble(FPRegisterID src,FPRegisterID dest)1764     void negateDouble(FPRegisterID src, FPRegisterID dest)
1765     {
1766         m_assembler.fneg<64>(dest, src);
1767     }
1768 
sqrtDouble(FPRegisterID src,FPRegisterID dest)1769     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1770     {
1771         m_assembler.fsqrt<64>(dest, src);
1772     }
1773 
sqrtFloat(FPRegisterID src,FPRegisterID dest)1774     void sqrtFloat(FPRegisterID src, FPRegisterID dest)
1775     {
1776         m_assembler.fsqrt<32>(dest, src);
1777     }
1778 
storeDouble(FPRegisterID src,ImplicitAddress address)1779     void storeDouble(FPRegisterID src, ImplicitAddress address)
1780     {
1781         if (tryStoreWithOffset<64>(src, address.base, address.offset))
1782             return;
1783 
1784         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1785         m_assembler.str<64>(src, address.base, memoryTempRegister);
1786     }
1787 
storeDouble(FPRegisterID src,TrustedImmPtr address)1788     void storeDouble(FPRegisterID src, TrustedImmPtr address)
1789     {
1790         moveToCachedReg(address, m_cachedMemoryTempRegister);
1791         m_assembler.str<64>(src, memoryTempRegister, ARM64Registers::zr);
1792     }
1793 
storeDouble(FPRegisterID src,BaseIndex address)1794     void storeDouble(FPRegisterID src, BaseIndex address)
1795     {
1796         if (!address.offset && (!address.scale || address.scale == 3)) {
1797             m_assembler.str<64>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1798             return;
1799         }
1800 
1801         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1802         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1803         m_assembler.str<64>(src, address.base, memoryTempRegister);
1804     }
1805 
storeFloat(FPRegisterID src,ImplicitAddress address)1806     void storeFloat(FPRegisterID src, ImplicitAddress address)
1807     {
1808         if (tryStoreWithOffset<32>(src, address.base, address.offset))
1809             return;
1810 
1811         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1812         m_assembler.str<32>(src, address.base, memoryTempRegister);
1813     }
1814 
storeFloat(FPRegisterID src,BaseIndex address)1815     void storeFloat(FPRegisterID src, BaseIndex address)
1816     {
1817         if (!address.offset && (!address.scale || address.scale == 2)) {
1818             m_assembler.str<32>(src, address.base, address.index, ARM64Assembler::UXTX, address.scale);
1819             return;
1820         }
1821 
1822         signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate());
1823         m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale);
1824         m_assembler.str<32>(src, address.base, memoryTempRegister);
1825     }
1826 
subDouble(FPRegisterID src,FPRegisterID dest)1827     void subDouble(FPRegisterID src, FPRegisterID dest)
1828     {
1829         subDouble(dest, src, dest);
1830     }
1831 
subDouble(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1832     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1833     {
1834         m_assembler.fsub<64>(dest, op1, op2);
1835     }
1836 
subDouble(Address src,FPRegisterID dest)1837     void subDouble(Address src, FPRegisterID dest)
1838     {
1839         loadDouble(src, fpTempRegister);
1840         subDouble(fpTempRegister, dest);
1841     }
1842 
subFloat(FPRegisterID op1,FPRegisterID op2,FPRegisterID dest)1843     void subFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1844     {
1845         m_assembler.fsub<32>(dest, op1, op2);
1846     }
1847 
1848     // Result is undefined if the value is outside of the integer range.
truncateDoubleToInt32(FPRegisterID src,RegisterID dest)1849     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1850     {
1851         m_assembler.fcvtzs<32, 64>(dest, src);
1852     }
1853 
truncateDoubleToUint32(FPRegisterID src,RegisterID dest)1854     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1855     {
1856         m_assembler.fcvtzu<32, 64>(dest, src);
1857     }
1858 
1859 
1860     // Stack manipulation operations:
1861     //
1862     // The ABI is assumed to provide a stack abstraction to memory,
1863     // containing machine word sized units of data. Push and pop
1864     // operations add and remove a single register sized unit of data
1865     // to or from the stack. These operations are not supported on
1866     // ARM64. Peek and poke operations read or write values on the
1867     // stack, without moving the current stack position. Additionally,
1868     // there are popToRestore and pushToSave operations, which are
1869     // designed just for quick-and-dirty saving and restoring of
1870     // temporary values. These operations don't claim to have any
1871     // ABI compatibility.
1872 
pop(RegisterID)1873     void pop(RegisterID) NO_RETURN_DUE_TO_CRASH
1874     {
1875         CRASH();
1876     }
1877 
push(RegisterID)1878     void push(RegisterID) NO_RETURN_DUE_TO_CRASH
1879     {
1880         CRASH();
1881     }
1882 
push(Address)1883     void push(Address) NO_RETURN_DUE_TO_CRASH
1884     {
1885         CRASH();
1886     }
1887 
push(TrustedImm32)1888     void push(TrustedImm32) NO_RETURN_DUE_TO_CRASH
1889     {
1890         CRASH();
1891     }
1892 
popPair(RegisterID dest1,RegisterID dest2)1893     void popPair(RegisterID dest1, RegisterID dest2)
1894     {
1895         m_assembler.ldp<64>(dest1, dest2, ARM64Registers::sp, PairPostIndex(16));
1896     }
1897 
pushPair(RegisterID src1,RegisterID src2)1898     void pushPair(RegisterID src1, RegisterID src2)
1899     {
1900         m_assembler.stp<64>(src1, src2, ARM64Registers::sp, PairPreIndex(-16));
1901     }
1902 
popToRestore(RegisterID dest)1903     void popToRestore(RegisterID dest)
1904     {
1905         m_assembler.ldr<64>(dest, ARM64Registers::sp, PostIndex(16));
1906     }
1907 
pushToSave(RegisterID src)1908     void pushToSave(RegisterID src)
1909     {
1910         m_assembler.str<64>(src, ARM64Registers::sp, PreIndex(-16));
1911     }
1912 
pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32 imm)1913     void pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32 imm)
1914     {
1915         RegisterID reg = dataTempRegister;
1916         pushPair(reg, reg);
1917         move(imm, reg);
1918         store64(reg, stackPointerRegister);
1919         load64(Address(stackPointerRegister, 8), reg);
1920     }
1921 
pushToSave(Address address)1922     void pushToSave(Address address)
1923     {
1924         load32(address, getCachedDataTempRegisterIDAndInvalidate());
1925         pushToSave(dataTempRegister);
1926     }
1927 
pushToSave(TrustedImm32 imm)1928     void pushToSave(TrustedImm32 imm)
1929     {
1930         move(imm, getCachedDataTempRegisterIDAndInvalidate());
1931         pushToSave(dataTempRegister);
1932     }
1933 
popToRestore(FPRegisterID dest)1934     void popToRestore(FPRegisterID dest)
1935     {
1936         loadDouble(stackPointerRegister, dest);
1937         add64(TrustedImm32(16), stackPointerRegister);
1938     }
1939 
pushToSave(FPRegisterID src)1940     void pushToSave(FPRegisterID src)
1941     {
1942         sub64(TrustedImm32(16), stackPointerRegister);
1943         storeDouble(src, stackPointerRegister);
1944     }
1945 
pushToSaveByteOffset()1946     static ptrdiff_t pushToSaveByteOffset() { return 16; }
1947 
1948     // Register move operations:
1949 
move(RegisterID src,RegisterID dest)1950     void move(RegisterID src, RegisterID dest)
1951     {
1952         if (src != dest)
1953             m_assembler.mov<64>(dest, src);
1954     }
1955 
move(TrustedImm32 imm,RegisterID dest)1956     void move(TrustedImm32 imm, RegisterID dest)
1957     {
1958         moveInternal<TrustedImm32, int32_t>(imm, dest);
1959     }
1960 
move(TrustedImmPtr imm,RegisterID dest)1961     void move(TrustedImmPtr imm, RegisterID dest)
1962     {
1963         moveInternal<TrustedImmPtr, intptr_t>(imm, dest);
1964     }
1965 
move(TrustedImm64 imm,RegisterID dest)1966     void move(TrustedImm64 imm, RegisterID dest)
1967     {
1968         moveInternal<TrustedImm64, int64_t>(imm, dest);
1969     }
1970 
swap(RegisterID reg1,RegisterID reg2)1971     void swap(RegisterID reg1, RegisterID reg2)
1972     {
1973         move(reg1, getCachedDataTempRegisterIDAndInvalidate());
1974         move(reg2, reg1);
1975         move(dataTempRegister, reg2);
1976     }
1977 
signExtend32ToPtr(TrustedImm32 imm,RegisterID dest)1978     void signExtend32ToPtr(TrustedImm32 imm, RegisterID dest)
1979     {
1980         move(TrustedImmPtr(reinterpret_cast<void*>(static_cast<intptr_t>(imm.m_value))), dest);
1981     }
1982 
signExtend32ToPtr(RegisterID src,RegisterID dest)1983     void signExtend32ToPtr(RegisterID src, RegisterID dest)
1984     {
1985         m_assembler.sxtw(dest, src);
1986     }
1987 
zeroExtend32ToPtr(RegisterID src,RegisterID dest)1988     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1989     {
1990         m_assembler.uxtw(dest, src);
1991     }
1992 
moveConditionally32(RelationalCondition cond,RegisterID left,RegisterID right,RegisterID src,RegisterID dest)1993     void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
1994     {
1995         m_assembler.cmp<32>(left, right);
1996         m_assembler.csel<32>(dest, src, dest, ARM64Condition(cond));
1997     }
1998 
moveConditionally64(RelationalCondition cond,RegisterID left,RegisterID right,RegisterID src,RegisterID dest)1999     void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
2000     {
2001         m_assembler.cmp<64>(left, right);
2002         m_assembler.csel<64>(dest, src, dest, ARM64Condition(cond));
2003     }
2004 
moveConditionallyTest32(ResultCondition cond,RegisterID testReg,RegisterID mask,RegisterID src,RegisterID dest)2005     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
2006     {
2007         m_assembler.tst<32>(testReg, mask);
2008         m_assembler.csel<32>(dest, src, dest, ARM64Condition(cond));
2009     }
2010 
moveConditionallyTest64(ResultCondition cond,RegisterID testReg,RegisterID mask,RegisterID src,RegisterID dest)2011     void moveConditionallyTest64(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
2012     {
2013         m_assembler.tst<64>(testReg, mask);
2014         m_assembler.csel<64>(dest, src, dest, ARM64Condition(cond));
2015     }
2016 
2017     // Forwards / external control flow operations:
2018     //
2019     // This set of jump and conditional branch operations return a Jump
2020     // object which may linked at a later point, allow forwards jump,
2021     // or jumps that will require external linkage (after the code has been
2022     // relocated).
2023     //
2024     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
2025     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
2026     // used (representing the names 'below' and 'above').
2027     //
2028     // Operands to the comparision are provided in the expected order, e.g.
2029     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
2030     // treated as a signed 32bit value, is less than or equal to 5.
2031     //
2032     // jz and jnz test whether the first operand is equal to zero, and take
2033     // an optional second operand of a mask under which to perform the test.
2034 
branch32(RelationalCondition cond,RegisterID left,RegisterID right)2035     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
2036     {
2037         m_assembler.cmp<32>(left, right);
2038         return Jump(makeBranch(cond));
2039     }
2040 
branch32(RelationalCondition cond,RegisterID left,TrustedImm32 right)2041     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
2042     {
2043         if (isUInt12(right.m_value))
2044             m_assembler.cmp<32>(left, UInt12(right.m_value));
2045         else if (isUInt12(-right.m_value))
2046             m_assembler.cmn<32>(left, UInt12(-right.m_value));
2047         else {
2048             moveToCachedReg(right, m_dataMemoryTempRegister);
2049             m_assembler.cmp<32>(left, dataTempRegister);
2050         }
2051         return Jump(makeBranch(cond));
2052     }
2053 
branch32(RelationalCondition cond,RegisterID left,Address right)2054     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
2055     {
2056         load32(right, getCachedMemoryTempRegisterIDAndInvalidate());
2057         return branch32(cond, left, memoryTempRegister);
2058     }
2059 
branch32(RelationalCondition cond,Address left,RegisterID right)2060     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
2061     {
2062         load32(left, getCachedMemoryTempRegisterIDAndInvalidate());
2063         return branch32(cond, memoryTempRegister, right);
2064     }
2065 
branch32(RelationalCondition cond,Address left,TrustedImm32 right)2066     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
2067     {
2068         load32(left, getCachedMemoryTempRegisterIDAndInvalidate());
2069         return branch32(cond, memoryTempRegister, right);
2070     }
2071 
branch32(RelationalCondition cond,BaseIndex left,TrustedImm32 right)2072     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
2073     {
2074         load32(left, getCachedMemoryTempRegisterIDAndInvalidate());
2075         return branch32(cond, memoryTempRegister, right);
2076     }
2077 
branch32(RelationalCondition cond,AbsoluteAddress left,RegisterID right)2078     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
2079     {
2080         load32(left.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
2081         return branch32(cond, dataTempRegister, right);
2082     }
2083 
branch32(RelationalCondition cond,AbsoluteAddress left,TrustedImm32 right)2084     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
2085     {
2086         load32(left.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
2087         return branch32(cond, memoryTempRegister, right);
2088     }
2089 
branch64(RelationalCondition cond,RegisterID left,RegisterID right)2090     Jump branch64(RelationalCondition cond, RegisterID left, RegisterID right)
2091     {
2092         if (right == ARM64Registers::sp) {
2093             if (cond == Equal && left != ARM64Registers::sp) {
2094                 // CMP can only use SP for the left argument, since we are testing for equality, the order
2095                 // does not matter here.
2096                 std::swap(left, right);
2097             } else {
2098                 move(right, getCachedDataTempRegisterIDAndInvalidate());
2099                 right = dataTempRegister;
2100             }
2101         }
2102         m_assembler.cmp<64>(left, right);
2103         return Jump(makeBranch(cond));
2104     }
2105 
branch64(RelationalCondition cond,RegisterID left,TrustedImm64 right)2106     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
2107     {
2108         intptr_t immediate = right.m_value;
2109         if (isUInt12(immediate))
2110             m_assembler.cmp<64>(left, UInt12(static_cast<int32_t>(immediate)));
2111         else if (isUInt12(-immediate))
2112             m_assembler.cmn<64>(left, UInt12(static_cast<int32_t>(-immediate)));
2113         else {
2114             moveToCachedReg(right, m_dataMemoryTempRegister);
2115             m_assembler.cmp<64>(left, dataTempRegister);
2116         }
2117         return Jump(makeBranch(cond));
2118     }
2119 
branch64(RelationalCondition cond,RegisterID left,Address right)2120     Jump branch64(RelationalCondition cond, RegisterID left, Address right)
2121     {
2122         load64(right, getCachedMemoryTempRegisterIDAndInvalidate());
2123         return branch64(cond, left, memoryTempRegister);
2124     }
2125 
branch64(RelationalCondition cond,AbsoluteAddress left,RegisterID right)2126     Jump branch64(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
2127     {
2128         load64(left.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
2129         return branch64(cond, dataTempRegister, right);
2130     }
2131 
branch64(RelationalCondition cond,Address left,RegisterID right)2132     Jump branch64(RelationalCondition cond, Address left, RegisterID right)
2133     {
2134         load64(left, getCachedMemoryTempRegisterIDAndInvalidate());
2135         return branch64(cond, memoryTempRegister, right);
2136     }
2137 
branch64(RelationalCondition cond,Address left,TrustedImm64 right)2138     Jump branch64(RelationalCondition cond, Address left, TrustedImm64 right)
2139     {
2140         load64(left, getCachedMemoryTempRegisterIDAndInvalidate());
2141         return branch64(cond, memoryTempRegister, right);
2142     }
2143 
branchPtr(RelationalCondition cond,BaseIndex left,RegisterID right)2144     Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
2145     {
2146         load64(left, getCachedMemoryTempRegisterIDAndInvalidate());
2147         return branch64(cond, memoryTempRegister, right);
2148     }
2149 
branch8(RelationalCondition cond,Address left,TrustedImm32 right)2150     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
2151     {
2152         ASSERT(!(0xffffff00 & right.m_value));
2153         load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
2154         return branch32(cond, memoryTempRegister, right);
2155     }
2156 
branch8(RelationalCondition cond,BaseIndex left,TrustedImm32 right)2157     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
2158     {
2159         ASSERT(!(0xffffff00 & right.m_value));
2160         load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
2161         return branch32(cond, memoryTempRegister, right);
2162     }
2163 
branch8(RelationalCondition cond,AbsoluteAddress left,TrustedImm32 right)2164     Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
2165     {
2166         ASSERT(!(0xffffff00 & right.m_value));
2167         load8(left.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate());
2168         return branch32(cond, memoryTempRegister, right);
2169     }
2170 
branchTest32(ResultCondition cond,RegisterID reg,RegisterID mask)2171     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
2172     {
2173         m_assembler.tst<32>(reg, mask);
2174         return Jump(makeBranch(cond));
2175     }
2176 
2177     void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
2178     {
2179         if (mask.m_value == -1)
2180             m_assembler.tst<32>(reg, reg);
2181         else {
2182             bool testedWithImmediate = false;
2183             if ((cond == Zero) || (cond == NonZero)) {
2184                 LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
2185 
2186                 if (logicalImm.isValid()) {
2187                     m_assembler.tst<32>(reg, logicalImm);
2188                     testedWithImmediate = true;
2189                 }
2190             }
2191             if (!testedWithImmediate) {
2192                 move(mask, getCachedDataTempRegisterIDAndInvalidate());
2193                 m_assembler.tst<32>(reg, dataTempRegister);
2194             }
2195         }
2196     }
2197 
branch(ResultCondition cond)2198     Jump branch(ResultCondition cond)
2199     {
2200         return Jump(makeBranch(cond));
2201     }
2202 
2203     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
2204     {
2205         if (mask.m_value == -1) {
2206             if ((cond == Zero) || (cond == NonZero))
2207                 return Jump(makeCompareAndBranch<32>(static_cast<ZeroCondition>(cond), reg));
2208             m_assembler.tst<32>(reg, reg);
2209         } else if (hasOneBitSet(mask.m_value) && ((cond == Zero) || (cond == NonZero)))
2210             return Jump(makeTestBitAndBranch(reg, getLSBSet(mask.m_value), static_cast<ZeroCondition>(cond)));
2211         else {
2212             if ((cond == Zero) || (cond == NonZero)) {
2213                 LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value);
2214 
2215                 if (logicalImm.isValid()) {
2216                     m_assembler.tst<32>(reg, logicalImm);
2217                     return Jump(makeBranch(cond));
2218                 }
2219             }
2220 
2221             move(mask, getCachedDataTempRegisterIDAndInvalidate());
2222             m_assembler.tst<32>(reg, dataTempRegister);
2223         }
2224         return Jump(makeBranch(cond));
2225     }
2226 
2227     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
2228     {
2229         load32(address, getCachedMemoryTempRegisterIDAndInvalidate());
2230         return branchTest32(cond, memoryTempRegister, mask);
2231     }
2232 
2233     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
2234     {
2235         load32(address, getCachedMemoryTempRegisterIDAndInvalidate());
2236         return branchTest32(cond, memoryTempRegister, mask);
2237     }
2238 
branchTest64(ResultCondition cond,RegisterID reg,RegisterID mask)2239     Jump branchTest64(ResultCondition cond, RegisterID reg, RegisterID mask)
2240     {
2241         m_assembler.tst<64>(reg, mask);
2242         return Jump(makeBranch(cond));
2243     }
2244 
2245     Jump branchTest64(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
2246     {
2247         if (mask.m_value == -1) {
2248             if ((cond == Zero) || (cond == NonZero))
2249                 return Jump(makeCompareAndBranch<64>(static_cast<ZeroCondition>(cond), reg));
2250             m_assembler.tst<64>(reg, reg);
2251         } else if (hasOneBitSet(mask.m_value) && ((cond == Zero) || (cond == NonZero)))
2252             return Jump(makeTestBitAndBranch(reg, getLSBSet(mask.m_value), static_cast<ZeroCondition>(cond)));
2253         else {
2254             if ((cond == Zero) || (cond == NonZero)) {
2255                 LogicalImmediate logicalImm = LogicalImmediate::create64(mask.m_value);
2256 
2257                 if (logicalImm.isValid()) {
2258                     m_assembler.tst<64>(reg, logicalImm);
2259                     return Jump(makeBranch(cond));
2260                 }
2261             }
2262 
2263             signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
2264             m_assembler.tst<64>(reg, dataTempRegister);
2265         }
2266         return Jump(makeBranch(cond));
2267     }
2268 
branchTest64(ResultCondition cond,RegisterID reg,TrustedImm64 mask)2269     Jump branchTest64(ResultCondition cond, RegisterID reg, TrustedImm64 mask)
2270     {
2271         move(mask, getCachedDataTempRegisterIDAndInvalidate());
2272         return branchTest64(cond, reg, dataTempRegister);
2273     }
2274 
branchTest64(ResultCondition cond,Address address,RegisterID mask)2275     Jump branchTest64(ResultCondition cond, Address address, RegisterID mask)
2276     {
2277         load64(address, getCachedDataTempRegisterIDAndInvalidate());
2278         return branchTest64(cond, dataTempRegister, mask);
2279     }
2280 
2281     Jump branchTest64(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
2282     {
2283         load64(address, getCachedDataTempRegisterIDAndInvalidate());
2284         return branchTest64(cond, dataTempRegister, mask);
2285     }
2286 
2287     Jump branchTest64(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
2288     {
2289         load64(address, getCachedDataTempRegisterIDAndInvalidate());
2290         return branchTest64(cond, dataTempRegister, mask);
2291     }
2292 
2293     Jump branchTest64(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
2294     {
2295         load64(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
2296         return branchTest64(cond, dataTempRegister, mask);
2297     }
2298 
2299     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
2300     {
2301         load8(address, getCachedDataTempRegisterIDAndInvalidate());
2302         return branchTest32(cond, dataTempRegister, mask);
2303     }
2304 
2305     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
2306     {
2307         load8(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
2308         return branchTest32(cond, dataTempRegister, mask);
2309     }
2310 
2311     Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
2312     {
2313         move(TrustedImmPtr(reinterpret_cast<void*>(address.offset)), getCachedDataTempRegisterIDAndInvalidate());
2314         m_assembler.ldrb(dataTempRegister, address.base, dataTempRegister);
2315         return branchTest32(cond, dataTempRegister, mask);
2316     }
2317 
2318     Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
2319     {
2320         load8(address, getCachedDataTempRegisterIDAndInvalidate());
2321         return branchTest32(cond, dataTempRegister, mask);
2322     }
2323 
branch32WithUnalignedHalfWords(RelationalCondition cond,BaseIndex left,TrustedImm32 right)2324     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
2325     {
2326         return branch32(cond, left, right);
2327     }
2328 
2329 
2330     // Arithmetic control flow operations:
2331     //
2332     // This set of conditional branch operations branch based
2333     // on the result of an arithmetic operation. The operation
2334     // is performed as normal, storing the result.
2335     //
2336     // * jz operations branch if the result is zero.
2337     // * jo operations branch if the (signed) arithmetic
2338     //   operation caused an overflow to occur.
2339 
branchAdd32(ResultCondition cond,RegisterID op1,RegisterID op2,RegisterID dest)2340     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
2341     {
2342         m_assembler.add<32, S>(dest, op1, op2);
2343         return Jump(makeBranch(cond));
2344     }
2345 
branchAdd32(ResultCondition cond,RegisterID op1,TrustedImm32 imm,RegisterID dest)2346     Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
2347     {
2348         if (isUInt12(imm.m_value)) {
2349             m_assembler.add<32, S>(dest, op1, UInt12(imm.m_value));
2350             return Jump(makeBranch(cond));
2351         }
2352         if (isUInt12(-imm.m_value)) {
2353             m_assembler.sub<32, S>(dest, op1, UInt12(-imm.m_value));
2354             return Jump(makeBranch(cond));
2355         }
2356 
2357         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
2358         return branchAdd32(cond, op1, dataTempRegister, dest);
2359     }
2360 
branchAdd32(ResultCondition cond,Address src,RegisterID dest)2361     Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
2362     {
2363         load32(src, getCachedDataTempRegisterIDAndInvalidate());
2364         return branchAdd32(cond, dest, dataTempRegister, dest);
2365     }
2366 
branchAdd32(ResultCondition cond,RegisterID src,RegisterID dest)2367     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
2368     {
2369         return branchAdd32(cond, dest, src, dest);
2370     }
2371 
branchAdd32(ResultCondition cond,TrustedImm32 imm,RegisterID dest)2372     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2373     {
2374         return branchAdd32(cond, dest, imm, dest);
2375     }
2376 
branchAdd32(ResultCondition cond,TrustedImm32 imm,AbsoluteAddress address)2377     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress address)
2378     {
2379         load32(address.m_ptr, getCachedDataTempRegisterIDAndInvalidate());
2380 
2381         if (isUInt12(imm.m_value)) {
2382             m_assembler.add<32, S>(dataTempRegister, dataTempRegister, UInt12(imm.m_value));
2383             store32(dataTempRegister, address.m_ptr);
2384         } else if (isUInt12(-imm.m_value)) {
2385             m_assembler.sub<32, S>(dataTempRegister, dataTempRegister, UInt12(-imm.m_value));
2386             store32(dataTempRegister, address.m_ptr);
2387         } else {
2388             move(imm, getCachedMemoryTempRegisterIDAndInvalidate());
2389             m_assembler.add<32, S>(dataTempRegister, dataTempRegister, memoryTempRegister);
2390             store32(dataTempRegister, address.m_ptr);
2391         }
2392 
2393         return Jump(makeBranch(cond));
2394     }
2395 
branchAdd64(ResultCondition cond,RegisterID op1,RegisterID op2,RegisterID dest)2396     Jump branchAdd64(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
2397     {
2398         m_assembler.add<64, S>(dest, op1, op2);
2399         return Jump(makeBranch(cond));
2400     }
2401 
branchAdd64(ResultCondition cond,RegisterID op1,TrustedImm32 imm,RegisterID dest)2402     Jump branchAdd64(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
2403     {
2404         if (isUInt12(imm.m_value)) {
2405             m_assembler.add<64, S>(dest, op1, UInt12(imm.m_value));
2406             return Jump(makeBranch(cond));
2407         }
2408         if (isUInt12(-imm.m_value)) {
2409             m_assembler.sub<64, S>(dest, op1, UInt12(-imm.m_value));
2410             return Jump(makeBranch(cond));
2411         }
2412 
2413         move(imm, getCachedDataTempRegisterIDAndInvalidate());
2414         return branchAdd64(cond, op1, dataTempRegister, dest);
2415     }
2416 
branchAdd64(ResultCondition cond,RegisterID src,RegisterID dest)2417     Jump branchAdd64(ResultCondition cond, RegisterID src, RegisterID dest)
2418     {
2419         return branchAdd64(cond, dest, src, dest);
2420     }
2421 
branchAdd64(ResultCondition cond,TrustedImm32 imm,RegisterID dest)2422     Jump branchAdd64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2423     {
2424         return branchAdd64(cond, dest, imm, dest);
2425     }
2426 
branchMul32(ResultCondition cond,RegisterID src1,RegisterID src2,RegisterID scratch1,RegisterID scratch2,RegisterID dest)2427     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID scratch1, RegisterID scratch2, RegisterID dest)
2428     {
2429         ASSERT(cond != Signed);
2430 
2431         if (cond != Overflow) {
2432             m_assembler.mul<32>(dest, src1, src2);
2433             return branchTest32(cond, dest);
2434         }
2435 
2436         // This is a signed multiple of two 32-bit values, producing a 64-bit result.
2437         m_assembler.smull(dest, src1, src2);
2438         // Copy bits 63..32 of the result to bits 31..0 of scratch1.
2439         m_assembler.asr<64>(scratch1, dest, 32);
2440         // Splat bit 31 of the result to bits 31..0 of scratch2.
2441         m_assembler.asr<32>(scratch2, dest, 31);
2442         // After a mul32 the top 32 bits of the register should be clear.
2443         zeroExtend32ToPtr(dest, dest);
2444         // Check that bits 31..63 of the original result were all equal.
2445         return branch32(NotEqual, scratch2, scratch1);
2446     }
2447 
branchMul32(ResultCondition cond,RegisterID src1,RegisterID src2,RegisterID dest)2448     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2449     {
2450         return branchMul32(cond, src1, src2, getCachedDataTempRegisterIDAndInvalidate(), getCachedMemoryTempRegisterIDAndInvalidate(), dest);
2451     }
2452 
branchMul32(ResultCondition cond,RegisterID src,RegisterID dest)2453     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
2454     {
2455         return branchMul32(cond, dest, src, dest);
2456     }
2457 
branchMul32(ResultCondition cond,RegisterID src,TrustedImm32 imm,RegisterID dest)2458     Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
2459     {
2460         move(imm, getCachedDataTempRegisterIDAndInvalidate());
2461         return branchMul32(cond, dataTempRegister, src, dest);
2462     }
2463 
branchMul32(ResultCondition cond,TrustedImm32 imm,RegisterID src,RegisterID dest)2464     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
2465     {
2466         move(imm, dataTempRegister);
2467         return branchMul32(cond, dataTempRegister, src, dest);
2468     }
2469 
branchMul64(ResultCondition cond,RegisterID src1,RegisterID src2,RegisterID scratch1,RegisterID scratch2,RegisterID dest)2470     Jump branchMul64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID scratch1, RegisterID scratch2, RegisterID dest)
2471     {
2472         ASSERT(cond != Signed);
2473 
2474         // This is a signed multiple of two 64-bit values, producing a 64-bit result.
2475         m_assembler.mul<64>(dest, src1, src2);
2476 
2477         if (cond != Overflow)
2478             return branchTest64(cond, dest);
2479 
2480         // Compute bits 127..64 of the result into scratch1.
2481         m_assembler.smulh(scratch1, src1, src2);
2482         // Splat bit 63 of the result to bits 63..0 of scratch2.
2483         m_assembler.asr<64>(scratch2, dest, 63);
2484         // Check that bits 31..63 of the original result were all equal.
2485         return branch64(NotEqual, scratch2, scratch1);
2486     }
2487 
branchMul64(ResultCondition cond,RegisterID src1,RegisterID src2,RegisterID dest)2488     Jump branchMul64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2489     {
2490         return branchMul64(cond, src1, src2, getCachedDataTempRegisterIDAndInvalidate(), getCachedMemoryTempRegisterIDAndInvalidate(), dest);
2491     }
2492 
branchMul64(ResultCondition cond,RegisterID src,RegisterID dest)2493     Jump branchMul64(ResultCondition cond, RegisterID src, RegisterID dest)
2494     {
2495         return branchMul64(cond, dest, src, dest);
2496     }
2497 
branchNeg32(ResultCondition cond,RegisterID dest)2498     Jump branchNeg32(ResultCondition cond, RegisterID dest)
2499     {
2500         m_assembler.neg<32, S>(dest, dest);
2501         return Jump(makeBranch(cond));
2502     }
2503 
branchNeg64(ResultCondition cond,RegisterID srcDest)2504     Jump branchNeg64(ResultCondition cond, RegisterID srcDest)
2505     {
2506         m_assembler.neg<64, S>(srcDest, srcDest);
2507         return Jump(makeBranch(cond));
2508     }
2509 
branchSub32(ResultCondition cond,RegisterID dest)2510     Jump branchSub32(ResultCondition cond, RegisterID dest)
2511     {
2512         m_assembler.neg<32, S>(dest, dest);
2513         return Jump(makeBranch(cond));
2514     }
2515 
branchSub32(ResultCondition cond,RegisterID op1,RegisterID op2,RegisterID dest)2516     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
2517     {
2518         m_assembler.sub<32, S>(dest, op1, op2);
2519         return Jump(makeBranch(cond));
2520     }
2521 
branchSub32(ResultCondition cond,RegisterID op1,TrustedImm32 imm,RegisterID dest)2522     Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
2523     {
2524         if (isUInt12(imm.m_value)) {
2525             m_assembler.sub<32, S>(dest, op1, UInt12(imm.m_value));
2526             return Jump(makeBranch(cond));
2527         }
2528         if (isUInt12(-imm.m_value)) {
2529             m_assembler.add<32, S>(dest, op1, UInt12(-imm.m_value));
2530             return Jump(makeBranch(cond));
2531         }
2532 
2533         signExtend32ToPtr(imm, getCachedDataTempRegisterIDAndInvalidate());
2534         return branchSub32(cond, op1, dataTempRegister, dest);
2535     }
2536 
branchSub32(ResultCondition cond,RegisterID src,RegisterID dest)2537     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
2538     {
2539         return branchSub32(cond, dest, src, dest);
2540     }
2541 
branchSub32(ResultCondition cond,TrustedImm32 imm,RegisterID dest)2542     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2543     {
2544         return branchSub32(cond, dest, imm, dest);
2545     }
2546 
branchSub64(ResultCondition cond,RegisterID op1,RegisterID op2,RegisterID dest)2547     Jump branchSub64(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
2548     {
2549         m_assembler.sub<64, S>(dest, op1, op2);
2550         return Jump(makeBranch(cond));
2551     }
2552 
branchSub64(ResultCondition cond,RegisterID op1,TrustedImm32 imm,RegisterID dest)2553     Jump branchSub64(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
2554     {
2555         if (isUInt12(imm.m_value)) {
2556             m_assembler.sub<64, S>(dest, op1, UInt12(imm.m_value));
2557             return Jump(makeBranch(cond));
2558         }
2559         if (isUInt12(-imm.m_value)) {
2560             m_assembler.add<64, S>(dest, op1, UInt12(-imm.m_value));
2561             return Jump(makeBranch(cond));
2562         }
2563 
2564         move(imm, getCachedDataTempRegisterIDAndInvalidate());
2565         return branchSub64(cond, op1, dataTempRegister, dest);
2566     }
2567 
branchSub64(ResultCondition cond,RegisterID src,RegisterID dest)2568     Jump branchSub64(ResultCondition cond, RegisterID src, RegisterID dest)
2569     {
2570         return branchSub64(cond, dest, src, dest);
2571     }
2572 
branchSub64(ResultCondition cond,TrustedImm32 imm,RegisterID dest)2573     Jump branchSub64(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2574     {
2575         return branchSub64(cond, dest, imm, dest);
2576     }
2577 
2578 
2579     // Jumps, calls, returns
2580 
call()2581     ALWAYS_INLINE Call call()
2582     {
2583         AssemblerLabel pointerLabel = m_assembler.label();
2584         moveWithFixedWidth(TrustedImmPtr(0), getCachedDataTempRegisterIDAndInvalidate());
2585         invalidateAllTempRegisters();
2586         m_assembler.blr(dataTempRegister);
2587         AssemblerLabel callLabel = m_assembler.label();
2588         ASSERT_UNUSED(pointerLabel, ARM64Assembler::getDifferenceBetweenLabels(callLabel, pointerLabel) == REPATCH_OFFSET_CALL_TO_POINTER);
2589         return Call(callLabel, Call::Linkable);
2590     }
2591 
call(RegisterID target)2592     ALWAYS_INLINE Call call(RegisterID target)
2593     {
2594         invalidateAllTempRegisters();
2595         m_assembler.blr(target);
2596         return Call(m_assembler.label(), Call::None);
2597     }
2598 
call(Address address)2599     ALWAYS_INLINE Call call(Address address)
2600     {
2601         load64(address, getCachedDataTempRegisterIDAndInvalidate());
2602         return call(dataTempRegister);
2603     }
2604 
jump()2605     ALWAYS_INLINE Jump jump()
2606     {
2607         AssemblerLabel label = m_assembler.label();
2608         m_assembler.b();
2609         return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpNoConditionFixedSize : ARM64Assembler::JumpNoCondition);
2610     }
2611 
jump(RegisterID target)2612     void jump(RegisterID target)
2613     {
2614         m_assembler.br(target);
2615     }
2616 
jump(Address address)2617     void jump(Address address)
2618     {
2619         load64(address, getCachedDataTempRegisterIDAndInvalidate());
2620         m_assembler.br(dataTempRegister);
2621     }
2622 
jump(AbsoluteAddress address)2623     void jump(AbsoluteAddress address)
2624     {
2625         move(TrustedImmPtr(address.m_ptr), getCachedDataTempRegisterIDAndInvalidate());
2626         load64(Address(dataTempRegister), dataTempRegister);
2627         m_assembler.br(dataTempRegister);
2628     }
2629 
makeTailRecursiveCall(Jump oldJump)2630     ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
2631     {
2632         oldJump.link(this);
2633         return tailRecursiveCall();
2634     }
2635 
nearCall()2636     ALWAYS_INLINE Call nearCall()
2637     {
2638         m_assembler.bl();
2639         return Call(m_assembler.label(), Call::LinkableNear);
2640     }
2641 
2642 #if 0
2643     ALWAYS_INLINE Call nearTailCall()
2644     {
2645         AssemblerLabel label = m_assembler.label();
2646         m_assembler.b();
2647         return Call(label, Call::LinkableNearTail);
2648     }
2649 #endif
2650 
ret()2651     ALWAYS_INLINE void ret()
2652     {
2653         m_assembler.ret();
2654     }
2655 
tailRecursiveCall()2656     ALWAYS_INLINE Call tailRecursiveCall()
2657     {
2658         // Like a normal call, but don't link.
2659         AssemblerLabel pointerLabel = m_assembler.label();
2660         moveWithFixedWidth(TrustedImmPtr(0), getCachedDataTempRegisterIDAndInvalidate());
2661         m_assembler.br(dataTempRegister);
2662         AssemblerLabel callLabel = m_assembler.label();
2663         ASSERT_UNUSED(pointerLabel, ARM64Assembler::getDifferenceBetweenLabels(callLabel, pointerLabel) == REPATCH_OFFSET_CALL_TO_POINTER);
2664         return Call(callLabel, Call::Linkable);
2665     }
2666 
2667 
2668     // Comparisons operations
2669 
compare32(RelationalCondition cond,RegisterID left,RegisterID right,RegisterID dest)2670     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
2671     {
2672         m_assembler.cmp<32>(left, right);
2673         m_assembler.cset<32>(dest, ARM64Condition(cond));
2674     }
2675 
compare32(RelationalCondition cond,Address left,RegisterID right,RegisterID dest)2676     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
2677     {
2678         load32(left, getCachedDataTempRegisterIDAndInvalidate());
2679         m_assembler.cmp<32>(dataTempRegister, right);
2680         m_assembler.cset<32>(dest, ARM64Condition(cond));
2681     }
2682 
compare32(RelationalCondition cond,RegisterID left,TrustedImm32 right,RegisterID dest)2683     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
2684     {
2685         move(right, getCachedDataTempRegisterIDAndInvalidate());
2686         m_assembler.cmp<32>(left, dataTempRegister);
2687         m_assembler.cset<32>(dest, ARM64Condition(cond));
2688     }
2689 
compare64(RelationalCondition cond,RegisterID left,RegisterID right,RegisterID dest)2690     void compare64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
2691     {
2692         m_assembler.cmp<64>(left, right);
2693         m_assembler.cset<32>(dest, ARM64Condition(cond));
2694     }
2695 
compare64(RelationalCondition cond,RegisterID left,TrustedImm32 right,RegisterID dest)2696     void compare64(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
2697     {
2698         signExtend32ToPtr(right, getCachedDataTempRegisterIDAndInvalidate());
2699         m_assembler.cmp<64>(left, dataTempRegister);
2700         m_assembler.cset<32>(dest, ARM64Condition(cond));
2701     }
2702 
compare8(RelationalCondition cond,Address left,TrustedImm32 right,RegisterID dest)2703     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
2704     {
2705         load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
2706         move(right, getCachedDataTempRegisterIDAndInvalidate());
2707         compare32(cond, memoryTempRegister, dataTempRegister, dest);
2708     }
2709 
test32(ResultCondition cond,RegisterID src,RegisterID mask,RegisterID dest)2710     void test32(ResultCondition cond, RegisterID src, RegisterID mask, RegisterID dest)
2711     {
2712         m_assembler.tst<32>(src, mask);
2713         m_assembler.cset<32>(dest, ARM64Condition(cond));
2714     }
2715 
test32(ResultCondition cond,RegisterID src,TrustedImm32 mask,RegisterID dest)2716     void test32(ResultCondition cond, RegisterID src, TrustedImm32 mask, RegisterID dest)
2717     {
2718         if (mask.m_value == -1)
2719             m_assembler.tst<32>(src, src);
2720         else {
2721             signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
2722             m_assembler.tst<32>(src, dataTempRegister);
2723         }
2724         m_assembler.cset<32>(dest, ARM64Condition(cond));
2725     }
2726 
test32(ResultCondition cond,Address address,TrustedImm32 mask,RegisterID dest)2727     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2728     {
2729         load32(address, getCachedMemoryTempRegisterIDAndInvalidate());
2730         test32(cond, memoryTempRegister, mask, dest);
2731     }
2732 
test8(ResultCondition cond,Address address,TrustedImm32 mask,RegisterID dest)2733     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2734     {
2735         load8(address, getCachedMemoryTempRegisterIDAndInvalidate());
2736         test32(cond, memoryTempRegister, mask, dest);
2737     }
2738 
test64(ResultCondition cond,RegisterID op1,RegisterID op2,RegisterID dest)2739     void test64(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
2740     {
2741         m_assembler.tst<64>(op1, op2);
2742         m_assembler.cset<32>(dest, ARM64Condition(cond));
2743     }
2744 
test64(ResultCondition cond,RegisterID src,TrustedImm32 mask,RegisterID dest)2745     void test64(ResultCondition cond, RegisterID src, TrustedImm32 mask, RegisterID dest)
2746     {
2747         if (mask.m_value == -1)
2748             m_assembler.tst<64>(src, src);
2749         else {
2750             signExtend32ToPtr(mask, getCachedDataTempRegisterIDAndInvalidate());
2751             m_assembler.tst<64>(src, dataTempRegister);
2752         }
2753         m_assembler.cset<32>(dest, ARM64Condition(cond));
2754     }
2755 
setCarry(RegisterID dest)2756     void setCarry(RegisterID dest)
2757     {
2758         m_assembler.cset<32>(dest, ARM64Assembler::ConditionCS);
2759     }
2760 
2761     // Patchable operations
2762 
moveWithPatch(TrustedImm32 imm,RegisterID dest)2763     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
2764     {
2765         DataLabel32 label(this);
2766         moveWithFixedWidth(imm, dest);
2767         return label;
2768     }
2769 
moveWithPatch(TrustedImmPtr imm,RegisterID dest)2770     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dest)
2771     {
2772         DataLabelPtr label(this);
2773         moveWithFixedWidth(imm, dest);
2774         return label;
2775     }
2776 
2777     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2778     {
2779         dataLabel = DataLabelPtr(this);
2780         moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate());
2781         return branch64(cond, left, dataTempRegister);
2782     }
2783 
2784     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2785     {
2786         dataLabel = DataLabelPtr(this);
2787         moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate());
2788         return branch64(cond, left, dataTempRegister);
2789     }
2790 
2791     ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
2792     {
2793         dataLabel = DataLabel32(this);
2794         moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate());
2795         return branch32(cond, left, dataTempRegister);
2796     }
2797 
patchableBranchPtr(RelationalCondition cond,Address left,TrustedImmPtr right)2798     PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
2799     {
2800         m_makeJumpPatchable = true;
2801         Jump result = branch64(cond, left, TrustedImm64(right));
2802         m_makeJumpPatchable = false;
2803         return PatchableJump(result);
2804     }
2805 
2806     PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
2807     {
2808         m_makeJumpPatchable = true;
2809         Jump result = branchTest32(cond, reg, mask);
2810         m_makeJumpPatchable = false;
2811         return PatchableJump(result);
2812     }
2813 
patchableBranch32(RelationalCondition cond,RegisterID reg,TrustedImm32 imm)2814     PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
2815     {
2816         m_makeJumpPatchable = true;
2817         Jump result = branch32(cond, reg, imm);
2818         m_makeJumpPatchable = false;
2819         return PatchableJump(result);
2820     }
2821 
patchableBranch64(RelationalCondition cond,RegisterID reg,TrustedImm64 imm)2822     PatchableJump patchableBranch64(RelationalCondition cond, RegisterID reg, TrustedImm64 imm)
2823     {
2824         m_makeJumpPatchable = true;
2825         Jump result = branch64(cond, reg, imm);
2826         m_makeJumpPatchable = false;
2827         return PatchableJump(result);
2828     }
2829 
patchableBranch64(RelationalCondition cond,RegisterID left,RegisterID right)2830     PatchableJump patchableBranch64(RelationalCondition cond, RegisterID left, RegisterID right)
2831     {
2832         m_makeJumpPatchable = true;
2833         Jump result = branch64(cond, left, right);
2834         m_makeJumpPatchable = false;
2835         return PatchableJump(result);
2836     }
2837 
2838     PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
2839     {
2840         m_makeJumpPatchable = true;
2841         Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
2842         m_makeJumpPatchable = false;
2843         return PatchableJump(result);
2844     }
2845 
2846     PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
2847     {
2848         m_makeJumpPatchable = true;
2849         Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue);
2850         m_makeJumpPatchable = false;
2851         return PatchableJump(result);
2852     }
2853 
patchableJump()2854     PatchableJump patchableJump()
2855     {
2856         m_makeJumpPatchable = true;
2857         Jump result = jump();
2858         m_makeJumpPatchable = false;
2859         return PatchableJump(result);
2860     }
2861 
storePtrWithPatch(TrustedImmPtr initialValue,ImplicitAddress address)2862     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
2863     {
2864         DataLabelPtr label(this);
2865         moveWithFixedWidth(initialValue, getCachedDataTempRegisterIDAndInvalidate());
2866         store64(dataTempRegister, address);
2867         return label;
2868     }
2869 
storePtrWithPatch(ImplicitAddress address)2870     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address)
2871     {
2872         return storePtrWithPatch(TrustedImmPtr(0), address);
2873     }
2874 
reemitInitialMoveWithPatch(void * address,void * value)2875     static void reemitInitialMoveWithPatch(void* address, void* value)
2876     {
2877         ARM64Assembler::setPointer(static_cast<int*>(address), value, dataTempRegister, true);
2878     }
2879 
2880     // Miscellaneous operations:
2881 
2882     void breakpoint(uint16_t imm = 0)
2883     {
2884         m_assembler.brk(imm);
2885     }
2886 
nop()2887     void nop()
2888     {
2889         m_assembler.nop();
2890     }
2891 
memoryFence()2892     void memoryFence()
2893     {
2894         m_assembler.dmbSY();
2895     }
2896 
2897 
2898     // Misc helper functions.
2899 
2900     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
invert(RelationalCondition cond)2901     static RelationalCondition invert(RelationalCondition cond)
2902     {
2903         return static_cast<RelationalCondition>(ARM64Assembler::invert(static_cast<ARM64Assembler::Condition>(cond)));
2904     }
2905 
readCallTarget(CodeLocationCall call)2906     static FunctionPtr readCallTarget(CodeLocationCall call)
2907     {
2908         return FunctionPtr(reinterpret_cast<void(*)()>(ARM64Assembler::readCallTarget(call.dataLocation())));
2909     }
2910 
replaceWithJump(CodeLocationLabel instructionStart,CodeLocationLabel destination)2911     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
2912     {
2913         ARM64Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
2914     }
2915 
maxJumpReplacementSize()2916     static ptrdiff_t maxJumpReplacementSize()
2917     {
2918         return ARM64Assembler::maxJumpReplacementSize();
2919     }
2920 
scratchRegisterForBlinding()2921     RegisterID scratchRegisterForBlinding()
2922     {
2923         // We *do not* have a scratch register for blinding.
2924         RELEASE_ASSERT_NOT_REACHED();
2925         return getCachedDataTempRegisterIDAndInvalidate();
2926     }
2927 
canJumpReplacePatchableBranchPtrWithPatch()2928     static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
canJumpReplacePatchableBranch32WithPatch()2929     static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
2930 
startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)2931     static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
2932     {
2933         return label.labelAtOffset(0);
2934     }
2935 
startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)2936     static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
2937     {
2938         UNREACHABLE_FOR_PLATFORM();
2939         return CodeLocationLabel();
2940     }
2941 
startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32)2942     static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32)
2943     {
2944         UNREACHABLE_FOR_PLATFORM();
2945         return CodeLocationLabel();
2946     }
2947 
revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart,RegisterID,void * initialValue)2948     static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue)
2949     {
2950         reemitInitialMoveWithPatch(instructionStart.dataLocation(), initialValue);
2951     }
2952 
revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel,Address,void *)2953     static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
2954     {
2955         UNREACHABLE_FOR_PLATFORM();
2956     }
2957 
revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel,Address,int32_t)2958     static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t)
2959     {
2960         UNREACHABLE_FOR_PLATFORM();
2961     }
2962 
repatchCall(CodeLocationCall call,CodeLocationLabel destination)2963     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
2964     {
2965         ARM64Assembler::repatchPointer(call.dataLabelPtrAtOffset(REPATCH_OFFSET_CALL_TO_POINTER).dataLocation(), destination.executableAddress());
2966     }
2967 
repatchCall(CodeLocationCall call,FunctionPtr destination)2968     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
2969     {
2970         ARM64Assembler::repatchPointer(call.dataLabelPtrAtOffset(REPATCH_OFFSET_CALL_TO_POINTER).dataLocation(), destination.executableAddress());
2971     }
2972 
2973 #if ENABLE(MASM_PROBE)
2974     void probe(ProbeFunction, void* arg1, void* arg2);
2975 #endif // ENABLE(MASM_PROBE)
2976 
2977 protected:
makeBranch(ARM64Assembler::Condition cond)2978     ALWAYS_INLINE Jump makeBranch(ARM64Assembler::Condition cond)
2979     {
2980         m_assembler.b_cond(cond);
2981         AssemblerLabel label = m_assembler.label();
2982         m_assembler.nop();
2983         return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpConditionFixedSize : ARM64Assembler::JumpCondition, cond);
2984     }
makeBranch(RelationalCondition cond)2985     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(ARM64Condition(cond)); }
makeBranch(ResultCondition cond)2986     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(ARM64Condition(cond)); }
makeBranch(DoubleCondition cond)2987     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(ARM64Condition(cond)); }
2988 
2989     template <int dataSize>
makeCompareAndBranch(ZeroCondition cond,RegisterID reg)2990     ALWAYS_INLINE Jump makeCompareAndBranch(ZeroCondition cond, RegisterID reg)
2991     {
2992         if (cond == IsZero)
2993             m_assembler.cbz<dataSize>(reg);
2994         else
2995             m_assembler.cbnz<dataSize>(reg);
2996         AssemblerLabel label = m_assembler.label();
2997         m_assembler.nop();
2998         return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpCompareAndBranchFixedSize : ARM64Assembler::JumpCompareAndBranch, static_cast<ARM64Assembler::Condition>(cond), dataSize == 64, reg);
2999     }
3000 
makeTestBitAndBranch(RegisterID reg,unsigned bit,ZeroCondition cond)3001     ALWAYS_INLINE Jump makeTestBitAndBranch(RegisterID reg, unsigned bit, ZeroCondition cond)
3002     {
3003         ASSERT(bit < 64);
3004         bit &= 0x3f;
3005         if (cond == IsZero)
3006             m_assembler.tbz(reg, bit);
3007         else
3008             m_assembler.tbnz(reg, bit);
3009         AssemblerLabel label = m_assembler.label();
3010         m_assembler.nop();
3011         return Jump(label, m_makeJumpPatchable ? ARM64Assembler::JumpTestBitFixedSize : ARM64Assembler::JumpTestBit, static_cast<ARM64Assembler::Condition>(cond), bit, reg);
3012     }
3013 
ARM64Condition(RelationalCondition cond)3014     ARM64Assembler::Condition ARM64Condition(RelationalCondition cond)
3015     {
3016         return static_cast<ARM64Assembler::Condition>(cond);
3017     }
3018 
ARM64Condition(ResultCondition cond)3019     ARM64Assembler::Condition ARM64Condition(ResultCondition cond)
3020     {
3021         return static_cast<ARM64Assembler::Condition>(cond);
3022     }
3023 
ARM64Condition(DoubleCondition cond)3024     ARM64Assembler::Condition ARM64Condition(DoubleCondition cond)
3025     {
3026         return static_cast<ARM64Assembler::Condition>(cond);
3027     }
3028 
3029 private:
getCachedDataTempRegisterIDAndInvalidate()3030     ALWAYS_INLINE RegisterID getCachedDataTempRegisterIDAndInvalidate()
3031     {
3032         RELEASE_ASSERT(m_allowScratchRegister);
3033         return m_dataMemoryTempRegister.registerIDInvalidate();
3034     }
getCachedMemoryTempRegisterIDAndInvalidate()3035     ALWAYS_INLINE RegisterID getCachedMemoryTempRegisterIDAndInvalidate()
3036     {
3037         RELEASE_ASSERT(m_allowScratchRegister);
3038         return m_cachedMemoryTempRegister.registerIDInvalidate();
3039     }
3040 
isInIntRange(int64_t value)3041     ALWAYS_INLINE bool isInIntRange(int64_t value)
3042     {
3043         return value == ((value << 32) >> 32);
3044     }
3045 
3046     template<typename ImmediateType, typename rawType>
moveInternal(ImmediateType imm,RegisterID dest)3047     void moveInternal(ImmediateType imm, RegisterID dest)
3048     {
3049         const int dataSize = sizeof(rawType) * 8;
3050         const int numberHalfWords = dataSize / 16;
3051         rawType value = bitwise_cast<rawType>(imm.m_value);
3052         uint16_t halfword[numberHalfWords];
3053 
3054         // Handle 0 and ~0 here to simplify code below
3055         if (!value) {
3056             m_assembler.movz<dataSize>(dest, 0);
3057             return;
3058         }
3059         if (!~value) {
3060             m_assembler.movn<dataSize>(dest, 0);
3061             return;
3062         }
3063 
3064         LogicalImmediate logicalImm = dataSize == 64 ? LogicalImmediate::create64(static_cast<uint64_t>(value)) : LogicalImmediate::create32(static_cast<uint32_t>(value));
3065 
3066         if (logicalImm.isValid()) {
3067             m_assembler.movi<dataSize>(dest, logicalImm);
3068             return;
3069         }
3070 
3071         // Figure out how many halfwords are 0 or FFFF, then choose movz or movn accordingly.
3072         int zeroOrNegateVote = 0;
3073         for (int i = 0; i < numberHalfWords; ++i) {
3074             halfword[i] = getHalfword(value, i);
3075             if (!halfword[i])
3076                 zeroOrNegateVote++;
3077             else if (halfword[i] == 0xffff)
3078                 zeroOrNegateVote--;
3079         }
3080 
3081         bool needToClearRegister = true;
3082         if (zeroOrNegateVote >= 0) {
3083             for (int i = 0; i < numberHalfWords; i++) {
3084                 if (halfword[i]) {
3085                     if (needToClearRegister) {
3086                         m_assembler.movz<dataSize>(dest, halfword[i], 16*i);
3087                         needToClearRegister = false;
3088                     } else
3089                         m_assembler.movk<dataSize>(dest, halfword[i], 16*i);
3090                 }
3091             }
3092         } else {
3093             for (int i = 0; i < numberHalfWords; i++) {
3094                 if (halfword[i] != 0xffff) {
3095                     if (needToClearRegister) {
3096                         m_assembler.movn<dataSize>(dest, ~halfword[i], 16*i);
3097                         needToClearRegister = false;
3098                     } else
3099                         m_assembler.movk<dataSize>(dest, halfword[i], 16*i);
3100                 }
3101             }
3102         }
3103     }
3104 
3105     template<int datasize>
3106     void loadUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm);
3107 
3108     template<int datasize>
3109     void loadUnscaledImmediate(RegisterID rt, RegisterID rn, int simm);
3110 
3111     template<int datasize>
3112     void loadSignedAddressedByUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm);
3113 
3114     template<int datasize>
3115     void loadSignedAddressedByUnscaledImmediate(RegisterID rt, RegisterID rn, int simm);
3116 
3117     template<int datasize>
3118     void storeUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm);
3119 
3120     template<int datasize>
3121     void storeUnscaledImmediate(RegisterID rt, RegisterID rn, int simm);
3122 
moveWithFixedWidth(TrustedImm32 imm,RegisterID dest)3123     void moveWithFixedWidth(TrustedImm32 imm, RegisterID dest)
3124     {
3125         int32_t value = imm.m_value;
3126         m_assembler.movz<32>(dest, getHalfword(value, 0));
3127         m_assembler.movk<32>(dest, getHalfword(value, 1), 16);
3128     }
3129 
moveWithFixedWidth(TrustedImmPtr imm,RegisterID dest)3130     void moveWithFixedWidth(TrustedImmPtr imm, RegisterID dest)
3131     {
3132         intptr_t value = reinterpret_cast<intptr_t>(imm.m_value);
3133         m_assembler.movz<64>(dest, getHalfword(value, 0));
3134         m_assembler.movk<64>(dest, getHalfword(value, 1), 16);
3135         m_assembler.movk<64>(dest, getHalfword(value, 2), 32);
3136     }
3137 
signExtend32ToPtrWithFixedWidth(int32_t value,RegisterID dest)3138     void signExtend32ToPtrWithFixedWidth(int32_t value, RegisterID dest)
3139     {
3140         if (value >= 0) {
3141             m_assembler.movz<32>(dest, getHalfword(value, 0));
3142             m_assembler.movk<32>(dest, getHalfword(value, 1), 16);
3143         } else {
3144             m_assembler.movn<32>(dest, ~getHalfword(value, 0));
3145             m_assembler.movk<32>(dest, getHalfword(value, 1), 16);
3146         }
3147     }
3148 
3149     template<int datasize>
load(const void * address,RegisterID dest)3150     ALWAYS_INLINE void load(const void* address, RegisterID dest)
3151     {
3152         intptr_t currentRegisterContents;
3153         if (m_cachedMemoryTempRegister.value(currentRegisterContents)) {
3154             intptr_t addressAsInt = reinterpret_cast<intptr_t>(address);
3155             intptr_t addressDelta = addressAsInt - currentRegisterContents;
3156 
3157             if (dest == memoryTempRegister)
3158                 m_cachedMemoryTempRegister.invalidate();
3159 
3160             if (isInIntRange(addressDelta)) {
3161                 if (ARM64Assembler::canEncodeSImmOffset(addressDelta)) {
3162                     m_assembler.ldur<datasize>(dest,  memoryTempRegister, addressDelta);
3163                     return;
3164                 }
3165 
3166                 if (ARM64Assembler::canEncodePImmOffset<datasize>(addressDelta)) {
3167                     m_assembler.ldr<datasize>(dest,  memoryTempRegister, addressDelta);
3168                     return;
3169                 }
3170             }
3171 
3172             if ((addressAsInt & (~maskHalfWord0)) == (currentRegisterContents & (~maskHalfWord0))) {
3173                 m_assembler.movk<64>(memoryTempRegister, addressAsInt & maskHalfWord0, 0);
3174                 m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
3175                 m_assembler.ldr<datasize>(dest, memoryTempRegister, ARM64Registers::zr);
3176                 return;
3177             }
3178         }
3179 
3180         move(TrustedImmPtr(address), memoryTempRegister);
3181         if (dest == memoryTempRegister)
3182             m_cachedMemoryTempRegister.invalidate();
3183         else
3184             m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
3185         m_assembler.ldr<datasize>(dest, memoryTempRegister, ARM64Registers::zr);
3186     }
3187 
3188     template<int datasize>
store(RegisterID src,const void * address)3189     ALWAYS_INLINE void store(RegisterID src, const void* address)
3190     {
3191         ASSERT(src != memoryTempRegister);
3192         intptr_t currentRegisterContents;
3193         if (m_cachedMemoryTempRegister.value(currentRegisterContents)) {
3194             intptr_t addressAsInt = reinterpret_cast<intptr_t>(address);
3195             intptr_t addressDelta = addressAsInt - currentRegisterContents;
3196 
3197             if (isInIntRange(addressDelta)) {
3198                 if (ARM64Assembler::canEncodeSImmOffset(addressDelta)) {
3199                     m_assembler.stur<datasize>(src, memoryTempRegister, addressDelta);
3200                     return;
3201                 }
3202 
3203                 if (ARM64Assembler::canEncodePImmOffset<datasize>(addressDelta)) {
3204                     m_assembler.str<datasize>(src, memoryTempRegister, addressDelta);
3205                     return;
3206                 }
3207             }
3208 
3209             if ((addressAsInt & (~maskHalfWord0)) == (currentRegisterContents & (~maskHalfWord0))) {
3210                 m_assembler.movk<64>(memoryTempRegister, addressAsInt & maskHalfWord0, 0);
3211                 m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
3212                 m_assembler.str<datasize>(src, memoryTempRegister, ARM64Registers::zr);
3213                 return;
3214             }
3215         }
3216 
3217         move(TrustedImmPtr(address), memoryTempRegister);
3218         m_cachedMemoryTempRegister.setValue(reinterpret_cast<intptr_t>(address));
3219         m_assembler.str<datasize>(src, memoryTempRegister, ARM64Registers::zr);
3220     }
3221 
3222     template <int dataSize>
tryMoveUsingCacheRegisterContents(intptr_t immediate,CachedTempRegister & dest)3223     ALWAYS_INLINE bool tryMoveUsingCacheRegisterContents(intptr_t immediate, CachedTempRegister& dest)
3224     {
3225 #if 1
3226         Q_UNUSED(immediate);
3227         Q_UNUSED(dest)
3228 #else
3229         intptr_t currentRegisterContents;
3230         if (dest.value(currentRegisterContents)) {
3231             if (currentRegisterContents == immediate)
3232                 return true;
3233 
3234             LogicalImmediate logicalImm = dataSize == 64 ? LogicalImmediate::create64(static_cast<uint64_t>(immediate)) : LogicalImmediate::create32(static_cast<uint32_t>(immediate));
3235 
3236             if (logicalImm.isValid()) {
3237                 m_assembler.movi<dataSize>(dest.registerIDNoInvalidate(), logicalImm);
3238                 dest.setValue(immediate);
3239                 return true;
3240             }
3241 
3242             if ((immediate & maskUpperWord) == (currentRegisterContents & maskUpperWord)) {
3243                 if ((immediate & maskHalfWord1) != (currentRegisterContents & maskHalfWord1))
3244                     m_assembler.movk<dataSize>(dest.registerIDNoInvalidate(), (immediate & maskHalfWord1) >> 16, 16);
3245 
3246                 if ((immediate & maskHalfWord0) != (currentRegisterContents & maskHalfWord0))
3247                     m_assembler.movk<dataSize>(dest.registerIDNoInvalidate(), immediate & maskHalfWord0, 0);
3248 
3249                 dest.setValue(immediate);
3250                 return true;
3251             }
3252         }
3253 #endif
3254 
3255         return false;
3256     }
3257 
moveToCachedReg(TrustedImm32 imm,CachedTempRegister & dest)3258     void moveToCachedReg(TrustedImm32 imm, CachedTempRegister& dest)
3259     {
3260         if (tryMoveUsingCacheRegisterContents<32>(static_cast<intptr_t>(imm.m_value), dest))
3261             return;
3262 
3263         moveInternal<TrustedImm32, int32_t>(imm, dest.registerIDNoInvalidate());
3264         dest.setValue(imm.m_value);
3265     }
3266 
moveToCachedReg(TrustedImmPtr imm,CachedTempRegister & dest)3267     void moveToCachedReg(TrustedImmPtr imm, CachedTempRegister& dest)
3268     {
3269         if (tryMoveUsingCacheRegisterContents<64>(imm.asIntptr(), dest))
3270             return;
3271 
3272         moveInternal<TrustedImmPtr, intptr_t>(imm, dest.registerIDNoInvalidate());
3273         dest.setValue(imm.asIntptr());
3274     }
3275 
moveToCachedReg(TrustedImm64 imm,CachedTempRegister & dest)3276     void moveToCachedReg(TrustedImm64 imm, CachedTempRegister& dest)
3277     {
3278         if (tryMoveUsingCacheRegisterContents<64>(static_cast<intptr_t>(imm.m_value), dest))
3279             return;
3280 
3281         moveInternal<TrustedImm64, int64_t>(imm, dest.registerIDNoInvalidate());
3282         dest.setValue(imm.m_value);
3283     }
3284 
3285     template<int datasize>
3286     bool tryLoadWithOffset(RegisterID rt, RegisterID rn, int32_t offset);
3287 
3288     template<int datasize>
3289     bool tryLoadSignedWithOffset(RegisterID rt, RegisterID rn, int32_t offset);
3290 
3291     template<int datasize>
3292     bool tryLoadWithOffset(FPRegisterID rt, RegisterID rn, int32_t offset);
3293 
3294     template<int datasize>
3295     bool tryStoreWithOffset(RegisterID rt, RegisterID rn, int32_t offset);
3296 
3297     template<int datasize>
3298     bool tryStoreWithOffset(FPRegisterID rt, RegisterID rn, int32_t offset);
3299 
jumpAfterFloatingPointCompare(DoubleCondition cond)3300     Jump jumpAfterFloatingPointCompare(DoubleCondition cond)
3301     {
3302         if (cond == DoubleNotEqual) {
3303             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
3304             Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
3305             Jump result = makeBranch(ARM64Assembler::ConditionNE);
3306             unordered.link(this);
3307             return result;
3308         }
3309         if (cond == DoubleEqualOrUnordered) {
3310             Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
3311             Jump notEqual = makeBranch(ARM64Assembler::ConditionNE);
3312             unordered.link(this);
3313             // We get here if either unordered or equal.
3314             Jump result = jump();
3315             notEqual.link(this);
3316             return result;
3317         }
3318         return makeBranch(cond);
3319     }
3320 
3321     template <typename, template <typename> class> friend class LinkBufferBase;
3322     template <typename> friend class BranchCompactingLinkBuffer;
3323     template <typename> friend struct BranchCompactingExecutableOffsetCalculator;
recordLinkOffsets(int32_t regionStart,int32_t regionEnd,int32_t offset)3324     void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
executableOffsetFor(int location)3325     int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); }
3326 
linkCall(void * code,Call call,FunctionPtr function)3327     static void linkCall(void* code, Call call, FunctionPtr function)
3328     {
3329         if (!call.isFlagSet(Call::Near))
3330             ARM64Assembler::linkPointer(code, call.m_label.labelAtOffset(REPATCH_OFFSET_CALL_TO_POINTER), function.value());
3331 #if 0
3332         else if (call.isFlagSet(Call::Tail))
3333             ARM64Assembler::linkJump(code, call.m_label, function.value());
3334 #endif
3335         else
3336             ARM64Assembler::linkCall(code, call.m_label, function.value());
3337     }
3338 
3339     CachedTempRegister m_dataMemoryTempRegister;
3340     CachedTempRegister m_cachedMemoryTempRegister;
3341     bool m_makeJumpPatchable;
3342     bool m_allowScratchRegister = true;
3343 };
3344 
3345 template<int datasize>
loadUnsignedImmediate(RegisterID rt,RegisterID rn,unsigned pimm)3346 ALWAYS_INLINE void MacroAssemblerARM64::loadUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm)
3347 {
3348     m_assembler.ldr<datasize>(rt, rn, pimm);
3349 }
3350 
3351 template<int datasize>
loadUnscaledImmediate(RegisterID rt,RegisterID rn,int simm)3352 ALWAYS_INLINE void MacroAssemblerARM64::loadUnscaledImmediate(RegisterID rt, RegisterID rn, int simm)
3353 {
3354     m_assembler.ldur<datasize>(rt, rn, simm);
3355 }
3356 
3357 template<int datasize>
loadSignedAddressedByUnsignedImmediate(RegisterID rt,RegisterID rn,unsigned pimm)3358 ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm)
3359 {
3360     loadUnsignedImmediate<datasize>(rt, rn, pimm);
3361 }
3362 
3363 template<int datasize>
loadSignedAddressedByUnscaledImmediate(RegisterID rt,RegisterID rn,int simm)3364 ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnscaledImmediate(RegisterID rt, RegisterID rn, int simm)
3365 {
3366     loadUnscaledImmediate<datasize>(rt, rn, simm);
3367 }
3368 
3369 template<int datasize>
storeUnsignedImmediate(RegisterID rt,RegisterID rn,unsigned pimm)3370 ALWAYS_INLINE void MacroAssemblerARM64::storeUnsignedImmediate(RegisterID rt, RegisterID rn, unsigned pimm)
3371 {
3372     m_assembler.str<datasize>(rt, rn, pimm);
3373 }
3374 
3375 template<int datasize>
storeUnscaledImmediate(RegisterID rt,RegisterID rn,int simm)3376 ALWAYS_INLINE void MacroAssemblerARM64::storeUnscaledImmediate(RegisterID rt, RegisterID rn, int simm)
3377 {
3378     m_assembler.stur<datasize>(rt, rn, simm);
3379 }
3380 
3381 
3382 // Extend the {load,store}{Unsigned,Unscaled}Immediate templated general register methods to cover all load/store sizes
3383 template<>
3384 ALWAYS_INLINE void MacroAssemblerARM64::loadUnsignedImmediate<8>(RegisterID rt, RegisterID rn, unsigned pimm)
3385 {
3386     m_assembler.ldrb(rt, rn, pimm);
3387 }
3388 
3389 template<>
3390 ALWAYS_INLINE void MacroAssemblerARM64::loadUnsignedImmediate<16>(RegisterID rt, RegisterID rn, unsigned pimm)
3391 {
3392     m_assembler.ldrh(rt, rn, pimm);
3393 }
3394 
3395 template<>
3396 ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnsignedImmediate<8>(RegisterID rt, RegisterID rn, unsigned pimm)
3397 {
3398     m_assembler.ldrsb<64>(rt, rn, pimm);
3399 }
3400 
3401 template<>
3402 ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnsignedImmediate<16>(RegisterID rt, RegisterID rn, unsigned pimm)
3403 {
3404     m_assembler.ldrsh<64>(rt, rn, pimm);
3405 }
3406 
3407 template<>
3408 ALWAYS_INLINE void MacroAssemblerARM64::loadUnscaledImmediate<8>(RegisterID rt, RegisterID rn, int simm)
3409 {
3410     m_assembler.ldurb(rt, rn, simm);
3411 }
3412 
3413 template<>
3414 ALWAYS_INLINE void MacroAssemblerARM64::loadUnscaledImmediate<16>(RegisterID rt, RegisterID rn, int simm)
3415 {
3416     m_assembler.ldurh(rt, rn, simm);
3417 }
3418 
3419 template<>
3420 ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnscaledImmediate<8>(RegisterID rt, RegisterID rn, int simm)
3421 {
3422     m_assembler.ldursb<64>(rt, rn, simm);
3423 }
3424 
3425 template<>
3426 ALWAYS_INLINE void MacroAssemblerARM64::loadSignedAddressedByUnscaledImmediate<16>(RegisterID rt, RegisterID rn, int simm)
3427 {
3428     m_assembler.ldursh<64>(rt, rn, simm);
3429 }
3430 
3431 template<>
3432 ALWAYS_INLINE void MacroAssemblerARM64::storeUnsignedImmediate<8>(RegisterID rt, RegisterID rn, unsigned pimm)
3433 {
3434     m_assembler.strb(rt, rn, pimm);
3435 }
3436 
3437 template<>
3438 ALWAYS_INLINE void MacroAssemblerARM64::storeUnsignedImmediate<16>(RegisterID rt, RegisterID rn, unsigned pimm)
3439 {
3440     m_assembler.strh(rt, rn, pimm);
3441 }
3442 
3443 template<>
3444 ALWAYS_INLINE void MacroAssemblerARM64::storeUnscaledImmediate<8>(RegisterID rt, RegisterID rn, int simm)
3445 {
3446     m_assembler.sturb(rt, rn, simm);
3447 }
3448 
3449 template<>
3450 ALWAYS_INLINE void MacroAssemblerARM64::storeUnscaledImmediate<16>(RegisterID rt, RegisterID rn, int simm)
3451 {
3452     m_assembler.sturh(rt, rn, simm);
3453 }
3454 
3455 template<int datasize>
tryLoadSignedWithOffset(RegisterID rt,RegisterID rn,int32_t offset)3456 ALWAYS_INLINE bool MacroAssemblerARM64::tryLoadSignedWithOffset(RegisterID rt, RegisterID rn, int32_t offset)
3457 {
3458     if (ARM64Assembler::canEncodeSImmOffset(offset)) {
3459         loadSignedAddressedByUnscaledImmediate<datasize>(rt, rn, offset);
3460         return true;
3461     }
3462     if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
3463         loadSignedAddressedByUnsignedImmediate<datasize>(rt, rn, static_cast<unsigned>(offset));
3464         return true;
3465     }
3466     return false;
3467 }
3468 
3469 template<int datasize>
tryStoreWithOffset(RegisterID rt,RegisterID rn,int32_t offset)3470 ALWAYS_INLINE bool MacroAssemblerARM64::tryStoreWithOffset(RegisterID rt, RegisterID rn, int32_t offset)
3471 {
3472     if (ARM64Assembler::canEncodeSImmOffset(offset)) {
3473         storeUnscaledImmediate<datasize>(rt, rn, offset);
3474         return true;
3475     }
3476     if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
3477         storeUnsignedImmediate<datasize>(rt, rn, static_cast<unsigned>(offset));
3478         return true;
3479     }
3480     return false;
3481 }
3482 
3483 template<int datasize>
tryStoreWithOffset(FPRegisterID rt,RegisterID rn,int32_t offset)3484 ALWAYS_INLINE bool MacroAssemblerARM64::tryStoreWithOffset(FPRegisterID rt, RegisterID rn, int32_t offset)
3485 {
3486     if (ARM64Assembler::canEncodeSImmOffset(offset)) {
3487         m_assembler.stur<datasize>(rt, rn, offset);
3488         return true;
3489     }
3490     if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
3491         m_assembler.str<datasize>(rt, rn, static_cast<unsigned>(offset));
3492         return true;
3493     }
3494     return false;
3495 }
3496 
3497 
3498 template<int datasize>
tryLoadWithOffset(RegisterID rt,RegisterID rn,int32_t offset)3499 ALWAYS_INLINE bool MacroAssemblerARM64::tryLoadWithOffset(RegisterID rt, RegisterID rn, int32_t offset)
3500 {
3501     if (ARM64Assembler::canEncodeSImmOffset(offset)) {
3502         loadUnscaledImmediate<datasize>(rt, rn, offset);
3503         return true;
3504     }
3505     if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
3506         loadUnsignedImmediate<datasize>(rt, rn, static_cast<unsigned>(offset));
3507         return true;
3508     }
3509     return false;
3510 }
3511 
3512 template<int datasize>
tryLoadWithOffset(FPRegisterID rt,RegisterID rn,int32_t offset)3513 ALWAYS_INLINE bool MacroAssemblerARM64::tryLoadWithOffset(FPRegisterID rt, RegisterID rn, int32_t offset)
3514     {
3515         if (ARM64Assembler::canEncodeSImmOffset(offset)) {
3516             m_assembler.ldur<datasize>(rt, rn, offset);
3517             return true;
3518         }
3519         if (ARM64Assembler::canEncodePImmOffset<datasize>(offset)) {
3520             m_assembler.ldr<datasize>(rt, rn, static_cast<unsigned>(offset));
3521             return true;
3522         }
3523         return false;
3524     }
3525 
3526 } // namespace JSC
3527 
3528 #endif // ENABLE(ASSEMBLER)
3529 
3530 #endif // MacroAssemblerARM64_h
3531