• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #ifndef MacroAssemblerARMv7_h
27 #define MacroAssemblerARMv7_h
28 
29 #include <wtf/Platform.h>
30 
31 #if ENABLE(ASSEMBLER)
32 
33 #include "ARMv7Assembler.h"
34 #include "AbstractMacroAssembler.h"
35 
36 namespace JSC {
37 
38 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
39     // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
40     //        - dTR is likely used more than aTR, and we'll get better instruction
41     //        encoding if it's in the low 8 registers.
42     static const ARM::RegisterID dataTempRegister = ARM::ip;
43     static const RegisterID addressTempRegister = ARM::r3;
44     static const FPRegisterID fpTempRegister = ARM::d7;
45 
46     struct ArmAddress {
47         enum AddressType {
48             HasOffset,
49             HasIndex,
50         } type;
51         RegisterID base;
52         union {
53             int32_t offset;
54             struct {
55                 RegisterID index;
56                 Scale scale;
57             };
58         } u;
59 
60         explicit ArmAddress(RegisterID base, int32_t offset = 0)
typeArmAddress61             : type(HasOffset)
62             , base(base)
63         {
64             u.offset = offset;
65         }
66 
67         explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
typeArmAddress68             : type(HasIndex)
69             , base(base)
70         {
71             u.index = index;
72             u.scale = scale;
73         }
74     };
75 
76 public:
77 
78     static const Scale ScalePtr = TimesFour;
79 
80     enum Condition {
81         Equal = ARMv7Assembler::ConditionEQ,
82         NotEqual = ARMv7Assembler::ConditionNE,
83         Above = ARMv7Assembler::ConditionHI,
84         AboveOrEqual = ARMv7Assembler::ConditionHS,
85         Below = ARMv7Assembler::ConditionLO,
86         BelowOrEqual = ARMv7Assembler::ConditionLS,
87         GreaterThan = ARMv7Assembler::ConditionGT,
88         GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
89         LessThan = ARMv7Assembler::ConditionLT,
90         LessThanOrEqual = ARMv7Assembler::ConditionLE,
91         Overflow = ARMv7Assembler::ConditionVS,
92         Signed = ARMv7Assembler::ConditionMI,
93         Zero = ARMv7Assembler::ConditionEQ,
94         NonZero = ARMv7Assembler::ConditionNE
95     };
96 
97     enum DoubleCondition {
98         DoubleEqual = ARMv7Assembler::ConditionEQ,
99         DoubleGreaterThan = ARMv7Assembler::ConditionGT,
100         DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
101         DoubleLessThan = ARMv7Assembler::ConditionLO,
102         DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
103     };
104 
105     static const RegisterID stackPointerRegister = ARM::sp;
106     static const RegisterID linkRegister = ARM::lr;
107 
108     // Integer arithmetic operations:
109     //
110     // Operations are typically two operand - operation(source, srcDst)
111     // For many operations the source may be an Imm32, the srcDst operand
112     // may often be a memory location (explictly described using an Address
113     // object).
114 
add32(RegisterID src,RegisterID dest)115     void add32(RegisterID src, RegisterID dest)
116     {
117         m_assembler.add(dest, dest, src);
118     }
119 
add32(Imm32 imm,RegisterID dest)120     void add32(Imm32 imm, RegisterID dest)
121     {
122         add32(imm, dest, dest);
123     }
124 
add32(Imm32 imm,RegisterID src,RegisterID dest)125     void add32(Imm32 imm, RegisterID src, RegisterID dest)
126     {
127         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
128         if (armImm.isValid())
129             m_assembler.add(dest, src, armImm);
130         else {
131             move(imm, dataTempRegister);
132             m_assembler.add(dest, src, dataTempRegister);
133         }
134     }
135 
add32(Imm32 imm,Address address)136     void add32(Imm32 imm, Address address)
137     {
138         load32(address, dataTempRegister);
139 
140         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
141         if (armImm.isValid())
142             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
143         else {
144             // Hrrrm, since dataTempRegister holds the data loaded,
145             // use addressTempRegister to hold the immediate.
146             move(imm, addressTempRegister);
147             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
148         }
149 
150         store32(dataTempRegister, address);
151     }
152 
add32(Address src,RegisterID dest)153     void add32(Address src, RegisterID dest)
154     {
155         load32(src, dataTempRegister);
156         add32(dataTempRegister, dest);
157     }
158 
add32(Imm32 imm,AbsoluteAddress address)159     void add32(Imm32 imm, AbsoluteAddress address)
160     {
161         load32(address.m_ptr, dataTempRegister);
162 
163         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
164         if (armImm.isValid())
165             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
166         else {
167             // Hrrrm, since dataTempRegister holds the data loaded,
168             // use addressTempRegister to hold the immediate.
169             move(imm, addressTempRegister);
170             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
171         }
172 
173         store32(dataTempRegister, address.m_ptr);
174     }
175 
and32(RegisterID src,RegisterID dest)176     void and32(RegisterID src, RegisterID dest)
177     {
178         m_assembler.ARM_and(dest, dest, src);
179     }
180 
and32(Imm32 imm,RegisterID dest)181     void and32(Imm32 imm, RegisterID dest)
182     {
183         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
184         if (armImm.isValid())
185             m_assembler.ARM_and(dest, dest, armImm);
186         else {
187             move(imm, dataTempRegister);
188             m_assembler.ARM_and(dest, dest, dataTempRegister);
189         }
190     }
191 
lshift32(Imm32 imm,RegisterID dest)192     void lshift32(Imm32 imm, RegisterID dest)
193     {
194         m_assembler.lsl(dest, dest, imm.m_value);
195     }
196 
lshift32(RegisterID shift_amount,RegisterID dest)197     void lshift32(RegisterID shift_amount, RegisterID dest)
198     {
199         m_assembler.lsl(dest, dest, shift_amount);
200     }
201 
mul32(RegisterID src,RegisterID dest)202     void mul32(RegisterID src, RegisterID dest)
203     {
204         m_assembler.smull(dest, dataTempRegister, dest, src);
205     }
206 
mul32(Imm32 imm,RegisterID src,RegisterID dest)207     void mul32(Imm32 imm, RegisterID src, RegisterID dest)
208     {
209         move(imm, dataTempRegister);
210         m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
211     }
212 
not32(RegisterID srcDest)213     void not32(RegisterID srcDest)
214     {
215         m_assembler.mvn(srcDest, srcDest);
216     }
217 
or32(RegisterID src,RegisterID dest)218     void or32(RegisterID src, RegisterID dest)
219     {
220         m_assembler.orr(dest, dest, src);
221     }
222 
or32(Imm32 imm,RegisterID dest)223     void or32(Imm32 imm, RegisterID dest)
224     {
225         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
226         if (armImm.isValid())
227             m_assembler.orr(dest, dest, armImm);
228         else {
229             move(imm, dataTempRegister);
230             m_assembler.orr(dest, dest, dataTempRegister);
231         }
232     }
233 
rshift32(RegisterID shift_amount,RegisterID dest)234     void rshift32(RegisterID shift_amount, RegisterID dest)
235     {
236         m_assembler.asr(dest, dest, shift_amount);
237     }
238 
rshift32(Imm32 imm,RegisterID dest)239     void rshift32(Imm32 imm, RegisterID dest)
240     {
241         m_assembler.asr(dest, dest, imm.m_value);
242     }
243 
sub32(RegisterID src,RegisterID dest)244     void sub32(RegisterID src, RegisterID dest)
245     {
246         m_assembler.sub(dest, dest, src);
247     }
248 
sub32(Imm32 imm,RegisterID dest)249     void sub32(Imm32 imm, RegisterID dest)
250     {
251         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
252         if (armImm.isValid())
253             m_assembler.sub(dest, dest, armImm);
254         else {
255             move(imm, dataTempRegister);
256             m_assembler.sub(dest, dest, dataTempRegister);
257         }
258     }
259 
sub32(Imm32 imm,Address address)260     void sub32(Imm32 imm, Address address)
261     {
262         load32(address, dataTempRegister);
263 
264         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
265         if (armImm.isValid())
266             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
267         else {
268             // Hrrrm, since dataTempRegister holds the data loaded,
269             // use addressTempRegister to hold the immediate.
270             move(imm, addressTempRegister);
271             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
272         }
273 
274         store32(dataTempRegister, address);
275     }
276 
sub32(Address src,RegisterID dest)277     void sub32(Address src, RegisterID dest)
278     {
279         load32(src, dataTempRegister);
280         sub32(dataTempRegister, dest);
281     }
282 
sub32(Imm32 imm,AbsoluteAddress address)283     void sub32(Imm32 imm, AbsoluteAddress address)
284     {
285         load32(address.m_ptr, dataTempRegister);
286 
287         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
288         if (armImm.isValid())
289             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
290         else {
291             // Hrrrm, since dataTempRegister holds the data loaded,
292             // use addressTempRegister to hold the immediate.
293             move(imm, addressTempRegister);
294             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
295         }
296 
297         store32(dataTempRegister, address.m_ptr);
298     }
299 
xor32(RegisterID src,RegisterID dest)300     void xor32(RegisterID src, RegisterID dest)
301     {
302         m_assembler.eor(dest, dest, src);
303     }
304 
xor32(Imm32 imm,RegisterID dest)305     void xor32(Imm32 imm, RegisterID dest)
306     {
307         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
308         if (armImm.isValid())
309             m_assembler.eor(dest, dest, armImm);
310         else {
311             move(imm, dataTempRegister);
312             m_assembler.eor(dest, dest, dataTempRegister);
313         }
314     }
315 
316 
317     // Memory access operations:
318     //
319     // Loads are of the form load(address, destination) and stores of the form
320     // store(source, address).  The source for a store may be an Imm32.  Address
321     // operand objects to loads and store will be implicitly constructed if a
322     // register is passed.
323 
324 private:
load32(ArmAddress address,RegisterID dest)325     void load32(ArmAddress address, RegisterID dest)
326     {
327         if (address.type == ArmAddress::HasIndex)
328             m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
329         else if (address.u.offset >= 0) {
330             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
331             ASSERT(armImm.isValid());
332             m_assembler.ldr(dest, address.base, armImm);
333         } else {
334             ASSERT(address.u.offset >= -255);
335             m_assembler.ldr(dest, address.base, address.u.offset, true, false);
336         }
337     }
338 
load16(ArmAddress address,RegisterID dest)339     void load16(ArmAddress address, RegisterID dest)
340     {
341         if (address.type == ArmAddress::HasIndex)
342             m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
343         else if (address.u.offset >= 0) {
344             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
345             ASSERT(armImm.isValid());
346             m_assembler.ldrh(dest, address.base, armImm);
347         } else {
348             ASSERT(address.u.offset >= -255);
349             m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
350         }
351     }
352 
store32(RegisterID src,ArmAddress address)353     void store32(RegisterID src, ArmAddress address)
354     {
355         if (address.type == ArmAddress::HasIndex)
356             m_assembler.str(src, address.base, address.u.index, address.u.scale);
357         else if (address.u.offset >= 0) {
358             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
359             ASSERT(armImm.isValid());
360             m_assembler.str(src, address.base, armImm);
361         } else {
362             ASSERT(address.u.offset >= -255);
363             m_assembler.str(src, address.base, address.u.offset, true, false);
364         }
365     }
366 
367 public:
load32(ImplicitAddress address,RegisterID dest)368     void load32(ImplicitAddress address, RegisterID dest)
369     {
370         load32(setupArmAddress(address), dest);
371     }
372 
load32(BaseIndex address,RegisterID dest)373     void load32(BaseIndex address, RegisterID dest)
374     {
375         load32(setupArmAddress(address), dest);
376     }
377 
load32(void * address,RegisterID dest)378     void load32(void* address, RegisterID dest)
379     {
380         move(ImmPtr(address), addressTempRegister);
381         m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
382     }
383 
load32WithAddressOffsetPatch(Address address,RegisterID dest)384     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
385     {
386         DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister);
387         load32(ArmAddress(address.base, dataTempRegister), dest);
388         return label;
389     }
390 
loadPtrWithPatchToLEA(Address address,RegisterID dest)391     Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
392     {
393         Label label(this);
394         moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister);
395         load32(ArmAddress(address.base, dataTempRegister), dest);
396         return label;
397     }
398 
load16(BaseIndex address,RegisterID dest)399     void load16(BaseIndex address, RegisterID dest)
400     {
401         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
402     }
403 
store32WithAddressOffsetPatch(RegisterID src,Address address)404     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
405     {
406         DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister);
407         store32(src, ArmAddress(address.base, dataTempRegister));
408         return label;
409     }
410 
store32(RegisterID src,ImplicitAddress address)411     void store32(RegisterID src, ImplicitAddress address)
412     {
413         store32(src, setupArmAddress(address));
414     }
415 
store32(RegisterID src,BaseIndex address)416     void store32(RegisterID src, BaseIndex address)
417     {
418         store32(src, setupArmAddress(address));
419     }
420 
store32(Imm32 imm,ImplicitAddress address)421     void store32(Imm32 imm, ImplicitAddress address)
422     {
423         move(imm, dataTempRegister);
424         store32(dataTempRegister, setupArmAddress(address));
425     }
426 
store32(RegisterID src,void * address)427     void store32(RegisterID src, void* address)
428     {
429         move(ImmPtr(address), addressTempRegister);
430         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
431     }
432 
store32(Imm32 imm,void * address)433     void store32(Imm32 imm, void* address)
434     {
435         move(imm, dataTempRegister);
436         store32(dataTempRegister, address);
437     }
438 
439 
440     // Floating-point operations:
441 
supportsFloatingPoint()442     bool supportsFloatingPoint() const { return true; }
443     // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer.
444     // If a value is not representable as an integer, and possibly for some values that are,
445     // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input)
446     // a branch will  be taken.  It is not clear whether this interface will be well suited to
447     // other platforms.  On ARMv7 the hardware truncation operation produces multiple possible
448     // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0).  This is a
449     // temporary solution while we work out what this interface should be.  Either we need to
450     // decide to make this interface work on all platforms, rework the interface to make it more
451     // generic, or decide that the MacroAssembler cannot practically be used to abstracted these
452     // operations, and make clients go directly to the m_assembler to plant truncation instructions.
453     // In short, FIXME:.
supportsFloatingPointTruncate()454     bool supportsFloatingPointTruncate() const { return false; }
455 
loadDouble(ImplicitAddress address,FPRegisterID dest)456     void loadDouble(ImplicitAddress address, FPRegisterID dest)
457     {
458         RegisterID base = address.base;
459         int32_t offset = address.offset;
460 
461         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
462         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
463             add32(Imm32(offset), base, addressTempRegister);
464             base = addressTempRegister;
465             offset = 0;
466         }
467 
468         m_assembler.vldr(dest, base, offset);
469     }
470 
storeDouble(FPRegisterID src,ImplicitAddress address)471     void storeDouble(FPRegisterID src, ImplicitAddress address)
472     {
473         RegisterID base = address.base;
474         int32_t offset = address.offset;
475 
476         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
477         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
478             add32(Imm32(offset), base, addressTempRegister);
479             base = addressTempRegister;
480             offset = 0;
481         }
482 
483         m_assembler.vstr(src, base, offset);
484     }
485 
addDouble(FPRegisterID src,FPRegisterID dest)486     void addDouble(FPRegisterID src, FPRegisterID dest)
487     {
488         m_assembler.vadd_F64(dest, dest, src);
489     }
490 
addDouble(Address src,FPRegisterID dest)491     void addDouble(Address src, FPRegisterID dest)
492     {
493         loadDouble(src, fpTempRegister);
494         addDouble(fpTempRegister, dest);
495     }
496 
subDouble(FPRegisterID src,FPRegisterID dest)497     void subDouble(FPRegisterID src, FPRegisterID dest)
498     {
499         m_assembler.vsub_F64(dest, dest, src);
500     }
501 
subDouble(Address src,FPRegisterID dest)502     void subDouble(Address src, FPRegisterID dest)
503     {
504         loadDouble(src, fpTempRegister);
505         subDouble(fpTempRegister, dest);
506     }
507 
mulDouble(FPRegisterID src,FPRegisterID dest)508     void mulDouble(FPRegisterID src, FPRegisterID dest)
509     {
510         m_assembler.vmul_F64(dest, dest, src);
511     }
512 
mulDouble(Address src,FPRegisterID dest)513     void mulDouble(Address src, FPRegisterID dest)
514     {
515         loadDouble(src, fpTempRegister);
516         mulDouble(fpTempRegister, dest);
517     }
518 
convertInt32ToDouble(RegisterID src,FPRegisterID dest)519     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
520     {
521         m_assembler.vmov(fpTempRegister, src);
522         m_assembler.vcvt_F64_S32(dest, fpTempRegister);
523     }
524 
branchDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right)525     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
526     {
527         m_assembler.vcmp_F64(left, right);
528         m_assembler.vmrs_APSR_nzcv_FPSCR();
529         return makeBranch(cond);
530     }
531 
branchTruncateDoubleToInt32(FPRegisterID,RegisterID)532     Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID)
533     {
534         ASSERT_NOT_REACHED();
535     }
536 
537 
538     // Stack manipulation operations:
539     //
540     // The ABI is assumed to provide a stack abstraction to memory,
541     // containing machine word sized units of data.  Push and pop
542     // operations add and remove a single register sized unit of data
543     // to or from the stack.  Peek and poke operations read or write
544     // values on the stack, without moving the current stack position.
545 
pop(RegisterID dest)546     void pop(RegisterID dest)
547     {
548         // store postindexed with writeback
549         m_assembler.ldr(dest, ARM::sp, sizeof(void*), false, true);
550     }
551 
push(RegisterID src)552     void push(RegisterID src)
553     {
554         // store preindexed with writeback
555         m_assembler.str(src, ARM::sp, -sizeof(void*), true, true);
556     }
557 
push(Address address)558     void push(Address address)
559     {
560         load32(address, dataTempRegister);
561         push(dataTempRegister);
562     }
563 
push(Imm32 imm)564     void push(Imm32 imm)
565     {
566         move(imm, dataTempRegister);
567         push(dataTempRegister);
568     }
569 
570     // Register move operations:
571     //
572     // Move values in registers.
573 
move(Imm32 imm,RegisterID dest)574     void move(Imm32 imm, RegisterID dest)
575     {
576         uint32_t value = imm.m_value;
577 
578         if (imm.m_isPointer)
579             moveFixedWidthEncoding(imm, dest);
580         else {
581             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
582 
583             if (armImm.isValid())
584                 m_assembler.mov(dest, armImm);
585             else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
586                 m_assembler.mvn(dest, armImm);
587             else {
588                 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
589                 if (value & 0xffff0000)
590                     m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
591             }
592         }
593     }
594 
move(RegisterID src,RegisterID dest)595     void move(RegisterID src, RegisterID dest)
596     {
597         m_assembler.mov(dest, src);
598     }
599 
move(ImmPtr imm,RegisterID dest)600     void move(ImmPtr imm, RegisterID dest)
601     {
602         move(Imm32(imm), dest);
603     }
604 
swap(RegisterID reg1,RegisterID reg2)605     void swap(RegisterID reg1, RegisterID reg2)
606     {
607         move(reg1, dataTempRegister);
608         move(reg2, reg1);
609         move(dataTempRegister, reg2);
610     }
611 
signExtend32ToPtr(RegisterID src,RegisterID dest)612     void signExtend32ToPtr(RegisterID src, RegisterID dest)
613     {
614         if (src != dest)
615             move(src, dest);
616     }
617 
zeroExtend32ToPtr(RegisterID src,RegisterID dest)618     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
619     {
620         if (src != dest)
621             move(src, dest);
622     }
623 
624 
625     // Forwards / external control flow operations:
626     //
627     // This set of jump and conditional branch operations return a Jump
628     // object which may linked at a later point, allow forwards jump,
629     // or jumps that will require external linkage (after the code has been
630     // relocated).
631     //
632     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
633     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
634     // used (representing the names 'below' and 'above').
635     //
636     // Operands to the comparision are provided in the expected order, e.g.
637     // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
638     // treated as a signed 32bit value, is less than or equal to 5.
639     //
640     // jz and jnz test whether the first operand is equal to zero, and take
641     // an optional second operand of a mask under which to perform the test.
642 private:
643 
644     // Should we be using TEQ for equal/not-equal?
compare32(RegisterID left,Imm32 right)645     void compare32(RegisterID left, Imm32 right)
646     {
647         int32_t imm = right.m_value;
648         if (!imm)
649             m_assembler.tst(left, left);
650         else {
651             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
652             if (armImm.isValid())
653                 m_assembler.cmp(left, armImm);
654             if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
655                 m_assembler.cmn(left, armImm);
656             else {
657                 move(Imm32(imm), dataTempRegister);
658                 m_assembler.cmp(left, dataTempRegister);
659             }
660         }
661     }
662 
test32(RegisterID reg,Imm32 mask)663     void test32(RegisterID reg, Imm32 mask)
664     {
665         int32_t imm = mask.m_value;
666 
667         if (imm == -1)
668             m_assembler.tst(reg, reg);
669         else {
670             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
671             if (armImm.isValid())
672                 m_assembler.tst(reg, armImm);
673             else {
674                 move(mask, dataTempRegister);
675                 m_assembler.tst(reg, dataTempRegister);
676             }
677         }
678     }
679 
680 public:
branch32(Condition cond,RegisterID left,RegisterID right)681     Jump branch32(Condition cond, RegisterID left, RegisterID right)
682     {
683         m_assembler.cmp(left, right);
684         return Jump(makeBranch(cond));
685     }
686 
branch32(Condition cond,RegisterID left,Imm32 right)687     Jump branch32(Condition cond, RegisterID left, Imm32 right)
688     {
689         compare32(left, right);
690         return Jump(makeBranch(cond));
691     }
692 
branch32(Condition cond,RegisterID left,Address right)693     Jump branch32(Condition cond, RegisterID left, Address right)
694     {
695         load32(right, dataTempRegister);
696         return branch32(cond, left, dataTempRegister);
697     }
698 
branch32(Condition cond,Address left,RegisterID right)699     Jump branch32(Condition cond, Address left, RegisterID right)
700     {
701         load32(left, dataTempRegister);
702         return branch32(cond, dataTempRegister, right);
703     }
704 
branch32(Condition cond,Address left,Imm32 right)705     Jump branch32(Condition cond, Address left, Imm32 right)
706     {
707         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
708         load32(left, addressTempRegister);
709         return branch32(cond, addressTempRegister, right);
710     }
711 
branch32(Condition cond,BaseIndex left,Imm32 right)712     Jump branch32(Condition cond, BaseIndex left, Imm32 right)
713     {
714         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
715         load32(left, addressTempRegister);
716         return branch32(cond, addressTempRegister, right);
717     }
718 
branch32(Condition cond,AbsoluteAddress left,RegisterID right)719     Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
720     {
721         load32(left.m_ptr, dataTempRegister);
722         return branch32(cond, dataTempRegister, right);
723     }
724 
branch32(Condition cond,AbsoluteAddress left,Imm32 right)725     Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
726     {
727         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
728         load32(left.m_ptr, addressTempRegister);
729         return branch32(cond, addressTempRegister, right);
730     }
731 
branch16(Condition cond,BaseIndex left,RegisterID right)732     Jump branch16(Condition cond, BaseIndex left, RegisterID right)
733     {
734         load16(left, dataTempRegister);
735         m_assembler.lsl(addressTempRegister, right, 16);
736         m_assembler.lsl(dataTempRegister, dataTempRegister, 16);
737         return branch32(cond, dataTempRegister, addressTempRegister);
738     }
739 
branch16(Condition cond,BaseIndex left,Imm32 right)740     Jump branch16(Condition cond, BaseIndex left, Imm32 right)
741     {
742         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
743         load16(left, addressTempRegister);
744         m_assembler.lsl(addressTempRegister, addressTempRegister, 16);
745         return branch32(cond, addressTempRegister, Imm32(right.m_value << 16));
746     }
747 
branchTest32(Condition cond,RegisterID reg,RegisterID mask)748     Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
749     {
750         ASSERT((cond == Zero) || (cond == NonZero));
751         m_assembler.tst(reg, mask);
752         return Jump(makeBranch(cond));
753     }
754 
755     Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
756     {
757         ASSERT((cond == Zero) || (cond == NonZero));
758         test32(reg, mask);
759         return Jump(makeBranch(cond));
760     }
761 
762     Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
763     {
764         ASSERT((cond == Zero) || (cond == NonZero));
765         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
766         load32(address, addressTempRegister);
767         return branchTest32(cond, addressTempRegister, mask);
768     }
769 
770     Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
771     {
772         ASSERT((cond == Zero) || (cond == NonZero));
773         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
774         load32(address, addressTempRegister);
775         return branchTest32(cond, addressTempRegister, mask);
776     }
777 
jump()778     Jump jump()
779     {
780         return Jump(makeJump());
781     }
782 
jump(RegisterID target)783     void jump(RegisterID target)
784     {
785         m_assembler.bx(target);
786     }
787 
788     // Address is a memory location containing the address to jump to
jump(Address address)789     void jump(Address address)
790     {
791         load32(address, dataTempRegister);
792         m_assembler.bx(dataTempRegister);
793     }
794 
795 
796     // Arithmetic control flow operations:
797     //
798     // This set of conditional branch operations branch based
799     // on the result of an arithmetic operation.  The operation
800     // is performed as normal, storing the result.
801     //
802     // * jz operations branch if the result is zero.
803     // * jo operations branch if the (signed) arithmetic
804     //   operation caused an overflow to occur.
805 
branchAdd32(Condition cond,RegisterID src,RegisterID dest)806     Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
807     {
808         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
809         m_assembler.add_S(dest, dest, src);
810         return Jump(makeBranch(cond));
811     }
812 
branchAdd32(Condition cond,Imm32 imm,RegisterID dest)813     Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
814     {
815         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
816         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
817         if (armImm.isValid())
818             m_assembler.add_S(dest, dest, armImm);
819         else {
820             move(imm, dataTempRegister);
821             m_assembler.add_S(dest, dest, dataTempRegister);
822         }
823         return Jump(makeBranch(cond));
824     }
825 
branchMul32(Condition cond,RegisterID src,RegisterID dest)826     Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
827     {
828         ASSERT(cond == Overflow);
829         m_assembler.smull(dest, dataTempRegister, dest, src);
830         m_assembler.asr(addressTempRegister, dest, 31);
831         return branch32(NotEqual, addressTempRegister, dataTempRegister);
832     }
833 
branchMul32(Condition cond,Imm32 imm,RegisterID src,RegisterID dest)834     Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
835     {
836         ASSERT(cond == Overflow);
837         move(imm, dataTempRegister);
838         m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
839         m_assembler.asr(addressTempRegister, dest, 31);
840         return branch32(NotEqual, addressTempRegister, dataTempRegister);
841     }
842 
branchSub32(Condition cond,RegisterID src,RegisterID dest)843     Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
844     {
845         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
846         m_assembler.sub_S(dest, dest, src);
847         return Jump(makeBranch(cond));
848     }
849 
branchSub32(Condition cond,Imm32 imm,RegisterID dest)850     Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
851     {
852         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
853         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
854         if (armImm.isValid())
855             m_assembler.sub_S(dest, dest, armImm);
856         else {
857             move(imm, dataTempRegister);
858             m_assembler.sub_S(dest, dest, dataTempRegister);
859         }
860         return Jump(makeBranch(cond));
861     }
862 
863 
864     // Miscellaneous operations:
865 
breakpoint()866     void breakpoint()
867     {
868         m_assembler.bkpt();
869     }
870 
nearCall()871     Call nearCall()
872     {
873         moveFixedWidthEncoding(Imm32(0), dataTempRegister);
874         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
875     }
876 
call()877     Call call()
878     {
879         moveFixedWidthEncoding(Imm32(0), dataTempRegister);
880         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
881     }
882 
call(RegisterID target)883     Call call(RegisterID target)
884     {
885         return Call(m_assembler.blx(target), Call::None);
886     }
887 
call(Address address)888     Call call(Address address)
889     {
890         load32(address, dataTempRegister);
891         return Call(m_assembler.blx(dataTempRegister), Call::None);
892     }
893 
ret()894     void ret()
895     {
896         m_assembler.bx(linkRegister);
897     }
898 
set32(Condition cond,RegisterID left,RegisterID right,RegisterID dest)899     void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
900     {
901         m_assembler.cmp(left, right);
902         m_assembler.it(armV7Condition(cond), false);
903         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
904         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
905     }
906 
set32(Condition cond,RegisterID left,Imm32 right,RegisterID dest)907     void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
908     {
909         compare32(left, right);
910         m_assembler.it(armV7Condition(cond), false);
911         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
912         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
913     }
914 
915     // FIXME:
916     // The mask should be optional... paerhaps the argument order should be
917     // dest-src, operations always have a dest? ... possibly not true, considering
918     // asm ops like test, or pseudo ops like pop().
setTest32(Condition cond,Address address,Imm32 mask,RegisterID dest)919     void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
920     {
921         load32(address, dataTempRegister);
922         test32(dataTempRegister, mask);
923         m_assembler.it(armV7Condition(cond), false);
924         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
925         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
926     }
927 
928 
moveWithPatch(Imm32 imm,RegisterID dst)929     DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
930     {
931         moveFixedWidthEncoding(imm, dst);
932         return DataLabel32(this);
933     }
934 
moveWithPatch(ImmPtr imm,RegisterID dst)935     DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
936     {
937         moveFixedWidthEncoding(Imm32(imm), dst);
938         return DataLabelPtr(this);
939     }
940 
941     Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
942     {
943         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
944         return branch32(cond, left, dataTempRegister);
945     }
946 
947     Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
948     {
949         load32(left, addressTempRegister);
950         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
951         return branch32(cond, addressTempRegister, dataTempRegister);
952     }
953 
storePtrWithPatch(ImmPtr initialValue,ImplicitAddress address)954     DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
955     {
956         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
957         store32(dataTempRegister, address);
958         return label;
959     }
storePtrWithPatch(ImplicitAddress address)960     DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); }
961 
962 
tailRecursiveCall()963     Call tailRecursiveCall()
964     {
965         // Like a normal call, but don't link.
966         moveFixedWidthEncoding(Imm32(0), dataTempRegister);
967         return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
968     }
969 
makeTailRecursiveCall(Jump oldJump)970     Call makeTailRecursiveCall(Jump oldJump)
971     {
972         oldJump.link(this);
973         return tailRecursiveCall();
974     }
975 
976 
977 protected:
makeJump()978     ARMv7Assembler::JmpSrc makeJump()
979     {
980         return m_assembler.b();
981     }
982 
makeBranch(ARMv7Assembler::Condition cond)983     ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond)
984     {
985         m_assembler.it(cond);
986         return m_assembler.b();
987     }
makeBranch(Condition cond)988     ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); }
makeBranch(DoubleCondition cond)989     ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
990 
setupArmAddress(BaseIndex address)991     ArmAddress setupArmAddress(BaseIndex address)
992     {
993         if (address.offset) {
994             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
995             if (imm.isValid())
996                 m_assembler.add(addressTempRegister, address.base, imm);
997             else {
998                 move(Imm32(address.offset), addressTempRegister);
999                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1000             }
1001 
1002             return ArmAddress(addressTempRegister, address.index, address.scale);
1003         } else
1004             return ArmAddress(address.base, address.index, address.scale);
1005     }
1006 
setupArmAddress(Address address)1007     ArmAddress setupArmAddress(Address address)
1008     {
1009         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1010             return ArmAddress(address.base, address.offset);
1011 
1012         move(Imm32(address.offset), addressTempRegister);
1013         return ArmAddress(address.base, addressTempRegister);
1014     }
1015 
setupArmAddress(ImplicitAddress address)1016     ArmAddress setupArmAddress(ImplicitAddress address)
1017     {
1018         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1019             return ArmAddress(address.base, address.offset);
1020 
1021         move(Imm32(address.offset), addressTempRegister);
1022         return ArmAddress(address.base, addressTempRegister);
1023     }
1024 
makeBaseIndexBase(BaseIndex address)1025     RegisterID makeBaseIndexBase(BaseIndex address)
1026     {
1027         if (!address.offset)
1028             return address.base;
1029 
1030         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1031         if (imm.isValid())
1032             m_assembler.add(addressTempRegister, address.base, imm);
1033         else {
1034             move(Imm32(address.offset), addressTempRegister);
1035             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1036         }
1037 
1038         return addressTempRegister;
1039     }
1040 
moveFixedWidthEncoding(Imm32 imm,RegisterID dst)1041     DataLabel32 moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
1042     {
1043         uint32_t value = imm.m_value;
1044         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1045         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1046     }
1047 
armV7Condition(Condition cond)1048     ARMv7Assembler::Condition armV7Condition(Condition cond)
1049     {
1050         return static_cast<ARMv7Assembler::Condition>(cond);
1051     }
1052 
armV7Condition(DoubleCondition cond)1053     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1054     {
1055         return static_cast<ARMv7Assembler::Condition>(cond);
1056     }
1057 
1058 private:
1059     friend class LinkBuffer;
1060     friend class RepatchBuffer;
1061 
linkCall(void * code,Call call,FunctionPtr function)1062     static void linkCall(void* code, Call call, FunctionPtr function)
1063     {
1064         ARMv7Assembler::linkCall(code, call.m_jmp, function.value());
1065     }
1066 
repatchCall(CodeLocationCall call,CodeLocationLabel destination)1067     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1068     {
1069         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1070     }
1071 
repatchCall(CodeLocationCall call,FunctionPtr destination)1072     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1073     {
1074         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1075     }
1076 };
1077 
1078 } // namespace JSC
1079 
1080 #endif // ENABLE(ASSEMBLER)
1081 
1082 #endif // MacroAssemblerARMv7_h
1083