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 ARMAssembler_h
|
---|
27 | #define ARMAssembler_h
|
---|
28 |
|
---|
29 | #include <wtf/Platform.h>
|
---|
30 |
|
---|
31 | #if ENABLE(ASSEMBLER) && PLATFORM(ARM_THUMB2)
|
---|
32 |
|
---|
33 | #include "AssemblerBuffer.h"
|
---|
34 | #include <wtf/Assertions.h>
|
---|
35 | #include <wtf/Vector.h>
|
---|
36 | #include <stdint.h>
|
---|
37 |
|
---|
38 | namespace JSC {
|
---|
39 |
|
---|
40 | namespace ARMRegisters {
|
---|
41 | typedef enum {
|
---|
42 | r0,
|
---|
43 | r1,
|
---|
44 | r2,
|
---|
45 | r3,
|
---|
46 | r4,
|
---|
47 | r5,
|
---|
48 | r6,
|
---|
49 | r7, wr = r7, // thumb work register
|
---|
50 | r8,
|
---|
51 | r9, sb = r9, // static base
|
---|
52 | r10, sl = r10, // stack limit
|
---|
53 | r11, fp = r11, // frame pointer
|
---|
54 | r12, ip = r12,
|
---|
55 | r13, sp = r13,
|
---|
56 | r14, lr = r14,
|
---|
57 | r15, pc = r15,
|
---|
58 | } RegisterID;
|
---|
59 |
|
---|
60 | // s0 == d0 == q0
|
---|
61 | // s4 == d2 == q1
|
---|
62 | // etc
|
---|
63 | typedef enum {
|
---|
64 | s0 = 0,
|
---|
65 | s1 = 1,
|
---|
66 | s2 = 2,
|
---|
67 | s3 = 3,
|
---|
68 | s4 = 4,
|
---|
69 | s5 = 5,
|
---|
70 | s6 = 6,
|
---|
71 | s7 = 7,
|
---|
72 | s8 = 8,
|
---|
73 | s9 = 9,
|
---|
74 | s10 = 10,
|
---|
75 | s11 = 11,
|
---|
76 | s12 = 12,
|
---|
77 | s13 = 13,
|
---|
78 | s14 = 14,
|
---|
79 | s15 = 15,
|
---|
80 | s16 = 16,
|
---|
81 | s17 = 17,
|
---|
82 | s18 = 18,
|
---|
83 | s19 = 19,
|
---|
84 | s20 = 20,
|
---|
85 | s21 = 21,
|
---|
86 | s22 = 22,
|
---|
87 | s23 = 23,
|
---|
88 | s24 = 24,
|
---|
89 | s25 = 25,
|
---|
90 | s26 = 26,
|
---|
91 | s27 = 27,
|
---|
92 | s28 = 28,
|
---|
93 | s29 = 29,
|
---|
94 | s30 = 30,
|
---|
95 | s31 = 31,
|
---|
96 | d0 = 0 << 1,
|
---|
97 | d1 = 1 << 1,
|
---|
98 | d2 = 2 << 1,
|
---|
99 | d3 = 3 << 1,
|
---|
100 | d4 = 4 << 1,
|
---|
101 | d5 = 5 << 1,
|
---|
102 | d6 = 6 << 1,
|
---|
103 | d7 = 7 << 1,
|
---|
104 | d8 = 8 << 1,
|
---|
105 | d9 = 9 << 1,
|
---|
106 | d10 = 10 << 1,
|
---|
107 | d11 = 11 << 1,
|
---|
108 | d12 = 12 << 1,
|
---|
109 | d13 = 13 << 1,
|
---|
110 | d14 = 14 << 1,
|
---|
111 | d15 = 15 << 1,
|
---|
112 | d16 = 16 << 1,
|
---|
113 | d17 = 17 << 1,
|
---|
114 | d18 = 18 << 1,
|
---|
115 | d19 = 19 << 1,
|
---|
116 | d20 = 20 << 1,
|
---|
117 | d21 = 21 << 1,
|
---|
118 | d22 = 22 << 1,
|
---|
119 | d23 = 23 << 1,
|
---|
120 | d24 = 24 << 1,
|
---|
121 | d25 = 25 << 1,
|
---|
122 | d26 = 26 << 1,
|
---|
123 | d27 = 27 << 1,
|
---|
124 | d28 = 28 << 1,
|
---|
125 | d29 = 29 << 1,
|
---|
126 | d30 = 30 << 1,
|
---|
127 | d31 = 31 << 1,
|
---|
128 | q0 = 0 << 2,
|
---|
129 | q1 = 1 << 2,
|
---|
130 | q2 = 2 << 2,
|
---|
131 | q3 = 3 << 2,
|
---|
132 | q4 = 4 << 2,
|
---|
133 | q5 = 5 << 2,
|
---|
134 | q6 = 6 << 2,
|
---|
135 | q7 = 7 << 2,
|
---|
136 | q8 = 8 << 2,
|
---|
137 | q9 = 9 << 2,
|
---|
138 | q10 = 10 << 2,
|
---|
139 | q11 = 11 << 2,
|
---|
140 | q12 = 12 << 2,
|
---|
141 | q13 = 13 << 2,
|
---|
142 | q14 = 14 << 2,
|
---|
143 | q15 = 15 << 2,
|
---|
144 | q16 = 16 << 2,
|
---|
145 | q17 = 17 << 2,
|
---|
146 | q18 = 18 << 2,
|
---|
147 | q19 = 19 << 2,
|
---|
148 | q20 = 20 << 2,
|
---|
149 | q21 = 21 << 2,
|
---|
150 | q22 = 22 << 2,
|
---|
151 | q23 = 23 << 2,
|
---|
152 | q24 = 24 << 2,
|
---|
153 | q25 = 25 << 2,
|
---|
154 | q26 = 26 << 2,
|
---|
155 | q27 = 27 << 2,
|
---|
156 | q28 = 28 << 2,
|
---|
157 | q29 = 29 << 2,
|
---|
158 | q30 = 30 << 2,
|
---|
159 | q31 = 31 << 2,
|
---|
160 | } FPRegisterID;
|
---|
161 | }
|
---|
162 |
|
---|
163 | class ARMv7Assembler;
|
---|
164 | class ARMThumbImmediate {
|
---|
165 | friend class ARMv7Assembler;
|
---|
166 |
|
---|
167 | typedef uint8_t ThumbImmediateType;
|
---|
168 | static const ThumbImmediateType TypeInvalid = 0;
|
---|
169 | static const ThumbImmediateType TypeEncoded = 1;
|
---|
170 | static const ThumbImmediateType TypeUInt16 = 2;
|
---|
171 |
|
---|
172 | typedef union {
|
---|
173 | int16_t asInt;
|
---|
174 | struct {
|
---|
175 | unsigned imm8 : 8;
|
---|
176 | unsigned imm3 : 3;
|
---|
177 | unsigned i : 1;
|
---|
178 | unsigned imm4 : 4;
|
---|
179 | };
|
---|
180 | // If this is an encoded immediate, then it may describe a shift, or a pattern.
|
---|
181 | struct {
|
---|
182 | unsigned shiftValue7 : 7;
|
---|
183 | unsigned shiftAmount : 5;
|
---|
184 | };
|
---|
185 | struct {
|
---|
186 | unsigned immediate : 8;
|
---|
187 | unsigned pattern : 4;
|
---|
188 | };
|
---|
189 | } ThumbImmediateValue;
|
---|
190 |
|
---|
191 | // byte0 contains least significant bit; not using an array to make client code endian agnostic.
|
---|
192 | typedef union {
|
---|
193 | int32_t asInt;
|
---|
194 | struct {
|
---|
195 | uint8_t byte0;
|
---|
196 | uint8_t byte1;
|
---|
197 | uint8_t byte2;
|
---|
198 | uint8_t byte3;
|
---|
199 | };
|
---|
200 | } PatternBytes;
|
---|
201 |
|
---|
202 | ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N)
|
---|
203 | {
|
---|
204 | if (value & ~((1<<N)-1)) /* check for any of the top N bits (of 2N bits) are set */ \
|
---|
205 | value >>= N; /* if any were set, lose the bottom N */ \
|
---|
206 | else /* if none of the top N bits are set, */ \
|
---|
207 | zeros += N; /* then we have identified N leading zeros */
|
---|
208 | }
|
---|
209 |
|
---|
210 | static int32_t countLeadingZeros(uint32_t value)
|
---|
211 | {
|
---|
212 | if (!value)
|
---|
213 | return 32;
|
---|
214 |
|
---|
215 | int32_t zeros = 0;
|
---|
216 | countLeadingZerosPartial(value, zeros, 16);
|
---|
217 | countLeadingZerosPartial(value, zeros, 8);
|
---|
218 | countLeadingZerosPartial(value, zeros, 4);
|
---|
219 | countLeadingZerosPartial(value, zeros, 2);
|
---|
220 | countLeadingZerosPartial(value, zeros, 1);
|
---|
221 | return zeros;
|
---|
222 | }
|
---|
223 |
|
---|
224 | ARMThumbImmediate()
|
---|
225 | : m_type(TypeInvalid)
|
---|
226 | {
|
---|
227 | m_value.asInt = 0;
|
---|
228 | }
|
---|
229 |
|
---|
230 | ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value)
|
---|
231 | : m_type(type)
|
---|
232 | , m_value(value)
|
---|
233 | {
|
---|
234 | }
|
---|
235 |
|
---|
236 | ARMThumbImmediate(ThumbImmediateType type, uint16_t value)
|
---|
237 | : m_type(TypeUInt16)
|
---|
238 | {
|
---|
239 | m_value.asInt = value;
|
---|
240 | }
|
---|
241 |
|
---|
242 | public:
|
---|
243 | static ARMThumbImmediate makeEncodedImm(uint32_t value)
|
---|
244 | {
|
---|
245 | ThumbImmediateValue encoding;
|
---|
246 | encoding.asInt = 0;
|
---|
247 |
|
---|
248 | // okay, these are easy.
|
---|
249 | if (value < 256) {
|
---|
250 | encoding.immediate = value;
|
---|
251 | encoding.pattern = 0;
|
---|
252 | return ARMThumbImmediate(TypeEncoded, encoding);
|
---|
253 | }
|
---|
254 |
|
---|
255 | int32_t leadingZeros = countLeadingZeros(value);
|
---|
256 | // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case.
|
---|
257 | ASSERT(leadingZeros < 24);
|
---|
258 |
|
---|
259 | // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32,
|
---|
260 | // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for
|
---|
261 | // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z).
|
---|
262 | int32_t rightShiftAmount = 24 - leadingZeros;
|
---|
263 | if (value == ((value >> rightShiftAmount) << rightShiftAmount)) {
|
---|
264 | // Shift the value down to the low byte position. The assign to
|
---|
265 | // shiftValue7 drops the implicit top bit.
|
---|
266 | encoding.shiftValue7 = value >> rightShiftAmount;
|
---|
267 | // The endoded shift amount is the magnitude of a right rotate.
|
---|
268 | encoding.shiftAmount = 8 + leadingZeros;
|
---|
269 | return ARMThumbImmediate(TypeEncoded, encoding);
|
---|
270 | }
|
---|
271 |
|
---|
272 | PatternBytes bytes;
|
---|
273 | bytes.asInt = value;
|
---|
274 |
|
---|
275 | if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) {
|
---|
276 | encoding.immediate = bytes.byte0;
|
---|
277 | encoding.pattern = 3;
|
---|
278 | return ARMThumbImmediate(TypeEncoded, encoding);
|
---|
279 | }
|
---|
280 |
|
---|
281 | if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) {
|
---|
282 | encoding.immediate = bytes.byte0;
|
---|
283 | encoding.pattern = 1;
|
---|
284 | return ARMThumbImmediate(TypeEncoded, encoding);
|
---|
285 | }
|
---|
286 |
|
---|
287 | if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) {
|
---|
288 | encoding.immediate = bytes.byte0;
|
---|
289 | encoding.pattern = 2;
|
---|
290 | return ARMThumbImmediate(TypeEncoded, encoding);
|
---|
291 | }
|
---|
292 |
|
---|
293 | return ARMThumbImmediate();
|
---|
294 | }
|
---|
295 |
|
---|
296 | static ARMThumbImmediate makeUInt12(int32_t value)
|
---|
297 | {
|
---|
298 | return (!(value & 0xfffff000))
|
---|
299 | ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
|
---|
300 | : ARMThumbImmediate();
|
---|
301 | }
|
---|
302 |
|
---|
303 | static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value)
|
---|
304 | {
|
---|
305 | // If this is not a 12-bit unsigned it, try making an encoded immediate.
|
---|
306 | return (!(value & 0xfffff000))
|
---|
307 | ? ARMThumbImmediate(TypeUInt16, (uint16_t)value)
|
---|
308 | : makeEncodedImm(value);
|
---|
309 | }
|
---|
310 |
|
---|
311 | // The 'make' methods, above, return a !isValid() value if the argument
|
---|
312 | // cannot be represented as the requested type. This methods is called
|
---|
313 | // 'get' since the argument can always be represented.
|
---|
314 | static ARMThumbImmediate makeUInt16(uint16_t value)
|
---|
315 | {
|
---|
316 | return ARMThumbImmediate(TypeUInt16, value);
|
---|
317 | }
|
---|
318 |
|
---|
319 | bool isValid()
|
---|
320 | {
|
---|
321 | return m_type != TypeInvalid;
|
---|
322 | }
|
---|
323 |
|
---|
324 | // These methods rely on the format of encoded byte values.
|
---|
325 | bool isUInt3() { return !(m_value.asInt & 0xfff8); }
|
---|
326 | bool isUInt4() { return !(m_value.asInt & 0xfff0); }
|
---|
327 | bool isUInt5() { return !(m_value.asInt & 0xffe0); }
|
---|
328 | bool isUInt6() { return !(m_value.asInt & 0xffc0); }
|
---|
329 | bool isUInt7() { return !(m_value.asInt & 0xff80); }
|
---|
330 | bool isUInt8() { return !(m_value.asInt & 0xff00); }
|
---|
331 | bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); }
|
---|
332 | bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); }
|
---|
333 | bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); }
|
---|
334 | bool isUInt16() { return m_type == TypeUInt16; }
|
---|
335 | uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; }
|
---|
336 | uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; }
|
---|
337 | uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; }
|
---|
338 | uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; }
|
---|
339 | uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; }
|
---|
340 | uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; }
|
---|
341 | uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; }
|
---|
342 | uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; }
|
---|
343 | uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; }
|
---|
344 | uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; }
|
---|
345 |
|
---|
346 | bool isEncodedImm() { return m_type == TypeEncoded; }
|
---|
347 |
|
---|
348 | private:
|
---|
349 | ThumbImmediateType m_type;
|
---|
350 | ThumbImmediateValue m_value;
|
---|
351 | };
|
---|
352 |
|
---|
353 |
|
---|
354 | typedef enum {
|
---|
355 | SRType_LSL,
|
---|
356 | SRType_LSR,
|
---|
357 | SRType_ASR,
|
---|
358 | SRType_ROR,
|
---|
359 |
|
---|
360 | SRType_RRX = SRType_ROR
|
---|
361 | } ARMShiftType;
|
---|
362 |
|
---|
363 | class ARMv7Assembler;
|
---|
364 | class ShiftTypeAndAmount {
|
---|
365 | friend class ARMv7Assembler;
|
---|
366 |
|
---|
367 | public:
|
---|
368 | ShiftTypeAndAmount()
|
---|
369 | {
|
---|
370 | m_u.type = (ARMShiftType)0;
|
---|
371 | m_u.amount = 0;
|
---|
372 | }
|
---|
373 |
|
---|
374 | ShiftTypeAndAmount(ARMShiftType type, unsigned amount)
|
---|
375 | {
|
---|
376 | m_u.type = type;
|
---|
377 | m_u.amount = amount & 31;
|
---|
378 | }
|
---|
379 |
|
---|
380 | unsigned lo4() { return m_u.lo4; }
|
---|
381 | unsigned hi4() { return m_u.hi4; }
|
---|
382 |
|
---|
383 | private:
|
---|
384 | union {
|
---|
385 | struct {
|
---|
386 | unsigned lo4 : 4;
|
---|
387 | unsigned hi4 : 4;
|
---|
388 | };
|
---|
389 | struct {
|
---|
390 | unsigned type : 2;
|
---|
391 | unsigned amount : 5;
|
---|
392 | };
|
---|
393 | } m_u;
|
---|
394 | };
|
---|
395 |
|
---|
396 |
|
---|
397 | /*
|
---|
398 | Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting
|
---|
399 | instructions supported by ARMv7-M are as follows:
|
---|
400 | • use of the PC as <Rd> or <Rm> in a 16-bit ADD (SP plus register) instruction
|
---|
401 | • use of the SP as <Rm> in a 16-bit ADD (SP plus register) instruction
|
---|
402 | • use of the SP as <Rm> in a 16-bit CMP (register) instruction
|
---|
403 | • use of MOV (register) instructions in which <Rd> is the SP or PC and <Rm> is also the SP or PC.
|
---|
404 | • use of <Rn> as the lowest-numbered register in the register list of a 16-bit STM instruction with base
|
---|
405 | register writeback
|
---|
406 | */
|
---|
407 |
|
---|
408 | class ARMv7Assembler {
|
---|
409 | public:
|
---|
410 | typedef ARMRegisters::RegisterID RegisterID;
|
---|
411 | typedef ARMRegisters::FPRegisterID FPRegisterID;
|
---|
412 |
|
---|
413 | // (HS, LO, HI, LS) -> (AE, B, A, BE)
|
---|
414 | // (VS, VC) -> (O, NO)
|
---|
415 | typedef enum {
|
---|
416 | ConditionEQ,
|
---|
417 | ConditionNE,
|
---|
418 | ConditionHS,
|
---|
419 | ConditionLO,
|
---|
420 | ConditionMI,
|
---|
421 | ConditionPL,
|
---|
422 | ConditionVS,
|
---|
423 | ConditionVC,
|
---|
424 | ConditionHI,
|
---|
425 | ConditionLS,
|
---|
426 | ConditionGE,
|
---|
427 | ConditionLT,
|
---|
428 | ConditionGT,
|
---|
429 | ConditionLE,
|
---|
430 | ConditionAL,
|
---|
431 |
|
---|
432 | ConditionCS = ConditionHS,
|
---|
433 | ConditionCC = ConditionLO,
|
---|
434 | } Condition;
|
---|
435 |
|
---|
436 | class JmpSrc {
|
---|
437 | friend class ARMv7Assembler;
|
---|
438 | friend class ARMInstructionFormatter;
|
---|
439 | public:
|
---|
440 | JmpSrc()
|
---|
441 | : m_offset(-1)
|
---|
442 | {
|
---|
443 | }
|
---|
444 |
|
---|
445 | private:
|
---|
446 | JmpSrc(int offset)
|
---|
447 | : m_offset(offset)
|
---|
448 | {
|
---|
449 | }
|
---|
450 |
|
---|
451 | int m_offset;
|
---|
452 | };
|
---|
453 |
|
---|
454 | class JmpDst {
|
---|
455 | friend class ARMv7Assembler;
|
---|
456 | friend class ARMInstructionFormatter;
|
---|
457 | public:
|
---|
458 | JmpDst()
|
---|
459 | : m_offset(-1)
|
---|
460 | , m_used(false)
|
---|
461 | {
|
---|
462 | }
|
---|
463 |
|
---|
464 | bool isUsed() const { return m_used; }
|
---|
465 | void used() { m_used = true; }
|
---|
466 | private:
|
---|
467 | JmpDst(int offset)
|
---|
468 | : m_offset(offset)
|
---|
469 | , m_used(false)
|
---|
470 | {
|
---|
471 | ASSERT(m_offset == offset);
|
---|
472 | }
|
---|
473 |
|
---|
474 | int m_offset : 31;
|
---|
475 | int m_used : 1;
|
---|
476 | };
|
---|
477 |
|
---|
478 | private:
|
---|
479 |
|
---|
480 | // ARMv7, Appx-A.6.3
|
---|
481 | bool BadReg(RegisterID reg)
|
---|
482 | {
|
---|
483 | return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc);
|
---|
484 | }
|
---|
485 |
|
---|
486 | bool isSingleRegister(FPRegisterID reg)
|
---|
487 | {
|
---|
488 | // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
|
---|
489 | return !(reg & ~31);
|
---|
490 | }
|
---|
491 |
|
---|
492 | bool isDoubleRegister(FPRegisterID reg)
|
---|
493 | {
|
---|
494 | // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc).
|
---|
495 | return !(reg & ~(31 << 1));
|
---|
496 | }
|
---|
497 |
|
---|
498 | bool isQuadRegister(FPRegisterID reg)
|
---|
499 | {
|
---|
500 | return !(reg & ~(31 << 2));
|
---|
501 | }
|
---|
502 |
|
---|
503 | uint32_t singleRegisterNum(FPRegisterID reg)
|
---|
504 | {
|
---|
505 | ASSERT(isSingleRegister(reg));
|
---|
506 | return reg;
|
---|
507 | }
|
---|
508 |
|
---|
509 | uint32_t doubleRegisterNum(FPRegisterID reg)
|
---|
510 | {
|
---|
511 | ASSERT(isDoubleRegister(reg));
|
---|
512 | return reg >> 1;
|
---|
513 | }
|
---|
514 |
|
---|
515 | uint32_t quadRegisterNum(FPRegisterID reg)
|
---|
516 | {
|
---|
517 | ASSERT(isQuadRegister(reg));
|
---|
518 | return reg >> 2;
|
---|
519 | }
|
---|
520 |
|
---|
521 | uint32_t singleRegisterMask(FPRegisterID rd, int highBitsShift, int lowBitShift)
|
---|
522 | {
|
---|
523 | uint32_t rdNum = singleRegisterNum(rd);
|
---|
524 | uint32_t rdMask = (rdNum >> 1) << highBitsShift;
|
---|
525 | if (rdNum & 1)
|
---|
526 | rdMask |= 1 << lowBitShift;
|
---|
527 | return rdMask;
|
---|
528 | }
|
---|
529 |
|
---|
530 | uint32_t doubleRegisterMask(FPRegisterID rd, int highBitShift, int lowBitsShift)
|
---|
531 | {
|
---|
532 | uint32_t rdNum = doubleRegisterNum(rd);
|
---|
533 | uint32_t rdMask = (rdNum & 0xf) << lowBitsShift;
|
---|
534 | if (rdNum & 16)
|
---|
535 | rdMask |= 1 << highBitShift;
|
---|
536 | return rdMask;
|
---|
537 | }
|
---|
538 |
|
---|
539 | typedef enum {
|
---|
540 | OP_ADD_reg_T1 = 0x1800,
|
---|
541 | OP_ADD_S_reg_T1 = 0x1800,
|
---|
542 | OP_SUB_reg_T1 = 0x1A00,
|
---|
543 | OP_SUB_S_reg_T1 = 0x1A00,
|
---|
544 | OP_ADD_imm_T1 = 0x1C00,
|
---|
545 | OP_ADD_S_imm_T1 = 0x1C00,
|
---|
546 | OP_SUB_imm_T1 = 0x1E00,
|
---|
547 | OP_SUB_S_imm_T1 = 0x1E00,
|
---|
548 | OP_MOV_imm_T1 = 0x2000,
|
---|
549 | OP_CMP_imm_T1 = 0x2800,
|
---|
550 | OP_ADD_imm_T2 = 0x3000,
|
---|
551 | OP_ADD_S_imm_T2 = 0x3000,
|
---|
552 | OP_SUB_imm_T2 = 0x3800,
|
---|
553 | OP_SUB_S_imm_T2 = 0x3800,
|
---|
554 | OP_AND_reg_T1 = 0x4000,
|
---|
555 | OP_EOR_reg_T1 = 0x4040,
|
---|
556 | OP_TST_reg_T1 = 0x4200,
|
---|
557 | OP_CMP_reg_T1 = 0x4280,
|
---|
558 | OP_ORR_reg_T1 = 0x4300,
|
---|
559 | OP_MVN_reg_T1 = 0x43C0,
|
---|
560 | OP_ADD_reg_T2 = 0x4400,
|
---|
561 | OP_MOV_reg_T1 = 0x4600,
|
---|
562 | OP_BLX = 0x4700,
|
---|
563 | OP_BX = 0x4700,
|
---|
564 | OP_LDRH_reg_T1 = 0x5A00,
|
---|
565 | OP_STR_reg_T1 = 0x5000,
|
---|
566 | OP_LDR_reg_T1 = 0x5800,
|
---|
567 | OP_STR_imm_T1 = 0x6000,
|
---|
568 | OP_LDR_imm_T1 = 0x6800,
|
---|
569 | OP_LDRH_imm_T1 = 0x8800,
|
---|
570 | OP_STR_imm_T2 = 0x9000,
|
---|
571 | OP_LDR_imm_T2 = 0x9800,
|
---|
572 | OP_ADD_SP_imm_T1 = 0xA800,
|
---|
573 | OP_ADD_SP_imm_T2 = 0xB000,
|
---|
574 | OP_SUB_SP_imm_T1 = 0xB080,
|
---|
575 | OP_BKPT = 0xBE00,
|
---|
576 | OP_IT = 0xBF00,
|
---|
577 | } OpcodeID;
|
---|
578 |
|
---|
579 | typedef enum {
|
---|
580 | OP_AND_reg_T2 = 0xEA00,
|
---|
581 | OP_TST_reg_T2 = 0xEA10,
|
---|
582 | OP_ORR_reg_T2 = 0xEA40,
|
---|
583 | OP_ASR_imm_T1 = 0xEA4F,
|
---|
584 | OP_LSL_imm_T1 = 0xEA4F,
|
---|
585 | OP_LSR_imm_T1 = 0xEA4F,
|
---|
586 | OP_ROR_imm_T1 = 0xEA4F,
|
---|
587 | OP_MVN_reg_T2 = 0xEA6F,
|
---|
588 | OP_EOR_reg_T2 = 0xEA80,
|
---|
589 | OP_ADD_reg_T3 = 0xEB00,
|
---|
590 | OP_ADD_S_reg_T3 = 0xEB10,
|
---|
591 | OP_SUB_reg_T2 = 0xEBA0,
|
---|
592 | OP_SUB_S_reg_T2 = 0xEBB0,
|
---|
593 | OP_CMP_reg_T2 = 0xEBB0,
|
---|
594 | OP_B_T4a = 0xF000,
|
---|
595 | OP_AND_imm_T1 = 0xF000,
|
---|
596 | OP_TST_imm = 0xF010,
|
---|
597 | OP_ORR_imm_T1 = 0xF040,
|
---|
598 | OP_MOV_imm_T2 = 0xF040,
|
---|
599 | OP_MVN_imm = 0xF060,
|
---|
600 | OP_EOR_imm_T1 = 0xF080,
|
---|
601 | OP_ADD_imm_T3 = 0xF100,
|
---|
602 | OP_ADD_S_imm_T3 = 0xF110,
|
---|
603 | OP_CMN_imm = 0xF110,
|
---|
604 | OP_SUB_imm_T3 = 0xF1A0,
|
---|
605 | OP_SUB_S_imm_T3 = 0xF1B0,
|
---|
606 | OP_CMP_imm_T2 = 0xF1B0,
|
---|
607 | OP_ADD_imm_T4 = 0xF200,
|
---|
608 | OP_MOV_imm_T3 = 0xF240,
|
---|
609 | OP_SUB_imm_T4 = 0xF2A0,
|
---|
610 | OP_MOVT = 0xF2C0,
|
---|
611 | OP_LDRH_reg_T2 = 0xF830,
|
---|
612 | OP_LDRH_imm_T3 = 0xF830,
|
---|
613 | OP_STR_imm_T4 = 0xF840,
|
---|
614 | OP_STR_reg_T2 = 0xF840,
|
---|
615 | OP_LDR_imm_T4 = 0xF850,
|
---|
616 | OP_LDR_reg_T2 = 0xF850,
|
---|
617 | OP_LDRH_imm_T2 = 0xF8B0,
|
---|
618 | OP_STR_imm_T3 = 0xF8C0,
|
---|
619 | OP_LDR_imm_T3 = 0xF8D0,
|
---|
620 | OP_LSL_reg_T2 = 0xFA00,
|
---|
621 | OP_LSR_reg_T2 = 0xFA20,
|
---|
622 | OP_ASR_reg_T2 = 0xFA40,
|
---|
623 | OP_ROR_reg_T2 = 0xFA60,
|
---|
624 | OP_SMULL_T1 = 0xFB80,
|
---|
625 | } OpcodeID1;
|
---|
626 |
|
---|
627 | typedef enum {
|
---|
628 | OP_B_T4b = 0x9000,
|
---|
629 | } OpcodeID2;
|
---|
630 |
|
---|
631 | struct FourFours {
|
---|
632 | FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0)
|
---|
633 | {
|
---|
634 | m_u.f0 = f0;
|
---|
635 | m_u.f1 = f1;
|
---|
636 | m_u.f2 = f2;
|
---|
637 | m_u.f3 = f3;
|
---|
638 | }
|
---|
639 |
|
---|
640 | union {
|
---|
641 | unsigned value;
|
---|
642 | struct {
|
---|
643 | unsigned f0 : 4;
|
---|
644 | unsigned f1 : 4;
|
---|
645 | unsigned f2 : 4;
|
---|
646 | unsigned f3 : 4;
|
---|
647 | };
|
---|
648 | } m_u;
|
---|
649 | };
|
---|
650 |
|
---|
651 | class ARMInstructionFormatter;
|
---|
652 |
|
---|
653 | // false means else!
|
---|
654 | bool ifThenElseConditionBit(Condition condition, bool isIf)
|
---|
655 | {
|
---|
656 | return isIf ? (condition & 1) : !(condition & 1);
|
---|
657 | }
|
---|
658 | uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if)
|
---|
659 | {
|
---|
660 | int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
|
---|
661 | | (ifThenElseConditionBit(condition, inst3if) << 2)
|
---|
662 | | (ifThenElseConditionBit(condition, inst4if) << 1)
|
---|
663 | | 1;
|
---|
664 | ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
|
---|
665 | return (condition << 4) | mask;
|
---|
666 | }
|
---|
667 | uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if)
|
---|
668 | {
|
---|
669 | int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
|
---|
670 | | (ifThenElseConditionBit(condition, inst3if) << 2)
|
---|
671 | | 2;
|
---|
672 | ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
|
---|
673 | return (condition << 4) | mask;
|
---|
674 | }
|
---|
675 | uint8_t ifThenElse(Condition condition, bool inst2if)
|
---|
676 | {
|
---|
677 | int mask = (ifThenElseConditionBit(condition, inst2if) << 3)
|
---|
678 | | 4;
|
---|
679 | ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
|
---|
680 | return (condition << 4) | mask;
|
---|
681 | }
|
---|
682 |
|
---|
683 | uint8_t ifThenElse(Condition condition)
|
---|
684 | {
|
---|
685 | int mask = 8;
|
---|
686 | ASSERT((condition != ConditionAL) || (mask & (mask - 1)));
|
---|
687 | return (condition << 4) | mask;
|
---|
688 | }
|
---|
689 |
|
---|
690 | public:
|
---|
691 |
|
---|
692 | void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
693 | {
|
---|
694 | // Rd can only be SP if Rn is also SP.
|
---|
695 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
696 | ASSERT(rd != ARMRegisters::pc);
|
---|
697 | ASSERT(rn != ARMRegisters::pc);
|
---|
698 | ASSERT(imm.isValid());
|
---|
699 |
|
---|
700 | if (rn == ARMRegisters::sp) {
|
---|
701 | if (!(rd & 8) && imm.isUInt10()) {
|
---|
702 | m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2);
|
---|
703 | return;
|
---|
704 | } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) {
|
---|
705 | m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2);
|
---|
706 | return;
|
---|
707 | }
|
---|
708 | } else if (!((rd | rn) & 8)) {
|
---|
709 | if (imm.isUInt3()) {
|
---|
710 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
|
---|
711 | return;
|
---|
712 | } else if ((rd == rn) && imm.isUInt8()) {
|
---|
713 | m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8());
|
---|
714 | return;
|
---|
715 | }
|
---|
716 | }
|
---|
717 |
|
---|
718 | if (imm.isEncodedImm())
|
---|
719 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm);
|
---|
720 | else {
|
---|
721 | ASSERT(imm.isUInt12());
|
---|
722 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm);
|
---|
723 | }
|
---|
724 | }
|
---|
725 |
|
---|
726 | void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
727 | {
|
---|
728 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
729 | ASSERT(rd != ARMRegisters::pc);
|
---|
730 | ASSERT(rn != ARMRegisters::pc);
|
---|
731 | ASSERT(!BadReg(rm));
|
---|
732 | m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
733 | }
|
---|
734 |
|
---|
735 | // NOTE: In an IT block, add doesn't modify the flags register.
|
---|
736 | void add(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
737 | {
|
---|
738 | if (rd == rn)
|
---|
739 | m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd);
|
---|
740 | else if (rd == rm)
|
---|
741 | m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd);
|
---|
742 | else if (!((rd | rn | rm) & 8))
|
---|
743 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd);
|
---|
744 | else
|
---|
745 | add(rd, rn, rm, ShiftTypeAndAmount());
|
---|
746 | }
|
---|
747 |
|
---|
748 | // Not allowed in an IT (if then) block.
|
---|
749 | void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
750 | {
|
---|
751 | // Rd can only be SP if Rn is also SP.
|
---|
752 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
753 | ASSERT(rd != ARMRegisters::pc);
|
---|
754 | ASSERT(rn != ARMRegisters::pc);
|
---|
755 | ASSERT(imm.isEncodedImm());
|
---|
756 |
|
---|
757 | if (!((rd | rn) & 8)) {
|
---|
758 | if (imm.isUInt3()) {
|
---|
759 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
|
---|
760 | return;
|
---|
761 | } else if ((rd == rn) && imm.isUInt8()) {
|
---|
762 | m_formatter.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2, rd, imm.getUInt8());
|
---|
763 | return;
|
---|
764 | }
|
---|
765 | }
|
---|
766 |
|
---|
767 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm);
|
---|
768 | }
|
---|
769 |
|
---|
770 | // Not allowed in an IT (if then) block?
|
---|
771 | void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
772 | {
|
---|
773 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
774 | ASSERT(rd != ARMRegisters::pc);
|
---|
775 | ASSERT(rn != ARMRegisters::pc);
|
---|
776 | ASSERT(!BadReg(rm));
|
---|
777 | m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
778 | }
|
---|
779 |
|
---|
780 | // Not allowed in an IT (if then) block.
|
---|
781 | void add_S(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
782 | {
|
---|
783 | if (!((rd | rn | rm) & 8))
|
---|
784 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1, rm, rn, rd);
|
---|
785 | else
|
---|
786 | add_S(rd, rn, rm, ShiftTypeAndAmount());
|
---|
787 | }
|
---|
788 |
|
---|
789 | void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
790 | {
|
---|
791 | ASSERT(!BadReg(rd));
|
---|
792 | ASSERT(!BadReg(rn));
|
---|
793 | ASSERT(imm.isEncodedImm());
|
---|
794 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm);
|
---|
795 | }
|
---|
796 |
|
---|
797 | void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
798 | {
|
---|
799 | ASSERT(!BadReg(rd));
|
---|
800 | ASSERT(!BadReg(rn));
|
---|
801 | ASSERT(!BadReg(rm));
|
---|
802 | m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
803 | }
|
---|
804 |
|
---|
805 | void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
806 | {
|
---|
807 | if ((rd == rn) && !((rd | rm) & 8))
|
---|
808 | m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd);
|
---|
809 | else if ((rd == rm) && !((rd | rn) & 8))
|
---|
810 | m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd);
|
---|
811 | else
|
---|
812 | ARM_and(rd, rn, rm, ShiftTypeAndAmount());
|
---|
813 | }
|
---|
814 |
|
---|
815 | void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
|
---|
816 | {
|
---|
817 | ASSERT(!BadReg(rd));
|
---|
818 | ASSERT(!BadReg(rm));
|
---|
819 | ShiftTypeAndAmount shift(SRType_ASR, shiftAmount);
|
---|
820 | m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
821 | }
|
---|
822 |
|
---|
823 | void asr(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
824 | {
|
---|
825 | ASSERT(!BadReg(rd));
|
---|
826 | ASSERT(!BadReg(rn));
|
---|
827 | ASSERT(!BadReg(rm));
|
---|
828 | m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
|
---|
829 | }
|
---|
830 |
|
---|
831 | // Only allowed in IT (if then) block if last instruction.
|
---|
832 | JmpSrc b()
|
---|
833 | {
|
---|
834 | m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b);
|
---|
835 | return JmpSrc(m_formatter.size());
|
---|
836 | }
|
---|
837 |
|
---|
838 | // Only allowed in IT (if then) block if last instruction.
|
---|
839 | JmpSrc blx(RegisterID rm)
|
---|
840 | {
|
---|
841 | ASSERT(rm != ARMRegisters::pc);
|
---|
842 | m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8);
|
---|
843 | return JmpSrc(m_formatter.size());
|
---|
844 | }
|
---|
845 |
|
---|
846 | // Only allowed in IT (if then) block if last instruction.
|
---|
847 | JmpSrc bx(RegisterID rm)
|
---|
848 | {
|
---|
849 | m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0);
|
---|
850 | return JmpSrc(m_formatter.size());
|
---|
851 | }
|
---|
852 |
|
---|
853 | void bkpt(uint8_t imm=0)
|
---|
854 | {
|
---|
855 | m_formatter.oneWordOp8Imm8(OP_BKPT, imm);
|
---|
856 | }
|
---|
857 |
|
---|
858 | void cmn(RegisterID rn, ARMThumbImmediate imm)
|
---|
859 | {
|
---|
860 | ASSERT(rn != ARMRegisters::pc);
|
---|
861 | ASSERT(imm.isEncodedImm());
|
---|
862 |
|
---|
863 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm);
|
---|
864 | }
|
---|
865 |
|
---|
866 | void cmp(RegisterID rn, ARMThumbImmediate imm)
|
---|
867 | {
|
---|
868 | ASSERT(rn != ARMRegisters::pc);
|
---|
869 | ASSERT(imm.isEncodedImm());
|
---|
870 |
|
---|
871 | if (!(rn & 8) && imm.isUInt8())
|
---|
872 | m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8());
|
---|
873 | else
|
---|
874 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm);
|
---|
875 | }
|
---|
876 |
|
---|
877 | void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
878 | {
|
---|
879 | ASSERT(rn != ARMRegisters::pc);
|
---|
880 | ASSERT(!BadReg(rm));
|
---|
881 | m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
|
---|
882 | }
|
---|
883 |
|
---|
884 | void cmp(RegisterID rn, RegisterID rm)
|
---|
885 | {
|
---|
886 | if ((rn | rm) & 8)
|
---|
887 | cmp(rn, rm, ShiftTypeAndAmount());
|
---|
888 | else
|
---|
889 | m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn);
|
---|
890 | }
|
---|
891 |
|
---|
892 | // xor is not spelled with an 'e'. :-(
|
---|
893 | void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
894 | {
|
---|
895 | ASSERT(!BadReg(rd));
|
---|
896 | ASSERT(!BadReg(rn));
|
---|
897 | ASSERT(imm.isEncodedImm());
|
---|
898 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm);
|
---|
899 | }
|
---|
900 |
|
---|
901 | // xor is not spelled with an 'e'. :-(
|
---|
902 | void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
903 | {
|
---|
904 | ASSERT(!BadReg(rd));
|
---|
905 | ASSERT(!BadReg(rn));
|
---|
906 | ASSERT(!BadReg(rm));
|
---|
907 | m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
908 | }
|
---|
909 |
|
---|
910 | // xor is not spelled with an 'e'. :-(
|
---|
911 | void eor(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
912 | {
|
---|
913 | if ((rd == rn) && !((rd | rm) & 8))
|
---|
914 | m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd);
|
---|
915 | else if ((rd == rm) && !((rd | rn) & 8))
|
---|
916 | m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd);
|
---|
917 | else
|
---|
918 | eor(rd, rn, rm, ShiftTypeAndAmount());
|
---|
919 | }
|
---|
920 |
|
---|
921 | void it(Condition cond)
|
---|
922 | {
|
---|
923 | m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond));
|
---|
924 | }
|
---|
925 |
|
---|
926 | void it(Condition cond, bool inst2if)
|
---|
927 | {
|
---|
928 | m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if));
|
---|
929 | }
|
---|
930 |
|
---|
931 | void it(Condition cond, bool inst2if, bool inst3if)
|
---|
932 | {
|
---|
933 | m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if));
|
---|
934 | }
|
---|
935 |
|
---|
936 | void it(Condition cond, bool inst2if, bool inst3if, bool inst4if)
|
---|
937 | {
|
---|
938 | m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if));
|
---|
939 | }
|
---|
940 |
|
---|
941 | // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
|
---|
942 | void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
|
---|
943 | {
|
---|
944 | ASSERT(rn != ARMRegisters::pc); // LDR (literal)
|
---|
945 | ASSERT(imm.isUInt12());
|
---|
946 |
|
---|
947 | if (!((rt | rn) & 8) && imm.isUInt7())
|
---|
948 | m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt);
|
---|
949 | else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
|
---|
950 | m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2);
|
---|
951 | else
|
---|
952 | m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
|
---|
953 | }
|
---|
954 |
|
---|
955 | // If index is set, this is a regular offset or a pre-indexed load;
|
---|
956 | // if index is not set then is is a post-index load.
|
---|
957 | //
|
---|
958 | // If wback is set rn is updated - this is a pre or post index load,
|
---|
959 | // if wback is not set this is a regular offset memory access.
|
---|
960 | //
|
---|
961 | // (-255 <= offset <= 255)
|
---|
962 | // _reg = REG[rn]
|
---|
963 | // _tmp = _reg + offset
|
---|
964 | // MEM[index ? _tmp : _reg] = REG[rt]
|
---|
965 | // if (wback) REG[rn] = _tmp
|
---|
966 | void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
|
---|
967 | {
|
---|
968 | ASSERT(rt != ARMRegisters::pc);
|
---|
969 | ASSERT(rn != ARMRegisters::pc);
|
---|
970 | ASSERT(index || wback);
|
---|
971 | ASSERT(!wback | (rt != rn));
|
---|
972 |
|
---|
973 | bool add = true;
|
---|
974 | if (offset < 0) {
|
---|
975 | add = false;
|
---|
976 | offset = -offset;
|
---|
977 | }
|
---|
978 | ASSERT((offset & ~0xff) == 0);
|
---|
979 |
|
---|
980 | offset |= (wback << 8);
|
---|
981 | offset |= (add << 9);
|
---|
982 | offset |= (index << 10);
|
---|
983 | offset |= (1 << 11);
|
---|
984 |
|
---|
985 | m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset);
|
---|
986 | }
|
---|
987 |
|
---|
988 | // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
|
---|
989 | void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
|
---|
990 | {
|
---|
991 | ASSERT(rn != ARMRegisters::pc); // LDR (literal)
|
---|
992 | ASSERT(!BadReg(rm));
|
---|
993 | ASSERT(shift <= 3);
|
---|
994 |
|
---|
995 | if (!shift && !((rt | rn | rm) & 8))
|
---|
996 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt);
|
---|
997 | else
|
---|
998 | m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm));
|
---|
999 | }
|
---|
1000 |
|
---|
1001 | // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
|
---|
1002 | void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
|
---|
1003 | {
|
---|
1004 | ASSERT(rn != ARMRegisters::pc); // LDR (literal)
|
---|
1005 | ASSERT(imm.isUInt12());
|
---|
1006 |
|
---|
1007 | if (!((rt | rn) & 8) && imm.isUInt6())
|
---|
1008 | m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
|
---|
1009 | else
|
---|
1010 | m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | // If index is set, this is a regular offset or a pre-indexed load;
|
---|
1014 | // if index is not set then is is a post-index load.
|
---|
1015 | //
|
---|
1016 | // If wback is set rn is updated - this is a pre or post index load,
|
---|
1017 | // if wback is not set this is a regular offset memory access.
|
---|
1018 | //
|
---|
1019 | // (-255 <= offset <= 255)
|
---|
1020 | // _reg = REG[rn]
|
---|
1021 | // _tmp = _reg + offset
|
---|
1022 | // MEM[index ? _tmp : _reg] = REG[rt]
|
---|
1023 | // if (wback) REG[rn] = _tmp
|
---|
1024 | void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
|
---|
1025 | {
|
---|
1026 | ASSERT(rt != ARMRegisters::pc);
|
---|
1027 | ASSERT(rn != ARMRegisters::pc);
|
---|
1028 | ASSERT(index || wback);
|
---|
1029 | ASSERT(!wback | (rt != rn));
|
---|
1030 |
|
---|
1031 | bool add = true;
|
---|
1032 | if (offset < 0) {
|
---|
1033 | add = false;
|
---|
1034 | offset = -offset;
|
---|
1035 | }
|
---|
1036 | ASSERT((offset & ~0xff) == 0);
|
---|
1037 |
|
---|
1038 | offset |= (wback << 8);
|
---|
1039 | offset |= (add << 9);
|
---|
1040 | offset |= (index << 10);
|
---|
1041 | offset |= (1 << 11);
|
---|
1042 |
|
---|
1043 | m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset);
|
---|
1044 | }
|
---|
1045 |
|
---|
1046 | void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
|
---|
1047 | {
|
---|
1048 | ASSERT(!BadReg(rt)); // Memory hint
|
---|
1049 | ASSERT(rn != ARMRegisters::pc); // LDRH (literal)
|
---|
1050 | ASSERT(!BadReg(rm));
|
---|
1051 | ASSERT(shift <= 3);
|
---|
1052 |
|
---|
1053 | if (!shift && !((rt | rn | rm) & 8))
|
---|
1054 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt);
|
---|
1055 | else
|
---|
1056 | m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm));
|
---|
1057 | }
|
---|
1058 |
|
---|
1059 | void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount)
|
---|
1060 | {
|
---|
1061 | ASSERT(!BadReg(rd));
|
---|
1062 | ASSERT(!BadReg(rm));
|
---|
1063 | ShiftTypeAndAmount shift(SRType_LSL, shiftAmount);
|
---|
1064 | m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1065 | }
|
---|
1066 |
|
---|
1067 | void lsl(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
1068 | {
|
---|
1069 | ASSERT(!BadReg(rd));
|
---|
1070 | ASSERT(!BadReg(rn));
|
---|
1071 | ASSERT(!BadReg(rm));
|
---|
1072 | m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm));
|
---|
1073 | }
|
---|
1074 |
|
---|
1075 | void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount)
|
---|
1076 | {
|
---|
1077 | ASSERT(!BadReg(rd));
|
---|
1078 | ASSERT(!BadReg(rm));
|
---|
1079 | ShiftTypeAndAmount shift(SRType_LSR, shiftAmount);
|
---|
1080 | m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1081 | }
|
---|
1082 |
|
---|
1083 | void lsr(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
1084 | {
|
---|
1085 | ASSERT(!BadReg(rd));
|
---|
1086 | ASSERT(!BadReg(rn));
|
---|
1087 | ASSERT(!BadReg(rm));
|
---|
1088 | m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
|
---|
1089 | }
|
---|
1090 |
|
---|
1091 | void movT3(RegisterID rd, ARMThumbImmediate imm)
|
---|
1092 | {
|
---|
1093 | ASSERT(imm.isValid());
|
---|
1094 | ASSERT(!imm.isEncodedImm());
|
---|
1095 | ASSERT(!BadReg(rd));
|
---|
1096 |
|
---|
1097 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm);
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | void mov(RegisterID rd, ARMThumbImmediate imm)
|
---|
1101 | {
|
---|
1102 | ASSERT(imm.isValid());
|
---|
1103 | ASSERT(!BadReg(rd));
|
---|
1104 |
|
---|
1105 | if ((rd < 8) && imm.isUInt8())
|
---|
1106 | m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8());
|
---|
1107 | else if (imm.isEncodedImm())
|
---|
1108 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm);
|
---|
1109 | else
|
---|
1110 | movT3(rd, imm);
|
---|
1111 | }
|
---|
1112 |
|
---|
1113 | void mov(RegisterID rd, RegisterID rm)
|
---|
1114 | {
|
---|
1115 | m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd);
|
---|
1116 | }
|
---|
1117 |
|
---|
1118 | void movt(RegisterID rd, ARMThumbImmediate imm)
|
---|
1119 | {
|
---|
1120 | ASSERT(imm.isUInt16());
|
---|
1121 | ASSERT(!BadReg(rd));
|
---|
1122 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm);
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 | void mvn(RegisterID rd, ARMThumbImmediate imm)
|
---|
1126 | {
|
---|
1127 | ASSERT(imm.isEncodedImm());
|
---|
1128 | ASSERT(!BadReg(rd));
|
---|
1129 |
|
---|
1130 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm);
|
---|
1131 | }
|
---|
1132 |
|
---|
1133 | void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
1134 | {
|
---|
1135 | ASSERT(!BadReg(rd));
|
---|
1136 | ASSERT(!BadReg(rm));
|
---|
1137 | m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1138 | }
|
---|
1139 |
|
---|
1140 | void mvn(RegisterID rd, RegisterID rm)
|
---|
1141 | {
|
---|
1142 | if (!((rd | rm) & 8))
|
---|
1143 | m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd);
|
---|
1144 | else
|
---|
1145 | mvn(rd, rm, ShiftTypeAndAmount());
|
---|
1146 | }
|
---|
1147 |
|
---|
1148 | void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
1149 | {
|
---|
1150 | ASSERT(!BadReg(rd));
|
---|
1151 | ASSERT(!BadReg(rn));
|
---|
1152 | ASSERT(imm.isEncodedImm());
|
---|
1153 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm);
|
---|
1154 | }
|
---|
1155 |
|
---|
1156 | void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
1157 | {
|
---|
1158 | ASSERT(!BadReg(rd));
|
---|
1159 | ASSERT(!BadReg(rn));
|
---|
1160 | ASSERT(!BadReg(rm));
|
---|
1161 | m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1162 | }
|
---|
1163 |
|
---|
1164 | void orr(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
1165 | {
|
---|
1166 | if ((rd == rn) && !((rd | rm) & 8))
|
---|
1167 | m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd);
|
---|
1168 | else if ((rd == rm) && !((rd | rn) & 8))
|
---|
1169 | m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd);
|
---|
1170 | else
|
---|
1171 | orr(rd, rn, rm, ShiftTypeAndAmount());
|
---|
1172 | }
|
---|
1173 |
|
---|
1174 | void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount)
|
---|
1175 | {
|
---|
1176 | ASSERT(!BadReg(rd));
|
---|
1177 | ASSERT(!BadReg(rm));
|
---|
1178 | ShiftTypeAndAmount shift(SRType_ROR, shiftAmount);
|
---|
1179 | m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | void ror(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
1183 | {
|
---|
1184 | ASSERT(!BadReg(rd));
|
---|
1185 | ASSERT(!BadReg(rn));
|
---|
1186 | ASSERT(!BadReg(rm));
|
---|
1187 | m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm));
|
---|
1188 | }
|
---|
1189 |
|
---|
1190 | void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm)
|
---|
1191 | {
|
---|
1192 | ASSERT(!BadReg(rdLo));
|
---|
1193 | ASSERT(!BadReg(rdHi));
|
---|
1194 | ASSERT(!BadReg(rn));
|
---|
1195 | ASSERT(!BadReg(rm));
|
---|
1196 | ASSERT(rdLo != rdHi);
|
---|
1197 | m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm));
|
---|
1198 | }
|
---|
1199 |
|
---|
1200 | // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
|
---|
1201 | void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
|
---|
1202 | {
|
---|
1203 | ASSERT(rt != ARMRegisters::pc);
|
---|
1204 | ASSERT(rn != ARMRegisters::pc);
|
---|
1205 | ASSERT(imm.isUInt12());
|
---|
1206 |
|
---|
1207 | if (!((rt | rn) & 8) && imm.isUInt7())
|
---|
1208 | m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt);
|
---|
1209 | else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10())
|
---|
1210 | m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2);
|
---|
1211 | else
|
---|
1212 | m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12());
|
---|
1213 | }
|
---|
1214 |
|
---|
1215 | // If index is set, this is a regular offset or a pre-indexed store;
|
---|
1216 | // if index is not set then is is a post-index store.
|
---|
1217 | //
|
---|
1218 | // If wback is set rn is updated - this is a pre or post index store,
|
---|
1219 | // if wback is not set this is a regular offset memory access.
|
---|
1220 | //
|
---|
1221 | // (-255 <= offset <= 255)
|
---|
1222 | // _reg = REG[rn]
|
---|
1223 | // _tmp = _reg + offset
|
---|
1224 | // MEM[index ? _tmp : _reg] = REG[rt]
|
---|
1225 | // if (wback) REG[rn] = _tmp
|
---|
1226 | void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback)
|
---|
1227 | {
|
---|
1228 | ASSERT(rt != ARMRegisters::pc);
|
---|
1229 | ASSERT(rn != ARMRegisters::pc);
|
---|
1230 | ASSERT(index || wback);
|
---|
1231 | ASSERT(!wback | (rt != rn));
|
---|
1232 |
|
---|
1233 | bool add = true;
|
---|
1234 | if (offset < 0) {
|
---|
1235 | add = false;
|
---|
1236 | offset = -offset;
|
---|
1237 | }
|
---|
1238 | ASSERT((offset & ~0xff) == 0);
|
---|
1239 |
|
---|
1240 | offset |= (wback << 8);
|
---|
1241 | offset |= (add << 9);
|
---|
1242 | offset |= (index << 10);
|
---|
1243 | offset |= (1 << 11);
|
---|
1244 |
|
---|
1245 | m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset);
|
---|
1246 | }
|
---|
1247 |
|
---|
1248 | // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block.
|
---|
1249 | void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0)
|
---|
1250 | {
|
---|
1251 | ASSERT(rn != ARMRegisters::pc);
|
---|
1252 | ASSERT(!BadReg(rm));
|
---|
1253 | ASSERT(shift <= 3);
|
---|
1254 |
|
---|
1255 | if (!shift && !((rt | rn | rm) & 8))
|
---|
1256 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt);
|
---|
1257 | else
|
---|
1258 | m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm));
|
---|
1259 | }
|
---|
1260 |
|
---|
1261 | void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
1262 | {
|
---|
1263 | // Rd can only be SP if Rn is also SP.
|
---|
1264 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
1265 | ASSERT(rd != ARMRegisters::pc);
|
---|
1266 | ASSERT(rn != ARMRegisters::pc);
|
---|
1267 | ASSERT(imm.isValid());
|
---|
1268 |
|
---|
1269 | if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
|
---|
1270 | m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
|
---|
1271 | return;
|
---|
1272 | } else if (!((rd | rn) & 8)) {
|
---|
1273 | if (imm.isUInt3()) {
|
---|
1274 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
|
---|
1275 | return;
|
---|
1276 | } else if ((rd == rn) && imm.isUInt8()) {
|
---|
1277 | m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8());
|
---|
1278 | return;
|
---|
1279 | }
|
---|
1280 | }
|
---|
1281 |
|
---|
1282 | if (imm.isEncodedImm())
|
---|
1283 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm);
|
---|
1284 | else {
|
---|
1285 | ASSERT(imm.isUInt12());
|
---|
1286 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm);
|
---|
1287 | }
|
---|
1288 | }
|
---|
1289 |
|
---|
1290 | void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
1291 | {
|
---|
1292 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
1293 | ASSERT(rd != ARMRegisters::pc);
|
---|
1294 | ASSERT(rn != ARMRegisters::pc);
|
---|
1295 | ASSERT(!BadReg(rm));
|
---|
1296 | m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1297 | }
|
---|
1298 |
|
---|
1299 | // NOTE: In an IT block, add doesn't modify the flags register.
|
---|
1300 | void sub(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
1301 | {
|
---|
1302 | if (!((rd | rn | rm) & 8))
|
---|
1303 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd);
|
---|
1304 | else
|
---|
1305 | sub(rd, rn, rm, ShiftTypeAndAmount());
|
---|
1306 | }
|
---|
1307 |
|
---|
1308 | // Not allowed in an IT (if then) block.
|
---|
1309 | void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm)
|
---|
1310 | {
|
---|
1311 | // Rd can only be SP if Rn is also SP.
|
---|
1312 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
1313 | ASSERT(rd != ARMRegisters::pc);
|
---|
1314 | ASSERT(rn != ARMRegisters::pc);
|
---|
1315 | ASSERT(imm.isValid());
|
---|
1316 |
|
---|
1317 | if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) {
|
---|
1318 | m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2);
|
---|
1319 | return;
|
---|
1320 | } else if (!((rd | rn) & 8)) {
|
---|
1321 | if (imm.isUInt3()) {
|
---|
1322 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd);
|
---|
1323 | return;
|
---|
1324 | } else if ((rd == rn) && imm.isUInt8()) {
|
---|
1325 | m_formatter.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2, rd, imm.getUInt8());
|
---|
1326 | return;
|
---|
1327 | }
|
---|
1328 | }
|
---|
1329 |
|
---|
1330 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm);
|
---|
1331 | }
|
---|
1332 |
|
---|
1333 | // Not allowed in an IT (if then) block?
|
---|
1334 | void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
1335 | {
|
---|
1336 | ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp));
|
---|
1337 | ASSERT(rd != ARMRegisters::pc);
|
---|
1338 | ASSERT(rn != ARMRegisters::pc);
|
---|
1339 | ASSERT(!BadReg(rm));
|
---|
1340 | m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm));
|
---|
1341 | }
|
---|
1342 |
|
---|
1343 | // Not allowed in an IT (if then) block.
|
---|
1344 | void sub_S(RegisterID rd, RegisterID rn, RegisterID rm)
|
---|
1345 | {
|
---|
1346 | if (!((rd | rn | rm) & 8))
|
---|
1347 | m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1, rm, rn, rd);
|
---|
1348 | else
|
---|
1349 | sub_S(rd, rn, rm, ShiftTypeAndAmount());
|
---|
1350 | }
|
---|
1351 |
|
---|
1352 | void tst(RegisterID rn, ARMThumbImmediate imm)
|
---|
1353 | {
|
---|
1354 | ASSERT(!BadReg(rn));
|
---|
1355 | ASSERT(imm.isEncodedImm());
|
---|
1356 |
|
---|
1357 | m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm);
|
---|
1358 | }
|
---|
1359 |
|
---|
1360 | void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift)
|
---|
1361 | {
|
---|
1362 | ASSERT(!BadReg(rn));
|
---|
1363 | ASSERT(!BadReg(rm));
|
---|
1364 | m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm));
|
---|
1365 | }
|
---|
1366 |
|
---|
1367 | void tst(RegisterID rn, RegisterID rm)
|
---|
1368 | {
|
---|
1369 | if ((rn | rm) & 8)
|
---|
1370 | tst(rn, rm, ShiftTypeAndAmount());
|
---|
1371 | else
|
---|
1372 | m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn);
|
---|
1373 | }
|
---|
1374 |
|
---|
1375 | void vadd_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
|
---|
1376 | {
|
---|
1377 | m_formatter.vfpOp(0x0b00ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
|
---|
1378 | }
|
---|
1379 |
|
---|
1380 | void vcmp_F64(FPRegisterID rd, FPRegisterID rm)
|
---|
1381 | {
|
---|
1382 | m_formatter.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rm, 21, 16));
|
---|
1383 | }
|
---|
1384 |
|
---|
1385 | void vcvt_F64_S32(FPRegisterID fd, FPRegisterID sm)
|
---|
1386 | {
|
---|
1387 | m_formatter.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd, 6, 28) | singleRegisterMask(sm, 16, 21));
|
---|
1388 | }
|
---|
1389 |
|
---|
1390 | void vcvt_S32_F64(FPRegisterID sd, FPRegisterID fm)
|
---|
1391 | {
|
---|
1392 | m_formatter.vfpOp(0x0bc0eebd | singleRegisterMask(sd, 28, 6) | doubleRegisterMask(fm, 21, 16));
|
---|
1393 | }
|
---|
1394 |
|
---|
1395 | void vldr(FPRegisterID rd, RegisterID rn, int32_t imm)
|
---|
1396 | {
|
---|
1397 | vmem(rd, rn, imm, true);
|
---|
1398 | }
|
---|
1399 |
|
---|
1400 | void vmov(RegisterID rd, FPRegisterID sn)
|
---|
1401 | {
|
---|
1402 | m_formatter.vfpOp(0x0a10ee10 | (rd << 28) | singleRegisterMask(sn, 0, 23));
|
---|
1403 | }
|
---|
1404 |
|
---|
1405 | void vmov(FPRegisterID sn, RegisterID rd)
|
---|
1406 | {
|
---|
1407 | m_formatter.vfpOp(0x0a10ee00 | (rd << 28) | singleRegisterMask(sn, 0, 23));
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | // move FPSCR flags to APSR.
|
---|
1411 | void vmrs_APSR_nzcv_FPSCR()
|
---|
1412 | {
|
---|
1413 | m_formatter.vfpOp(0xfa10eef1);
|
---|
1414 | }
|
---|
1415 |
|
---|
1416 | void vmul_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
|
---|
1417 | {
|
---|
1418 | m_formatter.vfpOp(0x0b00ee20 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
|
---|
1419 | }
|
---|
1420 |
|
---|
1421 | void vstr(FPRegisterID rd, RegisterID rn, int32_t imm)
|
---|
1422 | {
|
---|
1423 | vmem(rd, rn, imm, false);
|
---|
1424 | }
|
---|
1425 |
|
---|
1426 | void vsub_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm)
|
---|
1427 | {
|
---|
1428 | m_formatter.vfpOp(0x0b40ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16));
|
---|
1429 | }
|
---|
1430 |
|
---|
1431 |
|
---|
1432 | JmpDst label()
|
---|
1433 | {
|
---|
1434 | return JmpDst(m_formatter.size());
|
---|
1435 | }
|
---|
1436 |
|
---|
1437 | JmpDst align(int alignment)
|
---|
1438 | {
|
---|
1439 | while (!m_formatter.isAligned(alignment))
|
---|
1440 | bkpt();
|
---|
1441 |
|
---|
1442 | return label();
|
---|
1443 | }
|
---|
1444 |
|
---|
1445 | static void* getRelocatedAddress(void* code, JmpSrc jump)
|
---|
1446 | {
|
---|
1447 | ASSERT(jump.m_offset != -1);
|
---|
1448 |
|
---|
1449 | return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
|
---|
1450 | }
|
---|
1451 |
|
---|
1452 | static void* getRelocatedAddress(void* code, JmpDst destination)
|
---|
1453 | {
|
---|
1454 | ASSERT(destination.m_offset != -1);
|
---|
1455 |
|
---|
1456 | return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
|
---|
1457 | }
|
---|
1458 |
|
---|
1459 | static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
|
---|
1460 | {
|
---|
1461 | return dst.m_offset - src.m_offset;
|
---|
1462 | }
|
---|
1463 |
|
---|
1464 | static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
|
---|
1465 | {
|
---|
1466 | return dst.m_offset - src.m_offset;
|
---|
1467 | }
|
---|
1468 |
|
---|
1469 | static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
|
---|
1470 | {
|
---|
1471 | return dst.m_offset - src.m_offset;
|
---|
1472 | }
|
---|
1473 |
|
---|
1474 | // Assembler admin methods:
|
---|
1475 |
|
---|
1476 | size_t size() const
|
---|
1477 | {
|
---|
1478 | return m_formatter.size();
|
---|
1479 | }
|
---|
1480 |
|
---|
1481 | void* executableCopy(ExecutablePool* allocator)
|
---|
1482 | {
|
---|
1483 | void* copy = m_formatter.executableCopy(allocator);
|
---|
1484 | ASSERT(copy);
|
---|
1485 | return copy;
|
---|
1486 | }
|
---|
1487 |
|
---|
1488 | static unsigned getCallReturnOffset(JmpSrc call)
|
---|
1489 | {
|
---|
1490 | ASSERT(call.m_offset >= 0);
|
---|
1491 | return call.m_offset;
|
---|
1492 | }
|
---|
1493 |
|
---|
1494 | // Linking & patching:
|
---|
1495 | //
|
---|
1496 | // 'link' and 'patch' methods are for use on unprotected code - such as the code
|
---|
1497 | // within the AssemblerBuffer, and code being patched by the patch buffer. Once
|
---|
1498 | // code has been finalized it is (platform support permitting) within a non-
|
---|
1499 | // writable region of memory; to modify the code in an execute-only execuable
|
---|
1500 | // pool the 'repatch' and 'relink' methods should be used.
|
---|
1501 |
|
---|
1502 | void linkJump(JmpSrc from, JmpDst to)
|
---|
1503 | {
|
---|
1504 | ASSERT(to.m_offset != -1);
|
---|
1505 | ASSERT(from.m_offset != -1);
|
---|
1506 |
|
---|
1507 | uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(m_formatter.data()) + from.m_offset);
|
---|
1508 | intptr_t relative = to.m_offset - from.m_offset;
|
---|
1509 |
|
---|
1510 | linkWithOffset(location, relative);
|
---|
1511 | }
|
---|
1512 |
|
---|
1513 | static void linkJump(void* code, JmpSrc from, void* to)
|
---|
1514 | {
|
---|
1515 | ASSERT(from.m_offset != -1);
|
---|
1516 |
|
---|
1517 | uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
|
---|
1518 | intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(location);
|
---|
1519 |
|
---|
1520 | linkWithOffset(location, relative);
|
---|
1521 | }
|
---|
1522 |
|
---|
1523 | // bah, this mathod should really be static, since it is used by the LinkBuffer.
|
---|
1524 | // return a bool saying whether the link was successful?
|
---|
1525 | static void linkCall(void* code, JmpSrc from, void* to)
|
---|
1526 | {
|
---|
1527 | ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
|
---|
1528 | ASSERT(from.m_offset != -1);
|
---|
1529 | ASSERT(reinterpret_cast<intptr_t>(to) & 1);
|
---|
1530 |
|
---|
1531 | setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to);
|
---|
1532 | }
|
---|
1533 |
|
---|
1534 | static void linkPointer(void* code, JmpDst where, void* value)
|
---|
1535 | {
|
---|
1536 | setPointer(reinterpret_cast<char*>(code) + where.m_offset, value);
|
---|
1537 | }
|
---|
1538 |
|
---|
1539 | static void relinkJump(void* from, void* to)
|
---|
1540 | {
|
---|
1541 | ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
|
---|
1542 | ASSERT(!(reinterpret_cast<intptr_t>(to) & 1));
|
---|
1543 |
|
---|
1544 | intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from);
|
---|
1545 | linkWithOffset(reinterpret_cast<uint16_t*>(from), relative);
|
---|
1546 |
|
---|
1547 | ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 2, 2 * sizeof(uint16_t));
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | static void relinkCall(void* from, void* to)
|
---|
1551 | {
|
---|
1552 | ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
|
---|
1553 | ASSERT(reinterpret_cast<intptr_t>(to) & 1);
|
---|
1554 |
|
---|
1555 | setPointer(reinterpret_cast<uint16_t*>(from) - 1, to);
|
---|
1556 |
|
---|
1557 | ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 4 * sizeof(uint16_t));
|
---|
1558 | }
|
---|
1559 |
|
---|
1560 | static void repatchInt32(void* where, int32_t value)
|
---|
1561 | {
|
---|
1562 | ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
|
---|
1563 |
|
---|
1564 | setInt32(where, value);
|
---|
1565 |
|
---|
1566 | ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
|
---|
1567 | }
|
---|
1568 |
|
---|
1569 | static void repatchPointer(void* where, void* value)
|
---|
1570 | {
|
---|
1571 | ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
|
---|
1572 |
|
---|
1573 | setPointer(where, value);
|
---|
1574 |
|
---|
1575 | ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(where) - 4, 4 * sizeof(uint16_t));
|
---|
1576 | }
|
---|
1577 |
|
---|
1578 | static void repatchLoadPtrToLEA(void* where)
|
---|
1579 | {
|
---|
1580 | ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
|
---|
1581 |
|
---|
1582 | uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4;
|
---|
1583 | ASSERT((*loadOp & 0xfff0) == OP_LDR_reg_T2);
|
---|
1584 |
|
---|
1585 | *loadOp = OP_ADD_reg_T3 | (*loadOp & 0xf);
|
---|
1586 | ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t));
|
---|
1587 | }
|
---|
1588 |
|
---|
1589 | private:
|
---|
1590 |
|
---|
1591 | // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
|
---|
1592 | // (i.e. +/-(0..255) 32-bit words)
|
---|
1593 | void vmem(FPRegisterID rd, RegisterID rn, int32_t imm, bool isLoad)
|
---|
1594 | {
|
---|
1595 | bool up;
|
---|
1596 | uint32_t offset;
|
---|
1597 | if (imm < 0) {
|
---|
1598 | offset = -imm;
|
---|
1599 | up = false;
|
---|
1600 | } else {
|
---|
1601 | offset = imm;
|
---|
1602 | up = true;
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 | // offset is effectively leftshifted by 2 already (the bottom two bits are zero, and not
|
---|
1606 | // reperesented in the instruction. Left shift by 14, to mov it into position 0x00AA0000.
|
---|
1607 | ASSERT((offset & ~(0xff << 2)) == 0);
|
---|
1608 | offset <<= 14;
|
---|
1609 |
|
---|
1610 | m_formatter.vfpOp(0x0b00ed00 | offset | (up << 7) | (isLoad << 4) | doubleRegisterMask(rd, 6, 28) | rn);
|
---|
1611 | }
|
---|
1612 |
|
---|
1613 | static void setInt32(void* code, uint32_t value)
|
---|
1614 | {
|
---|
1615 | uint16_t* location = reinterpret_cast<uint16_t*>(code);
|
---|
1616 |
|
---|
1617 | uint16_t lo16 = value;
|
---|
1618 | uint16_t hi16 = value >> 16;
|
---|
1619 |
|
---|
1620 | spliceHi5(location - 4, lo16);
|
---|
1621 | spliceLo11(location - 3, lo16);
|
---|
1622 | spliceHi5(location - 2, hi16);
|
---|
1623 | spliceLo11(location - 1, hi16);
|
---|
1624 |
|
---|
1625 | ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t));
|
---|
1626 | }
|
---|
1627 |
|
---|
1628 | static void setPointer(void* code, void* value)
|
---|
1629 | {
|
---|
1630 | setInt32(code, reinterpret_cast<uint32_t>(value));
|
---|
1631 | }
|
---|
1632 |
|
---|
1633 | // Linking & patching:
|
---|
1634 | // This method assumes that the JmpSrc being linked is a T4 b instruction.
|
---|
1635 | static void linkWithOffset(uint16_t* instruction, intptr_t relative)
|
---|
1636 | {
|
---|
1637 | // Currently branches > 16m = mostly deathy.
|
---|
1638 | if (((relative << 7) >> 7) != relative) {
|
---|
1639 | // FIXME: This CRASH means we cannot turn the JIT on by default on arm-v7.
|
---|
1640 | fprintf(stderr, "Error: Cannot link T4b.\n");
|
---|
1641 | CRASH();
|
---|
1642 | }
|
---|
1643 |
|
---|
1644 | // ARM encoding for the top two bits below the sign bit is 'peculiar'.
|
---|
1645 | if (relative >= 0)
|
---|
1646 | relative ^= 0xC00000;
|
---|
1647 |
|
---|
1648 | // All branch offsets should be an even distance.
|
---|
1649 | ASSERT(!(relative & 1));
|
---|
1650 |
|
---|
1651 | int word1 = ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12);
|
---|
1652 | int word2 = ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1);
|
---|
1653 |
|
---|
1654 | instruction[-2] = OP_B_T4a | word1;
|
---|
1655 | instruction[-1] = OP_B_T4b | word2;
|
---|
1656 | }
|
---|
1657 |
|
---|
1658 | // These functions can be used to splice 16-bit immediates back into previously generated instructions.
|
---|
1659 | static void spliceHi5(uint16_t* where, uint16_t what)
|
---|
1660 | {
|
---|
1661 | uint16_t pattern = (what >> 12) | ((what & 0x0800) >> 1);
|
---|
1662 | *where = (*where & 0xFBF0) | pattern;
|
---|
1663 | }
|
---|
1664 | static void spliceLo11(uint16_t* where, uint16_t what)
|
---|
1665 | {
|
---|
1666 | uint16_t pattern = ((what & 0x0700) << 4) | (what & 0x00FF);
|
---|
1667 | *where = (*where & 0x8F00) | pattern;
|
---|
1668 | }
|
---|
1669 |
|
---|
1670 | class ARMInstructionFormatter {
|
---|
1671 | public:
|
---|
1672 | void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm)
|
---|
1673 | {
|
---|
1674 | m_buffer.putShort(op | (rd << 8) | imm);
|
---|
1675 | }
|
---|
1676 |
|
---|
1677 | void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2)
|
---|
1678 | {
|
---|
1679 | m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2);
|
---|
1680 | }
|
---|
1681 |
|
---|
1682 | void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3)
|
---|
1683 | {
|
---|
1684 | m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3);
|
---|
1685 | }
|
---|
1686 |
|
---|
1687 | void oneWordOp8Imm8(OpcodeID op, uint8_t imm)
|
---|
1688 | {
|
---|
1689 | m_buffer.putShort(op | imm);
|
---|
1690 | }
|
---|
1691 |
|
---|
1692 | void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2)
|
---|
1693 | {
|
---|
1694 | m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7));
|
---|
1695 | }
|
---|
1696 | void oneWordOp9Imm7(OpcodeID op, uint8_t imm)
|
---|
1697 | {
|
---|
1698 | m_buffer.putShort(op | imm);
|
---|
1699 | }
|
---|
1700 |
|
---|
1701 | void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2)
|
---|
1702 | {
|
---|
1703 | m_buffer.putShort(op | (reg1 << 3) | reg2);
|
---|
1704 | }
|
---|
1705 |
|
---|
1706 | void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff)
|
---|
1707 | {
|
---|
1708 | m_buffer.putShort(op | reg);
|
---|
1709 | m_buffer.putShort(ff.m_u.value);
|
---|
1710 | }
|
---|
1711 |
|
---|
1712 | void twoWordOp16FourFours(OpcodeID1 op, FourFours ff)
|
---|
1713 | {
|
---|
1714 | m_buffer.putShort(op);
|
---|
1715 | m_buffer.putShort(ff.m_u.value);
|
---|
1716 | }
|
---|
1717 |
|
---|
1718 | void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2)
|
---|
1719 | {
|
---|
1720 | m_buffer.putShort(op1);
|
---|
1721 | m_buffer.putShort(op2);
|
---|
1722 | }
|
---|
1723 |
|
---|
1724 | void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm)
|
---|
1725 | {
|
---|
1726 | m_buffer.putShort(op | (imm.m_value.i << 10) | imm4);
|
---|
1727 | m_buffer.putShort((imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8);
|
---|
1728 | }
|
---|
1729 |
|
---|
1730 | void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm)
|
---|
1731 | {
|
---|
1732 | m_buffer.putShort(op | reg1);
|
---|
1733 | m_buffer.putShort((reg2 << 12) | imm);
|
---|
1734 | }
|
---|
1735 |
|
---|
1736 | void vfpOp(int32_t op)
|
---|
1737 | {
|
---|
1738 | m_buffer.putInt(op);
|
---|
1739 | }
|
---|
1740 |
|
---|
1741 |
|
---|
1742 | // Administrative methods:
|
---|
1743 |
|
---|
1744 | size_t size() const { return m_buffer.size(); }
|
---|
1745 | bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
|
---|
1746 | void* data() const { return m_buffer.data(); }
|
---|
1747 | void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); }
|
---|
1748 |
|
---|
1749 | private:
|
---|
1750 | AssemblerBuffer m_buffer;
|
---|
1751 | } m_formatter;
|
---|
1752 | };
|
---|
1753 |
|
---|
1754 | } // namespace JSC
|
---|
1755 |
|
---|
1756 | #endif // ENABLE(ASSEMBLER) && PLATFORM(ARM_THUMB2)
|
---|
1757 |
|
---|
1758 | #endif // ARMAssembler_h
|
---|