blob: 6b16a2e068cdc3262d9ab807f5e166937283cb32 [file] [log] [blame]
Dave Allison65fcc2c2014-04-28 13:45:27 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "assembler_thumb2.h"
18
19#include "base/logging.h"
20#include "entrypoints/quick/quick_entrypoints.h"
21#include "offsets.h"
22#include "thread.h"
23#include "utils.h"
24
25namespace art {
26namespace arm {
27
28void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so,
29 Condition cond) {
30 EmitDataProcessing(cond, AND, 0, rn, rd, so);
31}
32
33
34void Thumb2Assembler::eor(Register rd, Register rn, const ShifterOperand& so,
35 Condition cond) {
36 EmitDataProcessing(cond, EOR, 0, rn, rd, so);
37}
38
39
40void Thumb2Assembler::sub(Register rd, Register rn, const ShifterOperand& so,
41 Condition cond) {
42 EmitDataProcessing(cond, SUB, 0, rn, rd, so);
43}
44
45
46void Thumb2Assembler::rsb(Register rd, Register rn, const ShifterOperand& so,
47 Condition cond) {
48 EmitDataProcessing(cond, RSB, 0, rn, rd, so);
49}
50
51
52void Thumb2Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so,
53 Condition cond) {
54 EmitDataProcessing(cond, RSB, 1, rn, rd, so);
55}
56
57
58void Thumb2Assembler::add(Register rd, Register rn, const ShifterOperand& so,
59 Condition cond) {
60 EmitDataProcessing(cond, ADD, 0, rn, rd, so);
61}
62
63
64void Thumb2Assembler::adds(Register rd, Register rn, const ShifterOperand& so,
65 Condition cond) {
66 EmitDataProcessing(cond, ADD, 1, rn, rd, so);
67}
68
69
70void Thumb2Assembler::subs(Register rd, Register rn, const ShifterOperand& so,
71 Condition cond) {
72 EmitDataProcessing(cond, SUB, 1, rn, rd, so);
73}
74
75
76void Thumb2Assembler::adc(Register rd, Register rn, const ShifterOperand& so,
77 Condition cond) {
78 EmitDataProcessing(cond, ADC, 0, rn, rd, so);
79}
80
81
82void Thumb2Assembler::sbc(Register rd, Register rn, const ShifterOperand& so,
83 Condition cond) {
84 EmitDataProcessing(cond, SBC, 0, rn, rd, so);
85}
86
87
88void Thumb2Assembler::rsc(Register rd, Register rn, const ShifterOperand& so,
89 Condition cond) {
90 EmitDataProcessing(cond, RSC, 0, rn, rd, so);
91}
92
93
94void Thumb2Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) {
95 CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker.
96 EmitDataProcessing(cond, TST, 1, rn, R0, so);
97}
98
99
100void Thumb2Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) {
101 CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker.
102 EmitDataProcessing(cond, TEQ, 1, rn, R0, so);
103}
104
105
106void Thumb2Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) {
107 EmitDataProcessing(cond, CMP, 1, rn, R0, so);
108}
109
110
111void Thumb2Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) {
112 EmitDataProcessing(cond, CMN, 1, rn, R0, so);
113}
114
115
116void Thumb2Assembler::orr(Register rd, Register rn,
117 const ShifterOperand& so, Condition cond) {
118 EmitDataProcessing(cond, ORR, 0, rn, rd, so);
119}
120
121
122void Thumb2Assembler::orrs(Register rd, Register rn,
123 const ShifterOperand& so, Condition cond) {
124 EmitDataProcessing(cond, ORR, 1, rn, rd, so);
125}
126
127
128void Thumb2Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) {
129 EmitDataProcessing(cond, MOV, 0, R0, rd, so);
130}
131
132
133void Thumb2Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) {
134 EmitDataProcessing(cond, MOV, 1, R0, rd, so);
135}
136
137
138void Thumb2Assembler::bic(Register rd, Register rn, const ShifterOperand& so,
139 Condition cond) {
140 EmitDataProcessing(cond, BIC, 0, rn, rd, so);
141}
142
143
144void Thumb2Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) {
145 EmitDataProcessing(cond, MVN, 0, R0, rd, so);
146}
147
148
149void Thumb2Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) {
150 EmitDataProcessing(cond, MVN, 1, R0, rd, so);
151}
152
153
154void Thumb2Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700155 CheckCondition(cond);
156
Dave Allison65fcc2c2014-04-28 13:45:27 -0700157 if (rd == rm && !IsHighRegister(rd) && !IsHighRegister(rn) && !force_32bit_) {
158 // 16 bit.
159 int16_t encoding = B14 | B9 | B8 | B6 |
160 rn << 3 | rd;
161 Emit16(encoding);
162 } else {
163 // 32 bit.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700164 uint32_t op1 = 0U /* 0b000 */;
165 uint32_t op2 = 0U /* 0b00 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700166 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
167 op1 << 20 |
168 B15 | B14 | B13 | B12 |
169 op2 << 4 |
170 static_cast<uint32_t>(rd) << 8 |
171 static_cast<uint32_t>(rn) << 16 |
172 static_cast<uint32_t>(rm);
173
174 Emit32(encoding);
175 }
176}
177
178
179void Thumb2Assembler::mla(Register rd, Register rn, Register rm, Register ra,
180 Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700181 CheckCondition(cond);
182
Andreas Gampec8ccf682014-09-29 20:07:43 -0700183 uint32_t op1 = 0U /* 0b000 */;
184 uint32_t op2 = 0U /* 0b00 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700185 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
186 op1 << 20 |
187 op2 << 4 |
188 static_cast<uint32_t>(rd) << 8 |
189 static_cast<uint32_t>(ra) << 12 |
190 static_cast<uint32_t>(rn) << 16 |
191 static_cast<uint32_t>(rm);
192
193 Emit32(encoding);
194}
195
196
197void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra,
198 Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700199 CheckCondition(cond);
200
Andreas Gampec8ccf682014-09-29 20:07:43 -0700201 uint32_t op1 = 0U /* 0b000 */;
202 uint32_t op2 = 01 /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700203 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
204 op1 << 20 |
205 op2 << 4 |
206 static_cast<uint32_t>(rd) << 8 |
207 static_cast<uint32_t>(ra) << 12 |
208 static_cast<uint32_t>(rn) << 16 |
209 static_cast<uint32_t>(rm);
210
211 Emit32(encoding);
212}
213
214
215void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
216 Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700217 CheckCondition(cond);
218
Andreas Gampec8ccf682014-09-29 20:07:43 -0700219 uint32_t op1 = 2U /* 0b010; */;
220 uint32_t op2 = 0U /* 0b0000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700221 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
222 op1 << 20 |
223 op2 << 4 |
224 static_cast<uint32_t>(rd_lo) << 12 |
225 static_cast<uint32_t>(rd_hi) << 8 |
226 static_cast<uint32_t>(rn) << 16 |
227 static_cast<uint32_t>(rm);
228
229 Emit32(encoding);
230}
231
232
233void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700234 CheckCondition(cond);
235
Andreas Gampec8ccf682014-09-29 20:07:43 -0700236 uint32_t op1 = 1U /* 0b001 */;
237 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700238 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 |
239 op1 << 20 |
240 op2 << 4 |
241 0xf << 12 |
242 static_cast<uint32_t>(rd) << 8 |
243 static_cast<uint32_t>(rn) << 16 |
244 static_cast<uint32_t>(rm);
245
246 Emit32(encoding);
247}
248
249
250void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700251 CheckCondition(cond);
252
Andreas Gampec8ccf682014-09-29 20:07:43 -0700253 uint32_t op1 = 1U /* 0b001 */;
254 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700255 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 |
256 op1 << 20 |
257 op2 << 4 |
258 0xf << 12 |
259 static_cast<uint32_t>(rd) << 8 |
260 static_cast<uint32_t>(rn) << 16 |
261 static_cast<uint32_t>(rm);
262
263 Emit32(encoding);
264}
265
266
Roland Levillain51d3fc42014-11-13 14:11:42 +0000267void Thumb2Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
268 CheckCondition(cond);
269 CHECK_LE(lsb, 31U);
270 CHECK(1U <= width && width <= 32U) << width;
271 uint32_t widthminus1 = width - 1;
272 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
273 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
274
275 uint32_t op = 20U /* 0b10100 */;
276 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
277 op << 20 |
278 static_cast<uint32_t>(rn) << 16 |
279 imm3 << 12 |
280 static_cast<uint32_t>(rd) << 8 |
281 imm2 << 6 |
282 widthminus1;
283
284 Emit32(encoding);
285}
286
287
Roland Levillain981e4542014-11-14 11:47:14 +0000288void Thumb2Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
289 CheckCondition(cond);
290 CHECK_LE(lsb, 31U);
291 CHECK(1U <= width && width <= 32U) << width;
292 uint32_t widthminus1 = width - 1;
293 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
294 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
295
296 uint32_t op = 28U /* 0b11100 */;
297 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
298 op << 20 |
299 static_cast<uint32_t>(rn) << 16 |
300 imm3 << 12 |
301 static_cast<uint32_t>(rd) << 8 |
302 imm2 << 6 |
303 widthminus1;
304
305 Emit32(encoding);
306}
307
308
Dave Allison65fcc2c2014-04-28 13:45:27 -0700309void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
310 EmitLoadStore(cond, true, false, false, false, rd, ad);
311}
312
313
314void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
315 EmitLoadStore(cond, false, false, false, false, rd, ad);
316}
317
318
319void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
320 EmitLoadStore(cond, true, true, false, false, rd, ad);
321}
322
323
324void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
325 EmitLoadStore(cond, false, true, false, false, rd, ad);
326}
327
328
329void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
330 EmitLoadStore(cond, true, false, true, false, rd, ad);
331}
332
333
334void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
335 EmitLoadStore(cond, false, false, true, false, rd, ad);
336}
337
338
339void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
340 EmitLoadStore(cond, true, true, false, true, rd, ad);
341}
342
343
344void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
345 EmitLoadStore(cond, true, false, true, true, rd, ad);
346}
347
348
349void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700350 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700351 CHECK_EQ(rd % 2, 0);
352 // This is different from other loads. The encoding is like ARM.
353 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
354 static_cast<int32_t>(rd) << 12 |
355 (static_cast<int32_t>(rd) + 1) << 8 |
356 ad.encodingThumbLdrdStrd();
357 Emit32(encoding);
358}
359
360
361void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700362 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700363 CHECK_EQ(rd % 2, 0);
364 // This is different from other loads. The encoding is like ARM.
365 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
366 static_cast<int32_t>(rd) << 12 |
367 (static_cast<int32_t>(rd) + 1) << 8 |
368 ad.encodingThumbLdrdStrd();
369 Emit32(encoding);
370}
371
372
373void Thumb2Assembler::ldm(BlockAddressMode am,
374 Register base,
375 RegList regs,
376 Condition cond) {
377 if (__builtin_popcount(regs) == 1) {
378 // Thumb doesn't support one reg in the list.
379 // Find the register number.
380 int reg = 0;
381 while (reg < 16) {
382 if ((regs & (1 << reg)) != 0) {
383 break;
384 }
385 ++reg;
386 }
387 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700388 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700389 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
390 } else {
391 EmitMultiMemOp(cond, am, true, base, regs);
392 }
393}
394
395
396void Thumb2Assembler::stm(BlockAddressMode am,
397 Register base,
398 RegList regs,
399 Condition cond) {
400 if (__builtin_popcount(regs) == 1) {
401 // Thumb doesn't support one reg in the list.
402 // Find the register number.
403 int reg = 0;
404 while (reg < 16) {
405 if ((regs & (1 << reg)) != 0) {
406 break;
407 }
408 ++reg;
409 }
410 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700411 CHECK(am == IA || am == IA_W);
412 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700413 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
414 } else {
415 EmitMultiMemOp(cond, am, false, base, regs);
416 }
417}
418
419
420bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
421 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
422 if (((imm32 & ((1 << 19) - 1)) == 0) &&
423 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
424 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
425 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
426 ((imm32 >> 19) & ((1 << 6) -1));
427 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
428 sd, S0, S0);
429 return true;
430 }
431 return false;
432}
433
434
435bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
436 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
437 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
438 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
439 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
440 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
441 ((imm64 >> 48) & ((1 << 6) -1));
442 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
443 dd, D0, D0);
444 return true;
445 }
446 return false;
447}
448
449
450void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
451 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
452}
453
454
455void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
456 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
457}
458
459
460void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
461 Condition cond) {
462 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
463}
464
465
466void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
467 Condition cond) {
468 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
469}
470
471
472void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
473 Condition cond) {
474 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
475}
476
477
478void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
479 Condition cond) {
480 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
481}
482
483
484void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
485 Condition cond) {
486 EmitVFPsss(cond, B21, sd, sn, sm);
487}
488
489
490void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
491 Condition cond) {
492 EmitVFPddd(cond, B21, dd, dn, dm);
493}
494
495
496void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
497 Condition cond) {
498 EmitVFPsss(cond, 0, sd, sn, sm);
499}
500
501
502void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
503 Condition cond) {
504 EmitVFPddd(cond, 0, dd, dn, dm);
505}
506
507
508void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
509 Condition cond) {
510 EmitVFPsss(cond, B6, sd, sn, sm);
511}
512
513
514void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
515 Condition cond) {
516 EmitVFPddd(cond, B6, dd, dn, dm);
517}
518
519
520void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
521 Condition cond) {
522 EmitVFPsss(cond, B23, sd, sn, sm);
523}
524
525
526void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
527 Condition cond) {
528 EmitVFPddd(cond, B23, dd, dn, dm);
529}
530
531
532void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
533 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
534}
535
536
537void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
538 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
539}
540
541
542void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
543 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
544}
545
546
547void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
548 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
549}
550
551
552void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
553 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
554}
555
556void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
557 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
558}
559
560
561void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
562 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
563}
564
565
566void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
567 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
568}
569
570
571void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
572 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
573}
574
575
576void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
577 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
578}
579
580
581void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
582 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
583}
584
585
586void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
587 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
588}
589
590
591void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
592 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
593}
594
595
596void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
597 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
598}
599
600
601void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
602 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
603}
604
605
606void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
607 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
608}
609
610
611void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
612 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
613}
614
615
616void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
617 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
618}
619
620
621void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
622 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
623}
624
625
626void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
627 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
628}
629
630void Thumb2Assembler::b(Label* label, Condition cond) {
631 EmitBranch(cond, label, false, false);
632}
633
634
635void Thumb2Assembler::bl(Label* label, Condition cond) {
636 CheckCondition(cond);
637 EmitBranch(cond, label, true, false);
638}
639
640
641void Thumb2Assembler::blx(Label* label) {
642 EmitBranch(AL, label, true, true);
643}
644
645
646void Thumb2Assembler::MarkExceptionHandler(Label* label) {
647 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
648 Label l;
649 b(&l);
650 EmitBranch(AL, label, false, false);
651 Bind(&l);
652}
653
654
655void Thumb2Assembler::Emit32(int32_t value) {
656 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
657 buffer_.Emit<int16_t>(value >> 16);
658 buffer_.Emit<int16_t>(value & 0xffff);
659}
660
661
662void Thumb2Assembler::Emit16(int16_t value) {
663 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
664 buffer_.Emit<int16_t>(value);
665}
666
667
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700668bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700669 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700670 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700671 Register rn,
672 Register rd,
673 const ShifterOperand& so) {
674 if (force_32bit_) {
675 return true;
676 }
677
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100678 bool can_contain_high_register = (opcode == MOV)
679 || ((opcode == ADD || opcode == SUB) && (rn == rd));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700680
681 if (IsHighRegister(rd) || IsHighRegister(rn)) {
682 if (can_contain_high_register) {
683 // There are high register instructions available for this opcode.
684 // However, there is no RRX available.
685 if (so.IsShift() && so.GetShift() == RRX) {
686 return true;
687 }
688
689 // Check special case for SP relative ADD and SUB immediate.
690 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
691 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
692 if (rn == SP && rd != SP && IsHighRegister(rd)) {
693 return true;
694 }
695
696 uint32_t imm = so.GetImmediate();
697 // If the immediates are out of range use 32 bit.
698 if (rd == SP && rn == SP) {
699 if (imm > (1 << 9)) { // 9 bit immediate.
700 return true;
701 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700702 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
703 if (imm > (1 << 10)) {
704 return true;
705 }
706 } else if (opcode == SUB && rd != SP && rn == SP) {
707 // SUB rd, SP, #imm is always 32 bit.
708 return true;
709 }
710 }
711 }
712
713 // The ADD,SUB and MOV instructions that work with high registers don't have
714 // immediate variants.
715 if (so.IsImmediate()) {
716 return true;
717 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100718
719 if (!can_contain_high_register) {
720 return true;
721 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700722 }
723
724 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
725 return true;
726 }
727
728 // Check for MOV with an ROR.
729 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
730 if (so.GetImmediate() != 0) {
731 return true;
732 }
733 }
734
735 bool rn_is_valid = true;
736
737 // Check for single operand instructions and ADD/SUB.
738 switch (opcode) {
739 case CMP:
740 case MOV:
741 case TST:
742 case MVN:
743 rn_is_valid = false; // There is no Rn for these instructions.
744 break;
745 case TEQ:
746 return true;
747 break;
748 case ADD:
749 case SUB:
750 break;
751 default:
752 if (so.IsRegister() && rd != rn) {
753 return true;
754 }
755 }
756
757 if (so.IsImmediate()) {
758 if (rn_is_valid && rn != rd) {
759 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
760 // immediate must be 3 bits.
761 if (opcode != ADD && opcode != SUB) {
762 return true;
763 } else {
764 // Check that the immediate is 3 bits for ADD and SUB.
765 if (so.GetImmediate() >= 8) {
766 return true;
767 }
768 }
769 } else {
770 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
771 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
772 return true;
773 } else {
774 if (so.GetImmediate() > 255) {
775 return true;
776 }
777 }
778 }
779 }
780
781 // The instruction can be encoded in 16 bits.
782 return false;
783}
784
785
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700786void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700787 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700788 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700789 Register rn,
790 Register rd,
791 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700792 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700793 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700794 case AND: thumb_opcode = 0U /* 0b0000 */; break;
795 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
796 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
797 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
798 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700799 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700800 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700801 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700802 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
803 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
804 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
805 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
806 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
807 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
808 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
809 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700810 default:
811 break;
812 }
813
Andreas Gampec8ccf682014-09-29 20:07:43 -0700814 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700815 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
816 }
817
818 int32_t encoding = 0;
819 if (so.IsImmediate()) {
820 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100821 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700822 if (opcode == SUB) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700823 thumb_opcode = 5U /* 0b0101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700824 } else {
825 thumb_opcode = 0;
826 }
827 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700828
829 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700830 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700831 uint32_t imm8 = imm & 0xff;
832
833 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700834 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100835 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700836 rd << 8 |
837 i << 26 |
838 imm3 << 12 |
839 imm8;
840 } else {
841 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700842 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700843 if (imm == kInvalidModifiedImmediate) {
844 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
845 }
846 encoding = B31 | B30 | B29 | B28 |
847 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700848 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700849 rn << 16 |
850 rd << 8 |
851 imm;
852 }
853 } else if (so.IsRegister()) {
854 // Register (possibly shifted)
855 encoding = B31 | B30 | B29 | B27 | B25 |
856 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700857 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700858 rn << 16 |
859 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700860 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700861 }
862 Emit32(encoding);
863}
864
865
866void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
867 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700868 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700869 Register rn,
870 Register rd,
871 const ShifterOperand& so) {
872 if (opcode == ADD || opcode == SUB) {
873 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
874 return;
875 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700876 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700877 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700878 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700879 uint8_t opcode_shift = 6;
880 uint8_t rd_shift = 0;
881 uint8_t rn_shift = 3;
882 uint8_t immediate_shift = 0;
883 bool use_immediate = false;
884 uint8_t immediate = 0;
885
886 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
887 // Convert shifted mov operand2 into 16 bit opcodes.
888 dp_opcode = 0;
889 opcode_shift = 11;
890
891 use_immediate = true;
892 immediate = so.GetImmediate();
893 immediate_shift = 6;
894
895 rn = so.GetRegister();
896
897 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700898 case LSL: thumb_opcode = 0U /* 0b00 */; break;
899 case LSR: thumb_opcode = 1U /* 0b01 */; break;
900 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700901 case ROR:
902 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700903 thumb_opcode = 7U /* 0b111 */;
904 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700905 opcode_shift = 6;
906 use_immediate = false;
907 break;
908 case RRX: break;
909 default:
910 break;
911 }
912 } else {
913 if (so.IsImmediate()) {
914 use_immediate = true;
915 immediate = so.GetImmediate();
916 }
917
918 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700919 case AND: thumb_opcode = 0U /* 0b0000 */; break;
920 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700921 case SUB: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700922 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700923 case ADD: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700924 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
925 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700926 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700927 case TST: thumb_opcode = 8U /* 0b1000 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700928 case TEQ: break;
929 case CMP:
930 if (use_immediate) {
931 // T2 encoding.
932 dp_opcode = 0;
933 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700934 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700935 rd_shift = 8;
936 rn_shift = 8;
937 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700938 thumb_opcode = 10U /* 0b1010 */;
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100939 rd = rn;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700940 rn = so.GetRegister();
941 }
942
943 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100944 case CMN: {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700945 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100946 rd = rn;
947 rn = so.GetRegister();
948 break;
949 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700950 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700951 case MOV:
952 dp_opcode = 0;
953 if (use_immediate) {
954 // T2 encoding.
955 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700956 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700957 rd_shift = 8;
958 rn_shift = 8;
959 } else {
960 rn = so.GetRegister();
961 if (IsHighRegister(rn) || IsHighRegister(rd)) {
962 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700963 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700964 opcode_shift = 7;
965 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700966 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
967 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700968 } else {
969 thumb_opcode = 0;
970 }
971 }
972 break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700973 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
974 case MVN: thumb_opcode = 15U /* 0b1111 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700975 default:
976 break;
977 }
978 }
979
Andreas Gampec8ccf682014-09-29 20:07:43 -0700980 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700981 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
982 }
983
984 int16_t encoding = dp_opcode << 14 |
985 (thumb_opcode << opcode_shift) |
986 rd << rd_shift |
987 rn << rn_shift |
988 (use_immediate ? (immediate << immediate_shift) : 0);
989
990 Emit16(encoding);
991}
992
993
994// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700995void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700996 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700997 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700998 Register rn,
999 Register rd,
1000 const ShifterOperand& so) {
1001 uint8_t dp_opcode = 0;
1002 uint8_t opcode_shift = 6;
1003 uint8_t rd_shift = 0;
1004 uint8_t rn_shift = 3;
1005 uint8_t immediate_shift = 0;
1006 bool use_immediate = false;
1007 uint8_t immediate = 0;
1008 uint8_t thumb_opcode;;
1009
1010 if (so.IsImmediate()) {
1011 use_immediate = true;
1012 immediate = so.GetImmediate();
1013 }
1014
1015 switch (opcode) {
1016 case ADD:
1017 if (so.IsRegister()) {
1018 Register rm = so.GetRegister();
1019 if (rn == rd) {
1020 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001021 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001022 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001023 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001024 // Make Rn also contain the top bit of rd.
1025 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001026 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1027 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001028 } else {
1029 // T1.
1030 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001031 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001032 immediate = static_cast<uint32_t>(so.GetRegister());
1033 use_immediate = true;
1034 immediate_shift = 6;
1035 }
1036 } else {
1037 // Immediate.
1038 if (rd == SP && rn == SP) {
1039 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001040 dp_opcode = 2U /* 0b10 */;
1041 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001042 opcode_shift = 12;
1043 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001044 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001045
1046 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1047 rn = R0;
1048 rd = R0;
1049 rd_shift = 0;
1050 rn_shift = 0;
1051 immediate >>= 2;
1052 } else if (rd != SP && rn == SP) {
1053 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001054 dp_opcode = 2U /* 0b10 */;
1055 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001056 opcode_shift = 11;
1057 CHECK_LT(immediate, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001058 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001059
1060 // Remove rn from instruction.
1061 rn = R0;
1062 rn_shift = 0;
1063 rd_shift = 8;
1064 immediate >>= 2;
1065 } else if (rn != rd) {
1066 // Must use T1.
1067 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001068 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001069 immediate_shift = 6;
1070 } else {
1071 // T2 encoding.
1072 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001073 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001074 rd_shift = 8;
1075 rn_shift = 8;
1076 }
1077 }
1078 break;
1079
1080 case SUB:
1081 if (so.IsRegister()) {
1082 // T1.
1083 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001084 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001085 immediate = static_cast<uint32_t>(so.GetRegister());
1086 use_immediate = true;
1087 immediate_shift = 6;
1088 } else {
1089 if (rd == SP && rn == SP) {
1090 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001091 dp_opcode = 2U /* 0b10 */;
1092 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001093 opcode_shift = 7;
1094 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001095 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001096
1097 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1098 rn = R0;
1099 rd = R0;
1100 rd_shift = 0;
1101 rn_shift = 0;
1102 immediate >>= 2;
1103 } else if (rn != rd) {
1104 // Must use T1.
1105 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001106 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001107 immediate_shift = 6;
1108 } else {
1109 // T2 encoding.
1110 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001111 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001112 rd_shift = 8;
1113 rn_shift = 8;
1114 }
1115 }
1116 break;
1117 default:
1118 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
1119 return;
1120 }
1121
1122 int16_t encoding = dp_opcode << 14 |
1123 (thumb_opcode << opcode_shift) |
1124 rd << rd_shift |
1125 rn << rn_shift |
1126 (use_immediate ? (immediate << immediate_shift) : 0);
1127
1128 Emit16(encoding);
1129}
1130
1131
1132void Thumb2Assembler::EmitDataProcessing(Condition cond,
1133 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001134 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001135 Register rn,
1136 Register rd,
1137 const ShifterOperand& so) {
1138 CHECK_NE(rd, kNoRegister);
1139 CheckCondition(cond);
1140
1141 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1142 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1143 } else {
1144 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1145 }
1146}
1147
Dave Allison45fdb932014-06-25 12:37:10 -07001148void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1149 CHECK_LT(amount, (1 << 5));
1150 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1151 uint16_t opcode = 0;
1152 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001153 case LSL: opcode = 0U /* 0b00 */; break;
1154 case LSR: opcode = 1U /* 0b01 */; break;
1155 case ASR: opcode = 2U /* 0b10 */; break;
1156 case ROR: opcode = 3U /* 0b11 */; break;
1157 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001158 default:
1159 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1160 }
1161 // 32 bit.
1162 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1163 0xf << 16 | (setcc ? B20 : 0);
1164 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001165 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001166 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1167 static_cast<int16_t>(rd) << 8 | opcode << 4;
1168 Emit32(encoding);
1169 } else {
1170 // 16 bit shift
1171 uint16_t opcode = 0;
1172 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001173 case LSL: opcode = 0U /* 0b00 */; break;
1174 case LSR: opcode = 1U /* 0b01 */; break;
1175 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001176 default:
1177 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1178 }
1179 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1180 static_cast<int16_t>(rd);
1181 Emit16(encoding);
1182 }
1183}
1184
1185void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1186 CHECK_NE(shift, RRX);
1187 bool must_be_32bit = false;
1188 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1189 must_be_32bit = true;
1190 }
1191
1192 if (must_be_32bit) {
1193 uint16_t opcode = 0;
1194 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001195 case LSL: opcode = 0U /* 0b00 */; break;
1196 case LSR: opcode = 1U /* 0b01 */; break;
1197 case ASR: opcode = 2U /* 0b10 */; break;
1198 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001199 default:
1200 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1201 }
1202 // 32 bit.
1203 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1204 0xf << 12 | (setcc ? B20 : 0);
1205 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1206 static_cast<int16_t>(rd) << 8 | opcode << 21;
1207 Emit32(encoding);
1208 } else {
1209 uint16_t opcode = 0;
1210 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001211 case LSL: opcode = 2U /* 0b0010 */; break;
1212 case LSR: opcode = 3U /* 0b0011 */; break;
1213 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001214 default:
1215 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1216 }
1217 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1218 static_cast<int16_t>(rd);
1219 Emit16(encoding);
1220 }
1221}
1222
1223
Dave Allison65fcc2c2014-04-28 13:45:27 -07001224
1225void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1226 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1227 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1228 int32_t offset = target_ - location_;
1229
1230 if (size_ == k32Bit) {
1231 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1232 if (link) {
1233 // BL or BLX immediate.
1234 encoding |= B14;
1235 if (!x) {
1236 encoding |= B12;
1237 } else {
1238 // Bottom bit of offset must be 0.
1239 CHECK_EQ((offset & 1), 0);
1240 }
1241 } else {
1242 if (x) {
1243 LOG(FATAL) << "Invalid use of BX";
1244 } else {
1245 if (cond_ == AL) {
1246 // Can use the T4 encoding allowing a 24 bit offset.
1247 if (!x) {
1248 encoding |= B12;
1249 }
1250 } else {
1251 // Must be T3 encoding with a 20 bit offset.
1252 encoding |= cond_ << 22;
1253 }
1254 }
1255 }
1256 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1257 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1258 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1259 } else {
1260 if (IsCompareAndBranch()) {
1261 offset -= 4;
1262 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001263 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001264 int16_t encoding = B15 | B13 | B12 |
1265 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1266 static_cast<uint32_t>(rn_) |
1267 B8 |
1268 i << 9 |
1269 imm5 << 3;
1270 buffer->Store<int16_t>(location_, encoding);
1271 } else {
1272 offset -= 4; // Account for PC offset.
1273 int16_t encoding;
1274 // 16 bit.
1275 if (cond_ == AL) {
1276 encoding = B15 | B14 | B13 |
1277 ((offset >> 1) & 0x7ff);
1278 } else {
1279 encoding = B15 | B14 | B12 |
1280 cond_ << 8 | ((offset >> 1) & 0xff);
1281 }
1282 buffer->Store<int16_t>(location_, encoding);
1283 }
1284 }
1285}
1286
1287
1288uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1289 uint32_t location = buffer_.Size();
1290
1291 // This is always unresolved as it must be a forward branch.
1292 Emit16(prev); // Previous link.
1293 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1294 location, rn);
1295}
1296
1297
1298// NOTE: this only support immediate offsets, not [rx,ry].
1299// TODO: support [rx,ry] instructions.
1300void Thumb2Assembler::EmitLoadStore(Condition cond,
1301 bool load,
1302 bool byte,
1303 bool half,
1304 bool is_signed,
1305 Register rd,
1306 const Address& ad) {
1307 CHECK_NE(rd, kNoRegister);
1308 CheckCondition(cond);
1309 bool must_be_32bit = force_32bit_;
1310 if (IsHighRegister(rd)) {
1311 must_be_32bit = true;
1312 }
1313
1314 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001315 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001316 must_be_32bit = true;
1317 }
1318
1319 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1320 must_be_32bit = true;
1321 }
1322
Dave Allison45fdb932014-06-25 12:37:10 -07001323 if (ad.IsImmediate()) {
1324 // Immediate offset
1325 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001326
Dave Allison45fdb932014-06-25 12:37:10 -07001327 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001328 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001329 must_be_32bit = true;
1330 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001331
1332 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001333 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001334 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001335 must_be_32bit = true;
1336 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001337 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001338 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001339 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001340 must_be_32bit = true;
1341 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001342 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001343 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001344 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001345 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001346 }
1347 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001348
Dave Allison45fdb932014-06-25 12:37:10 -07001349 if (must_be_32bit) {
1350 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1351 (load ? B20 : 0) |
1352 (is_signed ? B24 : 0) |
1353 static_cast<uint32_t>(rd) << 12 |
1354 ad.encodingThumb(true) |
1355 (byte ? 0 : half ? B21 : B22);
1356 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001357 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001358 // 16 bit thumb1.
1359 uint8_t opA = 0;
1360 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001361
1362 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001363 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001364 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001365 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001366 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001367 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001368 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001369 sp_relative = true;
1370 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001371 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001372 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001373 }
Dave Allison45fdb932014-06-25 12:37:10 -07001374 int16_t encoding = opA << 12 |
1375 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001376
Dave Allison45fdb932014-06-25 12:37:10 -07001377 CHECK_GE(offset, 0);
1378 if (sp_relative) {
1379 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001380 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001381 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001382 encoding |= rd << 8 | offset >> 2;
1383 } else {
1384 // No SP relative. The offset is shifted right depending on
1385 // the size of the load/store.
1386 encoding |= static_cast<uint32_t>(rd);
1387
1388 if (byte) {
1389 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001390 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001391 } else if (half) {
1392 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001393 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001394 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001395 offset >>= 1;
1396 } else {
1397 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001398 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001399 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001400 offset >>= 2;
1401 }
1402 encoding |= rn << 3 | offset << 6;
1403 }
1404
1405 Emit16(encoding);
1406 }
1407 } else {
1408 // Register shift.
1409 if (ad.GetRegister() == PC) {
1410 // PC relative literal encoding.
1411 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001412 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001413 int32_t up = B23;
1414 if (offset < 0) {
1415 offset = -offset;
1416 up = 0;
1417 }
1418 CHECK_LT(offset, (1 << 12));
1419 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1420 offset | up |
1421 static_cast<uint32_t>(rd) << 12;
1422 Emit32(encoding);
1423 } else {
1424 // 16 bit literal load.
1425 CHECK_GE(offset, 0);
1426 CHECK_LT(offset, (1 << 10));
1427 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1428 Emit16(encoding);
1429 }
1430 } else {
1431 if (ad.GetShiftCount() != 0) {
1432 // If there is a shift count this must be 32 bit.
1433 must_be_32bit = true;
1434 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1435 must_be_32bit = true;
1436 }
1437
1438 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001439 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001440 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001441 if (half) {
1442 encoding |= B21;
1443 } else if (!byte) {
1444 encoding |= B22;
1445 }
Dave Allison45fdb932014-06-25 12:37:10 -07001446 Emit32(encoding);
1447 } else {
1448 // 16 bit register offset.
1449 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1450 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001451 if (byte) {
1452 encoding |= B10;
1453 } else if (half) {
1454 encoding |= B9;
1455 }
Dave Allison45fdb932014-06-25 12:37:10 -07001456 Emit16(encoding);
1457 }
1458 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001459 }
1460}
1461
1462
1463void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001464 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001465 bool load,
1466 Register base,
1467 RegList regs) {
1468 CHECK_NE(base, kNoRegister);
1469 CheckCondition(cond);
1470 bool must_be_32bit = force_32bit_;
1471
1472 if ((regs & 0xff00) != 0) {
1473 must_be_32bit = true;
1474 }
1475
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001476 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001477 // 16 bit always uses writeback.
1478 if (!w_bit) {
1479 must_be_32bit = true;
1480 }
1481
1482 if (must_be_32bit) {
1483 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001484 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001485 case IA:
1486 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001487 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001488 break;
1489 case DB:
1490 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001491 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001492 break;
1493 case DA:
1494 case IB:
1495 case DA_W:
1496 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001497 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001498 }
1499 if (load) {
1500 // Cannot have SP in the list.
1501 CHECK_EQ((regs & (1 << SP)), 0);
1502 } else {
1503 // Cannot have PC or SP in the list.
1504 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1505 }
1506 int32_t encoding = B31 | B30 | B29 | B27 |
1507 (op << 23) |
1508 (load ? B20 : 0) |
1509 base << 16 |
1510 regs |
1511 (w_bit << 21);
1512 Emit32(encoding);
1513 } else {
1514 int16_t encoding = B15 | B14 |
1515 (load ? B11 : 0) |
1516 base << 8 |
1517 regs;
1518 Emit16(encoding);
1519 }
1520}
1521
1522
1523void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1524 uint32_t pc = buffer_.Size();
1525 Branch::Type branch_type;
1526 if (cond == AL) {
1527 if (link) {
1528 if (x) {
1529 branch_type = Branch::kUnconditionalLinkX; // BLX.
1530 } else {
1531 branch_type = Branch::kUnconditionalLink; // BX.
1532 }
1533 } else {
1534 branch_type = Branch::kUnconditional; // B.
1535 }
1536 } else {
1537 branch_type = Branch::kConditional; // B<cond>.
1538 }
1539
1540 if (label->IsBound()) {
1541 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1542
1543 // The branch is to a bound label which means that it's a backwards branch. We know the
1544 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1545 // branch the size may change if it so happens that other branches change size that change
1546 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1547 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001548 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001549 Emit16(0); // Space for a 16 bit branch.
1550 } else {
1551 Emit32(0); // Space for a 32 bit branch.
1552 }
1553 } else {
1554 // Branch is to an unbound label. Emit space for it.
1555 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001556 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001557 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1558 Emit16(0); // another 16 bits.
1559 } else {
1560 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1561 }
1562 label->LinkTo(branch_id); // Link to the branch ID.
1563 }
1564}
1565
1566
1567void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1568 CHECK_NE(rd, kNoRegister);
1569 CHECK_NE(rm, kNoRegister);
1570 CheckCondition(cond);
1571 CHECK_NE(rd, PC);
1572 CHECK_NE(rm, PC);
1573 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1574 B25 | B23 | B21 | B20 |
1575 static_cast<uint32_t>(rm) << 16 |
1576 0xf << 12 |
1577 static_cast<uint32_t>(rd) << 8 |
1578 B7 |
1579 static_cast<uint32_t>(rm);
1580 Emit32(encoding);
1581}
1582
1583
1584void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1585 CheckCondition(cond);
1586 bool must_be_32bit = force_32bit_;
1587 if (IsHighRegister(rd)|| imm16 >= 256u) {
1588 must_be_32bit = true;
1589 }
1590
1591 if (must_be_32bit) {
1592 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001593 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1594 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1595 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001596 uint32_t imm8 = imm16 & 0xff;
1597 int32_t encoding = B31 | B30 | B29 | B28 |
1598 B25 | B22 |
1599 static_cast<uint32_t>(rd) << 8 |
1600 i << 26 |
1601 imm4 << 16 |
1602 imm3 << 12 |
1603 imm8;
1604 Emit32(encoding);
1605 } else {
1606 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1607 imm16;
1608 Emit16(encoding);
1609 }
1610}
1611
1612
1613void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1614 CheckCondition(cond);
1615 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001616 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1617 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1618 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001619 uint32_t imm8 = imm16 & 0xff;
1620 int32_t encoding = B31 | B30 | B29 | B28 |
1621 B25 | B23 | B22 |
1622 static_cast<uint32_t>(rd) << 8 |
1623 i << 26 |
1624 imm4 << 16 |
1625 imm3 << 12 |
1626 imm8;
1627 Emit32(encoding);
1628}
1629
1630
1631void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1632 CHECK_NE(rn, kNoRegister);
1633 CHECK_NE(rt, kNoRegister);
1634 CheckCondition(cond);
1635 CHECK_NE(rn, kNoRegister);
1636 CHECK_NE(rt, kNoRegister);
1637 CheckCondition(cond);
1638 CHECK_LT(imm, (1u << 10));
1639
1640 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1641 static_cast<uint32_t>(rn) << 16 |
1642 static_cast<uint32_t>(rt) << 12 |
1643 0xf << 8 |
1644 imm >> 2;
1645 Emit32(encoding);
1646}
1647
1648
1649void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1650 ldrex(rt, rn, 0, cond);
1651}
1652
1653
1654void Thumb2Assembler::strex(Register rd,
1655 Register rt,
1656 Register rn,
1657 uint16_t imm,
1658 Condition cond) {
1659 CHECK_NE(rn, kNoRegister);
1660 CHECK_NE(rd, kNoRegister);
1661 CHECK_NE(rt, kNoRegister);
1662 CheckCondition(cond);
1663 CHECK_LT(imm, (1u << 10));
1664
1665 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1666 static_cast<uint32_t>(rn) << 16 |
1667 static_cast<uint32_t>(rt) << 12 |
1668 static_cast<uint32_t>(rd) << 8 |
1669 imm >> 2;
1670 Emit32(encoding);
1671}
1672
1673
1674void Thumb2Assembler::strex(Register rd,
1675 Register rt,
1676 Register rn,
1677 Condition cond) {
1678 strex(rd, rt, rn, 0, cond);
1679}
1680
1681
1682void Thumb2Assembler::clrex(Condition cond) {
1683 CheckCondition(cond);
1684 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1685 B21 | B20 |
1686 0xf << 16 |
1687 B15 |
1688 0xf << 8 |
1689 B5 |
1690 0xf;
1691 Emit32(encoding);
1692}
1693
1694
1695void Thumb2Assembler::nop(Condition cond) {
1696 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001697 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001698 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001699 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001700}
1701
1702
1703void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1704 CHECK_NE(sn, kNoSRegister);
1705 CHECK_NE(rt, kNoRegister);
1706 CHECK_NE(rt, SP);
1707 CHECK_NE(rt, PC);
1708 CheckCondition(cond);
1709 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1710 B27 | B26 | B25 |
1711 ((static_cast<int32_t>(sn) >> 1)*B16) |
1712 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1713 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1714 Emit32(encoding);
1715}
1716
1717
1718void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1719 CHECK_NE(sn, kNoSRegister);
1720 CHECK_NE(rt, kNoRegister);
1721 CHECK_NE(rt, SP);
1722 CHECK_NE(rt, PC);
1723 CheckCondition(cond);
1724 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1725 B27 | B26 | B25 | B20 |
1726 ((static_cast<int32_t>(sn) >> 1)*B16) |
1727 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1728 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1729 Emit32(encoding);
1730}
1731
1732
1733void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1734 Condition cond) {
1735 CHECK_NE(sm, kNoSRegister);
1736 CHECK_NE(sm, S31);
1737 CHECK_NE(rt, kNoRegister);
1738 CHECK_NE(rt, SP);
1739 CHECK_NE(rt, PC);
1740 CHECK_NE(rt2, kNoRegister);
1741 CHECK_NE(rt2, SP);
1742 CHECK_NE(rt2, PC);
1743 CheckCondition(cond);
1744 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1745 B27 | B26 | B22 |
1746 (static_cast<int32_t>(rt2)*B16) |
1747 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1748 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1749 (static_cast<int32_t>(sm) >> 1);
1750 Emit32(encoding);
1751}
1752
1753
1754void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1755 Condition cond) {
1756 CHECK_NE(sm, kNoSRegister);
1757 CHECK_NE(sm, S31);
1758 CHECK_NE(rt, kNoRegister);
1759 CHECK_NE(rt, SP);
1760 CHECK_NE(rt, PC);
1761 CHECK_NE(rt2, kNoRegister);
1762 CHECK_NE(rt2, SP);
1763 CHECK_NE(rt2, PC);
1764 CHECK_NE(rt, rt2);
1765 CheckCondition(cond);
1766 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1767 B27 | B26 | B22 | B20 |
1768 (static_cast<int32_t>(rt2)*B16) |
1769 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1770 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1771 (static_cast<int32_t>(sm) >> 1);
1772 Emit32(encoding);
1773}
1774
1775
1776void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1777 Condition cond) {
1778 CHECK_NE(dm, kNoDRegister);
1779 CHECK_NE(rt, kNoRegister);
1780 CHECK_NE(rt, SP);
1781 CHECK_NE(rt, PC);
1782 CHECK_NE(rt2, kNoRegister);
1783 CHECK_NE(rt2, SP);
1784 CHECK_NE(rt2, PC);
1785 CheckCondition(cond);
1786 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1787 B27 | B26 | B22 |
1788 (static_cast<int32_t>(rt2)*B16) |
1789 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1790 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1791 (static_cast<int32_t>(dm) & 0xf);
1792 Emit32(encoding);
1793}
1794
1795
1796void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1797 Condition cond) {
1798 CHECK_NE(dm, kNoDRegister);
1799 CHECK_NE(rt, kNoRegister);
1800 CHECK_NE(rt, SP);
1801 CHECK_NE(rt, PC);
1802 CHECK_NE(rt2, kNoRegister);
1803 CHECK_NE(rt2, SP);
1804 CHECK_NE(rt2, PC);
1805 CHECK_NE(rt, rt2);
1806 CheckCondition(cond);
1807 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1808 B27 | B26 | B22 | B20 |
1809 (static_cast<int32_t>(rt2)*B16) |
1810 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1811 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1812 (static_cast<int32_t>(dm) & 0xf);
1813 Emit32(encoding);
1814}
1815
1816
1817void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1818 const Address& addr = static_cast<const Address&>(ad);
1819 CHECK_NE(sd, kNoSRegister);
1820 CheckCondition(cond);
1821 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1822 B27 | B26 | B24 | B20 |
1823 ((static_cast<int32_t>(sd) & 1)*B22) |
1824 ((static_cast<int32_t>(sd) >> 1)*B12) |
1825 B11 | B9 | addr.vencoding();
1826 Emit32(encoding);
1827}
1828
1829
1830void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1831 const Address& addr = static_cast<const Address&>(ad);
1832 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1833 CHECK_NE(sd, kNoSRegister);
1834 CheckCondition(cond);
1835 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1836 B27 | B26 | B24 |
1837 ((static_cast<int32_t>(sd) & 1)*B22) |
1838 ((static_cast<int32_t>(sd) >> 1)*B12) |
1839 B11 | B9 | addr.vencoding();
1840 Emit32(encoding);
1841}
1842
1843
1844void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1845 const Address& addr = static_cast<const Address&>(ad);
1846 CHECK_NE(dd, kNoDRegister);
1847 CheckCondition(cond);
1848 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1849 B27 | B26 | B24 | B20 |
1850 ((static_cast<int32_t>(dd) >> 4)*B22) |
1851 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1852 B11 | B9 | B8 | addr.vencoding();
1853 Emit32(encoding);
1854}
1855
1856
1857void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1858 const Address& addr = static_cast<const Address&>(ad);
1859 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1860 CHECK_NE(dd, kNoDRegister);
1861 CheckCondition(cond);
1862 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1863 B27 | B26 | B24 |
1864 ((static_cast<int32_t>(dd) >> 4)*B22) |
1865 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1866 B11 | B9 | B8 | addr.vencoding();
1867 Emit32(encoding);
1868}
1869
1870
1871void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1872 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1873}
1874
1875
1876void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1877 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1878}
1879
1880
1881void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1882 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1883}
1884
1885
1886void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1887 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1888}
1889
1890
1891void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1892 CheckCondition(cond);
1893
1894 uint32_t D;
1895 uint32_t Vd;
1896 if (dbl) {
1897 // Encoded as D:Vd.
1898 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001899 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001900 } else {
1901 // Encoded as Vd:D.
1902 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001903 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001904 }
1905 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1906 B11 | B9 |
1907 (dbl ? B8 : 0) |
1908 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001909 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001910 nregs << (dbl ? 1 : 0) |
1911 D << 22 |
1912 Vd << 12;
1913 Emit32(encoding);
1914}
1915
1916
1917void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1918 SRegister sd, SRegister sn, SRegister sm) {
1919 CHECK_NE(sd, kNoSRegister);
1920 CHECK_NE(sn, kNoSRegister);
1921 CHECK_NE(sm, kNoSRegister);
1922 CheckCondition(cond);
1923 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1924 B27 | B26 | B25 | B11 | B9 | opcode |
1925 ((static_cast<int32_t>(sd) & 1)*B22) |
1926 ((static_cast<int32_t>(sn) >> 1)*B16) |
1927 ((static_cast<int32_t>(sd) >> 1)*B12) |
1928 ((static_cast<int32_t>(sn) & 1)*B7) |
1929 ((static_cast<int32_t>(sm) & 1)*B5) |
1930 (static_cast<int32_t>(sm) >> 1);
1931 Emit32(encoding);
1932}
1933
1934
1935void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1936 DRegister dd, DRegister dn, DRegister dm) {
1937 CHECK_NE(dd, kNoDRegister);
1938 CHECK_NE(dn, kNoDRegister);
1939 CHECK_NE(dm, kNoDRegister);
1940 CheckCondition(cond);
1941 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1942 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1943 ((static_cast<int32_t>(dd) >> 4)*B22) |
1944 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1945 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1946 ((static_cast<int32_t>(dn) >> 4)*B7) |
1947 ((static_cast<int32_t>(dm) >> 4)*B5) |
1948 (static_cast<int32_t>(dm) & 0xf);
1949 Emit32(encoding);
1950}
1951
1952
1953void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1954 SRegister sd, DRegister dm) {
1955 CHECK_NE(sd, kNoSRegister);
1956 CHECK_NE(dm, kNoDRegister);
1957 CheckCondition(cond);
1958 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1959 B27 | B26 | B25 | B11 | B9 | opcode |
1960 ((static_cast<int32_t>(sd) & 1)*B22) |
1961 ((static_cast<int32_t>(sd) >> 1)*B12) |
1962 ((static_cast<int32_t>(dm) >> 4)*B5) |
1963 (static_cast<int32_t>(dm) & 0xf);
1964 Emit32(encoding);
1965}
1966
1967
1968void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
1969 DRegister dd, SRegister sm) {
1970 CHECK_NE(dd, kNoDRegister);
1971 CHECK_NE(sm, kNoSRegister);
1972 CheckCondition(cond);
1973 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1974 B27 | B26 | B25 | B11 | B9 | opcode |
1975 ((static_cast<int32_t>(dd) >> 4)*B22) |
1976 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1977 ((static_cast<int32_t>(sm) & 1)*B5) |
1978 (static_cast<int32_t>(sm) >> 1);
1979 Emit32(encoding);
1980}
1981
1982
1983void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00001984 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001985 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00001986 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1987 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
1988 (static_cast<int32_t>(PC)*B12) |
1989 B11 | B9 | B4;
1990 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001991}
1992
1993
1994void Thumb2Assembler::svc(uint32_t imm8) {
1995 CHECK(IsUint(8, imm8)) << imm8;
1996 int16_t encoding = B15 | B14 | B12 |
1997 B11 | B10 | B9 | B8 |
1998 imm8;
1999 Emit16(encoding);
2000}
2001
2002
2003void Thumb2Assembler::bkpt(uint16_t imm8) {
2004 CHECK(IsUint(8, imm8)) << imm8;
2005 int16_t encoding = B15 | B13 | B12 |
2006 B11 | B10 | B9 |
2007 imm8;
2008 Emit16(encoding);
2009}
2010
2011// Convert the given IT state to a mask bit given bit 0 of the first
2012// condition and a shift position.
2013static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2014 switch (s) {
2015 case kItOmitted: return 1 << shift;
2016 case kItThen: return firstcond0 << shift;
2017 case kItElse: return !firstcond0 << shift;
2018 }
2019 return 0;
2020}
2021
2022
2023// Set the IT condition in the given position for the given state. This is used
2024// to check that conditional instructions match the preceding IT statement.
2025void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2026 switch (s) {
2027 case kItOmitted: it_conditions_[index] = AL; break;
2028 case kItThen: it_conditions_[index] = cond; break;
2029 case kItElse:
2030 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2031 break;
2032 }
2033}
2034
2035
2036void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2037 CheckCondition(AL); // Not allowed in IT block.
2038 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2039
2040 // All conditions to AL.
2041 for (uint8_t i = 0; i < 4; ++i) {
2042 it_conditions_[i] = AL;
2043 }
2044
2045 SetItCondition(kItThen, firstcond, 0);
2046 uint8_t mask = ToItMask(i1, firstcond0, 3);
2047 SetItCondition(i1, firstcond, 1);
2048
2049 if (i1 != kItOmitted) {
2050 mask |= ToItMask(i2, firstcond0, 2);
2051 SetItCondition(i2, firstcond, 2);
2052 if (i2 != kItOmitted) {
2053 mask |= ToItMask(i3, firstcond0, 1);
2054 SetItCondition(i3, firstcond, 3);
2055 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002056 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002057 }
2058 }
2059 }
2060
2061 // Start at first condition.
2062 it_cond_index_ = 0;
2063 next_condition_ = it_conditions_[0];
2064 uint16_t encoding = B15 | B13 | B12 |
2065 B11 | B10 | B9 | B8 |
2066 firstcond << 4 |
2067 mask;
2068 Emit16(encoding);
2069}
2070
2071
2072void Thumb2Assembler::cbz(Register rn, Label* label) {
2073 CheckCondition(AL);
2074 if (label->IsBound()) {
2075 LOG(FATAL) << "cbz can only be used to branch forwards";
2076 } else {
2077 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2078 label->LinkTo(branchid);
2079 }
2080}
2081
2082
2083void Thumb2Assembler::cbnz(Register rn, Label* label) {
2084 CheckCondition(AL);
2085 if (label->IsBound()) {
2086 LOG(FATAL) << "cbnz can only be used to branch forwards";
2087 } else {
2088 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2089 label->LinkTo(branchid);
2090 }
2091}
2092
2093
2094void Thumb2Assembler::blx(Register rm, Condition cond) {
2095 CHECK_NE(rm, kNoRegister);
2096 CheckCondition(cond);
2097 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2098 Emit16(encoding);
2099}
2100
2101
2102void Thumb2Assembler::bx(Register rm, Condition cond) {
2103 CHECK_NE(rm, kNoRegister);
2104 CheckCondition(cond);
2105 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2106 Emit16(encoding);
2107}
2108
2109
2110void Thumb2Assembler::Push(Register rd, Condition cond) {
2111 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2112}
2113
2114
2115void Thumb2Assembler::Pop(Register rd, Condition cond) {
2116 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2117}
2118
2119
2120void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2121 stm(DB_W, SP, regs, cond);
2122}
2123
2124
2125void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2126 ldm(IA_W, SP, regs, cond);
2127}
2128
2129
2130void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2131 if (cond != AL || rd != rm) {
2132 mov(rd, ShifterOperand(rm), cond);
2133 }
2134}
2135
2136
2137// A branch has changed size. Make a hole for it.
2138void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2139 // Move the contents of the buffer using: Move(newposition, oldposition)
2140 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2141 buffer_.Move(location + delta, location);
2142}
2143
2144
2145void Thumb2Assembler::Bind(Label* label) {
2146 CHECK(!label->IsBound());
2147 uint32_t bound_pc = buffer_.Size();
2148 std::vector<Branch*> changed_branches;
2149
2150 while (label->IsLinked()) {
2151 uint16_t position = label->Position(); // Branch id for linked branch.
2152 Branch* branch = GetBranch(position); // Get the branch at this id.
2153 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2154 uint32_t branch_location = branch->GetLocation();
2155 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2156 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002157 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002158 MakeHoleForBranch(branch->GetLocation(), 2);
2159 if (branch->IsCompareAndBranch()) {
2160 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2161 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2162 // cmp rn, #0
2163 // b<eq|ne> target
2164 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2165 Condition cond = n ? NE : EQ;
2166 branch->Move(2); // Move the branch forward by 2 bytes.
2167 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2168 branch->ResetSize(Branch::k16Bit);
2169
2170 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002171 buffer_.Store<int16_t>(branch_location,
2172 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002173
2174 // Since have moved made a hole in the code we need to reload the
2175 // current pc.
2176 bound_pc = buffer_.Size();
2177
2178 // Now resolve the newly added branch.
2179 changed = branch->Resolve(bound_pc);
2180 if (changed) {
2181 MakeHoleForBranch(branch->GetLocation(), 2);
2182 changed_branches.push_back(branch);
2183 }
2184 } else {
2185 changed_branches.push_back(branch);
2186 }
2187 }
2188 label->position_ = next; // Move to next.
2189 }
2190 label->BindTo(bound_pc);
2191
2192 // Now relocate any changed branches. Do this until there are no more changes.
2193 std::vector<Branch*> branches_to_process = changed_branches;
2194 while (branches_to_process.size() != 0) {
2195 changed_branches.clear();
2196 for (auto& changed_branch : branches_to_process) {
2197 for (auto& branch : branches_) {
2198 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2199 if (changed) {
2200 changed_branches.push_back(branch);
2201 }
2202 }
2203 branches_to_process = changed_branches;
2204 }
2205 }
2206}
2207
2208
2209void Thumb2Assembler::EmitBranches() {
2210 for (auto& branch : branches_) {
2211 branch->Emit(&buffer_);
2212 }
2213}
2214
2215
2216void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002217 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002218 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002219 CheckCondition(cond);
2220 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002221}
2222
2223
2224void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002225 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002226 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002227 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002228 CheckCondition(cond);
2229 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002230}
2231
2232
2233void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002234 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002235 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002236 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002237 CheckCondition(cond);
2238 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002239}
2240
2241
2242void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002243 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002244 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002245 CheckCondition(cond);
2246 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002247}
2248
2249
Dave Allison45fdb932014-06-25 12:37:10 -07002250void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2251 CheckCondition(cond);
2252 EmitShift(rd, rm, RRX, rm, setcc);
2253}
2254
2255
2256void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2257 bool setcc, Condition cond) {
2258 CheckCondition(cond);
2259 EmitShift(rd, rm, LSL, rn, setcc);
2260}
2261
2262
2263void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2264 bool setcc, Condition cond) {
2265 CheckCondition(cond);
2266 EmitShift(rd, rm, LSR, rn, setcc);
2267}
2268
2269
2270void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2271 bool setcc, Condition cond) {
2272 CheckCondition(cond);
2273 EmitShift(rd, rm, ASR, rn, setcc);
2274}
2275
2276
2277void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2278 bool setcc, Condition cond) {
2279 CheckCondition(cond);
2280 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002281}
2282
2283
2284int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2285 // The offset is off by 4 due to the way the ARM CPUs read PC.
2286 offset -= 4;
2287 offset >>= 1;
2288
2289 uint32_t value = 0;
2290 // There are two different encodings depending on the value of bit 12. In one case
2291 // intermediate values are calculated using the sign bit.
2292 if ((inst & B12) == B12) {
2293 // 25 bits of offset.
2294 uint32_t signbit = (offset >> 31) & 0x1;
2295 uint32_t i1 = (offset >> 22) & 0x1;
2296 uint32_t i2 = (offset >> 21) & 0x1;
2297 uint32_t imm10 = (offset >> 11) & 0x03ff;
2298 uint32_t imm11 = offset & 0x07ff;
2299 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2300 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2301 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2302 imm11;
2303 // Remove the offset from the current encoding.
2304 inst &= ~(0x3ff << 16 | 0x7ff);
2305 } else {
2306 uint32_t signbit = (offset >> 31) & 0x1;
2307 uint32_t imm6 = (offset >> 11) & 0x03f;
2308 uint32_t imm11 = offset & 0x07ff;
2309 uint32_t j1 = (offset >> 19) & 1;
2310 uint32_t j2 = (offset >> 17) & 1;
2311 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2312 imm11;
2313 // Remove the offset from the current encoding.
2314 inst &= ~(0x3f << 16 | 0x7ff);
2315 }
2316 // Mask out offset bits in current instruction.
2317 inst &= ~(B26 | B13 | B11);
2318 inst |= value;
2319 return inst;
2320}
2321
2322
2323int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2324 int32_t imm32;
2325 if ((instr & B12) == B12) {
2326 uint32_t S = (instr >> 26) & 1;
2327 uint32_t J2 = (instr >> 11) & 1;
2328 uint32_t J1 = (instr >> 13) & 1;
2329 uint32_t imm10 = (instr >> 16) & 0x3FF;
2330 uint32_t imm11 = instr & 0x7FF;
2331
2332 uint32_t I1 = ~(J1 ^ S) & 1;
2333 uint32_t I2 = ~(J2 ^ S) & 1;
2334 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2335 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2336 } else {
2337 uint32_t S = (instr >> 26) & 1;
2338 uint32_t J2 = (instr >> 11) & 1;
2339 uint32_t J1 = (instr >> 13) & 1;
2340 uint32_t imm6 = (instr >> 16) & 0x3F;
2341 uint32_t imm11 = instr & 0x7FF;
2342
2343 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2344 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2345 }
2346 imm32 += 4;
2347 return imm32;
2348}
2349
2350
2351void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2352 AddConstant(rd, rd, value, cond);
2353}
2354
2355
2356void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2357 Condition cond) {
2358 if (value == 0) {
2359 if (rd != rn) {
2360 mov(rd, ShifterOperand(rn), cond);
2361 }
2362 return;
2363 }
2364 // We prefer to select the shorter code sequence rather than selecting add for
2365 // positive values and sub for negatives ones, which would slightly improve
2366 // the readability of generated code for some constants.
2367 ShifterOperand shifter_op;
2368 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2369 add(rd, rn, shifter_op, cond);
2370 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2371 sub(rd, rn, shifter_op, cond);
2372 } else {
2373 CHECK(rn != IP);
2374 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2375 mvn(IP, shifter_op, cond);
2376 add(rd, rn, ShifterOperand(IP), cond);
2377 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2378 mvn(IP, shifter_op, cond);
2379 sub(rd, rn, ShifterOperand(IP), cond);
2380 } else {
2381 movw(IP, Low16Bits(value), cond);
2382 uint16_t value_high = High16Bits(value);
2383 if (value_high != 0) {
2384 movt(IP, value_high, cond);
2385 }
2386 add(rd, rn, ShifterOperand(IP), cond);
2387 }
2388 }
2389}
2390
2391
2392void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2393 Condition cond) {
2394 ShifterOperand shifter_op;
2395 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2396 adds(rd, rn, shifter_op, cond);
2397 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2398 subs(rd, rn, shifter_op, cond);
2399 } else {
2400 CHECK(rn != IP);
2401 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2402 mvn(IP, shifter_op, cond);
2403 adds(rd, rn, ShifterOperand(IP), cond);
2404 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2405 mvn(IP, shifter_op, cond);
2406 subs(rd, rn, ShifterOperand(IP), cond);
2407 } else {
2408 movw(IP, Low16Bits(value), cond);
2409 uint16_t value_high = High16Bits(value);
2410 if (value_high != 0) {
2411 movt(IP, value_high, cond);
2412 }
2413 adds(rd, rn, ShifterOperand(IP), cond);
2414 }
2415 }
2416}
2417
Dave Allison65fcc2c2014-04-28 13:45:27 -07002418void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2419 ShifterOperand shifter_op;
2420 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2421 mov(rd, shifter_op, cond);
2422 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2423 mvn(rd, shifter_op, cond);
2424 } else {
2425 movw(rd, Low16Bits(value), cond);
2426 uint16_t value_high = High16Bits(value);
2427 if (value_high != 0) {
2428 movt(rd, value_high, cond);
2429 }
2430 }
2431}
2432
2433// Implementation note: this method must emit at most one instruction when
2434// Address::CanHoldLoadOffsetThumb.
2435void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2436 Register reg,
2437 Register base,
2438 int32_t offset,
2439 Condition cond) {
2440 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002441 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002442 LoadImmediate(IP, offset, cond);
2443 add(IP, IP, ShifterOperand(base), cond);
2444 base = IP;
2445 offset = 0;
2446 }
2447 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2448 switch (type) {
2449 case kLoadSignedByte:
2450 ldrsb(reg, Address(base, offset), cond);
2451 break;
2452 case kLoadUnsignedByte:
2453 ldrb(reg, Address(base, offset), cond);
2454 break;
2455 case kLoadSignedHalfword:
2456 ldrsh(reg, Address(base, offset), cond);
2457 break;
2458 case kLoadUnsignedHalfword:
2459 ldrh(reg, Address(base, offset), cond);
2460 break;
2461 case kLoadWord:
2462 ldr(reg, Address(base, offset), cond);
2463 break;
2464 case kLoadWordPair:
2465 ldrd(reg, Address(base, offset), cond);
2466 break;
2467 default:
2468 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002469 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002470 }
2471}
2472
2473
2474// Implementation note: this method must emit at most one instruction when
2475// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2476void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2477 Register base,
2478 int32_t offset,
2479 Condition cond) {
2480 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2481 CHECK_NE(base, IP);
2482 LoadImmediate(IP, offset, cond);
2483 add(IP, IP, ShifterOperand(base), cond);
2484 base = IP;
2485 offset = 0;
2486 }
2487 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2488 vldrs(reg, Address(base, offset), cond);
2489}
2490
2491
2492// Implementation note: this method must emit at most one instruction when
2493// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2494void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2495 Register base,
2496 int32_t offset,
2497 Condition cond) {
2498 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2499 CHECK_NE(base, IP);
2500 LoadImmediate(IP, offset, cond);
2501 add(IP, IP, ShifterOperand(base), cond);
2502 base = IP;
2503 offset = 0;
2504 }
2505 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2506 vldrd(reg, Address(base, offset), cond);
2507}
2508
2509
2510// Implementation note: this method must emit at most one instruction when
2511// Address::CanHoldStoreOffsetThumb.
2512void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2513 Register reg,
2514 Register base,
2515 int32_t offset,
2516 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002517 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002518 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002519 CHECK_NE(base, IP);
2520 if (reg != IP) {
2521 tmp_reg = IP;
2522 } else {
2523 // Be careful not to use IP twice (for `reg` and to build the
2524 // Address object used by the store instruction(s) below).
2525 // Instead, save R5 on the stack (or R6 if R5 is not available),
2526 // use it as secondary temporary register, and restore it after
2527 // the store instruction has been emitted.
2528 tmp_reg = base != R5 ? R5 : R6;
2529 Push(tmp_reg);
2530 if (base == SP) {
2531 offset += kRegisterSize;
2532 }
2533 }
2534 LoadImmediate(tmp_reg, offset, cond);
2535 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2536 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002537 offset = 0;
2538 }
2539 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2540 switch (type) {
2541 case kStoreByte:
2542 strb(reg, Address(base, offset), cond);
2543 break;
2544 case kStoreHalfword:
2545 strh(reg, Address(base, offset), cond);
2546 break;
2547 case kStoreWord:
2548 str(reg, Address(base, offset), cond);
2549 break;
2550 case kStoreWordPair:
2551 strd(reg, Address(base, offset), cond);
2552 break;
2553 default:
2554 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002555 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002556 }
Roland Levillain775ef492014-11-04 17:43:11 +00002557 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2558 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2559 Pop(tmp_reg);
2560 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002561}
2562
2563
2564// Implementation note: this method must emit at most one instruction when
2565// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2566void Thumb2Assembler::StoreSToOffset(SRegister reg,
2567 Register base,
2568 int32_t offset,
2569 Condition cond) {
2570 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2571 CHECK_NE(base, IP);
2572 LoadImmediate(IP, offset, cond);
2573 add(IP, IP, ShifterOperand(base), cond);
2574 base = IP;
2575 offset = 0;
2576 }
2577 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2578 vstrs(reg, Address(base, offset), cond);
2579}
2580
2581
2582// Implementation note: this method must emit at most one instruction when
2583// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2584void Thumb2Assembler::StoreDToOffset(DRegister reg,
2585 Register base,
2586 int32_t offset,
2587 Condition cond) {
2588 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2589 CHECK_NE(base, IP);
2590 LoadImmediate(IP, offset, cond);
2591 add(IP, IP, ShifterOperand(base), cond);
2592 base = IP;
2593 offset = 0;
2594 }
2595 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2596 vstrd(reg, Address(base, offset), cond);
2597}
2598
2599
2600void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2601 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002602 dmb(SY);
2603}
2604
2605
2606void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002607 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2608 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002609}
2610
2611
2612void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002613 if (force_32bit_branches_) {
2614 cmp(r, ShifterOperand(0));
2615 b(label, EQ);
2616 } else {
2617 cbz(r, label);
2618 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002619}
2620
2621
2622void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002623 if (force_32bit_branches_) {
2624 cmp(r, ShifterOperand(0));
2625 b(label, NE);
2626 } else {
2627 cbnz(r, label);
2628 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002629}
2630} // namespace arm
2631} // namespace art