blob: 3ab9b2ba033cf375101a1ca77bace6b86be4dcff [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.
1984 CheckCondition(cond);
1985 UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
1986}
1987
1988
1989void Thumb2Assembler::svc(uint32_t imm8) {
1990 CHECK(IsUint(8, imm8)) << imm8;
1991 int16_t encoding = B15 | B14 | B12 |
1992 B11 | B10 | B9 | B8 |
1993 imm8;
1994 Emit16(encoding);
1995}
1996
1997
1998void Thumb2Assembler::bkpt(uint16_t imm8) {
1999 CHECK(IsUint(8, imm8)) << imm8;
2000 int16_t encoding = B15 | B13 | B12 |
2001 B11 | B10 | B9 |
2002 imm8;
2003 Emit16(encoding);
2004}
2005
2006// Convert the given IT state to a mask bit given bit 0 of the first
2007// condition and a shift position.
2008static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2009 switch (s) {
2010 case kItOmitted: return 1 << shift;
2011 case kItThen: return firstcond0 << shift;
2012 case kItElse: return !firstcond0 << shift;
2013 }
2014 return 0;
2015}
2016
2017
2018// Set the IT condition in the given position for the given state. This is used
2019// to check that conditional instructions match the preceding IT statement.
2020void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2021 switch (s) {
2022 case kItOmitted: it_conditions_[index] = AL; break;
2023 case kItThen: it_conditions_[index] = cond; break;
2024 case kItElse:
2025 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2026 break;
2027 }
2028}
2029
2030
2031void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2032 CheckCondition(AL); // Not allowed in IT block.
2033 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2034
2035 // All conditions to AL.
2036 for (uint8_t i = 0; i < 4; ++i) {
2037 it_conditions_[i] = AL;
2038 }
2039
2040 SetItCondition(kItThen, firstcond, 0);
2041 uint8_t mask = ToItMask(i1, firstcond0, 3);
2042 SetItCondition(i1, firstcond, 1);
2043
2044 if (i1 != kItOmitted) {
2045 mask |= ToItMask(i2, firstcond0, 2);
2046 SetItCondition(i2, firstcond, 2);
2047 if (i2 != kItOmitted) {
2048 mask |= ToItMask(i3, firstcond0, 1);
2049 SetItCondition(i3, firstcond, 3);
2050 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002051 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002052 }
2053 }
2054 }
2055
2056 // Start at first condition.
2057 it_cond_index_ = 0;
2058 next_condition_ = it_conditions_[0];
2059 uint16_t encoding = B15 | B13 | B12 |
2060 B11 | B10 | B9 | B8 |
2061 firstcond << 4 |
2062 mask;
2063 Emit16(encoding);
2064}
2065
2066
2067void Thumb2Assembler::cbz(Register rn, Label* label) {
2068 CheckCondition(AL);
2069 if (label->IsBound()) {
2070 LOG(FATAL) << "cbz can only be used to branch forwards";
2071 } else {
2072 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2073 label->LinkTo(branchid);
2074 }
2075}
2076
2077
2078void Thumb2Assembler::cbnz(Register rn, Label* label) {
2079 CheckCondition(AL);
2080 if (label->IsBound()) {
2081 LOG(FATAL) << "cbnz can only be used to branch forwards";
2082 } else {
2083 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2084 label->LinkTo(branchid);
2085 }
2086}
2087
2088
2089void Thumb2Assembler::blx(Register rm, Condition cond) {
2090 CHECK_NE(rm, kNoRegister);
2091 CheckCondition(cond);
2092 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2093 Emit16(encoding);
2094}
2095
2096
2097void Thumb2Assembler::bx(Register rm, Condition cond) {
2098 CHECK_NE(rm, kNoRegister);
2099 CheckCondition(cond);
2100 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2101 Emit16(encoding);
2102}
2103
2104
2105void Thumb2Assembler::Push(Register rd, Condition cond) {
2106 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2107}
2108
2109
2110void Thumb2Assembler::Pop(Register rd, Condition cond) {
2111 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2112}
2113
2114
2115void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2116 stm(DB_W, SP, regs, cond);
2117}
2118
2119
2120void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2121 ldm(IA_W, SP, regs, cond);
2122}
2123
2124
2125void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2126 if (cond != AL || rd != rm) {
2127 mov(rd, ShifterOperand(rm), cond);
2128 }
2129}
2130
2131
2132// A branch has changed size. Make a hole for it.
2133void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2134 // Move the contents of the buffer using: Move(newposition, oldposition)
2135 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2136 buffer_.Move(location + delta, location);
2137}
2138
2139
2140void Thumb2Assembler::Bind(Label* label) {
2141 CHECK(!label->IsBound());
2142 uint32_t bound_pc = buffer_.Size();
2143 std::vector<Branch*> changed_branches;
2144
2145 while (label->IsLinked()) {
2146 uint16_t position = label->Position(); // Branch id for linked branch.
2147 Branch* branch = GetBranch(position); // Get the branch at this id.
2148 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2149 uint32_t branch_location = branch->GetLocation();
2150 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2151 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002152 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002153 MakeHoleForBranch(branch->GetLocation(), 2);
2154 if (branch->IsCompareAndBranch()) {
2155 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2156 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2157 // cmp rn, #0
2158 // b<eq|ne> target
2159 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2160 Condition cond = n ? NE : EQ;
2161 branch->Move(2); // Move the branch forward by 2 bytes.
2162 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2163 branch->ResetSize(Branch::k16Bit);
2164
2165 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002166 buffer_.Store<int16_t>(branch_location,
2167 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002168
2169 // Since have moved made a hole in the code we need to reload the
2170 // current pc.
2171 bound_pc = buffer_.Size();
2172
2173 // Now resolve the newly added branch.
2174 changed = branch->Resolve(bound_pc);
2175 if (changed) {
2176 MakeHoleForBranch(branch->GetLocation(), 2);
2177 changed_branches.push_back(branch);
2178 }
2179 } else {
2180 changed_branches.push_back(branch);
2181 }
2182 }
2183 label->position_ = next; // Move to next.
2184 }
2185 label->BindTo(bound_pc);
2186
2187 // Now relocate any changed branches. Do this until there are no more changes.
2188 std::vector<Branch*> branches_to_process = changed_branches;
2189 while (branches_to_process.size() != 0) {
2190 changed_branches.clear();
2191 for (auto& changed_branch : branches_to_process) {
2192 for (auto& branch : branches_) {
2193 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2194 if (changed) {
2195 changed_branches.push_back(branch);
2196 }
2197 }
2198 branches_to_process = changed_branches;
2199 }
2200 }
2201}
2202
2203
2204void Thumb2Assembler::EmitBranches() {
2205 for (auto& branch : branches_) {
2206 branch->Emit(&buffer_);
2207 }
2208}
2209
2210
2211void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002212 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002213 CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted.
Dave Allison45fdb932014-06-25 12:37:10 -07002214 CheckCondition(cond);
2215 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002216}
2217
2218
2219void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002220 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002221 CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted.
2222 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002223 CheckCondition(cond);
2224 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002225}
2226
2227
2228void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002229 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002230 CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted.
2231 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002232 CheckCondition(cond);
2233 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002234}
2235
2236
2237void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002238 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002239 CHECK_NE(shift_imm, 0u); // Use Rrx instruction.
Dave Allison45fdb932014-06-25 12:37:10 -07002240 CheckCondition(cond);
2241 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002242}
2243
2244
Dave Allison45fdb932014-06-25 12:37:10 -07002245void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2246 CheckCondition(cond);
2247 EmitShift(rd, rm, RRX, rm, setcc);
2248}
2249
2250
2251void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2252 bool setcc, Condition cond) {
2253 CheckCondition(cond);
2254 EmitShift(rd, rm, LSL, rn, setcc);
2255}
2256
2257
2258void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2259 bool setcc, Condition cond) {
2260 CheckCondition(cond);
2261 EmitShift(rd, rm, LSR, rn, setcc);
2262}
2263
2264
2265void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2266 bool setcc, Condition cond) {
2267 CheckCondition(cond);
2268 EmitShift(rd, rm, ASR, rn, setcc);
2269}
2270
2271
2272void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2273 bool setcc, Condition cond) {
2274 CheckCondition(cond);
2275 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002276}
2277
2278
2279int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2280 // The offset is off by 4 due to the way the ARM CPUs read PC.
2281 offset -= 4;
2282 offset >>= 1;
2283
2284 uint32_t value = 0;
2285 // There are two different encodings depending on the value of bit 12. In one case
2286 // intermediate values are calculated using the sign bit.
2287 if ((inst & B12) == B12) {
2288 // 25 bits of offset.
2289 uint32_t signbit = (offset >> 31) & 0x1;
2290 uint32_t i1 = (offset >> 22) & 0x1;
2291 uint32_t i2 = (offset >> 21) & 0x1;
2292 uint32_t imm10 = (offset >> 11) & 0x03ff;
2293 uint32_t imm11 = offset & 0x07ff;
2294 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2295 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2296 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2297 imm11;
2298 // Remove the offset from the current encoding.
2299 inst &= ~(0x3ff << 16 | 0x7ff);
2300 } else {
2301 uint32_t signbit = (offset >> 31) & 0x1;
2302 uint32_t imm6 = (offset >> 11) & 0x03f;
2303 uint32_t imm11 = offset & 0x07ff;
2304 uint32_t j1 = (offset >> 19) & 1;
2305 uint32_t j2 = (offset >> 17) & 1;
2306 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2307 imm11;
2308 // Remove the offset from the current encoding.
2309 inst &= ~(0x3f << 16 | 0x7ff);
2310 }
2311 // Mask out offset bits in current instruction.
2312 inst &= ~(B26 | B13 | B11);
2313 inst |= value;
2314 return inst;
2315}
2316
2317
2318int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2319 int32_t imm32;
2320 if ((instr & B12) == B12) {
2321 uint32_t S = (instr >> 26) & 1;
2322 uint32_t J2 = (instr >> 11) & 1;
2323 uint32_t J1 = (instr >> 13) & 1;
2324 uint32_t imm10 = (instr >> 16) & 0x3FF;
2325 uint32_t imm11 = instr & 0x7FF;
2326
2327 uint32_t I1 = ~(J1 ^ S) & 1;
2328 uint32_t I2 = ~(J2 ^ S) & 1;
2329 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2330 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2331 } else {
2332 uint32_t S = (instr >> 26) & 1;
2333 uint32_t J2 = (instr >> 11) & 1;
2334 uint32_t J1 = (instr >> 13) & 1;
2335 uint32_t imm6 = (instr >> 16) & 0x3F;
2336 uint32_t imm11 = instr & 0x7FF;
2337
2338 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2339 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2340 }
2341 imm32 += 4;
2342 return imm32;
2343}
2344
2345
2346void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2347 AddConstant(rd, rd, value, cond);
2348}
2349
2350
2351void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2352 Condition cond) {
2353 if (value == 0) {
2354 if (rd != rn) {
2355 mov(rd, ShifterOperand(rn), cond);
2356 }
2357 return;
2358 }
2359 // We prefer to select the shorter code sequence rather than selecting add for
2360 // positive values and sub for negatives ones, which would slightly improve
2361 // the readability of generated code for some constants.
2362 ShifterOperand shifter_op;
2363 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2364 add(rd, rn, shifter_op, cond);
2365 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2366 sub(rd, rn, shifter_op, cond);
2367 } else {
2368 CHECK(rn != IP);
2369 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2370 mvn(IP, shifter_op, cond);
2371 add(rd, rn, ShifterOperand(IP), cond);
2372 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2373 mvn(IP, shifter_op, cond);
2374 sub(rd, rn, ShifterOperand(IP), cond);
2375 } else {
2376 movw(IP, Low16Bits(value), cond);
2377 uint16_t value_high = High16Bits(value);
2378 if (value_high != 0) {
2379 movt(IP, value_high, cond);
2380 }
2381 add(rd, rn, ShifterOperand(IP), cond);
2382 }
2383 }
2384}
2385
2386
2387void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2388 Condition cond) {
2389 ShifterOperand shifter_op;
2390 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2391 adds(rd, rn, shifter_op, cond);
2392 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2393 subs(rd, rn, shifter_op, cond);
2394 } else {
2395 CHECK(rn != IP);
2396 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2397 mvn(IP, shifter_op, cond);
2398 adds(rd, rn, ShifterOperand(IP), cond);
2399 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2400 mvn(IP, shifter_op, cond);
2401 subs(rd, rn, ShifterOperand(IP), cond);
2402 } else {
2403 movw(IP, Low16Bits(value), cond);
2404 uint16_t value_high = High16Bits(value);
2405 if (value_high != 0) {
2406 movt(IP, value_high, cond);
2407 }
2408 adds(rd, rn, ShifterOperand(IP), cond);
2409 }
2410 }
2411}
2412
Dave Allison65fcc2c2014-04-28 13:45:27 -07002413void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2414 ShifterOperand shifter_op;
2415 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2416 mov(rd, shifter_op, cond);
2417 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2418 mvn(rd, shifter_op, cond);
2419 } else {
2420 movw(rd, Low16Bits(value), cond);
2421 uint16_t value_high = High16Bits(value);
2422 if (value_high != 0) {
2423 movt(rd, value_high, cond);
2424 }
2425 }
2426}
2427
2428// Implementation note: this method must emit at most one instruction when
2429// Address::CanHoldLoadOffsetThumb.
2430void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2431 Register reg,
2432 Register base,
2433 int32_t offset,
2434 Condition cond) {
2435 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002436 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002437 LoadImmediate(IP, offset, cond);
2438 add(IP, IP, ShifterOperand(base), cond);
2439 base = IP;
2440 offset = 0;
2441 }
2442 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2443 switch (type) {
2444 case kLoadSignedByte:
2445 ldrsb(reg, Address(base, offset), cond);
2446 break;
2447 case kLoadUnsignedByte:
2448 ldrb(reg, Address(base, offset), cond);
2449 break;
2450 case kLoadSignedHalfword:
2451 ldrsh(reg, Address(base, offset), cond);
2452 break;
2453 case kLoadUnsignedHalfword:
2454 ldrh(reg, Address(base, offset), cond);
2455 break;
2456 case kLoadWord:
2457 ldr(reg, Address(base, offset), cond);
2458 break;
2459 case kLoadWordPair:
2460 ldrd(reg, Address(base, offset), cond);
2461 break;
2462 default:
2463 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002464 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002465 }
2466}
2467
2468
2469// Implementation note: this method must emit at most one instruction when
2470// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2471void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2472 Register base,
2473 int32_t offset,
2474 Condition cond) {
2475 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2476 CHECK_NE(base, IP);
2477 LoadImmediate(IP, offset, cond);
2478 add(IP, IP, ShifterOperand(base), cond);
2479 base = IP;
2480 offset = 0;
2481 }
2482 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2483 vldrs(reg, Address(base, offset), cond);
2484}
2485
2486
2487// Implementation note: this method must emit at most one instruction when
2488// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2489void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2490 Register base,
2491 int32_t offset,
2492 Condition cond) {
2493 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2494 CHECK_NE(base, IP);
2495 LoadImmediate(IP, offset, cond);
2496 add(IP, IP, ShifterOperand(base), cond);
2497 base = IP;
2498 offset = 0;
2499 }
2500 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2501 vldrd(reg, Address(base, offset), cond);
2502}
2503
2504
2505// Implementation note: this method must emit at most one instruction when
2506// Address::CanHoldStoreOffsetThumb.
2507void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2508 Register reg,
2509 Register base,
2510 int32_t offset,
2511 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002512 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002513 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002514 CHECK_NE(base, IP);
2515 if (reg != IP) {
2516 tmp_reg = IP;
2517 } else {
2518 // Be careful not to use IP twice (for `reg` and to build the
2519 // Address object used by the store instruction(s) below).
2520 // Instead, save R5 on the stack (or R6 if R5 is not available),
2521 // use it as secondary temporary register, and restore it after
2522 // the store instruction has been emitted.
2523 tmp_reg = base != R5 ? R5 : R6;
2524 Push(tmp_reg);
2525 if (base == SP) {
2526 offset += kRegisterSize;
2527 }
2528 }
2529 LoadImmediate(tmp_reg, offset, cond);
2530 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2531 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002532 offset = 0;
2533 }
2534 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2535 switch (type) {
2536 case kStoreByte:
2537 strb(reg, Address(base, offset), cond);
2538 break;
2539 case kStoreHalfword:
2540 strh(reg, Address(base, offset), cond);
2541 break;
2542 case kStoreWord:
2543 str(reg, Address(base, offset), cond);
2544 break;
2545 case kStoreWordPair:
2546 strd(reg, Address(base, offset), cond);
2547 break;
2548 default:
2549 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002550 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002551 }
Roland Levillain775ef492014-11-04 17:43:11 +00002552 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2553 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2554 Pop(tmp_reg);
2555 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002556}
2557
2558
2559// Implementation note: this method must emit at most one instruction when
2560// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2561void Thumb2Assembler::StoreSToOffset(SRegister reg,
2562 Register base,
2563 int32_t offset,
2564 Condition cond) {
2565 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2566 CHECK_NE(base, IP);
2567 LoadImmediate(IP, offset, cond);
2568 add(IP, IP, ShifterOperand(base), cond);
2569 base = IP;
2570 offset = 0;
2571 }
2572 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2573 vstrs(reg, Address(base, offset), cond);
2574}
2575
2576
2577// Implementation note: this method must emit at most one instruction when
2578// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2579void Thumb2Assembler::StoreDToOffset(DRegister reg,
2580 Register base,
2581 int32_t offset,
2582 Condition cond) {
2583 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2584 CHECK_NE(base, IP);
2585 LoadImmediate(IP, offset, cond);
2586 add(IP, IP, ShifterOperand(base), cond);
2587 base = IP;
2588 offset = 0;
2589 }
2590 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2591 vstrd(reg, Address(base, offset), cond);
2592}
2593
2594
2595void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2596 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002597 dmb(SY);
2598}
2599
2600
2601void Thumb2Assembler::dmb(DmbOptions flavor) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002602#if ANDROID_SMP != 0
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002603 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2604 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002605#endif
2606}
2607
2608
2609void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002610 if (force_32bit_branches_) {
2611 cmp(r, ShifterOperand(0));
2612 b(label, EQ);
2613 } else {
2614 cbz(r, label);
2615 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002616}
2617
2618
2619void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002620 if (force_32bit_branches_) {
2621 cmp(r, ShifterOperand(0));
2622 b(label, NE);
2623 } else {
2624 cbnz(r, label);
2625 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002626}
2627} // namespace arm
2628} // namespace art