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