blob: e26e3d2d03ad60bcd41d96cab80bd8a292af618c [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) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000377 CHECK_NE(regs, 0u); // Do not use ldm if there's nothing to load.
378 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700379 // Thumb doesn't support one reg in the list.
380 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000381 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700382 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700383 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700384 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
385 } else {
386 EmitMultiMemOp(cond, am, true, base, regs);
387 }
388}
389
390
391void Thumb2Assembler::stm(BlockAddressMode am,
392 Register base,
393 RegList regs,
394 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000395 CHECK_NE(regs, 0u); // Do not use stm if there's nothing to store.
396 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700397 // Thumb doesn't support one reg in the list.
398 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000399 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700400 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700401 CHECK(am == IA || am == IA_W);
402 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700403 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
404 } else {
405 EmitMultiMemOp(cond, am, false, base, regs);
406 }
407}
408
409
410bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
411 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
412 if (((imm32 & ((1 << 19) - 1)) == 0) &&
413 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
414 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
415 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
416 ((imm32 >> 19) & ((1 << 6) -1));
417 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
418 sd, S0, S0);
419 return true;
420 }
421 return false;
422}
423
424
425bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
426 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
427 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
428 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
429 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
430 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
431 ((imm64 >> 48) & ((1 << 6) -1));
432 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
433 dd, D0, D0);
434 return true;
435 }
436 return false;
437}
438
439
440void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
441 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
442}
443
444
445void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
446 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
447}
448
449
450void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
451 Condition cond) {
452 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
453}
454
455
456void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
457 Condition cond) {
458 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
459}
460
461
462void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
463 Condition cond) {
464 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
465}
466
467
468void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
469 Condition cond) {
470 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
471}
472
473
474void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
475 Condition cond) {
476 EmitVFPsss(cond, B21, sd, sn, sm);
477}
478
479
480void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
481 Condition cond) {
482 EmitVFPddd(cond, B21, dd, dn, dm);
483}
484
485
486void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
487 Condition cond) {
488 EmitVFPsss(cond, 0, sd, sn, sm);
489}
490
491
492void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
493 Condition cond) {
494 EmitVFPddd(cond, 0, dd, dn, dm);
495}
496
497
498void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
499 Condition cond) {
500 EmitVFPsss(cond, B6, sd, sn, sm);
501}
502
503
504void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
505 Condition cond) {
506 EmitVFPddd(cond, B6, dd, dn, dm);
507}
508
509
510void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
511 Condition cond) {
512 EmitVFPsss(cond, B23, sd, sn, sm);
513}
514
515
516void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
517 Condition cond) {
518 EmitVFPddd(cond, B23, dd, dn, dm);
519}
520
521
522void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
523 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
524}
525
526
527void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
528 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
529}
530
531
532void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
533 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
534}
535
536
537void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
538 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
539}
540
541
542void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
543 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
544}
545
546void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
547 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
548}
549
550
551void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
552 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
553}
554
555
556void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
557 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
558}
559
560
561void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
562 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
563}
564
565
566void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
567 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
568}
569
570
571void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
572 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
573}
574
575
576void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
577 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
578}
579
580
581void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
582 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
583}
584
585
586void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
587 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
588}
589
590
591void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
592 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
593}
594
595
596void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
597 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
598}
599
600
601void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
602 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
603}
604
605
606void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
607 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
608}
609
610
611void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
612 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
613}
614
615
616void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
617 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
618}
619
620void Thumb2Assembler::b(Label* label, Condition cond) {
621 EmitBranch(cond, label, false, false);
622}
623
624
625void Thumb2Assembler::bl(Label* label, Condition cond) {
626 CheckCondition(cond);
627 EmitBranch(cond, label, true, false);
628}
629
630
631void Thumb2Assembler::blx(Label* label) {
632 EmitBranch(AL, label, true, true);
633}
634
635
636void Thumb2Assembler::MarkExceptionHandler(Label* label) {
637 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
638 Label l;
639 b(&l);
640 EmitBranch(AL, label, false, false);
641 Bind(&l);
642}
643
644
645void Thumb2Assembler::Emit32(int32_t value) {
646 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
647 buffer_.Emit<int16_t>(value >> 16);
648 buffer_.Emit<int16_t>(value & 0xffff);
649}
650
651
652void Thumb2Assembler::Emit16(int16_t value) {
653 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
654 buffer_.Emit<int16_t>(value);
655}
656
657
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700658bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700659 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700660 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700661 Register rn,
662 Register rd,
663 const ShifterOperand& so) {
664 if (force_32bit_) {
665 return true;
666 }
667
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100668 bool can_contain_high_register = (opcode == MOV)
669 || ((opcode == ADD || opcode == SUB) && (rn == rd));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700670
671 if (IsHighRegister(rd) || IsHighRegister(rn)) {
672 if (can_contain_high_register) {
673 // There are high register instructions available for this opcode.
674 // However, there is no RRX available.
675 if (so.IsShift() && so.GetShift() == RRX) {
676 return true;
677 }
678
679 // Check special case for SP relative ADD and SUB immediate.
680 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
681 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
682 if (rn == SP && rd != SP && IsHighRegister(rd)) {
683 return true;
684 }
685
686 uint32_t imm = so.GetImmediate();
687 // If the immediates are out of range use 32 bit.
688 if (rd == SP && rn == SP) {
689 if (imm > (1 << 9)) { // 9 bit immediate.
690 return true;
691 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700692 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
693 if (imm > (1 << 10)) {
694 return true;
695 }
696 } else if (opcode == SUB && rd != SP && rn == SP) {
697 // SUB rd, SP, #imm is always 32 bit.
698 return true;
699 }
700 }
701 }
702
703 // The ADD,SUB and MOV instructions that work with high registers don't have
704 // immediate variants.
705 if (so.IsImmediate()) {
706 return true;
707 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100708
709 if (!can_contain_high_register) {
710 return true;
711 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700712 }
713
714 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
715 return true;
716 }
717
718 // Check for MOV with an ROR.
719 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
720 if (so.GetImmediate() != 0) {
721 return true;
722 }
723 }
724
725 bool rn_is_valid = true;
726
727 // Check for single operand instructions and ADD/SUB.
728 switch (opcode) {
729 case CMP:
730 case MOV:
731 case TST:
732 case MVN:
733 rn_is_valid = false; // There is no Rn for these instructions.
734 break;
735 case TEQ:
736 return true;
737 break;
738 case ADD:
739 case SUB:
740 break;
741 default:
742 if (so.IsRegister() && rd != rn) {
743 return true;
744 }
745 }
746
747 if (so.IsImmediate()) {
748 if (rn_is_valid && rn != rd) {
749 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
750 // immediate must be 3 bits.
751 if (opcode != ADD && opcode != SUB) {
752 return true;
753 } else {
754 // Check that the immediate is 3 bits for ADD and SUB.
755 if (so.GetImmediate() >= 8) {
756 return true;
757 }
758 }
759 } else {
760 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
761 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
762 return true;
763 } else {
764 if (so.GetImmediate() > 255) {
765 return true;
766 }
767 }
768 }
769 }
770
771 // The instruction can be encoded in 16 bits.
772 return false;
773}
774
775
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700776void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700777 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700778 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700779 Register rn,
780 Register rd,
781 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700782 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700783 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700784 case AND: thumb_opcode = 0U /* 0b0000 */; break;
785 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
786 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
787 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
788 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700789 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700790 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700791 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700792 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
793 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
794 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
795 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
796 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
797 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
798 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
799 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700800 default:
801 break;
802 }
803
Andreas Gampec8ccf682014-09-29 20:07:43 -0700804 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700805 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000806 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700807 }
808
809 int32_t encoding = 0;
810 if (so.IsImmediate()) {
811 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100812 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700813 if (opcode == SUB) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700814 thumb_opcode = 5U /* 0b0101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700815 } else {
816 thumb_opcode = 0;
817 }
818 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700819
820 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700821 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700822 uint32_t imm8 = imm & 0xff;
823
824 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700825 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100826 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700827 rd << 8 |
828 i << 26 |
829 imm3 << 12 |
830 imm8;
831 } else {
832 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700833 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700834 if (imm == kInvalidModifiedImmediate) {
835 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
Vladimir Markoe8469c12014-11-26 18:09:30 +0000836 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700837 }
838 encoding = B31 | B30 | B29 | B28 |
839 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700840 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700841 rn << 16 |
842 rd << 8 |
843 imm;
844 }
845 } else if (so.IsRegister()) {
846 // Register (possibly shifted)
847 encoding = B31 | B30 | B29 | B27 | B25 |
848 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700849 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700850 rn << 16 |
851 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700852 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700853 }
854 Emit32(encoding);
855}
856
857
858void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
859 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700860 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700861 Register rn,
862 Register rd,
863 const ShifterOperand& so) {
864 if (opcode == ADD || opcode == SUB) {
865 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
866 return;
867 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700868 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700869 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700870 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700871 uint8_t opcode_shift = 6;
872 uint8_t rd_shift = 0;
873 uint8_t rn_shift = 3;
874 uint8_t immediate_shift = 0;
875 bool use_immediate = false;
876 uint8_t immediate = 0;
877
878 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
879 // Convert shifted mov operand2 into 16 bit opcodes.
880 dp_opcode = 0;
881 opcode_shift = 11;
882
883 use_immediate = true;
884 immediate = so.GetImmediate();
885 immediate_shift = 6;
886
887 rn = so.GetRegister();
888
889 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700890 case LSL: thumb_opcode = 0U /* 0b00 */; break;
891 case LSR: thumb_opcode = 1U /* 0b01 */; break;
892 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700893 case ROR:
894 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700895 thumb_opcode = 7U /* 0b111 */;
896 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700897 opcode_shift = 6;
898 use_immediate = false;
899 break;
900 case RRX: break;
901 default:
902 break;
903 }
904 } else {
905 if (so.IsImmediate()) {
906 use_immediate = true;
907 immediate = so.GetImmediate();
908 }
909
910 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700911 case AND: thumb_opcode = 0U /* 0b0000 */; break;
912 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700913 case SUB: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700914 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700915 case ADD: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700916 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
917 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700918 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700919 case TST: thumb_opcode = 8U /* 0b1000 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700920 case TEQ: break;
921 case CMP:
922 if (use_immediate) {
923 // T2 encoding.
924 dp_opcode = 0;
925 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700926 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700927 rd_shift = 8;
928 rn_shift = 8;
929 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700930 thumb_opcode = 10U /* 0b1010 */;
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100931 rd = rn;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700932 rn = so.GetRegister();
933 }
934
935 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100936 case CMN: {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700937 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100938 rd = rn;
939 rn = so.GetRegister();
940 break;
941 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700942 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700943 case MOV:
944 dp_opcode = 0;
945 if (use_immediate) {
946 // T2 encoding.
947 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700948 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700949 rd_shift = 8;
950 rn_shift = 8;
951 } else {
952 rn = so.GetRegister();
953 if (IsHighRegister(rn) || IsHighRegister(rd)) {
954 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700955 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700956 opcode_shift = 7;
957 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700958 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
959 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700960 } else {
961 thumb_opcode = 0;
962 }
963 }
964 break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700965 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
966 case MVN: thumb_opcode = 15U /* 0b1111 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700967 default:
968 break;
969 }
970 }
971
Andreas Gampec8ccf682014-09-29 20:07:43 -0700972 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700973 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000974 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700975 }
976
977 int16_t encoding = dp_opcode << 14 |
978 (thumb_opcode << opcode_shift) |
979 rd << rd_shift |
980 rn << rn_shift |
981 (use_immediate ? (immediate << immediate_shift) : 0);
982
983 Emit16(encoding);
984}
985
986
987// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700988void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700989 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700990 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700991 Register rn,
992 Register rd,
993 const ShifterOperand& so) {
994 uint8_t dp_opcode = 0;
995 uint8_t opcode_shift = 6;
996 uint8_t rd_shift = 0;
997 uint8_t rn_shift = 3;
998 uint8_t immediate_shift = 0;
999 bool use_immediate = false;
1000 uint8_t immediate = 0;
1001 uint8_t thumb_opcode;;
1002
1003 if (so.IsImmediate()) {
1004 use_immediate = true;
1005 immediate = so.GetImmediate();
1006 }
1007
1008 switch (opcode) {
1009 case ADD:
1010 if (so.IsRegister()) {
1011 Register rm = so.GetRegister();
1012 if (rn == rd) {
1013 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001014 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001015 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001016 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001017 // Make Rn also contain the top bit of rd.
1018 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001019 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1020 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001021 } else {
1022 // T1.
1023 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001024 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001025 immediate = static_cast<uint32_t>(so.GetRegister());
1026 use_immediate = true;
1027 immediate_shift = 6;
1028 }
1029 } else {
1030 // Immediate.
1031 if (rd == SP && rn == SP) {
1032 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001033 dp_opcode = 2U /* 0b10 */;
1034 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001035 opcode_shift = 12;
1036 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001037 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001038
1039 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1040 rn = R0;
1041 rd = R0;
1042 rd_shift = 0;
1043 rn_shift = 0;
1044 immediate >>= 2;
1045 } else if (rd != SP && rn == SP) {
1046 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001047 dp_opcode = 2U /* 0b10 */;
1048 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001049 opcode_shift = 11;
1050 CHECK_LT(immediate, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001051 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001052
1053 // Remove rn from instruction.
1054 rn = R0;
1055 rn_shift = 0;
1056 rd_shift = 8;
1057 immediate >>= 2;
1058 } else if (rn != rd) {
1059 // Must use T1.
1060 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001061 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001062 immediate_shift = 6;
1063 } else {
1064 // T2 encoding.
1065 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001066 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001067 rd_shift = 8;
1068 rn_shift = 8;
1069 }
1070 }
1071 break;
1072
1073 case SUB:
1074 if (so.IsRegister()) {
1075 // T1.
1076 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001077 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001078 immediate = static_cast<uint32_t>(so.GetRegister());
1079 use_immediate = true;
1080 immediate_shift = 6;
1081 } else {
1082 if (rd == SP && rn == SP) {
1083 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001084 dp_opcode = 2U /* 0b10 */;
1085 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001086 opcode_shift = 7;
1087 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001088 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001089
1090 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1091 rn = R0;
1092 rd = R0;
1093 rd_shift = 0;
1094 rn_shift = 0;
1095 immediate >>= 2;
1096 } else if (rn != rd) {
1097 // Must use T1.
1098 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001099 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001100 immediate_shift = 6;
1101 } else {
1102 // T2 encoding.
1103 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001104 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001105 rd_shift = 8;
1106 rn_shift = 8;
1107 }
1108 }
1109 break;
1110 default:
1111 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001112 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001113 }
1114
1115 int16_t encoding = dp_opcode << 14 |
1116 (thumb_opcode << opcode_shift) |
1117 rd << rd_shift |
1118 rn << rn_shift |
1119 (use_immediate ? (immediate << immediate_shift) : 0);
1120
1121 Emit16(encoding);
1122}
1123
1124
1125void Thumb2Assembler::EmitDataProcessing(Condition cond,
1126 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001127 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001128 Register rn,
1129 Register rd,
1130 const ShifterOperand& so) {
1131 CHECK_NE(rd, kNoRegister);
1132 CheckCondition(cond);
1133
1134 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1135 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1136 } else {
1137 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1138 }
1139}
1140
Dave Allison45fdb932014-06-25 12:37:10 -07001141void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1142 CHECK_LT(amount, (1 << 5));
1143 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1144 uint16_t opcode = 0;
1145 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001146 case LSL: opcode = 0U /* 0b00 */; break;
1147 case LSR: opcode = 1U /* 0b01 */; break;
1148 case ASR: opcode = 2U /* 0b10 */; break;
1149 case ROR: opcode = 3U /* 0b11 */; break;
1150 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001151 default:
1152 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001153 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001154 }
1155 // 32 bit.
1156 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1157 0xf << 16 | (setcc ? B20 : 0);
1158 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001159 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001160 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1161 static_cast<int16_t>(rd) << 8 | opcode << 4;
1162 Emit32(encoding);
1163 } else {
1164 // 16 bit shift
1165 uint16_t opcode = 0;
1166 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001167 case LSL: opcode = 0U /* 0b00 */; break;
1168 case LSR: opcode = 1U /* 0b01 */; break;
1169 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001170 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001171 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1172 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001173 }
1174 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1175 static_cast<int16_t>(rd);
1176 Emit16(encoding);
1177 }
1178}
1179
1180void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1181 CHECK_NE(shift, RRX);
1182 bool must_be_32bit = false;
1183 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1184 must_be_32bit = true;
1185 }
1186
1187 if (must_be_32bit) {
1188 uint16_t opcode = 0;
1189 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001190 case LSL: opcode = 0U /* 0b00 */; break;
1191 case LSR: opcode = 1U /* 0b01 */; break;
1192 case ASR: opcode = 2U /* 0b10 */; break;
1193 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001194 default:
1195 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001196 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001197 }
1198 // 32 bit.
1199 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1200 0xf << 12 | (setcc ? B20 : 0);
1201 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1202 static_cast<int16_t>(rd) << 8 | opcode << 21;
1203 Emit32(encoding);
1204 } else {
1205 uint16_t opcode = 0;
1206 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001207 case LSL: opcode = 2U /* 0b0010 */; break;
1208 case LSR: opcode = 3U /* 0b0011 */; break;
1209 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001210 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001211 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1212 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001213 }
1214 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1215 static_cast<int16_t>(rd);
1216 Emit16(encoding);
1217 }
1218}
1219
1220
Dave Allison65fcc2c2014-04-28 13:45:27 -07001221
1222void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1223 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1224 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1225 int32_t offset = target_ - location_;
1226
1227 if (size_ == k32Bit) {
1228 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1229 if (link) {
1230 // BL or BLX immediate.
1231 encoding |= B14;
1232 if (!x) {
1233 encoding |= B12;
1234 } else {
1235 // Bottom bit of offset must be 0.
1236 CHECK_EQ((offset & 1), 0);
1237 }
1238 } else {
1239 if (x) {
1240 LOG(FATAL) << "Invalid use of BX";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001241 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001242 } else {
1243 if (cond_ == AL) {
1244 // Can use the T4 encoding allowing a 24 bit offset.
1245 if (!x) {
1246 encoding |= B12;
1247 }
1248 } else {
1249 // Must be T3 encoding with a 20 bit offset.
1250 encoding |= cond_ << 22;
1251 }
1252 }
1253 }
1254 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1255 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1256 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1257 } else {
1258 if (IsCompareAndBranch()) {
1259 offset -= 4;
1260 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001261 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001262 int16_t encoding = B15 | B13 | B12 |
1263 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1264 static_cast<uint32_t>(rn_) |
1265 B8 |
1266 i << 9 |
1267 imm5 << 3;
1268 buffer->Store<int16_t>(location_, encoding);
1269 } else {
1270 offset -= 4; // Account for PC offset.
1271 int16_t encoding;
1272 // 16 bit.
1273 if (cond_ == AL) {
1274 encoding = B15 | B14 | B13 |
1275 ((offset >> 1) & 0x7ff);
1276 } else {
1277 encoding = B15 | B14 | B12 |
1278 cond_ << 8 | ((offset >> 1) & 0xff);
1279 }
1280 buffer->Store<int16_t>(location_, encoding);
1281 }
1282 }
1283}
1284
1285
1286uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1287 uint32_t location = buffer_.Size();
1288
1289 // This is always unresolved as it must be a forward branch.
1290 Emit16(prev); // Previous link.
1291 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1292 location, rn);
1293}
1294
1295
1296// NOTE: this only support immediate offsets, not [rx,ry].
1297// TODO: support [rx,ry] instructions.
1298void Thumb2Assembler::EmitLoadStore(Condition cond,
1299 bool load,
1300 bool byte,
1301 bool half,
1302 bool is_signed,
1303 Register rd,
1304 const Address& ad) {
1305 CHECK_NE(rd, kNoRegister);
1306 CheckCondition(cond);
1307 bool must_be_32bit = force_32bit_;
1308 if (IsHighRegister(rd)) {
1309 must_be_32bit = true;
1310 }
1311
1312 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001313 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001314 must_be_32bit = true;
1315 }
1316
1317 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1318 must_be_32bit = true;
1319 }
1320
Dave Allison45fdb932014-06-25 12:37:10 -07001321 if (ad.IsImmediate()) {
1322 // Immediate offset
1323 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001324
Dave Allison45fdb932014-06-25 12:37:10 -07001325 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001326 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001327 must_be_32bit = true;
1328 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001329
1330 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001331 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001332 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001333 must_be_32bit = true;
1334 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001335 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001336 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001337 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001338 must_be_32bit = true;
1339 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001340 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001341 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001342 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001343 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001344 }
1345 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001346
Dave Allison45fdb932014-06-25 12:37:10 -07001347 if (must_be_32bit) {
1348 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1349 (load ? B20 : 0) |
1350 (is_signed ? B24 : 0) |
1351 static_cast<uint32_t>(rd) << 12 |
1352 ad.encodingThumb(true) |
1353 (byte ? 0 : half ? B21 : B22);
1354 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001355 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001356 // 16 bit thumb1.
1357 uint8_t opA = 0;
1358 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001359
1360 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001361 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001362 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001363 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001364 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001365 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001366 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001367 sp_relative = true;
1368 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001369 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001370 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001371 }
Dave Allison45fdb932014-06-25 12:37:10 -07001372 int16_t encoding = opA << 12 |
1373 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001374
Dave Allison45fdb932014-06-25 12:37:10 -07001375 CHECK_GE(offset, 0);
1376 if (sp_relative) {
1377 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001378 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001379 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001380 encoding |= rd << 8 | offset >> 2;
1381 } else {
1382 // No SP relative. The offset is shifted right depending on
1383 // the size of the load/store.
1384 encoding |= static_cast<uint32_t>(rd);
1385
1386 if (byte) {
1387 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001388 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001389 } else if (half) {
1390 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001391 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001392 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001393 offset >>= 1;
1394 } else {
1395 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001396 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001397 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001398 offset >>= 2;
1399 }
1400 encoding |= rn << 3 | offset << 6;
1401 }
1402
1403 Emit16(encoding);
1404 }
1405 } else {
1406 // Register shift.
1407 if (ad.GetRegister() == PC) {
1408 // PC relative literal encoding.
1409 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001410 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001411 int32_t up = B23;
1412 if (offset < 0) {
1413 offset = -offset;
1414 up = 0;
1415 }
1416 CHECK_LT(offset, (1 << 12));
1417 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1418 offset | up |
1419 static_cast<uint32_t>(rd) << 12;
1420 Emit32(encoding);
1421 } else {
1422 // 16 bit literal load.
1423 CHECK_GE(offset, 0);
1424 CHECK_LT(offset, (1 << 10));
1425 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1426 Emit16(encoding);
1427 }
1428 } else {
1429 if (ad.GetShiftCount() != 0) {
1430 // If there is a shift count this must be 32 bit.
1431 must_be_32bit = true;
1432 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1433 must_be_32bit = true;
1434 }
1435
1436 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001437 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001438 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001439 if (half) {
1440 encoding |= B21;
1441 } else if (!byte) {
1442 encoding |= B22;
1443 }
Dave Allison45fdb932014-06-25 12:37:10 -07001444 Emit32(encoding);
1445 } else {
1446 // 16 bit register offset.
1447 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1448 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001449 if (byte) {
1450 encoding |= B10;
1451 } else if (half) {
1452 encoding |= B9;
1453 }
Dave Allison45fdb932014-06-25 12:37:10 -07001454 Emit16(encoding);
1455 }
1456 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001457 }
1458}
1459
1460
1461void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001462 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001463 bool load,
1464 Register base,
1465 RegList regs) {
1466 CHECK_NE(base, kNoRegister);
1467 CheckCondition(cond);
1468 bool must_be_32bit = force_32bit_;
1469
Vladimir Markoe8469c12014-11-26 18:09:30 +00001470 if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
1471 (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
1472 // Use 16-bit PUSH/POP.
1473 int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
1474 ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
1475 Emit16(encoding);
1476 return;
1477 }
1478
Dave Allison65fcc2c2014-04-28 13:45:27 -07001479 if ((regs & 0xff00) != 0) {
1480 must_be_32bit = true;
1481 }
1482
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001483 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001484 // 16 bit always uses writeback.
1485 if (!w_bit) {
1486 must_be_32bit = true;
1487 }
1488
1489 if (must_be_32bit) {
1490 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001491 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001492 case IA:
1493 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001494 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001495 break;
1496 case DB:
1497 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001498 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001499 break;
1500 case DA:
1501 case IB:
1502 case DA_W:
1503 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001504 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001505 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001506 }
1507 if (load) {
1508 // Cannot have SP in the list.
1509 CHECK_EQ((regs & (1 << SP)), 0);
1510 } else {
1511 // Cannot have PC or SP in the list.
1512 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1513 }
1514 int32_t encoding = B31 | B30 | B29 | B27 |
1515 (op << 23) |
1516 (load ? B20 : 0) |
1517 base << 16 |
1518 regs |
1519 (w_bit << 21);
1520 Emit32(encoding);
1521 } else {
1522 int16_t encoding = B15 | B14 |
1523 (load ? B11 : 0) |
1524 base << 8 |
1525 regs;
1526 Emit16(encoding);
1527 }
1528}
1529
1530
1531void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1532 uint32_t pc = buffer_.Size();
1533 Branch::Type branch_type;
1534 if (cond == AL) {
1535 if (link) {
1536 if (x) {
1537 branch_type = Branch::kUnconditionalLinkX; // BLX.
1538 } else {
1539 branch_type = Branch::kUnconditionalLink; // BX.
1540 }
1541 } else {
1542 branch_type = Branch::kUnconditional; // B.
1543 }
1544 } else {
1545 branch_type = Branch::kConditional; // B<cond>.
1546 }
1547
1548 if (label->IsBound()) {
1549 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1550
1551 // The branch is to a bound label which means that it's a backwards branch. We know the
1552 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1553 // branch the size may change if it so happens that other branches change size that change
1554 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1555 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001556 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001557 Emit16(0); // Space for a 16 bit branch.
1558 } else {
1559 Emit32(0); // Space for a 32 bit branch.
1560 }
1561 } else {
1562 // Branch is to an unbound label. Emit space for it.
1563 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001564 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001565 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1566 Emit16(0); // another 16 bits.
1567 } else {
1568 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1569 }
1570 label->LinkTo(branch_id); // Link to the branch ID.
1571 }
1572}
1573
1574
1575void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1576 CHECK_NE(rd, kNoRegister);
1577 CHECK_NE(rm, kNoRegister);
1578 CheckCondition(cond);
1579 CHECK_NE(rd, PC);
1580 CHECK_NE(rm, PC);
1581 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1582 B25 | B23 | B21 | B20 |
1583 static_cast<uint32_t>(rm) << 16 |
1584 0xf << 12 |
1585 static_cast<uint32_t>(rd) << 8 |
1586 B7 |
1587 static_cast<uint32_t>(rm);
1588 Emit32(encoding);
1589}
1590
1591
1592void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1593 CheckCondition(cond);
1594 bool must_be_32bit = force_32bit_;
1595 if (IsHighRegister(rd)|| imm16 >= 256u) {
1596 must_be_32bit = true;
1597 }
1598
1599 if (must_be_32bit) {
1600 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001601 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1602 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1603 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001604 uint32_t imm8 = imm16 & 0xff;
1605 int32_t encoding = B31 | B30 | B29 | B28 |
1606 B25 | B22 |
1607 static_cast<uint32_t>(rd) << 8 |
1608 i << 26 |
1609 imm4 << 16 |
1610 imm3 << 12 |
1611 imm8;
1612 Emit32(encoding);
1613 } else {
1614 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1615 imm16;
1616 Emit16(encoding);
1617 }
1618}
1619
1620
1621void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1622 CheckCondition(cond);
1623 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001624 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1625 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1626 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001627 uint32_t imm8 = imm16 & 0xff;
1628 int32_t encoding = B31 | B30 | B29 | B28 |
1629 B25 | B23 | B22 |
1630 static_cast<uint32_t>(rd) << 8 |
1631 i << 26 |
1632 imm4 << 16 |
1633 imm3 << 12 |
1634 imm8;
1635 Emit32(encoding);
1636}
1637
1638
1639void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1640 CHECK_NE(rn, kNoRegister);
1641 CHECK_NE(rt, kNoRegister);
1642 CheckCondition(cond);
1643 CHECK_NE(rn, kNoRegister);
1644 CHECK_NE(rt, kNoRegister);
1645 CheckCondition(cond);
1646 CHECK_LT(imm, (1u << 10));
1647
1648 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1649 static_cast<uint32_t>(rn) << 16 |
1650 static_cast<uint32_t>(rt) << 12 |
1651 0xf << 8 |
1652 imm >> 2;
1653 Emit32(encoding);
1654}
1655
1656
1657void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1658 ldrex(rt, rn, 0, cond);
1659}
1660
1661
1662void Thumb2Assembler::strex(Register rd,
1663 Register rt,
1664 Register rn,
1665 uint16_t imm,
1666 Condition cond) {
1667 CHECK_NE(rn, kNoRegister);
1668 CHECK_NE(rd, kNoRegister);
1669 CHECK_NE(rt, kNoRegister);
1670 CheckCondition(cond);
1671 CHECK_LT(imm, (1u << 10));
1672
1673 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1674 static_cast<uint32_t>(rn) << 16 |
1675 static_cast<uint32_t>(rt) << 12 |
1676 static_cast<uint32_t>(rd) << 8 |
1677 imm >> 2;
1678 Emit32(encoding);
1679}
1680
1681
1682void Thumb2Assembler::strex(Register rd,
1683 Register rt,
1684 Register rn,
1685 Condition cond) {
1686 strex(rd, rt, rn, 0, cond);
1687}
1688
1689
1690void Thumb2Assembler::clrex(Condition cond) {
1691 CheckCondition(cond);
1692 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1693 B21 | B20 |
1694 0xf << 16 |
1695 B15 |
1696 0xf << 8 |
1697 B5 |
1698 0xf;
1699 Emit32(encoding);
1700}
1701
1702
1703void Thumb2Assembler::nop(Condition cond) {
1704 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001705 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001706 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001707 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001708}
1709
1710
1711void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1712 CHECK_NE(sn, kNoSRegister);
1713 CHECK_NE(rt, kNoRegister);
1714 CHECK_NE(rt, SP);
1715 CHECK_NE(rt, PC);
1716 CheckCondition(cond);
1717 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1718 B27 | B26 | B25 |
1719 ((static_cast<int32_t>(sn) >> 1)*B16) |
1720 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1721 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1722 Emit32(encoding);
1723}
1724
1725
1726void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1727 CHECK_NE(sn, kNoSRegister);
1728 CHECK_NE(rt, kNoRegister);
1729 CHECK_NE(rt, SP);
1730 CHECK_NE(rt, PC);
1731 CheckCondition(cond);
1732 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1733 B27 | B26 | B25 | B20 |
1734 ((static_cast<int32_t>(sn) >> 1)*B16) |
1735 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1736 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1737 Emit32(encoding);
1738}
1739
1740
1741void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1742 Condition cond) {
1743 CHECK_NE(sm, kNoSRegister);
1744 CHECK_NE(sm, S31);
1745 CHECK_NE(rt, kNoRegister);
1746 CHECK_NE(rt, SP);
1747 CHECK_NE(rt, PC);
1748 CHECK_NE(rt2, kNoRegister);
1749 CHECK_NE(rt2, SP);
1750 CHECK_NE(rt2, PC);
1751 CheckCondition(cond);
1752 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1753 B27 | B26 | B22 |
1754 (static_cast<int32_t>(rt2)*B16) |
1755 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1756 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1757 (static_cast<int32_t>(sm) >> 1);
1758 Emit32(encoding);
1759}
1760
1761
1762void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1763 Condition cond) {
1764 CHECK_NE(sm, kNoSRegister);
1765 CHECK_NE(sm, S31);
1766 CHECK_NE(rt, kNoRegister);
1767 CHECK_NE(rt, SP);
1768 CHECK_NE(rt, PC);
1769 CHECK_NE(rt2, kNoRegister);
1770 CHECK_NE(rt2, SP);
1771 CHECK_NE(rt2, PC);
1772 CHECK_NE(rt, rt2);
1773 CheckCondition(cond);
1774 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1775 B27 | B26 | B22 | B20 |
1776 (static_cast<int32_t>(rt2)*B16) |
1777 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1778 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1779 (static_cast<int32_t>(sm) >> 1);
1780 Emit32(encoding);
1781}
1782
1783
1784void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1785 Condition cond) {
1786 CHECK_NE(dm, kNoDRegister);
1787 CHECK_NE(rt, kNoRegister);
1788 CHECK_NE(rt, SP);
1789 CHECK_NE(rt, PC);
1790 CHECK_NE(rt2, kNoRegister);
1791 CHECK_NE(rt2, SP);
1792 CHECK_NE(rt2, PC);
1793 CheckCondition(cond);
1794 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1795 B27 | B26 | B22 |
1796 (static_cast<int32_t>(rt2)*B16) |
1797 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1798 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1799 (static_cast<int32_t>(dm) & 0xf);
1800 Emit32(encoding);
1801}
1802
1803
1804void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1805 Condition cond) {
1806 CHECK_NE(dm, kNoDRegister);
1807 CHECK_NE(rt, kNoRegister);
1808 CHECK_NE(rt, SP);
1809 CHECK_NE(rt, PC);
1810 CHECK_NE(rt2, kNoRegister);
1811 CHECK_NE(rt2, SP);
1812 CHECK_NE(rt2, PC);
1813 CHECK_NE(rt, rt2);
1814 CheckCondition(cond);
1815 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1816 B27 | B26 | B22 | B20 |
1817 (static_cast<int32_t>(rt2)*B16) |
1818 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1819 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1820 (static_cast<int32_t>(dm) & 0xf);
1821 Emit32(encoding);
1822}
1823
1824
1825void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1826 const Address& addr = static_cast<const Address&>(ad);
1827 CHECK_NE(sd, kNoSRegister);
1828 CheckCondition(cond);
1829 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1830 B27 | B26 | B24 | B20 |
1831 ((static_cast<int32_t>(sd) & 1)*B22) |
1832 ((static_cast<int32_t>(sd) >> 1)*B12) |
1833 B11 | B9 | addr.vencoding();
1834 Emit32(encoding);
1835}
1836
1837
1838void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1839 const Address& addr = static_cast<const Address&>(ad);
1840 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1841 CHECK_NE(sd, kNoSRegister);
1842 CheckCondition(cond);
1843 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1844 B27 | B26 | B24 |
1845 ((static_cast<int32_t>(sd) & 1)*B22) |
1846 ((static_cast<int32_t>(sd) >> 1)*B12) |
1847 B11 | B9 | addr.vencoding();
1848 Emit32(encoding);
1849}
1850
1851
1852void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1853 const Address& addr = static_cast<const Address&>(ad);
1854 CHECK_NE(dd, kNoDRegister);
1855 CheckCondition(cond);
1856 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1857 B27 | B26 | B24 | B20 |
1858 ((static_cast<int32_t>(dd) >> 4)*B22) |
1859 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1860 B11 | B9 | B8 | addr.vencoding();
1861 Emit32(encoding);
1862}
1863
1864
1865void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1866 const Address& addr = static_cast<const Address&>(ad);
1867 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1868 CHECK_NE(dd, kNoDRegister);
1869 CheckCondition(cond);
1870 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1871 B27 | B26 | B24 |
1872 ((static_cast<int32_t>(dd) >> 4)*B22) |
1873 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1874 B11 | B9 | B8 | addr.vencoding();
1875 Emit32(encoding);
1876}
1877
1878
1879void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1880 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1881}
1882
1883
1884void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1885 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1886}
1887
1888
1889void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1890 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1891}
1892
1893
1894void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1895 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1896}
1897
1898
1899void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1900 CheckCondition(cond);
1901
1902 uint32_t D;
1903 uint32_t Vd;
1904 if (dbl) {
1905 // Encoded as D:Vd.
1906 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001907 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001908 } else {
1909 // Encoded as Vd:D.
1910 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001911 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001912 }
1913 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1914 B11 | B9 |
1915 (dbl ? B8 : 0) |
1916 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001917 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001918 nregs << (dbl ? 1 : 0) |
1919 D << 22 |
1920 Vd << 12;
1921 Emit32(encoding);
1922}
1923
1924
1925void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1926 SRegister sd, SRegister sn, SRegister sm) {
1927 CHECK_NE(sd, kNoSRegister);
1928 CHECK_NE(sn, kNoSRegister);
1929 CHECK_NE(sm, kNoSRegister);
1930 CheckCondition(cond);
1931 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1932 B27 | B26 | B25 | B11 | B9 | opcode |
1933 ((static_cast<int32_t>(sd) & 1)*B22) |
1934 ((static_cast<int32_t>(sn) >> 1)*B16) |
1935 ((static_cast<int32_t>(sd) >> 1)*B12) |
1936 ((static_cast<int32_t>(sn) & 1)*B7) |
1937 ((static_cast<int32_t>(sm) & 1)*B5) |
1938 (static_cast<int32_t>(sm) >> 1);
1939 Emit32(encoding);
1940}
1941
1942
1943void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1944 DRegister dd, DRegister dn, DRegister dm) {
1945 CHECK_NE(dd, kNoDRegister);
1946 CHECK_NE(dn, kNoDRegister);
1947 CHECK_NE(dm, kNoDRegister);
1948 CheckCondition(cond);
1949 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1950 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1951 ((static_cast<int32_t>(dd) >> 4)*B22) |
1952 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1953 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1954 ((static_cast<int32_t>(dn) >> 4)*B7) |
1955 ((static_cast<int32_t>(dm) >> 4)*B5) |
1956 (static_cast<int32_t>(dm) & 0xf);
1957 Emit32(encoding);
1958}
1959
1960
1961void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1962 SRegister sd, DRegister dm) {
1963 CHECK_NE(sd, kNoSRegister);
1964 CHECK_NE(dm, kNoDRegister);
1965 CheckCondition(cond);
1966 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1967 B27 | B26 | B25 | B11 | B9 | opcode |
1968 ((static_cast<int32_t>(sd) & 1)*B22) |
1969 ((static_cast<int32_t>(sd) >> 1)*B12) |
1970 ((static_cast<int32_t>(dm) >> 4)*B5) |
1971 (static_cast<int32_t>(dm) & 0xf);
1972 Emit32(encoding);
1973}
1974
1975
1976void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
1977 DRegister dd, SRegister sm) {
1978 CHECK_NE(dd, kNoDRegister);
1979 CHECK_NE(sm, kNoSRegister);
1980 CheckCondition(cond);
1981 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1982 B27 | B26 | B25 | B11 | B9 | opcode |
1983 ((static_cast<int32_t>(dd) >> 4)*B22) |
1984 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1985 ((static_cast<int32_t>(sm) & 1)*B5) |
1986 (static_cast<int32_t>(sm) >> 1);
1987 Emit32(encoding);
1988}
1989
1990
1991void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
1992 CheckCondition(cond);
1993 UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
1994}
1995
1996
1997void Thumb2Assembler::svc(uint32_t imm8) {
1998 CHECK(IsUint(8, imm8)) << imm8;
1999 int16_t encoding = B15 | B14 | B12 |
2000 B11 | B10 | B9 | B8 |
2001 imm8;
2002 Emit16(encoding);
2003}
2004
2005
2006void Thumb2Assembler::bkpt(uint16_t imm8) {
2007 CHECK(IsUint(8, imm8)) << imm8;
2008 int16_t encoding = B15 | B13 | B12 |
2009 B11 | B10 | B9 |
2010 imm8;
2011 Emit16(encoding);
2012}
2013
2014// Convert the given IT state to a mask bit given bit 0 of the first
2015// condition and a shift position.
2016static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2017 switch (s) {
2018 case kItOmitted: return 1 << shift;
2019 case kItThen: return firstcond0 << shift;
2020 case kItElse: return !firstcond0 << shift;
2021 }
2022 return 0;
2023}
2024
2025
2026// Set the IT condition in the given position for the given state. This is used
2027// to check that conditional instructions match the preceding IT statement.
2028void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2029 switch (s) {
2030 case kItOmitted: it_conditions_[index] = AL; break;
2031 case kItThen: it_conditions_[index] = cond; break;
2032 case kItElse:
2033 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2034 break;
2035 }
2036}
2037
2038
2039void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2040 CheckCondition(AL); // Not allowed in IT block.
2041 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2042
2043 // All conditions to AL.
2044 for (uint8_t i = 0; i < 4; ++i) {
2045 it_conditions_[i] = AL;
2046 }
2047
2048 SetItCondition(kItThen, firstcond, 0);
2049 uint8_t mask = ToItMask(i1, firstcond0, 3);
2050 SetItCondition(i1, firstcond, 1);
2051
2052 if (i1 != kItOmitted) {
2053 mask |= ToItMask(i2, firstcond0, 2);
2054 SetItCondition(i2, firstcond, 2);
2055 if (i2 != kItOmitted) {
2056 mask |= ToItMask(i3, firstcond0, 1);
2057 SetItCondition(i3, firstcond, 3);
2058 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002059 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002060 }
2061 }
2062 }
2063
2064 // Start at first condition.
2065 it_cond_index_ = 0;
2066 next_condition_ = it_conditions_[0];
2067 uint16_t encoding = B15 | B13 | B12 |
2068 B11 | B10 | B9 | B8 |
2069 firstcond << 4 |
2070 mask;
2071 Emit16(encoding);
2072}
2073
2074
2075void Thumb2Assembler::cbz(Register rn, Label* label) {
2076 CheckCondition(AL);
2077 if (label->IsBound()) {
2078 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002079 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002080 } else {
2081 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2082 label->LinkTo(branchid);
2083 }
2084}
2085
2086
2087void Thumb2Assembler::cbnz(Register rn, Label* label) {
2088 CheckCondition(AL);
2089 if (label->IsBound()) {
2090 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002091 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002092 } else {
2093 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2094 label->LinkTo(branchid);
2095 }
2096}
2097
2098
2099void Thumb2Assembler::blx(Register rm, Condition cond) {
2100 CHECK_NE(rm, kNoRegister);
2101 CheckCondition(cond);
2102 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2103 Emit16(encoding);
2104}
2105
2106
2107void Thumb2Assembler::bx(Register rm, Condition cond) {
2108 CHECK_NE(rm, kNoRegister);
2109 CheckCondition(cond);
2110 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2111 Emit16(encoding);
2112}
2113
2114
2115void Thumb2Assembler::Push(Register rd, Condition cond) {
2116 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2117}
2118
2119
2120void Thumb2Assembler::Pop(Register rd, Condition cond) {
2121 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2122}
2123
2124
2125void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2126 stm(DB_W, SP, regs, cond);
2127}
2128
2129
2130void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2131 ldm(IA_W, SP, regs, cond);
2132}
2133
2134
2135void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2136 if (cond != AL || rd != rm) {
2137 mov(rd, ShifterOperand(rm), cond);
2138 }
2139}
2140
2141
2142// A branch has changed size. Make a hole for it.
2143void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2144 // Move the contents of the buffer using: Move(newposition, oldposition)
2145 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2146 buffer_.Move(location + delta, location);
2147}
2148
2149
2150void Thumb2Assembler::Bind(Label* label) {
2151 CHECK(!label->IsBound());
2152 uint32_t bound_pc = buffer_.Size();
2153 std::vector<Branch*> changed_branches;
2154
2155 while (label->IsLinked()) {
2156 uint16_t position = label->Position(); // Branch id for linked branch.
2157 Branch* branch = GetBranch(position); // Get the branch at this id.
2158 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2159 uint32_t branch_location = branch->GetLocation();
2160 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2161 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002162 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002163 MakeHoleForBranch(branch->GetLocation(), 2);
2164 if (branch->IsCompareAndBranch()) {
2165 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2166 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2167 // cmp rn, #0
2168 // b<eq|ne> target
2169 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2170 Condition cond = n ? NE : EQ;
2171 branch->Move(2); // Move the branch forward by 2 bytes.
2172 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2173 branch->ResetSize(Branch::k16Bit);
2174
2175 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002176 buffer_.Store<int16_t>(branch_location,
2177 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002178
2179 // Since have moved made a hole in the code we need to reload the
2180 // current pc.
2181 bound_pc = buffer_.Size();
2182
2183 // Now resolve the newly added branch.
2184 changed = branch->Resolve(bound_pc);
2185 if (changed) {
2186 MakeHoleForBranch(branch->GetLocation(), 2);
2187 changed_branches.push_back(branch);
2188 }
2189 } else {
2190 changed_branches.push_back(branch);
2191 }
2192 }
2193 label->position_ = next; // Move to next.
2194 }
2195 label->BindTo(bound_pc);
2196
2197 // Now relocate any changed branches. Do this until there are no more changes.
2198 std::vector<Branch*> branches_to_process = changed_branches;
2199 while (branches_to_process.size() != 0) {
2200 changed_branches.clear();
2201 for (auto& changed_branch : branches_to_process) {
2202 for (auto& branch : branches_) {
2203 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2204 if (changed) {
2205 changed_branches.push_back(branch);
2206 }
2207 }
2208 branches_to_process = changed_branches;
2209 }
2210 }
2211}
2212
2213
2214void Thumb2Assembler::EmitBranches() {
2215 for (auto& branch : branches_) {
2216 branch->Emit(&buffer_);
2217 }
2218}
2219
2220
2221void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002222 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002223 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002224 CheckCondition(cond);
2225 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002226}
2227
2228
2229void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002230 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002231 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002232 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002233 CheckCondition(cond);
2234 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002235}
2236
2237
2238void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002239 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002240 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002241 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002242 CheckCondition(cond);
2243 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002244}
2245
2246
2247void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002248 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002249 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002250 CheckCondition(cond);
2251 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002252}
2253
2254
Dave Allison45fdb932014-06-25 12:37:10 -07002255void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2256 CheckCondition(cond);
2257 EmitShift(rd, rm, RRX, rm, setcc);
2258}
2259
2260
2261void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2262 bool setcc, Condition cond) {
2263 CheckCondition(cond);
2264 EmitShift(rd, rm, LSL, rn, setcc);
2265}
2266
2267
2268void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2269 bool setcc, Condition cond) {
2270 CheckCondition(cond);
2271 EmitShift(rd, rm, LSR, rn, setcc);
2272}
2273
2274
2275void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2276 bool setcc, Condition cond) {
2277 CheckCondition(cond);
2278 EmitShift(rd, rm, ASR, rn, setcc);
2279}
2280
2281
2282void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2283 bool setcc, Condition cond) {
2284 CheckCondition(cond);
2285 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002286}
2287
2288
2289int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2290 // The offset is off by 4 due to the way the ARM CPUs read PC.
2291 offset -= 4;
2292 offset >>= 1;
2293
2294 uint32_t value = 0;
2295 // There are two different encodings depending on the value of bit 12. In one case
2296 // intermediate values are calculated using the sign bit.
2297 if ((inst & B12) == B12) {
2298 // 25 bits of offset.
2299 uint32_t signbit = (offset >> 31) & 0x1;
2300 uint32_t i1 = (offset >> 22) & 0x1;
2301 uint32_t i2 = (offset >> 21) & 0x1;
2302 uint32_t imm10 = (offset >> 11) & 0x03ff;
2303 uint32_t imm11 = offset & 0x07ff;
2304 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2305 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2306 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2307 imm11;
2308 // Remove the offset from the current encoding.
2309 inst &= ~(0x3ff << 16 | 0x7ff);
2310 } else {
2311 uint32_t signbit = (offset >> 31) & 0x1;
2312 uint32_t imm6 = (offset >> 11) & 0x03f;
2313 uint32_t imm11 = offset & 0x07ff;
2314 uint32_t j1 = (offset >> 19) & 1;
2315 uint32_t j2 = (offset >> 17) & 1;
2316 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2317 imm11;
2318 // Remove the offset from the current encoding.
2319 inst &= ~(0x3f << 16 | 0x7ff);
2320 }
2321 // Mask out offset bits in current instruction.
2322 inst &= ~(B26 | B13 | B11);
2323 inst |= value;
2324 return inst;
2325}
2326
2327
2328int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2329 int32_t imm32;
2330 if ((instr & B12) == B12) {
2331 uint32_t S = (instr >> 26) & 1;
2332 uint32_t J2 = (instr >> 11) & 1;
2333 uint32_t J1 = (instr >> 13) & 1;
2334 uint32_t imm10 = (instr >> 16) & 0x3FF;
2335 uint32_t imm11 = instr & 0x7FF;
2336
2337 uint32_t I1 = ~(J1 ^ S) & 1;
2338 uint32_t I2 = ~(J2 ^ S) & 1;
2339 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2340 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2341 } else {
2342 uint32_t S = (instr >> 26) & 1;
2343 uint32_t J2 = (instr >> 11) & 1;
2344 uint32_t J1 = (instr >> 13) & 1;
2345 uint32_t imm6 = (instr >> 16) & 0x3F;
2346 uint32_t imm11 = instr & 0x7FF;
2347
2348 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2349 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2350 }
2351 imm32 += 4;
2352 return imm32;
2353}
2354
2355
2356void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2357 AddConstant(rd, rd, value, cond);
2358}
2359
2360
2361void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2362 Condition cond) {
2363 if (value == 0) {
2364 if (rd != rn) {
2365 mov(rd, ShifterOperand(rn), cond);
2366 }
2367 return;
2368 }
2369 // We prefer to select the shorter code sequence rather than selecting add for
2370 // positive values and sub for negatives ones, which would slightly improve
2371 // the readability of generated code for some constants.
2372 ShifterOperand shifter_op;
2373 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2374 add(rd, rn, shifter_op, cond);
2375 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2376 sub(rd, rn, shifter_op, cond);
2377 } else {
2378 CHECK(rn != IP);
2379 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2380 mvn(IP, shifter_op, cond);
2381 add(rd, rn, ShifterOperand(IP), cond);
2382 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2383 mvn(IP, shifter_op, cond);
2384 sub(rd, rn, ShifterOperand(IP), cond);
2385 } else {
2386 movw(IP, Low16Bits(value), cond);
2387 uint16_t value_high = High16Bits(value);
2388 if (value_high != 0) {
2389 movt(IP, value_high, cond);
2390 }
2391 add(rd, rn, ShifterOperand(IP), cond);
2392 }
2393 }
2394}
2395
2396
2397void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2398 Condition cond) {
2399 ShifterOperand shifter_op;
2400 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2401 adds(rd, rn, shifter_op, cond);
2402 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2403 subs(rd, rn, shifter_op, cond);
2404 } else {
2405 CHECK(rn != IP);
2406 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2407 mvn(IP, shifter_op, cond);
2408 adds(rd, rn, ShifterOperand(IP), cond);
2409 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2410 mvn(IP, shifter_op, cond);
2411 subs(rd, rn, ShifterOperand(IP), cond);
2412 } else {
2413 movw(IP, Low16Bits(value), cond);
2414 uint16_t value_high = High16Bits(value);
2415 if (value_high != 0) {
2416 movt(IP, value_high, cond);
2417 }
2418 adds(rd, rn, ShifterOperand(IP), cond);
2419 }
2420 }
2421}
2422
Dave Allison65fcc2c2014-04-28 13:45:27 -07002423void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2424 ShifterOperand shifter_op;
2425 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2426 mov(rd, shifter_op, cond);
2427 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2428 mvn(rd, shifter_op, cond);
2429 } else {
2430 movw(rd, Low16Bits(value), cond);
2431 uint16_t value_high = High16Bits(value);
2432 if (value_high != 0) {
2433 movt(rd, value_high, cond);
2434 }
2435 }
2436}
2437
2438// Implementation note: this method must emit at most one instruction when
2439// Address::CanHoldLoadOffsetThumb.
2440void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2441 Register reg,
2442 Register base,
2443 int32_t offset,
2444 Condition cond) {
2445 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002446 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002447 LoadImmediate(IP, offset, cond);
2448 add(IP, IP, ShifterOperand(base), cond);
2449 base = IP;
2450 offset = 0;
2451 }
2452 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2453 switch (type) {
2454 case kLoadSignedByte:
2455 ldrsb(reg, Address(base, offset), cond);
2456 break;
2457 case kLoadUnsignedByte:
2458 ldrb(reg, Address(base, offset), cond);
2459 break;
2460 case kLoadSignedHalfword:
2461 ldrsh(reg, Address(base, offset), cond);
2462 break;
2463 case kLoadUnsignedHalfword:
2464 ldrh(reg, Address(base, offset), cond);
2465 break;
2466 case kLoadWord:
2467 ldr(reg, Address(base, offset), cond);
2468 break;
2469 case kLoadWordPair:
2470 ldrd(reg, Address(base, offset), cond);
2471 break;
2472 default:
2473 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002474 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002475 }
2476}
2477
2478
2479// Implementation note: this method must emit at most one instruction when
2480// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2481void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2482 Register base,
2483 int32_t offset,
2484 Condition cond) {
2485 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2486 CHECK_NE(base, IP);
2487 LoadImmediate(IP, offset, cond);
2488 add(IP, IP, ShifterOperand(base), cond);
2489 base = IP;
2490 offset = 0;
2491 }
2492 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2493 vldrs(reg, Address(base, offset), cond);
2494}
2495
2496
2497// Implementation note: this method must emit at most one instruction when
2498// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2499void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2500 Register base,
2501 int32_t offset,
2502 Condition cond) {
2503 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2504 CHECK_NE(base, IP);
2505 LoadImmediate(IP, offset, cond);
2506 add(IP, IP, ShifterOperand(base), cond);
2507 base = IP;
2508 offset = 0;
2509 }
2510 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2511 vldrd(reg, Address(base, offset), cond);
2512}
2513
2514
2515// Implementation note: this method must emit at most one instruction when
2516// Address::CanHoldStoreOffsetThumb.
2517void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2518 Register reg,
2519 Register base,
2520 int32_t offset,
2521 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002522 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002523 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002524 CHECK_NE(base, IP);
2525 if (reg != IP) {
2526 tmp_reg = IP;
2527 } else {
2528 // Be careful not to use IP twice (for `reg` and to build the
2529 // Address object used by the store instruction(s) below).
2530 // Instead, save R5 on the stack (or R6 if R5 is not available),
2531 // use it as secondary temporary register, and restore it after
2532 // the store instruction has been emitted.
2533 tmp_reg = base != R5 ? R5 : R6;
2534 Push(tmp_reg);
2535 if (base == SP) {
2536 offset += kRegisterSize;
2537 }
2538 }
2539 LoadImmediate(tmp_reg, offset, cond);
2540 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2541 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002542 offset = 0;
2543 }
2544 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2545 switch (type) {
2546 case kStoreByte:
2547 strb(reg, Address(base, offset), cond);
2548 break;
2549 case kStoreHalfword:
2550 strh(reg, Address(base, offset), cond);
2551 break;
2552 case kStoreWord:
2553 str(reg, Address(base, offset), cond);
2554 break;
2555 case kStoreWordPair:
2556 strd(reg, Address(base, offset), cond);
2557 break;
2558 default:
2559 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002560 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002561 }
Roland Levillain775ef492014-11-04 17:43:11 +00002562 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2563 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2564 Pop(tmp_reg);
2565 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002566}
2567
2568
2569// Implementation note: this method must emit at most one instruction when
2570// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2571void Thumb2Assembler::StoreSToOffset(SRegister reg,
2572 Register base,
2573 int32_t offset,
2574 Condition cond) {
2575 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2576 CHECK_NE(base, IP);
2577 LoadImmediate(IP, offset, cond);
2578 add(IP, IP, ShifterOperand(base), cond);
2579 base = IP;
2580 offset = 0;
2581 }
2582 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2583 vstrs(reg, Address(base, offset), cond);
2584}
2585
2586
2587// Implementation note: this method must emit at most one instruction when
2588// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2589void Thumb2Assembler::StoreDToOffset(DRegister reg,
2590 Register base,
2591 int32_t offset,
2592 Condition cond) {
2593 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2594 CHECK_NE(base, IP);
2595 LoadImmediate(IP, offset, cond);
2596 add(IP, IP, ShifterOperand(base), cond);
2597 base = IP;
2598 offset = 0;
2599 }
2600 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2601 vstrd(reg, Address(base, offset), cond);
2602}
2603
2604
2605void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2606 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002607 dmb(SY);
2608}
2609
2610
2611void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002612 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2613 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002614}
2615
2616
2617void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002618 if (force_32bit_branches_) {
2619 cmp(r, ShifterOperand(0));
2620 b(label, EQ);
2621 } else {
2622 cbz(r, label);
2623 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002624}
2625
2626
2627void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002628 if (force_32bit_branches_) {
2629 cmp(r, ShifterOperand(0));
2630 b(label, NE);
2631 } else {
2632 cbnz(r, label);
2633 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002634}
2635} // namespace arm
2636} // namespace art