blob: fd2613a89eb017362e4123c9e081c360f4788a0d [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
267void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
268 EmitLoadStore(cond, true, false, false, false, rd, ad);
269}
270
271
272void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
273 EmitLoadStore(cond, false, false, false, false, rd, ad);
274}
275
276
277void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
278 EmitLoadStore(cond, true, true, false, false, rd, ad);
279}
280
281
282void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
283 EmitLoadStore(cond, false, true, false, false, rd, ad);
284}
285
286
287void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
288 EmitLoadStore(cond, true, false, true, false, rd, ad);
289}
290
291
292void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
293 EmitLoadStore(cond, false, false, true, false, rd, ad);
294}
295
296
297void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
298 EmitLoadStore(cond, true, true, false, true, rd, ad);
299}
300
301
302void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
303 EmitLoadStore(cond, true, false, true, true, rd, ad);
304}
305
306
307void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700308 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700309 CHECK_EQ(rd % 2, 0);
310 // This is different from other loads. The encoding is like ARM.
311 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
312 static_cast<int32_t>(rd) << 12 |
313 (static_cast<int32_t>(rd) + 1) << 8 |
314 ad.encodingThumbLdrdStrd();
315 Emit32(encoding);
316}
317
318
319void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700320 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700321 CHECK_EQ(rd % 2, 0);
322 // This is different from other loads. The encoding is like ARM.
323 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
324 static_cast<int32_t>(rd) << 12 |
325 (static_cast<int32_t>(rd) + 1) << 8 |
326 ad.encodingThumbLdrdStrd();
327 Emit32(encoding);
328}
329
330
331void Thumb2Assembler::ldm(BlockAddressMode am,
332 Register base,
333 RegList regs,
334 Condition cond) {
335 if (__builtin_popcount(regs) == 1) {
336 // Thumb doesn't support one reg in the list.
337 // Find the register number.
338 int reg = 0;
339 while (reg < 16) {
340 if ((regs & (1 << reg)) != 0) {
341 break;
342 }
343 ++reg;
344 }
345 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700346 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700347 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
348 } else {
349 EmitMultiMemOp(cond, am, true, base, regs);
350 }
351}
352
353
354void Thumb2Assembler::stm(BlockAddressMode am,
355 Register base,
356 RegList regs,
357 Condition cond) {
358 if (__builtin_popcount(regs) == 1) {
359 // Thumb doesn't support one reg in the list.
360 // Find the register number.
361 int reg = 0;
362 while (reg < 16) {
363 if ((regs & (1 << reg)) != 0) {
364 break;
365 }
366 ++reg;
367 }
368 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700369 CHECK(am == IA || am == IA_W);
370 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700371 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
372 } else {
373 EmitMultiMemOp(cond, am, false, base, regs);
374 }
375}
376
377
378bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
379 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
380 if (((imm32 & ((1 << 19) - 1)) == 0) &&
381 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
382 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
383 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
384 ((imm32 >> 19) & ((1 << 6) -1));
385 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
386 sd, S0, S0);
387 return true;
388 }
389 return false;
390}
391
392
393bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
394 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
395 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
396 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
397 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
398 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
399 ((imm64 >> 48) & ((1 << 6) -1));
400 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
401 dd, D0, D0);
402 return true;
403 }
404 return false;
405}
406
407
408void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
409 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
410}
411
412
413void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
414 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
415}
416
417
418void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
419 Condition cond) {
420 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
421}
422
423
424void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
425 Condition cond) {
426 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
427}
428
429
430void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
431 Condition cond) {
432 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
433}
434
435
436void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
437 Condition cond) {
438 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
439}
440
441
442void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
443 Condition cond) {
444 EmitVFPsss(cond, B21, sd, sn, sm);
445}
446
447
448void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
449 Condition cond) {
450 EmitVFPddd(cond, B21, dd, dn, dm);
451}
452
453
454void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
455 Condition cond) {
456 EmitVFPsss(cond, 0, sd, sn, sm);
457}
458
459
460void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
461 Condition cond) {
462 EmitVFPddd(cond, 0, dd, dn, dm);
463}
464
465
466void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
467 Condition cond) {
468 EmitVFPsss(cond, B6, sd, sn, sm);
469}
470
471
472void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
473 Condition cond) {
474 EmitVFPddd(cond, B6, dd, dn, dm);
475}
476
477
478void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
479 Condition cond) {
480 EmitVFPsss(cond, B23, sd, sn, sm);
481}
482
483
484void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
485 Condition cond) {
486 EmitVFPddd(cond, B23, dd, dn, dm);
487}
488
489
490void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
491 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
492}
493
494
495void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
496 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
497}
498
499
500void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
501 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
502}
503
504
505void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
506 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
507}
508
509
510void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
511 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
512}
513
514void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
515 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
516}
517
518
519void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
520 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
521}
522
523
524void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
525 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
526}
527
528
529void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
530 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
531}
532
533
534void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
535 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
536}
537
538
539void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
540 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
541}
542
543
544void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
545 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
546}
547
548
549void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
550 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
551}
552
553
554void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
555 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
556}
557
558
559void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
560 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
561}
562
563
564void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
565 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
566}
567
568
569void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
570 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
571}
572
573
574void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
575 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
576}
577
578
579void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
580 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
581}
582
583
584void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
585 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
586}
587
588void Thumb2Assembler::b(Label* label, Condition cond) {
589 EmitBranch(cond, label, false, false);
590}
591
592
593void Thumb2Assembler::bl(Label* label, Condition cond) {
594 CheckCondition(cond);
595 EmitBranch(cond, label, true, false);
596}
597
598
599void Thumb2Assembler::blx(Label* label) {
600 EmitBranch(AL, label, true, true);
601}
602
603
604void Thumb2Assembler::MarkExceptionHandler(Label* label) {
605 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
606 Label l;
607 b(&l);
608 EmitBranch(AL, label, false, false);
609 Bind(&l);
610}
611
612
613void Thumb2Assembler::Emit32(int32_t value) {
614 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
615 buffer_.Emit<int16_t>(value >> 16);
616 buffer_.Emit<int16_t>(value & 0xffff);
617}
618
619
620void Thumb2Assembler::Emit16(int16_t value) {
621 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
622 buffer_.Emit<int16_t>(value);
623}
624
625
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700626bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700627 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700628 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700629 Register rn,
630 Register rd,
631 const ShifterOperand& so) {
632 if (force_32bit_) {
633 return true;
634 }
635
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100636 bool can_contain_high_register = (opcode == MOV)
637 || ((opcode == ADD || opcode == SUB) && (rn == rd));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700638
639 if (IsHighRegister(rd) || IsHighRegister(rn)) {
640 if (can_contain_high_register) {
641 // There are high register instructions available for this opcode.
642 // However, there is no RRX available.
643 if (so.IsShift() && so.GetShift() == RRX) {
644 return true;
645 }
646
647 // Check special case for SP relative ADD and SUB immediate.
648 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
649 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
650 if (rn == SP && rd != SP && IsHighRegister(rd)) {
651 return true;
652 }
653
654 uint32_t imm = so.GetImmediate();
655 // If the immediates are out of range use 32 bit.
656 if (rd == SP && rn == SP) {
657 if (imm > (1 << 9)) { // 9 bit immediate.
658 return true;
659 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700660 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
661 if (imm > (1 << 10)) {
662 return true;
663 }
664 } else if (opcode == SUB && rd != SP && rn == SP) {
665 // SUB rd, SP, #imm is always 32 bit.
666 return true;
667 }
668 }
669 }
670
671 // The ADD,SUB and MOV instructions that work with high registers don't have
672 // immediate variants.
673 if (so.IsImmediate()) {
674 return true;
675 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100676
677 if (!can_contain_high_register) {
678 return true;
679 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700680 }
681
682 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
683 return true;
684 }
685
686 // Check for MOV with an ROR.
687 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
688 if (so.GetImmediate() != 0) {
689 return true;
690 }
691 }
692
693 bool rn_is_valid = true;
694
695 // Check for single operand instructions and ADD/SUB.
696 switch (opcode) {
697 case CMP:
698 case MOV:
699 case TST:
700 case MVN:
701 rn_is_valid = false; // There is no Rn for these instructions.
702 break;
703 case TEQ:
704 return true;
705 break;
706 case ADD:
707 case SUB:
708 break;
709 default:
710 if (so.IsRegister() && rd != rn) {
711 return true;
712 }
713 }
714
715 if (so.IsImmediate()) {
716 if (rn_is_valid && rn != rd) {
717 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
718 // immediate must be 3 bits.
719 if (opcode != ADD && opcode != SUB) {
720 return true;
721 } else {
722 // Check that the immediate is 3 bits for ADD and SUB.
723 if (so.GetImmediate() >= 8) {
724 return true;
725 }
726 }
727 } else {
728 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
729 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
730 return true;
731 } else {
732 if (so.GetImmediate() > 255) {
733 return true;
734 }
735 }
736 }
737 }
738
739 // The instruction can be encoded in 16 bits.
740 return false;
741}
742
743
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700744void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700745 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700746 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700747 Register rn,
748 Register rd,
749 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700750 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700751 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700752 case AND: thumb_opcode = 0U /* 0b0000 */; break;
753 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
754 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
755 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
756 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700757 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700758 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700759 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700760 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
761 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
762 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
763 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
764 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
765 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
766 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
767 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700768 default:
769 break;
770 }
771
Andreas Gampec8ccf682014-09-29 20:07:43 -0700772 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700773 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
774 }
775
776 int32_t encoding = 0;
777 if (so.IsImmediate()) {
778 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100779 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700780 if (opcode == SUB) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700781 thumb_opcode = 5U /* 0b0101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700782 } else {
783 thumb_opcode = 0;
784 }
785 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700786
787 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700788 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700789 uint32_t imm8 = imm & 0xff;
790
791 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700792 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100793 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700794 rd << 8 |
795 i << 26 |
796 imm3 << 12 |
797 imm8;
798 } else {
799 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700800 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700801 if (imm == kInvalidModifiedImmediate) {
802 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
803 }
804 encoding = B31 | B30 | B29 | B28 |
805 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700806 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700807 rn << 16 |
808 rd << 8 |
809 imm;
810 }
811 } else if (so.IsRegister()) {
812 // Register (possibly shifted)
813 encoding = B31 | B30 | B29 | B27 | B25 |
814 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700815 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700816 rn << 16 |
817 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700818 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700819 }
820 Emit32(encoding);
821}
822
823
824void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
825 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700826 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700827 Register rn,
828 Register rd,
829 const ShifterOperand& so) {
830 if (opcode == ADD || opcode == SUB) {
831 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
832 return;
833 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700834 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700835 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700836 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700837 uint8_t opcode_shift = 6;
838 uint8_t rd_shift = 0;
839 uint8_t rn_shift = 3;
840 uint8_t immediate_shift = 0;
841 bool use_immediate = false;
842 uint8_t immediate = 0;
843
844 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
845 // Convert shifted mov operand2 into 16 bit opcodes.
846 dp_opcode = 0;
847 opcode_shift = 11;
848
849 use_immediate = true;
850 immediate = so.GetImmediate();
851 immediate_shift = 6;
852
853 rn = so.GetRegister();
854
855 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700856 case LSL: thumb_opcode = 0U /* 0b00 */; break;
857 case LSR: thumb_opcode = 1U /* 0b01 */; break;
858 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700859 case ROR:
860 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700861 thumb_opcode = 7U /* 0b111 */;
862 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700863 opcode_shift = 6;
864 use_immediate = false;
865 break;
866 case RRX: break;
867 default:
868 break;
869 }
870 } else {
871 if (so.IsImmediate()) {
872 use_immediate = true;
873 immediate = so.GetImmediate();
874 }
875
876 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700877 case AND: thumb_opcode = 0U /* 0b0000 */; break;
878 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700879 case SUB: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700880 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700881 case ADD: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700882 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
883 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700884 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700885 case TST: thumb_opcode = 8U /* 0b1000 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700886 case TEQ: break;
887 case CMP:
888 if (use_immediate) {
889 // T2 encoding.
890 dp_opcode = 0;
891 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700892 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700893 rd_shift = 8;
894 rn_shift = 8;
895 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700896 thumb_opcode = 10U /* 0b1010 */;
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100897 rd = rn;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700898 rn = so.GetRegister();
899 }
900
901 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100902 case CMN: {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700903 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100904 rd = rn;
905 rn = so.GetRegister();
906 break;
907 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700908 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700909 case MOV:
910 dp_opcode = 0;
911 if (use_immediate) {
912 // T2 encoding.
913 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700914 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700915 rd_shift = 8;
916 rn_shift = 8;
917 } else {
918 rn = so.GetRegister();
919 if (IsHighRegister(rn) || IsHighRegister(rd)) {
920 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700921 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700922 opcode_shift = 7;
923 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700924 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
925 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700926 } else {
927 thumb_opcode = 0;
928 }
929 }
930 break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700931 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
932 case MVN: thumb_opcode = 15U /* 0b1111 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700933 default:
934 break;
935 }
936 }
937
Andreas Gampec8ccf682014-09-29 20:07:43 -0700938 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700939 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
940 }
941
942 int16_t encoding = dp_opcode << 14 |
943 (thumb_opcode << opcode_shift) |
944 rd << rd_shift |
945 rn << rn_shift |
946 (use_immediate ? (immediate << immediate_shift) : 0);
947
948 Emit16(encoding);
949}
950
951
952// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700953void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700954 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700955 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700956 Register rn,
957 Register rd,
958 const ShifterOperand& so) {
959 uint8_t dp_opcode = 0;
960 uint8_t opcode_shift = 6;
961 uint8_t rd_shift = 0;
962 uint8_t rn_shift = 3;
963 uint8_t immediate_shift = 0;
964 bool use_immediate = false;
965 uint8_t immediate = 0;
966 uint8_t thumb_opcode;;
967
968 if (so.IsImmediate()) {
969 use_immediate = true;
970 immediate = so.GetImmediate();
971 }
972
973 switch (opcode) {
974 case ADD:
975 if (so.IsRegister()) {
976 Register rm = so.GetRegister();
977 if (rn == rd) {
978 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -0700979 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700980 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700981 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700982 // Make Rn also contain the top bit of rd.
983 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -0700984 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
985 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700986 } else {
987 // T1.
988 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700989 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700990 immediate = static_cast<uint32_t>(so.GetRegister());
991 use_immediate = true;
992 immediate_shift = 6;
993 }
994 } else {
995 // Immediate.
996 if (rd == SP && rn == SP) {
997 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -0700998 dp_opcode = 2U /* 0b10 */;
999 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001000 opcode_shift = 12;
1001 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001002 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001003
1004 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1005 rn = R0;
1006 rd = R0;
1007 rd_shift = 0;
1008 rn_shift = 0;
1009 immediate >>= 2;
1010 } else if (rd != SP && rn == SP) {
1011 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001012 dp_opcode = 2U /* 0b10 */;
1013 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001014 opcode_shift = 11;
1015 CHECK_LT(immediate, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001016 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001017
1018 // Remove rn from instruction.
1019 rn = R0;
1020 rn_shift = 0;
1021 rd_shift = 8;
1022 immediate >>= 2;
1023 } else if (rn != rd) {
1024 // Must use T1.
1025 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001026 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001027 immediate_shift = 6;
1028 } else {
1029 // T2 encoding.
1030 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001031 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001032 rd_shift = 8;
1033 rn_shift = 8;
1034 }
1035 }
1036 break;
1037
1038 case SUB:
1039 if (so.IsRegister()) {
1040 // T1.
1041 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001042 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001043 immediate = static_cast<uint32_t>(so.GetRegister());
1044 use_immediate = true;
1045 immediate_shift = 6;
1046 } else {
1047 if (rd == SP && rn == SP) {
1048 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001049 dp_opcode = 2U /* 0b10 */;
1050 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001051 opcode_shift = 7;
1052 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001053 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001054
1055 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1056 rn = R0;
1057 rd = R0;
1058 rd_shift = 0;
1059 rn_shift = 0;
1060 immediate >>= 2;
1061 } else if (rn != rd) {
1062 // Must use T1.
1063 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001064 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001065 immediate_shift = 6;
1066 } else {
1067 // T2 encoding.
1068 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001069 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001070 rd_shift = 8;
1071 rn_shift = 8;
1072 }
1073 }
1074 break;
1075 default:
1076 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
1077 return;
1078 }
1079
1080 int16_t encoding = dp_opcode << 14 |
1081 (thumb_opcode << opcode_shift) |
1082 rd << rd_shift |
1083 rn << rn_shift |
1084 (use_immediate ? (immediate << immediate_shift) : 0);
1085
1086 Emit16(encoding);
1087}
1088
1089
1090void Thumb2Assembler::EmitDataProcessing(Condition cond,
1091 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001092 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001093 Register rn,
1094 Register rd,
1095 const ShifterOperand& so) {
1096 CHECK_NE(rd, kNoRegister);
1097 CheckCondition(cond);
1098
1099 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1100 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1101 } else {
1102 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1103 }
1104}
1105
Dave Allison45fdb932014-06-25 12:37:10 -07001106void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1107 CHECK_LT(amount, (1 << 5));
1108 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1109 uint16_t opcode = 0;
1110 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001111 case LSL: opcode = 0U /* 0b00 */; break;
1112 case LSR: opcode = 1U /* 0b01 */; break;
1113 case ASR: opcode = 2U /* 0b10 */; break;
1114 case ROR: opcode = 3U /* 0b11 */; break;
1115 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001116 default:
1117 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1118 }
1119 // 32 bit.
1120 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1121 0xf << 16 | (setcc ? B20 : 0);
1122 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001123 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001124 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1125 static_cast<int16_t>(rd) << 8 | opcode << 4;
1126 Emit32(encoding);
1127 } else {
1128 // 16 bit shift
1129 uint16_t opcode = 0;
1130 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001131 case LSL: opcode = 0U /* 0b00 */; break;
1132 case LSR: opcode = 1U /* 0b01 */; break;
1133 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001134 default:
1135 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1136 }
1137 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1138 static_cast<int16_t>(rd);
1139 Emit16(encoding);
1140 }
1141}
1142
1143void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1144 CHECK_NE(shift, RRX);
1145 bool must_be_32bit = false;
1146 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1147 must_be_32bit = true;
1148 }
1149
1150 if (must_be_32bit) {
1151 uint16_t opcode = 0;
1152 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001153 case LSL: opcode = 0U /* 0b00 */; break;
1154 case LSR: opcode = 1U /* 0b01 */; break;
1155 case ASR: opcode = 2U /* 0b10 */; break;
1156 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001157 default:
1158 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1159 }
1160 // 32 bit.
1161 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1162 0xf << 12 | (setcc ? B20 : 0);
1163 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1164 static_cast<int16_t>(rd) << 8 | opcode << 21;
1165 Emit32(encoding);
1166 } else {
1167 uint16_t opcode = 0;
1168 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001169 case LSL: opcode = 2U /* 0b0010 */; break;
1170 case LSR: opcode = 3U /* 0b0011 */; break;
1171 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001172 default:
1173 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1174 }
1175 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1176 static_cast<int16_t>(rd);
1177 Emit16(encoding);
1178 }
1179}
1180
1181
Dave Allison65fcc2c2014-04-28 13:45:27 -07001182
1183void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1184 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1185 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1186 int32_t offset = target_ - location_;
1187
1188 if (size_ == k32Bit) {
1189 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1190 if (link) {
1191 // BL or BLX immediate.
1192 encoding |= B14;
1193 if (!x) {
1194 encoding |= B12;
1195 } else {
1196 // Bottom bit of offset must be 0.
1197 CHECK_EQ((offset & 1), 0);
1198 }
1199 } else {
1200 if (x) {
1201 LOG(FATAL) << "Invalid use of BX";
1202 } else {
1203 if (cond_ == AL) {
1204 // Can use the T4 encoding allowing a 24 bit offset.
1205 if (!x) {
1206 encoding |= B12;
1207 }
1208 } else {
1209 // Must be T3 encoding with a 20 bit offset.
1210 encoding |= cond_ << 22;
1211 }
1212 }
1213 }
1214 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1215 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1216 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1217 } else {
1218 if (IsCompareAndBranch()) {
1219 offset -= 4;
1220 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001221 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001222 int16_t encoding = B15 | B13 | B12 |
1223 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1224 static_cast<uint32_t>(rn_) |
1225 B8 |
1226 i << 9 |
1227 imm5 << 3;
1228 buffer->Store<int16_t>(location_, encoding);
1229 } else {
1230 offset -= 4; // Account for PC offset.
1231 int16_t encoding;
1232 // 16 bit.
1233 if (cond_ == AL) {
1234 encoding = B15 | B14 | B13 |
1235 ((offset >> 1) & 0x7ff);
1236 } else {
1237 encoding = B15 | B14 | B12 |
1238 cond_ << 8 | ((offset >> 1) & 0xff);
1239 }
1240 buffer->Store<int16_t>(location_, encoding);
1241 }
1242 }
1243}
1244
1245
1246uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1247 uint32_t location = buffer_.Size();
1248
1249 // This is always unresolved as it must be a forward branch.
1250 Emit16(prev); // Previous link.
1251 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1252 location, rn);
1253}
1254
1255
1256// NOTE: this only support immediate offsets, not [rx,ry].
1257// TODO: support [rx,ry] instructions.
1258void Thumb2Assembler::EmitLoadStore(Condition cond,
1259 bool load,
1260 bool byte,
1261 bool half,
1262 bool is_signed,
1263 Register rd,
1264 const Address& ad) {
1265 CHECK_NE(rd, kNoRegister);
1266 CheckCondition(cond);
1267 bool must_be_32bit = force_32bit_;
1268 if (IsHighRegister(rd)) {
1269 must_be_32bit = true;
1270 }
1271
1272 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001273 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001274 must_be_32bit = true;
1275 }
1276
1277 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1278 must_be_32bit = true;
1279 }
1280
Dave Allison45fdb932014-06-25 12:37:10 -07001281 if (ad.IsImmediate()) {
1282 // Immediate offset
1283 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001284
Dave Allison45fdb932014-06-25 12:37:10 -07001285 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001286 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001287 must_be_32bit = true;
1288 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001289
1290 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001291 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001292 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001293 must_be_32bit = true;
1294 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001295 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001296 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001297 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001298 must_be_32bit = true;
1299 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001300 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001301 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001302 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001303 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001304 }
1305 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001306
Dave Allison45fdb932014-06-25 12:37:10 -07001307 if (must_be_32bit) {
1308 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1309 (load ? B20 : 0) |
1310 (is_signed ? B24 : 0) |
1311 static_cast<uint32_t>(rd) << 12 |
1312 ad.encodingThumb(true) |
1313 (byte ? 0 : half ? B21 : B22);
1314 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001315 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001316 // 16 bit thumb1.
1317 uint8_t opA = 0;
1318 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001319
1320 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001321 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001322 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001323 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001324 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001325 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001326 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001327 sp_relative = true;
1328 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001329 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001330 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001331 }
Dave Allison45fdb932014-06-25 12:37:10 -07001332 int16_t encoding = opA << 12 |
1333 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001334
Dave Allison45fdb932014-06-25 12:37:10 -07001335 CHECK_GE(offset, 0);
1336 if (sp_relative) {
1337 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001338 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001339 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001340 encoding |= rd << 8 | offset >> 2;
1341 } else {
1342 // No SP relative. The offset is shifted right depending on
1343 // the size of the load/store.
1344 encoding |= static_cast<uint32_t>(rd);
1345
1346 if (byte) {
1347 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001348 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001349 } else if (half) {
1350 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001351 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001352 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001353 offset >>= 1;
1354 } else {
1355 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001356 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001357 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001358 offset >>= 2;
1359 }
1360 encoding |= rn << 3 | offset << 6;
1361 }
1362
1363 Emit16(encoding);
1364 }
1365 } else {
1366 // Register shift.
1367 if (ad.GetRegister() == PC) {
1368 // PC relative literal encoding.
1369 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001370 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001371 int32_t up = B23;
1372 if (offset < 0) {
1373 offset = -offset;
1374 up = 0;
1375 }
1376 CHECK_LT(offset, (1 << 12));
1377 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1378 offset | up |
1379 static_cast<uint32_t>(rd) << 12;
1380 Emit32(encoding);
1381 } else {
1382 // 16 bit literal load.
1383 CHECK_GE(offset, 0);
1384 CHECK_LT(offset, (1 << 10));
1385 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1386 Emit16(encoding);
1387 }
1388 } else {
1389 if (ad.GetShiftCount() != 0) {
1390 // If there is a shift count this must be 32 bit.
1391 must_be_32bit = true;
1392 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1393 must_be_32bit = true;
1394 }
1395
1396 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001397 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001398 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001399 if (half) {
1400 encoding |= B21;
1401 } else if (!byte) {
1402 encoding |= B22;
1403 }
Dave Allison45fdb932014-06-25 12:37:10 -07001404 Emit32(encoding);
1405 } else {
1406 // 16 bit register offset.
1407 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1408 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001409 if (byte) {
1410 encoding |= B10;
1411 } else if (half) {
1412 encoding |= B9;
1413 }
Dave Allison45fdb932014-06-25 12:37:10 -07001414 Emit16(encoding);
1415 }
1416 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001417 }
1418}
1419
1420
1421void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001422 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001423 bool load,
1424 Register base,
1425 RegList regs) {
1426 CHECK_NE(base, kNoRegister);
1427 CheckCondition(cond);
1428 bool must_be_32bit = force_32bit_;
1429
1430 if ((regs & 0xff00) != 0) {
1431 must_be_32bit = true;
1432 }
1433
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001434 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001435 // 16 bit always uses writeback.
1436 if (!w_bit) {
1437 must_be_32bit = true;
1438 }
1439
1440 if (must_be_32bit) {
1441 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001442 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001443 case IA:
1444 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001445 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001446 break;
1447 case DB:
1448 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001449 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001450 break;
1451 case DA:
1452 case IB:
1453 case DA_W:
1454 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001455 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001456 }
1457 if (load) {
1458 // Cannot have SP in the list.
1459 CHECK_EQ((regs & (1 << SP)), 0);
1460 } else {
1461 // Cannot have PC or SP in the list.
1462 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1463 }
1464 int32_t encoding = B31 | B30 | B29 | B27 |
1465 (op << 23) |
1466 (load ? B20 : 0) |
1467 base << 16 |
1468 regs |
1469 (w_bit << 21);
1470 Emit32(encoding);
1471 } else {
1472 int16_t encoding = B15 | B14 |
1473 (load ? B11 : 0) |
1474 base << 8 |
1475 regs;
1476 Emit16(encoding);
1477 }
1478}
1479
1480
1481void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1482 uint32_t pc = buffer_.Size();
1483 Branch::Type branch_type;
1484 if (cond == AL) {
1485 if (link) {
1486 if (x) {
1487 branch_type = Branch::kUnconditionalLinkX; // BLX.
1488 } else {
1489 branch_type = Branch::kUnconditionalLink; // BX.
1490 }
1491 } else {
1492 branch_type = Branch::kUnconditional; // B.
1493 }
1494 } else {
1495 branch_type = Branch::kConditional; // B<cond>.
1496 }
1497
1498 if (label->IsBound()) {
1499 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1500
1501 // The branch is to a bound label which means that it's a backwards branch. We know the
1502 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1503 // branch the size may change if it so happens that other branches change size that change
1504 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1505 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001506 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001507 Emit16(0); // Space for a 16 bit branch.
1508 } else {
1509 Emit32(0); // Space for a 32 bit branch.
1510 }
1511 } else {
1512 // Branch is to an unbound label. Emit space for it.
1513 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001514 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001515 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1516 Emit16(0); // another 16 bits.
1517 } else {
1518 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1519 }
1520 label->LinkTo(branch_id); // Link to the branch ID.
1521 }
1522}
1523
1524
1525void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1526 CHECK_NE(rd, kNoRegister);
1527 CHECK_NE(rm, kNoRegister);
1528 CheckCondition(cond);
1529 CHECK_NE(rd, PC);
1530 CHECK_NE(rm, PC);
1531 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1532 B25 | B23 | B21 | B20 |
1533 static_cast<uint32_t>(rm) << 16 |
1534 0xf << 12 |
1535 static_cast<uint32_t>(rd) << 8 |
1536 B7 |
1537 static_cast<uint32_t>(rm);
1538 Emit32(encoding);
1539}
1540
1541
1542void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1543 CheckCondition(cond);
1544 bool must_be_32bit = force_32bit_;
1545 if (IsHighRegister(rd)|| imm16 >= 256u) {
1546 must_be_32bit = true;
1547 }
1548
1549 if (must_be_32bit) {
1550 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001551 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1552 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1553 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001554 uint32_t imm8 = imm16 & 0xff;
1555 int32_t encoding = B31 | B30 | B29 | B28 |
1556 B25 | B22 |
1557 static_cast<uint32_t>(rd) << 8 |
1558 i << 26 |
1559 imm4 << 16 |
1560 imm3 << 12 |
1561 imm8;
1562 Emit32(encoding);
1563 } else {
1564 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1565 imm16;
1566 Emit16(encoding);
1567 }
1568}
1569
1570
1571void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1572 CheckCondition(cond);
1573 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001574 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1575 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1576 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001577 uint32_t imm8 = imm16 & 0xff;
1578 int32_t encoding = B31 | B30 | B29 | B28 |
1579 B25 | B23 | B22 |
1580 static_cast<uint32_t>(rd) << 8 |
1581 i << 26 |
1582 imm4 << 16 |
1583 imm3 << 12 |
1584 imm8;
1585 Emit32(encoding);
1586}
1587
1588
1589void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1590 CHECK_NE(rn, kNoRegister);
1591 CHECK_NE(rt, kNoRegister);
1592 CheckCondition(cond);
1593 CHECK_NE(rn, kNoRegister);
1594 CHECK_NE(rt, kNoRegister);
1595 CheckCondition(cond);
1596 CHECK_LT(imm, (1u << 10));
1597
1598 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1599 static_cast<uint32_t>(rn) << 16 |
1600 static_cast<uint32_t>(rt) << 12 |
1601 0xf << 8 |
1602 imm >> 2;
1603 Emit32(encoding);
1604}
1605
1606
1607void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1608 ldrex(rt, rn, 0, cond);
1609}
1610
1611
1612void Thumb2Assembler::strex(Register rd,
1613 Register rt,
1614 Register rn,
1615 uint16_t imm,
1616 Condition cond) {
1617 CHECK_NE(rn, kNoRegister);
1618 CHECK_NE(rd, kNoRegister);
1619 CHECK_NE(rt, kNoRegister);
1620 CheckCondition(cond);
1621 CHECK_LT(imm, (1u << 10));
1622
1623 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1624 static_cast<uint32_t>(rn) << 16 |
1625 static_cast<uint32_t>(rt) << 12 |
1626 static_cast<uint32_t>(rd) << 8 |
1627 imm >> 2;
1628 Emit32(encoding);
1629}
1630
1631
1632void Thumb2Assembler::strex(Register rd,
1633 Register rt,
1634 Register rn,
1635 Condition cond) {
1636 strex(rd, rt, rn, 0, cond);
1637}
1638
1639
1640void Thumb2Assembler::clrex(Condition cond) {
1641 CheckCondition(cond);
1642 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1643 B21 | B20 |
1644 0xf << 16 |
1645 B15 |
1646 0xf << 8 |
1647 B5 |
1648 0xf;
1649 Emit32(encoding);
1650}
1651
1652
1653void Thumb2Assembler::nop(Condition cond) {
1654 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001655 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001656 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001657 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001658}
1659
1660
1661void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1662 CHECK_NE(sn, kNoSRegister);
1663 CHECK_NE(rt, kNoRegister);
1664 CHECK_NE(rt, SP);
1665 CHECK_NE(rt, PC);
1666 CheckCondition(cond);
1667 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1668 B27 | B26 | B25 |
1669 ((static_cast<int32_t>(sn) >> 1)*B16) |
1670 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1671 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1672 Emit32(encoding);
1673}
1674
1675
1676void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1677 CHECK_NE(sn, kNoSRegister);
1678 CHECK_NE(rt, kNoRegister);
1679 CHECK_NE(rt, SP);
1680 CHECK_NE(rt, PC);
1681 CheckCondition(cond);
1682 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1683 B27 | B26 | B25 | B20 |
1684 ((static_cast<int32_t>(sn) >> 1)*B16) |
1685 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1686 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1687 Emit32(encoding);
1688}
1689
1690
1691void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1692 Condition cond) {
1693 CHECK_NE(sm, kNoSRegister);
1694 CHECK_NE(sm, S31);
1695 CHECK_NE(rt, kNoRegister);
1696 CHECK_NE(rt, SP);
1697 CHECK_NE(rt, PC);
1698 CHECK_NE(rt2, kNoRegister);
1699 CHECK_NE(rt2, SP);
1700 CHECK_NE(rt2, PC);
1701 CheckCondition(cond);
1702 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1703 B27 | B26 | B22 |
1704 (static_cast<int32_t>(rt2)*B16) |
1705 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1706 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1707 (static_cast<int32_t>(sm) >> 1);
1708 Emit32(encoding);
1709}
1710
1711
1712void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1713 Condition cond) {
1714 CHECK_NE(sm, kNoSRegister);
1715 CHECK_NE(sm, S31);
1716 CHECK_NE(rt, kNoRegister);
1717 CHECK_NE(rt, SP);
1718 CHECK_NE(rt, PC);
1719 CHECK_NE(rt2, kNoRegister);
1720 CHECK_NE(rt2, SP);
1721 CHECK_NE(rt2, PC);
1722 CHECK_NE(rt, rt2);
1723 CheckCondition(cond);
1724 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1725 B27 | B26 | B22 | B20 |
1726 (static_cast<int32_t>(rt2)*B16) |
1727 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1728 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1729 (static_cast<int32_t>(sm) >> 1);
1730 Emit32(encoding);
1731}
1732
1733
1734void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1735 Condition cond) {
1736 CHECK_NE(dm, kNoDRegister);
1737 CHECK_NE(rt, kNoRegister);
1738 CHECK_NE(rt, SP);
1739 CHECK_NE(rt, PC);
1740 CHECK_NE(rt2, kNoRegister);
1741 CHECK_NE(rt2, SP);
1742 CHECK_NE(rt2, PC);
1743 CheckCondition(cond);
1744 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1745 B27 | B26 | B22 |
1746 (static_cast<int32_t>(rt2)*B16) |
1747 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1748 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1749 (static_cast<int32_t>(dm) & 0xf);
1750 Emit32(encoding);
1751}
1752
1753
1754void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1755 Condition cond) {
1756 CHECK_NE(dm, kNoDRegister);
1757 CHECK_NE(rt, kNoRegister);
1758 CHECK_NE(rt, SP);
1759 CHECK_NE(rt, PC);
1760 CHECK_NE(rt2, kNoRegister);
1761 CHECK_NE(rt2, SP);
1762 CHECK_NE(rt2, PC);
1763 CHECK_NE(rt, rt2);
1764 CheckCondition(cond);
1765 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1766 B27 | B26 | B22 | B20 |
1767 (static_cast<int32_t>(rt2)*B16) |
1768 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1769 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1770 (static_cast<int32_t>(dm) & 0xf);
1771 Emit32(encoding);
1772}
1773
1774
1775void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1776 const Address& addr = static_cast<const Address&>(ad);
1777 CHECK_NE(sd, kNoSRegister);
1778 CheckCondition(cond);
1779 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1780 B27 | B26 | B24 | B20 |
1781 ((static_cast<int32_t>(sd) & 1)*B22) |
1782 ((static_cast<int32_t>(sd) >> 1)*B12) |
1783 B11 | B9 | addr.vencoding();
1784 Emit32(encoding);
1785}
1786
1787
1788void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1789 const Address& addr = static_cast<const Address&>(ad);
1790 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1791 CHECK_NE(sd, kNoSRegister);
1792 CheckCondition(cond);
1793 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1794 B27 | B26 | B24 |
1795 ((static_cast<int32_t>(sd) & 1)*B22) |
1796 ((static_cast<int32_t>(sd) >> 1)*B12) |
1797 B11 | B9 | addr.vencoding();
1798 Emit32(encoding);
1799}
1800
1801
1802void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1803 const Address& addr = static_cast<const Address&>(ad);
1804 CHECK_NE(dd, kNoDRegister);
1805 CheckCondition(cond);
1806 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1807 B27 | B26 | B24 | B20 |
1808 ((static_cast<int32_t>(dd) >> 4)*B22) |
1809 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1810 B11 | B9 | B8 | addr.vencoding();
1811 Emit32(encoding);
1812}
1813
1814
1815void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1816 const Address& addr = static_cast<const Address&>(ad);
1817 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1818 CHECK_NE(dd, kNoDRegister);
1819 CheckCondition(cond);
1820 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1821 B27 | B26 | B24 |
1822 ((static_cast<int32_t>(dd) >> 4)*B22) |
1823 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1824 B11 | B9 | B8 | addr.vencoding();
1825 Emit32(encoding);
1826}
1827
1828
1829void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1830 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1831}
1832
1833
1834void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1835 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1836}
1837
1838
1839void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1840 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1841}
1842
1843
1844void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1845 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1846}
1847
1848
1849void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1850 CheckCondition(cond);
1851
1852 uint32_t D;
1853 uint32_t Vd;
1854 if (dbl) {
1855 // Encoded as D:Vd.
1856 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001857 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001858 } else {
1859 // Encoded as Vd:D.
1860 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001861 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001862 }
1863 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1864 B11 | B9 |
1865 (dbl ? B8 : 0) |
1866 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001867 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001868 nregs << (dbl ? 1 : 0) |
1869 D << 22 |
1870 Vd << 12;
1871 Emit32(encoding);
1872}
1873
1874
1875void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1876 SRegister sd, SRegister sn, SRegister sm) {
1877 CHECK_NE(sd, kNoSRegister);
1878 CHECK_NE(sn, kNoSRegister);
1879 CHECK_NE(sm, kNoSRegister);
1880 CheckCondition(cond);
1881 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1882 B27 | B26 | B25 | B11 | B9 | opcode |
1883 ((static_cast<int32_t>(sd) & 1)*B22) |
1884 ((static_cast<int32_t>(sn) >> 1)*B16) |
1885 ((static_cast<int32_t>(sd) >> 1)*B12) |
1886 ((static_cast<int32_t>(sn) & 1)*B7) |
1887 ((static_cast<int32_t>(sm) & 1)*B5) |
1888 (static_cast<int32_t>(sm) >> 1);
1889 Emit32(encoding);
1890}
1891
1892
1893void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1894 DRegister dd, DRegister dn, DRegister dm) {
1895 CHECK_NE(dd, kNoDRegister);
1896 CHECK_NE(dn, kNoDRegister);
1897 CHECK_NE(dm, kNoDRegister);
1898 CheckCondition(cond);
1899 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1900 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1901 ((static_cast<int32_t>(dd) >> 4)*B22) |
1902 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1903 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1904 ((static_cast<int32_t>(dn) >> 4)*B7) |
1905 ((static_cast<int32_t>(dm) >> 4)*B5) |
1906 (static_cast<int32_t>(dm) & 0xf);
1907 Emit32(encoding);
1908}
1909
1910
1911void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1912 SRegister sd, DRegister dm) {
1913 CHECK_NE(sd, kNoSRegister);
1914 CHECK_NE(dm, kNoDRegister);
1915 CheckCondition(cond);
1916 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1917 B27 | B26 | B25 | B11 | B9 | opcode |
1918 ((static_cast<int32_t>(sd) & 1)*B22) |
1919 ((static_cast<int32_t>(sd) >> 1)*B12) |
1920 ((static_cast<int32_t>(dm) >> 4)*B5) |
1921 (static_cast<int32_t>(dm) & 0xf);
1922 Emit32(encoding);
1923}
1924
1925
1926void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
1927 DRegister dd, SRegister sm) {
1928 CHECK_NE(dd, kNoDRegister);
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>(dd) >> 4)*B22) |
1934 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1935 ((static_cast<int32_t>(sm) & 1)*B5) |
1936 (static_cast<int32_t>(sm) >> 1);
1937 Emit32(encoding);
1938}
1939
1940
1941void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
1942 CheckCondition(cond);
1943 UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
1944}
1945
1946
1947void Thumb2Assembler::svc(uint32_t imm8) {
1948 CHECK(IsUint(8, imm8)) << imm8;
1949 int16_t encoding = B15 | B14 | B12 |
1950 B11 | B10 | B9 | B8 |
1951 imm8;
1952 Emit16(encoding);
1953}
1954
1955
1956void Thumb2Assembler::bkpt(uint16_t imm8) {
1957 CHECK(IsUint(8, imm8)) << imm8;
1958 int16_t encoding = B15 | B13 | B12 |
1959 B11 | B10 | B9 |
1960 imm8;
1961 Emit16(encoding);
1962}
1963
1964// Convert the given IT state to a mask bit given bit 0 of the first
1965// condition and a shift position.
1966static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
1967 switch (s) {
1968 case kItOmitted: return 1 << shift;
1969 case kItThen: return firstcond0 << shift;
1970 case kItElse: return !firstcond0 << shift;
1971 }
1972 return 0;
1973}
1974
1975
1976// Set the IT condition in the given position for the given state. This is used
1977// to check that conditional instructions match the preceding IT statement.
1978void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
1979 switch (s) {
1980 case kItOmitted: it_conditions_[index] = AL; break;
1981 case kItThen: it_conditions_[index] = cond; break;
1982 case kItElse:
1983 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
1984 break;
1985 }
1986}
1987
1988
1989void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
1990 CheckCondition(AL); // Not allowed in IT block.
1991 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
1992
1993 // All conditions to AL.
1994 for (uint8_t i = 0; i < 4; ++i) {
1995 it_conditions_[i] = AL;
1996 }
1997
1998 SetItCondition(kItThen, firstcond, 0);
1999 uint8_t mask = ToItMask(i1, firstcond0, 3);
2000 SetItCondition(i1, firstcond, 1);
2001
2002 if (i1 != kItOmitted) {
2003 mask |= ToItMask(i2, firstcond0, 2);
2004 SetItCondition(i2, firstcond, 2);
2005 if (i2 != kItOmitted) {
2006 mask |= ToItMask(i3, firstcond0, 1);
2007 SetItCondition(i3, firstcond, 3);
2008 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002009 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002010 }
2011 }
2012 }
2013
2014 // Start at first condition.
2015 it_cond_index_ = 0;
2016 next_condition_ = it_conditions_[0];
2017 uint16_t encoding = B15 | B13 | B12 |
2018 B11 | B10 | B9 | B8 |
2019 firstcond << 4 |
2020 mask;
2021 Emit16(encoding);
2022}
2023
2024
2025void Thumb2Assembler::cbz(Register rn, Label* label) {
2026 CheckCondition(AL);
2027 if (label->IsBound()) {
2028 LOG(FATAL) << "cbz can only be used to branch forwards";
2029 } else {
2030 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2031 label->LinkTo(branchid);
2032 }
2033}
2034
2035
2036void Thumb2Assembler::cbnz(Register rn, Label* label) {
2037 CheckCondition(AL);
2038 if (label->IsBound()) {
2039 LOG(FATAL) << "cbnz can only be used to branch forwards";
2040 } else {
2041 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2042 label->LinkTo(branchid);
2043 }
2044}
2045
2046
2047void Thumb2Assembler::blx(Register rm, Condition cond) {
2048 CHECK_NE(rm, kNoRegister);
2049 CheckCondition(cond);
2050 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2051 Emit16(encoding);
2052}
2053
2054
2055void Thumb2Assembler::bx(Register rm, Condition cond) {
2056 CHECK_NE(rm, kNoRegister);
2057 CheckCondition(cond);
2058 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2059 Emit16(encoding);
2060}
2061
2062
2063void Thumb2Assembler::Push(Register rd, Condition cond) {
2064 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2065}
2066
2067
2068void Thumb2Assembler::Pop(Register rd, Condition cond) {
2069 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2070}
2071
2072
2073void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2074 stm(DB_W, SP, regs, cond);
2075}
2076
2077
2078void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2079 ldm(IA_W, SP, regs, cond);
2080}
2081
2082
2083void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2084 if (cond != AL || rd != rm) {
2085 mov(rd, ShifterOperand(rm), cond);
2086 }
2087}
2088
2089
2090// A branch has changed size. Make a hole for it.
2091void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2092 // Move the contents of the buffer using: Move(newposition, oldposition)
2093 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2094 buffer_.Move(location + delta, location);
2095}
2096
2097
2098void Thumb2Assembler::Bind(Label* label) {
2099 CHECK(!label->IsBound());
2100 uint32_t bound_pc = buffer_.Size();
2101 std::vector<Branch*> changed_branches;
2102
2103 while (label->IsLinked()) {
2104 uint16_t position = label->Position(); // Branch id for linked branch.
2105 Branch* branch = GetBranch(position); // Get the branch at this id.
2106 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2107 uint32_t branch_location = branch->GetLocation();
2108 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2109 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002110 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002111 MakeHoleForBranch(branch->GetLocation(), 2);
2112 if (branch->IsCompareAndBranch()) {
2113 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2114 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2115 // cmp rn, #0
2116 // b<eq|ne> target
2117 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2118 Condition cond = n ? NE : EQ;
2119 branch->Move(2); // Move the branch forward by 2 bytes.
2120 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2121 branch->ResetSize(Branch::k16Bit);
2122
2123 // Now add a compare instruction in the place the branch was.
2124 int16_t cmp = B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8;
2125 buffer_.Store<int16_t>(branch_location, cmp);
2126
2127 // Since have moved made a hole in the code we need to reload the
2128 // current pc.
2129 bound_pc = buffer_.Size();
2130
2131 // Now resolve the newly added branch.
2132 changed = branch->Resolve(bound_pc);
2133 if (changed) {
2134 MakeHoleForBranch(branch->GetLocation(), 2);
2135 changed_branches.push_back(branch);
2136 }
2137 } else {
2138 changed_branches.push_back(branch);
2139 }
2140 }
2141 label->position_ = next; // Move to next.
2142 }
2143 label->BindTo(bound_pc);
2144
2145 // Now relocate any changed branches. Do this until there are no more changes.
2146 std::vector<Branch*> branches_to_process = changed_branches;
2147 while (branches_to_process.size() != 0) {
2148 changed_branches.clear();
2149 for (auto& changed_branch : branches_to_process) {
2150 for (auto& branch : branches_) {
2151 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2152 if (changed) {
2153 changed_branches.push_back(branch);
2154 }
2155 }
2156 branches_to_process = changed_branches;
2157 }
2158 }
2159}
2160
2161
2162void Thumb2Assembler::EmitBranches() {
2163 for (auto& branch : branches_) {
2164 branch->Emit(&buffer_);
2165 }
2166}
2167
2168
2169void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002170 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002171 CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted.
Dave Allison45fdb932014-06-25 12:37:10 -07002172 CheckCondition(cond);
2173 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002174}
2175
2176
2177void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002178 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002179 CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted.
2180 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002181 CheckCondition(cond);
2182 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002183}
2184
2185
2186void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002187 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002188 CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted.
2189 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002190 CheckCondition(cond);
2191 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002192}
2193
2194
2195void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002196 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002197 CHECK_NE(shift_imm, 0u); // Use Rrx instruction.
Dave Allison45fdb932014-06-25 12:37:10 -07002198 CheckCondition(cond);
2199 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002200}
2201
2202
Dave Allison45fdb932014-06-25 12:37:10 -07002203void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2204 CheckCondition(cond);
2205 EmitShift(rd, rm, RRX, rm, setcc);
2206}
2207
2208
2209void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2210 bool setcc, Condition cond) {
2211 CheckCondition(cond);
2212 EmitShift(rd, rm, LSL, rn, setcc);
2213}
2214
2215
2216void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2217 bool setcc, Condition cond) {
2218 CheckCondition(cond);
2219 EmitShift(rd, rm, LSR, rn, setcc);
2220}
2221
2222
2223void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2224 bool setcc, Condition cond) {
2225 CheckCondition(cond);
2226 EmitShift(rd, rm, ASR, rn, setcc);
2227}
2228
2229
2230void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2231 bool setcc, Condition cond) {
2232 CheckCondition(cond);
2233 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002234}
2235
2236
2237int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2238 // The offset is off by 4 due to the way the ARM CPUs read PC.
2239 offset -= 4;
2240 offset >>= 1;
2241
2242 uint32_t value = 0;
2243 // There are two different encodings depending on the value of bit 12. In one case
2244 // intermediate values are calculated using the sign bit.
2245 if ((inst & B12) == B12) {
2246 // 25 bits of offset.
2247 uint32_t signbit = (offset >> 31) & 0x1;
2248 uint32_t i1 = (offset >> 22) & 0x1;
2249 uint32_t i2 = (offset >> 21) & 0x1;
2250 uint32_t imm10 = (offset >> 11) & 0x03ff;
2251 uint32_t imm11 = offset & 0x07ff;
2252 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2253 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2254 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2255 imm11;
2256 // Remove the offset from the current encoding.
2257 inst &= ~(0x3ff << 16 | 0x7ff);
2258 } else {
2259 uint32_t signbit = (offset >> 31) & 0x1;
2260 uint32_t imm6 = (offset >> 11) & 0x03f;
2261 uint32_t imm11 = offset & 0x07ff;
2262 uint32_t j1 = (offset >> 19) & 1;
2263 uint32_t j2 = (offset >> 17) & 1;
2264 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2265 imm11;
2266 // Remove the offset from the current encoding.
2267 inst &= ~(0x3f << 16 | 0x7ff);
2268 }
2269 // Mask out offset bits in current instruction.
2270 inst &= ~(B26 | B13 | B11);
2271 inst |= value;
2272 return inst;
2273}
2274
2275
2276int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2277 int32_t imm32;
2278 if ((instr & B12) == B12) {
2279 uint32_t S = (instr >> 26) & 1;
2280 uint32_t J2 = (instr >> 11) & 1;
2281 uint32_t J1 = (instr >> 13) & 1;
2282 uint32_t imm10 = (instr >> 16) & 0x3FF;
2283 uint32_t imm11 = instr & 0x7FF;
2284
2285 uint32_t I1 = ~(J1 ^ S) & 1;
2286 uint32_t I2 = ~(J2 ^ S) & 1;
2287 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2288 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2289 } else {
2290 uint32_t S = (instr >> 26) & 1;
2291 uint32_t J2 = (instr >> 11) & 1;
2292 uint32_t J1 = (instr >> 13) & 1;
2293 uint32_t imm6 = (instr >> 16) & 0x3F;
2294 uint32_t imm11 = instr & 0x7FF;
2295
2296 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2297 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2298 }
2299 imm32 += 4;
2300 return imm32;
2301}
2302
2303
2304void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2305 AddConstant(rd, rd, value, cond);
2306}
2307
2308
2309void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2310 Condition cond) {
2311 if (value == 0) {
2312 if (rd != rn) {
2313 mov(rd, ShifterOperand(rn), cond);
2314 }
2315 return;
2316 }
2317 // We prefer to select the shorter code sequence rather than selecting add for
2318 // positive values and sub for negatives ones, which would slightly improve
2319 // the readability of generated code for some constants.
2320 ShifterOperand shifter_op;
2321 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2322 add(rd, rn, shifter_op, cond);
2323 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2324 sub(rd, rn, shifter_op, cond);
2325 } else {
2326 CHECK(rn != IP);
2327 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2328 mvn(IP, shifter_op, cond);
2329 add(rd, rn, ShifterOperand(IP), cond);
2330 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2331 mvn(IP, shifter_op, cond);
2332 sub(rd, rn, ShifterOperand(IP), cond);
2333 } else {
2334 movw(IP, Low16Bits(value), cond);
2335 uint16_t value_high = High16Bits(value);
2336 if (value_high != 0) {
2337 movt(IP, value_high, cond);
2338 }
2339 add(rd, rn, ShifterOperand(IP), cond);
2340 }
2341 }
2342}
2343
2344
2345void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2346 Condition cond) {
2347 ShifterOperand shifter_op;
2348 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2349 adds(rd, rn, shifter_op, cond);
2350 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2351 subs(rd, rn, shifter_op, cond);
2352 } else {
2353 CHECK(rn != IP);
2354 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2355 mvn(IP, shifter_op, cond);
2356 adds(rd, rn, ShifterOperand(IP), cond);
2357 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2358 mvn(IP, shifter_op, cond);
2359 subs(rd, rn, ShifterOperand(IP), cond);
2360 } else {
2361 movw(IP, Low16Bits(value), cond);
2362 uint16_t value_high = High16Bits(value);
2363 if (value_high != 0) {
2364 movt(IP, value_high, cond);
2365 }
2366 adds(rd, rn, ShifterOperand(IP), cond);
2367 }
2368 }
2369}
2370
Dave Allison65fcc2c2014-04-28 13:45:27 -07002371void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2372 ShifterOperand shifter_op;
2373 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2374 mov(rd, shifter_op, cond);
2375 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2376 mvn(rd, shifter_op, cond);
2377 } else {
2378 movw(rd, Low16Bits(value), cond);
2379 uint16_t value_high = High16Bits(value);
2380 if (value_high != 0) {
2381 movt(rd, value_high, cond);
2382 }
2383 }
2384}
2385
2386// Implementation note: this method must emit at most one instruction when
2387// Address::CanHoldLoadOffsetThumb.
2388void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2389 Register reg,
2390 Register base,
2391 int32_t offset,
2392 Condition cond) {
2393 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
2394 CHECK(base != IP);
2395 LoadImmediate(IP, offset, cond);
2396 add(IP, IP, ShifterOperand(base), cond);
2397 base = IP;
2398 offset = 0;
2399 }
2400 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2401 switch (type) {
2402 case kLoadSignedByte:
2403 ldrsb(reg, Address(base, offset), cond);
2404 break;
2405 case kLoadUnsignedByte:
2406 ldrb(reg, Address(base, offset), cond);
2407 break;
2408 case kLoadSignedHalfword:
2409 ldrsh(reg, Address(base, offset), cond);
2410 break;
2411 case kLoadUnsignedHalfword:
2412 ldrh(reg, Address(base, offset), cond);
2413 break;
2414 case kLoadWord:
2415 ldr(reg, Address(base, offset), cond);
2416 break;
2417 case kLoadWordPair:
2418 ldrd(reg, Address(base, offset), cond);
2419 break;
2420 default:
2421 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002422 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002423 }
2424}
2425
2426
2427// Implementation note: this method must emit at most one instruction when
2428// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2429void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2430 Register base,
2431 int32_t offset,
2432 Condition cond) {
2433 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2434 CHECK_NE(base, IP);
2435 LoadImmediate(IP, offset, cond);
2436 add(IP, IP, ShifterOperand(base), cond);
2437 base = IP;
2438 offset = 0;
2439 }
2440 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2441 vldrs(reg, Address(base, offset), cond);
2442}
2443
2444
2445// Implementation note: this method must emit at most one instruction when
2446// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2447void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2448 Register base,
2449 int32_t offset,
2450 Condition cond) {
2451 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2452 CHECK_NE(base, IP);
2453 LoadImmediate(IP, offset, cond);
2454 add(IP, IP, ShifterOperand(base), cond);
2455 base = IP;
2456 offset = 0;
2457 }
2458 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2459 vldrd(reg, Address(base, offset), cond);
2460}
2461
2462
2463// Implementation note: this method must emit at most one instruction when
2464// Address::CanHoldStoreOffsetThumb.
2465void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2466 Register reg,
2467 Register base,
2468 int32_t offset,
2469 Condition cond) {
2470 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
2471 CHECK(reg != IP);
2472 CHECK(base != IP);
2473 LoadImmediate(IP, offset, cond);
2474 add(IP, IP, ShifterOperand(base), cond);
2475 base = IP;
2476 offset = 0;
2477 }
2478 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2479 switch (type) {
2480 case kStoreByte:
2481 strb(reg, Address(base, offset), cond);
2482 break;
2483 case kStoreHalfword:
2484 strh(reg, Address(base, offset), cond);
2485 break;
2486 case kStoreWord:
2487 str(reg, Address(base, offset), cond);
2488 break;
2489 case kStoreWordPair:
2490 strd(reg, Address(base, offset), cond);
2491 break;
2492 default:
2493 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002494 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002495 }
2496}
2497
2498
2499// Implementation note: this method must emit at most one instruction when
2500// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2501void Thumb2Assembler::StoreSToOffset(SRegister reg,
2502 Register base,
2503 int32_t offset,
2504 Condition cond) {
2505 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2506 CHECK_NE(base, IP);
2507 LoadImmediate(IP, offset, cond);
2508 add(IP, IP, ShifterOperand(base), cond);
2509 base = IP;
2510 offset = 0;
2511 }
2512 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2513 vstrs(reg, Address(base, offset), cond);
2514}
2515
2516
2517// Implementation note: this method must emit at most one instruction when
2518// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2519void Thumb2Assembler::StoreDToOffset(DRegister reg,
2520 Register base,
2521 int32_t offset,
2522 Condition cond) {
2523 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2524 CHECK_NE(base, IP);
2525 LoadImmediate(IP, offset, cond);
2526 add(IP, IP, ShifterOperand(base), cond);
2527 base = IP;
2528 offset = 0;
2529 }
2530 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2531 vstrd(reg, Address(base, offset), cond);
2532}
2533
2534
2535void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2536 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002537 dmb(SY);
2538}
2539
2540
2541void Thumb2Assembler::dmb(DmbOptions flavor) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002542#if ANDROID_SMP != 0
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002543 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2544 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002545#endif
2546}
2547
2548
2549void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002550 if (force_32bit_branches_) {
2551 cmp(r, ShifterOperand(0));
2552 b(label, EQ);
2553 } else {
2554 cbz(r, label);
2555 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002556}
2557
2558
2559void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002560 if (force_32bit_branches_) {
2561 cmp(r, ShifterOperand(0));
2562 b(label, NE);
2563 } else {
2564 cbnz(r, label);
2565 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002566}
2567} // namespace arm
2568} // namespace art