blob: a309e187df7ae2591684027c894be329df4cb8eb [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
Dave Allison65fcc2c2014-04-28 13:45:27 -0700288void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
289 EmitLoadStore(cond, true, false, false, false, rd, ad);
290}
291
292
293void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
294 EmitLoadStore(cond, false, false, false, false, rd, ad);
295}
296
297
298void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
299 EmitLoadStore(cond, true, true, false, false, rd, ad);
300}
301
302
303void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
304 EmitLoadStore(cond, false, true, false, false, rd, ad);
305}
306
307
308void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
309 EmitLoadStore(cond, true, false, true, false, rd, ad);
310}
311
312
313void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
314 EmitLoadStore(cond, false, false, true, false, rd, ad);
315}
316
317
318void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
319 EmitLoadStore(cond, true, true, false, true, rd, ad);
320}
321
322
323void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
324 EmitLoadStore(cond, true, false, true, true, rd, ad);
325}
326
327
328void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700329 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700330 CHECK_EQ(rd % 2, 0);
331 // This is different from other loads. The encoding is like ARM.
332 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
333 static_cast<int32_t>(rd) << 12 |
334 (static_cast<int32_t>(rd) + 1) << 8 |
335 ad.encodingThumbLdrdStrd();
336 Emit32(encoding);
337}
338
339
340void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700341 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700342 CHECK_EQ(rd % 2, 0);
343 // This is different from other loads. The encoding is like ARM.
344 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
345 static_cast<int32_t>(rd) << 12 |
346 (static_cast<int32_t>(rd) + 1) << 8 |
347 ad.encodingThumbLdrdStrd();
348 Emit32(encoding);
349}
350
351
352void Thumb2Assembler::ldm(BlockAddressMode am,
353 Register base,
354 RegList regs,
355 Condition cond) {
356 if (__builtin_popcount(regs) == 1) {
357 // Thumb doesn't support one reg in the list.
358 // Find the register number.
359 int reg = 0;
360 while (reg < 16) {
361 if ((regs & (1 << reg)) != 0) {
362 break;
363 }
364 ++reg;
365 }
366 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700367 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700368 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
369 } else {
370 EmitMultiMemOp(cond, am, true, base, regs);
371 }
372}
373
374
375void Thumb2Assembler::stm(BlockAddressMode am,
376 Register base,
377 RegList regs,
378 Condition cond) {
379 if (__builtin_popcount(regs) == 1) {
380 // Thumb doesn't support one reg in the list.
381 // Find the register number.
382 int reg = 0;
383 while (reg < 16) {
384 if ((regs & (1 << reg)) != 0) {
385 break;
386 }
387 ++reg;
388 }
389 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700390 CHECK(am == IA || am == IA_W);
391 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700392 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
393 } else {
394 EmitMultiMemOp(cond, am, false, base, regs);
395 }
396}
397
398
399bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
400 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
401 if (((imm32 & ((1 << 19) - 1)) == 0) &&
402 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
403 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
404 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
405 ((imm32 >> 19) & ((1 << 6) -1));
406 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
407 sd, S0, S0);
408 return true;
409 }
410 return false;
411}
412
413
414bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
415 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
416 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
417 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
418 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
419 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
420 ((imm64 >> 48) & ((1 << 6) -1));
421 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
422 dd, D0, D0);
423 return true;
424 }
425 return false;
426}
427
428
429void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
430 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
431}
432
433
434void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
435 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
436}
437
438
439void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
440 Condition cond) {
441 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
442}
443
444
445void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
446 Condition cond) {
447 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
448}
449
450
451void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
452 Condition cond) {
453 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
454}
455
456
457void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
458 Condition cond) {
459 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
460}
461
462
463void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
464 Condition cond) {
465 EmitVFPsss(cond, B21, sd, sn, sm);
466}
467
468
469void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
470 Condition cond) {
471 EmitVFPddd(cond, B21, dd, dn, dm);
472}
473
474
475void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
476 Condition cond) {
477 EmitVFPsss(cond, 0, sd, sn, sm);
478}
479
480
481void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
482 Condition cond) {
483 EmitVFPddd(cond, 0, dd, dn, dm);
484}
485
486
487void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
488 Condition cond) {
489 EmitVFPsss(cond, B6, sd, sn, sm);
490}
491
492
493void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
494 Condition cond) {
495 EmitVFPddd(cond, B6, dd, dn, dm);
496}
497
498
499void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
500 Condition cond) {
501 EmitVFPsss(cond, B23, sd, sn, sm);
502}
503
504
505void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
506 Condition cond) {
507 EmitVFPddd(cond, B23, dd, dn, dm);
508}
509
510
511void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
512 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
513}
514
515
516void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
517 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
518}
519
520
521void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
522 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
523}
524
525
526void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
527 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
528}
529
530
531void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
532 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
533}
534
535void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
536 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
537}
538
539
540void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
541 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
542}
543
544
545void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
546 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
547}
548
549
550void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
551 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
552}
553
554
555void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
556 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
557}
558
559
560void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
561 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
562}
563
564
565void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
566 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
567}
568
569
570void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
571 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
572}
573
574
575void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
576 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
577}
578
579
580void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
581 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
582}
583
584
585void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
586 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
587}
588
589
590void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
591 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
592}
593
594
595void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
596 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
597}
598
599
600void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
601 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
602}
603
604
605void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
606 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
607}
608
609void Thumb2Assembler::b(Label* label, Condition cond) {
610 EmitBranch(cond, label, false, false);
611}
612
613
614void Thumb2Assembler::bl(Label* label, Condition cond) {
615 CheckCondition(cond);
616 EmitBranch(cond, label, true, false);
617}
618
619
620void Thumb2Assembler::blx(Label* label) {
621 EmitBranch(AL, label, true, true);
622}
623
624
625void Thumb2Assembler::MarkExceptionHandler(Label* label) {
626 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
627 Label l;
628 b(&l);
629 EmitBranch(AL, label, false, false);
630 Bind(&l);
631}
632
633
634void Thumb2Assembler::Emit32(int32_t value) {
635 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
636 buffer_.Emit<int16_t>(value >> 16);
637 buffer_.Emit<int16_t>(value & 0xffff);
638}
639
640
641void Thumb2Assembler::Emit16(int16_t value) {
642 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
643 buffer_.Emit<int16_t>(value);
644}
645
646
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700647bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700648 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700649 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700650 Register rn,
651 Register rd,
652 const ShifterOperand& so) {
653 if (force_32bit_) {
654 return true;
655 }
656
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100657 bool can_contain_high_register = (opcode == MOV)
658 || ((opcode == ADD || opcode == SUB) && (rn == rd));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700659
660 if (IsHighRegister(rd) || IsHighRegister(rn)) {
661 if (can_contain_high_register) {
662 // There are high register instructions available for this opcode.
663 // However, there is no RRX available.
664 if (so.IsShift() && so.GetShift() == RRX) {
665 return true;
666 }
667
668 // Check special case for SP relative ADD and SUB immediate.
669 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
670 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
671 if (rn == SP && rd != SP && IsHighRegister(rd)) {
672 return true;
673 }
674
675 uint32_t imm = so.GetImmediate();
676 // If the immediates are out of range use 32 bit.
677 if (rd == SP && rn == SP) {
678 if (imm > (1 << 9)) { // 9 bit immediate.
679 return true;
680 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700681 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
682 if (imm > (1 << 10)) {
683 return true;
684 }
685 } else if (opcode == SUB && rd != SP && rn == SP) {
686 // SUB rd, SP, #imm is always 32 bit.
687 return true;
688 }
689 }
690 }
691
692 // The ADD,SUB and MOV instructions that work with high registers don't have
693 // immediate variants.
694 if (so.IsImmediate()) {
695 return true;
696 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100697
698 if (!can_contain_high_register) {
699 return true;
700 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700701 }
702
703 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
704 return true;
705 }
706
707 // Check for MOV with an ROR.
708 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
709 if (so.GetImmediate() != 0) {
710 return true;
711 }
712 }
713
714 bool rn_is_valid = true;
715
716 // Check for single operand instructions and ADD/SUB.
717 switch (opcode) {
718 case CMP:
719 case MOV:
720 case TST:
721 case MVN:
722 rn_is_valid = false; // There is no Rn for these instructions.
723 break;
724 case TEQ:
725 return true;
726 break;
727 case ADD:
728 case SUB:
729 break;
730 default:
731 if (so.IsRegister() && rd != rn) {
732 return true;
733 }
734 }
735
736 if (so.IsImmediate()) {
737 if (rn_is_valid && rn != rd) {
738 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
739 // immediate must be 3 bits.
740 if (opcode != ADD && opcode != SUB) {
741 return true;
742 } else {
743 // Check that the immediate is 3 bits for ADD and SUB.
744 if (so.GetImmediate() >= 8) {
745 return true;
746 }
747 }
748 } else {
749 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
750 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
751 return true;
752 } else {
753 if (so.GetImmediate() > 255) {
754 return true;
755 }
756 }
757 }
758 }
759
760 // The instruction can be encoded in 16 bits.
761 return false;
762}
763
764
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700765void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700766 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700767 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700768 Register rn,
769 Register rd,
770 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700771 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700772 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700773 case AND: thumb_opcode = 0U /* 0b0000 */; break;
774 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
775 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
776 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
777 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700778 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700779 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700780 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700781 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
782 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
783 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
784 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
785 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
786 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
787 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
788 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700789 default:
790 break;
791 }
792
Andreas Gampec8ccf682014-09-29 20:07:43 -0700793 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700794 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
795 }
796
797 int32_t encoding = 0;
798 if (so.IsImmediate()) {
799 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100800 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700801 if (opcode == SUB) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700802 thumb_opcode = 5U /* 0b0101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700803 } else {
804 thumb_opcode = 0;
805 }
806 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700807
808 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700809 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700810 uint32_t imm8 = imm & 0xff;
811
812 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700813 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100814 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700815 rd << 8 |
816 i << 26 |
817 imm3 << 12 |
818 imm8;
819 } else {
820 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700821 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700822 if (imm == kInvalidModifiedImmediate) {
823 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
824 }
825 encoding = B31 | B30 | B29 | B28 |
826 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700827 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700828 rn << 16 |
829 rd << 8 |
830 imm;
831 }
832 } else if (so.IsRegister()) {
833 // Register (possibly shifted)
834 encoding = B31 | B30 | B29 | B27 | B25 |
835 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700836 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700837 rn << 16 |
838 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700839 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700840 }
841 Emit32(encoding);
842}
843
844
845void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
846 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700847 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700848 Register rn,
849 Register rd,
850 const ShifterOperand& so) {
851 if (opcode == ADD || opcode == SUB) {
852 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
853 return;
854 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700855 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700856 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700857 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700858 uint8_t opcode_shift = 6;
859 uint8_t rd_shift = 0;
860 uint8_t rn_shift = 3;
861 uint8_t immediate_shift = 0;
862 bool use_immediate = false;
863 uint8_t immediate = 0;
864
865 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
866 // Convert shifted mov operand2 into 16 bit opcodes.
867 dp_opcode = 0;
868 opcode_shift = 11;
869
870 use_immediate = true;
871 immediate = so.GetImmediate();
872 immediate_shift = 6;
873
874 rn = so.GetRegister();
875
876 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700877 case LSL: thumb_opcode = 0U /* 0b00 */; break;
878 case LSR: thumb_opcode = 1U /* 0b01 */; break;
879 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700880 case ROR:
881 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700882 thumb_opcode = 7U /* 0b111 */;
883 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700884 opcode_shift = 6;
885 use_immediate = false;
886 break;
887 case RRX: break;
888 default:
889 break;
890 }
891 } else {
892 if (so.IsImmediate()) {
893 use_immediate = true;
894 immediate = so.GetImmediate();
895 }
896
897 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700898 case AND: thumb_opcode = 0U /* 0b0000 */; break;
899 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700900 case SUB: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700901 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700902 case ADD: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700903 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
904 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700905 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700906 case TST: thumb_opcode = 8U /* 0b1000 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700907 case TEQ: break;
908 case CMP:
909 if (use_immediate) {
910 // T2 encoding.
911 dp_opcode = 0;
912 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700913 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700914 rd_shift = 8;
915 rn_shift = 8;
916 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700917 thumb_opcode = 10U /* 0b1010 */;
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100918 rd = rn;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700919 rn = so.GetRegister();
920 }
921
922 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100923 case CMN: {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700924 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100925 rd = rn;
926 rn = so.GetRegister();
927 break;
928 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700929 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700930 case MOV:
931 dp_opcode = 0;
932 if (use_immediate) {
933 // T2 encoding.
934 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700935 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700936 rd_shift = 8;
937 rn_shift = 8;
938 } else {
939 rn = so.GetRegister();
940 if (IsHighRegister(rn) || IsHighRegister(rd)) {
941 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700942 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700943 opcode_shift = 7;
944 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700945 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
946 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700947 } else {
948 thumb_opcode = 0;
949 }
950 }
951 break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700952 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
953 case MVN: thumb_opcode = 15U /* 0b1111 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700954 default:
955 break;
956 }
957 }
958
Andreas Gampec8ccf682014-09-29 20:07:43 -0700959 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700960 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
961 }
962
963 int16_t encoding = dp_opcode << 14 |
964 (thumb_opcode << opcode_shift) |
965 rd << rd_shift |
966 rn << rn_shift |
967 (use_immediate ? (immediate << immediate_shift) : 0);
968
969 Emit16(encoding);
970}
971
972
973// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700974void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700975 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700976 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700977 Register rn,
978 Register rd,
979 const ShifterOperand& so) {
980 uint8_t dp_opcode = 0;
981 uint8_t opcode_shift = 6;
982 uint8_t rd_shift = 0;
983 uint8_t rn_shift = 3;
984 uint8_t immediate_shift = 0;
985 bool use_immediate = false;
986 uint8_t immediate = 0;
987 uint8_t thumb_opcode;;
988
989 if (so.IsImmediate()) {
990 use_immediate = true;
991 immediate = so.GetImmediate();
992 }
993
994 switch (opcode) {
995 case ADD:
996 if (so.IsRegister()) {
997 Register rm = so.GetRegister();
998 if (rn == rd) {
999 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001000 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001001 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001002 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001003 // Make Rn also contain the top bit of rd.
1004 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001005 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1006 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001007 } else {
1008 // T1.
1009 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001010 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001011 immediate = static_cast<uint32_t>(so.GetRegister());
1012 use_immediate = true;
1013 immediate_shift = 6;
1014 }
1015 } else {
1016 // Immediate.
1017 if (rd == SP && rn == SP) {
1018 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001019 dp_opcode = 2U /* 0b10 */;
1020 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001021 opcode_shift = 12;
1022 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001023 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001024
1025 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1026 rn = R0;
1027 rd = R0;
1028 rd_shift = 0;
1029 rn_shift = 0;
1030 immediate >>= 2;
1031 } else if (rd != SP && rn == SP) {
1032 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001033 dp_opcode = 2U /* 0b10 */;
1034 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001035 opcode_shift = 11;
1036 CHECK_LT(immediate, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001037 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001038
1039 // Remove rn from instruction.
1040 rn = R0;
1041 rn_shift = 0;
1042 rd_shift = 8;
1043 immediate >>= 2;
1044 } else if (rn != rd) {
1045 // Must use T1.
1046 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001047 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001048 immediate_shift = 6;
1049 } else {
1050 // T2 encoding.
1051 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001052 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001053 rd_shift = 8;
1054 rn_shift = 8;
1055 }
1056 }
1057 break;
1058
1059 case SUB:
1060 if (so.IsRegister()) {
1061 // T1.
1062 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001063 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001064 immediate = static_cast<uint32_t>(so.GetRegister());
1065 use_immediate = true;
1066 immediate_shift = 6;
1067 } else {
1068 if (rd == SP && rn == SP) {
1069 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001070 dp_opcode = 2U /* 0b10 */;
1071 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001072 opcode_shift = 7;
1073 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001074 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001075
1076 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1077 rn = R0;
1078 rd = R0;
1079 rd_shift = 0;
1080 rn_shift = 0;
1081 immediate >>= 2;
1082 } else if (rn != rd) {
1083 // Must use T1.
1084 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001085 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001086 immediate_shift = 6;
1087 } else {
1088 // T2 encoding.
1089 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001090 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001091 rd_shift = 8;
1092 rn_shift = 8;
1093 }
1094 }
1095 break;
1096 default:
1097 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
1098 return;
1099 }
1100
1101 int16_t encoding = dp_opcode << 14 |
1102 (thumb_opcode << opcode_shift) |
1103 rd << rd_shift |
1104 rn << rn_shift |
1105 (use_immediate ? (immediate << immediate_shift) : 0);
1106
1107 Emit16(encoding);
1108}
1109
1110
1111void Thumb2Assembler::EmitDataProcessing(Condition cond,
1112 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001113 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001114 Register rn,
1115 Register rd,
1116 const ShifterOperand& so) {
1117 CHECK_NE(rd, kNoRegister);
1118 CheckCondition(cond);
1119
1120 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1121 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1122 } else {
1123 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1124 }
1125}
1126
Dave Allison45fdb932014-06-25 12:37:10 -07001127void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1128 CHECK_LT(amount, (1 << 5));
1129 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1130 uint16_t opcode = 0;
1131 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001132 case LSL: opcode = 0U /* 0b00 */; break;
1133 case LSR: opcode = 1U /* 0b01 */; break;
1134 case ASR: opcode = 2U /* 0b10 */; break;
1135 case ROR: opcode = 3U /* 0b11 */; break;
1136 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001137 default:
1138 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1139 }
1140 // 32 bit.
1141 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1142 0xf << 16 | (setcc ? B20 : 0);
1143 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001144 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001145 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1146 static_cast<int16_t>(rd) << 8 | opcode << 4;
1147 Emit32(encoding);
1148 } else {
1149 // 16 bit shift
1150 uint16_t opcode = 0;
1151 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001152 case LSL: opcode = 0U /* 0b00 */; break;
1153 case LSR: opcode = 1U /* 0b01 */; break;
1154 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001155 default:
1156 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1157 }
1158 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1159 static_cast<int16_t>(rd);
1160 Emit16(encoding);
1161 }
1162}
1163
1164void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1165 CHECK_NE(shift, RRX);
1166 bool must_be_32bit = false;
1167 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1168 must_be_32bit = true;
1169 }
1170
1171 if (must_be_32bit) {
1172 uint16_t opcode = 0;
1173 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001174 case LSL: opcode = 0U /* 0b00 */; break;
1175 case LSR: opcode = 1U /* 0b01 */; break;
1176 case ASR: opcode = 2U /* 0b10 */; break;
1177 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001178 default:
1179 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1180 }
1181 // 32 bit.
1182 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1183 0xf << 12 | (setcc ? B20 : 0);
1184 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1185 static_cast<int16_t>(rd) << 8 | opcode << 21;
1186 Emit32(encoding);
1187 } else {
1188 uint16_t opcode = 0;
1189 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001190 case LSL: opcode = 2U /* 0b0010 */; break;
1191 case LSR: opcode = 3U /* 0b0011 */; break;
1192 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001193 default:
1194 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1195 }
1196 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1197 static_cast<int16_t>(rd);
1198 Emit16(encoding);
1199 }
1200}
1201
1202
Dave Allison65fcc2c2014-04-28 13:45:27 -07001203
1204void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1205 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1206 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1207 int32_t offset = target_ - location_;
1208
1209 if (size_ == k32Bit) {
1210 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1211 if (link) {
1212 // BL or BLX immediate.
1213 encoding |= B14;
1214 if (!x) {
1215 encoding |= B12;
1216 } else {
1217 // Bottom bit of offset must be 0.
1218 CHECK_EQ((offset & 1), 0);
1219 }
1220 } else {
1221 if (x) {
1222 LOG(FATAL) << "Invalid use of BX";
1223 } else {
1224 if (cond_ == AL) {
1225 // Can use the T4 encoding allowing a 24 bit offset.
1226 if (!x) {
1227 encoding |= B12;
1228 }
1229 } else {
1230 // Must be T3 encoding with a 20 bit offset.
1231 encoding |= cond_ << 22;
1232 }
1233 }
1234 }
1235 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1236 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1237 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1238 } else {
1239 if (IsCompareAndBranch()) {
1240 offset -= 4;
1241 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001242 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001243 int16_t encoding = B15 | B13 | B12 |
1244 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1245 static_cast<uint32_t>(rn_) |
1246 B8 |
1247 i << 9 |
1248 imm5 << 3;
1249 buffer->Store<int16_t>(location_, encoding);
1250 } else {
1251 offset -= 4; // Account for PC offset.
1252 int16_t encoding;
1253 // 16 bit.
1254 if (cond_ == AL) {
1255 encoding = B15 | B14 | B13 |
1256 ((offset >> 1) & 0x7ff);
1257 } else {
1258 encoding = B15 | B14 | B12 |
1259 cond_ << 8 | ((offset >> 1) & 0xff);
1260 }
1261 buffer->Store<int16_t>(location_, encoding);
1262 }
1263 }
1264}
1265
1266
1267uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1268 uint32_t location = buffer_.Size();
1269
1270 // This is always unresolved as it must be a forward branch.
1271 Emit16(prev); // Previous link.
1272 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1273 location, rn);
1274}
1275
1276
1277// NOTE: this only support immediate offsets, not [rx,ry].
1278// TODO: support [rx,ry] instructions.
1279void Thumb2Assembler::EmitLoadStore(Condition cond,
1280 bool load,
1281 bool byte,
1282 bool half,
1283 bool is_signed,
1284 Register rd,
1285 const Address& ad) {
1286 CHECK_NE(rd, kNoRegister);
1287 CheckCondition(cond);
1288 bool must_be_32bit = force_32bit_;
1289 if (IsHighRegister(rd)) {
1290 must_be_32bit = true;
1291 }
1292
1293 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001294 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001295 must_be_32bit = true;
1296 }
1297
1298 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1299 must_be_32bit = true;
1300 }
1301
Dave Allison45fdb932014-06-25 12:37:10 -07001302 if (ad.IsImmediate()) {
1303 // Immediate offset
1304 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001305
Dave Allison45fdb932014-06-25 12:37:10 -07001306 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001307 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001308 must_be_32bit = true;
1309 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001310
1311 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001312 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001313 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001314 must_be_32bit = true;
1315 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001316 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001317 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001318 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001319 must_be_32bit = true;
1320 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001321 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001322 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001323 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001324 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001325 }
1326 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001327
Dave Allison45fdb932014-06-25 12:37:10 -07001328 if (must_be_32bit) {
1329 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1330 (load ? B20 : 0) |
1331 (is_signed ? B24 : 0) |
1332 static_cast<uint32_t>(rd) << 12 |
1333 ad.encodingThumb(true) |
1334 (byte ? 0 : half ? B21 : B22);
1335 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001336 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001337 // 16 bit thumb1.
1338 uint8_t opA = 0;
1339 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001340
1341 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001342 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001343 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001344 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001345 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001346 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001347 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001348 sp_relative = true;
1349 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001350 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001351 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001352 }
Dave Allison45fdb932014-06-25 12:37:10 -07001353 int16_t encoding = opA << 12 |
1354 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001355
Dave Allison45fdb932014-06-25 12:37:10 -07001356 CHECK_GE(offset, 0);
1357 if (sp_relative) {
1358 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001359 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001360 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001361 encoding |= rd << 8 | offset >> 2;
1362 } else {
1363 // No SP relative. The offset is shifted right depending on
1364 // the size of the load/store.
1365 encoding |= static_cast<uint32_t>(rd);
1366
1367 if (byte) {
1368 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001369 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001370 } else if (half) {
1371 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001372 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001373 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001374 offset >>= 1;
1375 } else {
1376 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001377 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001378 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001379 offset >>= 2;
1380 }
1381 encoding |= rn << 3 | offset << 6;
1382 }
1383
1384 Emit16(encoding);
1385 }
1386 } else {
1387 // Register shift.
1388 if (ad.GetRegister() == PC) {
1389 // PC relative literal encoding.
1390 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001391 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001392 int32_t up = B23;
1393 if (offset < 0) {
1394 offset = -offset;
1395 up = 0;
1396 }
1397 CHECK_LT(offset, (1 << 12));
1398 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1399 offset | up |
1400 static_cast<uint32_t>(rd) << 12;
1401 Emit32(encoding);
1402 } else {
1403 // 16 bit literal load.
1404 CHECK_GE(offset, 0);
1405 CHECK_LT(offset, (1 << 10));
1406 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1407 Emit16(encoding);
1408 }
1409 } else {
1410 if (ad.GetShiftCount() != 0) {
1411 // If there is a shift count this must be 32 bit.
1412 must_be_32bit = true;
1413 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1414 must_be_32bit = true;
1415 }
1416
1417 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001418 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001419 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001420 if (half) {
1421 encoding |= B21;
1422 } else if (!byte) {
1423 encoding |= B22;
1424 }
Dave Allison45fdb932014-06-25 12:37:10 -07001425 Emit32(encoding);
1426 } else {
1427 // 16 bit register offset.
1428 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1429 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001430 if (byte) {
1431 encoding |= B10;
1432 } else if (half) {
1433 encoding |= B9;
1434 }
Dave Allison45fdb932014-06-25 12:37:10 -07001435 Emit16(encoding);
1436 }
1437 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001438 }
1439}
1440
1441
1442void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001443 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001444 bool load,
1445 Register base,
1446 RegList regs) {
1447 CHECK_NE(base, kNoRegister);
1448 CheckCondition(cond);
1449 bool must_be_32bit = force_32bit_;
1450
1451 if ((regs & 0xff00) != 0) {
1452 must_be_32bit = true;
1453 }
1454
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001455 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001456 // 16 bit always uses writeback.
1457 if (!w_bit) {
1458 must_be_32bit = true;
1459 }
1460
1461 if (must_be_32bit) {
1462 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001463 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001464 case IA:
1465 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001466 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001467 break;
1468 case DB:
1469 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001470 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001471 break;
1472 case DA:
1473 case IB:
1474 case DA_W:
1475 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001476 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001477 }
1478 if (load) {
1479 // Cannot have SP in the list.
1480 CHECK_EQ((regs & (1 << SP)), 0);
1481 } else {
1482 // Cannot have PC or SP in the list.
1483 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1484 }
1485 int32_t encoding = B31 | B30 | B29 | B27 |
1486 (op << 23) |
1487 (load ? B20 : 0) |
1488 base << 16 |
1489 regs |
1490 (w_bit << 21);
1491 Emit32(encoding);
1492 } else {
1493 int16_t encoding = B15 | B14 |
1494 (load ? B11 : 0) |
1495 base << 8 |
1496 regs;
1497 Emit16(encoding);
1498 }
1499}
1500
1501
1502void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1503 uint32_t pc = buffer_.Size();
1504 Branch::Type branch_type;
1505 if (cond == AL) {
1506 if (link) {
1507 if (x) {
1508 branch_type = Branch::kUnconditionalLinkX; // BLX.
1509 } else {
1510 branch_type = Branch::kUnconditionalLink; // BX.
1511 }
1512 } else {
1513 branch_type = Branch::kUnconditional; // B.
1514 }
1515 } else {
1516 branch_type = Branch::kConditional; // B<cond>.
1517 }
1518
1519 if (label->IsBound()) {
1520 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1521
1522 // The branch is to a bound label which means that it's a backwards branch. We know the
1523 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1524 // branch the size may change if it so happens that other branches change size that change
1525 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1526 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001527 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001528 Emit16(0); // Space for a 16 bit branch.
1529 } else {
1530 Emit32(0); // Space for a 32 bit branch.
1531 }
1532 } else {
1533 // Branch is to an unbound label. Emit space for it.
1534 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001535 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001536 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1537 Emit16(0); // another 16 bits.
1538 } else {
1539 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1540 }
1541 label->LinkTo(branch_id); // Link to the branch ID.
1542 }
1543}
1544
1545
1546void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1547 CHECK_NE(rd, kNoRegister);
1548 CHECK_NE(rm, kNoRegister);
1549 CheckCondition(cond);
1550 CHECK_NE(rd, PC);
1551 CHECK_NE(rm, PC);
1552 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1553 B25 | B23 | B21 | B20 |
1554 static_cast<uint32_t>(rm) << 16 |
1555 0xf << 12 |
1556 static_cast<uint32_t>(rd) << 8 |
1557 B7 |
1558 static_cast<uint32_t>(rm);
1559 Emit32(encoding);
1560}
1561
1562
1563void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1564 CheckCondition(cond);
1565 bool must_be_32bit = force_32bit_;
1566 if (IsHighRegister(rd)|| imm16 >= 256u) {
1567 must_be_32bit = true;
1568 }
1569
1570 if (must_be_32bit) {
1571 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001572 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1573 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1574 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001575 uint32_t imm8 = imm16 & 0xff;
1576 int32_t encoding = B31 | B30 | B29 | B28 |
1577 B25 | B22 |
1578 static_cast<uint32_t>(rd) << 8 |
1579 i << 26 |
1580 imm4 << 16 |
1581 imm3 << 12 |
1582 imm8;
1583 Emit32(encoding);
1584 } else {
1585 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1586 imm16;
1587 Emit16(encoding);
1588 }
1589}
1590
1591
1592void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1593 CheckCondition(cond);
1594 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001595 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1596 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1597 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001598 uint32_t imm8 = imm16 & 0xff;
1599 int32_t encoding = B31 | B30 | B29 | B28 |
1600 B25 | B23 | B22 |
1601 static_cast<uint32_t>(rd) << 8 |
1602 i << 26 |
1603 imm4 << 16 |
1604 imm3 << 12 |
1605 imm8;
1606 Emit32(encoding);
1607}
1608
1609
1610void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1611 CHECK_NE(rn, kNoRegister);
1612 CHECK_NE(rt, kNoRegister);
1613 CheckCondition(cond);
1614 CHECK_NE(rn, kNoRegister);
1615 CHECK_NE(rt, kNoRegister);
1616 CheckCondition(cond);
1617 CHECK_LT(imm, (1u << 10));
1618
1619 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1620 static_cast<uint32_t>(rn) << 16 |
1621 static_cast<uint32_t>(rt) << 12 |
1622 0xf << 8 |
1623 imm >> 2;
1624 Emit32(encoding);
1625}
1626
1627
1628void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1629 ldrex(rt, rn, 0, cond);
1630}
1631
1632
1633void Thumb2Assembler::strex(Register rd,
1634 Register rt,
1635 Register rn,
1636 uint16_t imm,
1637 Condition cond) {
1638 CHECK_NE(rn, kNoRegister);
1639 CHECK_NE(rd, kNoRegister);
1640 CHECK_NE(rt, kNoRegister);
1641 CheckCondition(cond);
1642 CHECK_LT(imm, (1u << 10));
1643
1644 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1645 static_cast<uint32_t>(rn) << 16 |
1646 static_cast<uint32_t>(rt) << 12 |
1647 static_cast<uint32_t>(rd) << 8 |
1648 imm >> 2;
1649 Emit32(encoding);
1650}
1651
1652
1653void Thumb2Assembler::strex(Register rd,
1654 Register rt,
1655 Register rn,
1656 Condition cond) {
1657 strex(rd, rt, rn, 0, cond);
1658}
1659
1660
1661void Thumb2Assembler::clrex(Condition cond) {
1662 CheckCondition(cond);
1663 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1664 B21 | B20 |
1665 0xf << 16 |
1666 B15 |
1667 0xf << 8 |
1668 B5 |
1669 0xf;
1670 Emit32(encoding);
1671}
1672
1673
1674void Thumb2Assembler::nop(Condition cond) {
1675 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001676 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001677 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001678 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001679}
1680
1681
1682void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1683 CHECK_NE(sn, kNoSRegister);
1684 CHECK_NE(rt, kNoRegister);
1685 CHECK_NE(rt, SP);
1686 CHECK_NE(rt, PC);
1687 CheckCondition(cond);
1688 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1689 B27 | B26 | B25 |
1690 ((static_cast<int32_t>(sn) >> 1)*B16) |
1691 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1692 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1693 Emit32(encoding);
1694}
1695
1696
1697void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1698 CHECK_NE(sn, kNoSRegister);
1699 CHECK_NE(rt, kNoRegister);
1700 CHECK_NE(rt, SP);
1701 CHECK_NE(rt, PC);
1702 CheckCondition(cond);
1703 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1704 B27 | B26 | B25 | B20 |
1705 ((static_cast<int32_t>(sn) >> 1)*B16) |
1706 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1707 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1708 Emit32(encoding);
1709}
1710
1711
1712void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
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 CheckCondition(cond);
1723 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1724 B27 | B26 | B22 |
1725 (static_cast<int32_t>(rt2)*B16) |
1726 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1727 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1728 (static_cast<int32_t>(sm) >> 1);
1729 Emit32(encoding);
1730}
1731
1732
1733void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1734 Condition cond) {
1735 CHECK_NE(sm, kNoSRegister);
1736 CHECK_NE(sm, S31);
1737 CHECK_NE(rt, kNoRegister);
1738 CHECK_NE(rt, SP);
1739 CHECK_NE(rt, PC);
1740 CHECK_NE(rt2, kNoRegister);
1741 CHECK_NE(rt2, SP);
1742 CHECK_NE(rt2, PC);
1743 CHECK_NE(rt, rt2);
1744 CheckCondition(cond);
1745 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1746 B27 | B26 | B22 | B20 |
1747 (static_cast<int32_t>(rt2)*B16) |
1748 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1749 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1750 (static_cast<int32_t>(sm) >> 1);
1751 Emit32(encoding);
1752}
1753
1754
1755void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1756 Condition cond) {
1757 CHECK_NE(dm, kNoDRegister);
1758 CHECK_NE(rt, kNoRegister);
1759 CHECK_NE(rt, SP);
1760 CHECK_NE(rt, PC);
1761 CHECK_NE(rt2, kNoRegister);
1762 CHECK_NE(rt2, SP);
1763 CHECK_NE(rt2, PC);
1764 CheckCondition(cond);
1765 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1766 B27 | B26 | B22 |
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::vmovrrd(Register rt, Register rt2, DRegister dm,
1776 Condition cond) {
1777 CHECK_NE(dm, kNoDRegister);
1778 CHECK_NE(rt, kNoRegister);
1779 CHECK_NE(rt, SP);
1780 CHECK_NE(rt, PC);
1781 CHECK_NE(rt2, kNoRegister);
1782 CHECK_NE(rt2, SP);
1783 CHECK_NE(rt2, PC);
1784 CHECK_NE(rt, rt2);
1785 CheckCondition(cond);
1786 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1787 B27 | B26 | B22 | B20 |
1788 (static_cast<int32_t>(rt2)*B16) |
1789 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1790 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1791 (static_cast<int32_t>(dm) & 0xf);
1792 Emit32(encoding);
1793}
1794
1795
1796void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1797 const Address& addr = static_cast<const Address&>(ad);
1798 CHECK_NE(sd, kNoSRegister);
1799 CheckCondition(cond);
1800 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1801 B27 | B26 | B24 | B20 |
1802 ((static_cast<int32_t>(sd) & 1)*B22) |
1803 ((static_cast<int32_t>(sd) >> 1)*B12) |
1804 B11 | B9 | addr.vencoding();
1805 Emit32(encoding);
1806}
1807
1808
1809void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1810 const Address& addr = static_cast<const Address&>(ad);
1811 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1812 CHECK_NE(sd, kNoSRegister);
1813 CheckCondition(cond);
1814 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1815 B27 | B26 | B24 |
1816 ((static_cast<int32_t>(sd) & 1)*B22) |
1817 ((static_cast<int32_t>(sd) >> 1)*B12) |
1818 B11 | B9 | addr.vencoding();
1819 Emit32(encoding);
1820}
1821
1822
1823void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1824 const Address& addr = static_cast<const Address&>(ad);
1825 CHECK_NE(dd, kNoDRegister);
1826 CheckCondition(cond);
1827 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1828 B27 | B26 | B24 | B20 |
1829 ((static_cast<int32_t>(dd) >> 4)*B22) |
1830 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1831 B11 | B9 | B8 | addr.vencoding();
1832 Emit32(encoding);
1833}
1834
1835
1836void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1837 const Address& addr = static_cast<const Address&>(ad);
1838 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1839 CHECK_NE(dd, kNoDRegister);
1840 CheckCondition(cond);
1841 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1842 B27 | B26 | B24 |
1843 ((static_cast<int32_t>(dd) >> 4)*B22) |
1844 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1845 B11 | B9 | B8 | addr.vencoding();
1846 Emit32(encoding);
1847}
1848
1849
1850void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1851 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1852}
1853
1854
1855void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1856 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1857}
1858
1859
1860void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1861 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1862}
1863
1864
1865void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1866 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1867}
1868
1869
1870void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1871 CheckCondition(cond);
1872
1873 uint32_t D;
1874 uint32_t Vd;
1875 if (dbl) {
1876 // Encoded as D:Vd.
1877 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001878 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001879 } else {
1880 // Encoded as Vd:D.
1881 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001882 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001883 }
1884 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1885 B11 | B9 |
1886 (dbl ? B8 : 0) |
1887 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001888 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001889 nregs << (dbl ? 1 : 0) |
1890 D << 22 |
1891 Vd << 12;
1892 Emit32(encoding);
1893}
1894
1895
1896void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1897 SRegister sd, SRegister sn, SRegister sm) {
1898 CHECK_NE(sd, kNoSRegister);
1899 CHECK_NE(sn, kNoSRegister);
1900 CHECK_NE(sm, kNoSRegister);
1901 CheckCondition(cond);
1902 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1903 B27 | B26 | B25 | B11 | B9 | opcode |
1904 ((static_cast<int32_t>(sd) & 1)*B22) |
1905 ((static_cast<int32_t>(sn) >> 1)*B16) |
1906 ((static_cast<int32_t>(sd) >> 1)*B12) |
1907 ((static_cast<int32_t>(sn) & 1)*B7) |
1908 ((static_cast<int32_t>(sm) & 1)*B5) |
1909 (static_cast<int32_t>(sm) >> 1);
1910 Emit32(encoding);
1911}
1912
1913
1914void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1915 DRegister dd, DRegister dn, DRegister dm) {
1916 CHECK_NE(dd, kNoDRegister);
1917 CHECK_NE(dn, kNoDRegister);
1918 CHECK_NE(dm, kNoDRegister);
1919 CheckCondition(cond);
1920 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1921 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1922 ((static_cast<int32_t>(dd) >> 4)*B22) |
1923 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1924 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1925 ((static_cast<int32_t>(dn) >> 4)*B7) |
1926 ((static_cast<int32_t>(dm) >> 4)*B5) |
1927 (static_cast<int32_t>(dm) & 0xf);
1928 Emit32(encoding);
1929}
1930
1931
1932void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1933 SRegister sd, DRegister dm) {
1934 CHECK_NE(sd, kNoSRegister);
1935 CHECK_NE(dm, kNoDRegister);
1936 CheckCondition(cond);
1937 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1938 B27 | B26 | B25 | B11 | B9 | opcode |
1939 ((static_cast<int32_t>(sd) & 1)*B22) |
1940 ((static_cast<int32_t>(sd) >> 1)*B12) |
1941 ((static_cast<int32_t>(dm) >> 4)*B5) |
1942 (static_cast<int32_t>(dm) & 0xf);
1943 Emit32(encoding);
1944}
1945
1946
1947void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
1948 DRegister dd, SRegister sm) {
1949 CHECK_NE(dd, kNoDRegister);
1950 CHECK_NE(sm, kNoSRegister);
1951 CheckCondition(cond);
1952 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1953 B27 | B26 | B25 | B11 | B9 | opcode |
1954 ((static_cast<int32_t>(dd) >> 4)*B22) |
1955 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1956 ((static_cast<int32_t>(sm) & 1)*B5) |
1957 (static_cast<int32_t>(sm) >> 1);
1958 Emit32(encoding);
1959}
1960
1961
1962void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
1963 CheckCondition(cond);
1964 UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
1965}
1966
1967
1968void Thumb2Assembler::svc(uint32_t imm8) {
1969 CHECK(IsUint(8, imm8)) << imm8;
1970 int16_t encoding = B15 | B14 | B12 |
1971 B11 | B10 | B9 | B8 |
1972 imm8;
1973 Emit16(encoding);
1974}
1975
1976
1977void Thumb2Assembler::bkpt(uint16_t imm8) {
1978 CHECK(IsUint(8, imm8)) << imm8;
1979 int16_t encoding = B15 | B13 | B12 |
1980 B11 | B10 | B9 |
1981 imm8;
1982 Emit16(encoding);
1983}
1984
1985// Convert the given IT state to a mask bit given bit 0 of the first
1986// condition and a shift position.
1987static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
1988 switch (s) {
1989 case kItOmitted: return 1 << shift;
1990 case kItThen: return firstcond0 << shift;
1991 case kItElse: return !firstcond0 << shift;
1992 }
1993 return 0;
1994}
1995
1996
1997// Set the IT condition in the given position for the given state. This is used
1998// to check that conditional instructions match the preceding IT statement.
1999void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2000 switch (s) {
2001 case kItOmitted: it_conditions_[index] = AL; break;
2002 case kItThen: it_conditions_[index] = cond; break;
2003 case kItElse:
2004 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2005 break;
2006 }
2007}
2008
2009
2010void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2011 CheckCondition(AL); // Not allowed in IT block.
2012 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2013
2014 // All conditions to AL.
2015 for (uint8_t i = 0; i < 4; ++i) {
2016 it_conditions_[i] = AL;
2017 }
2018
2019 SetItCondition(kItThen, firstcond, 0);
2020 uint8_t mask = ToItMask(i1, firstcond0, 3);
2021 SetItCondition(i1, firstcond, 1);
2022
2023 if (i1 != kItOmitted) {
2024 mask |= ToItMask(i2, firstcond0, 2);
2025 SetItCondition(i2, firstcond, 2);
2026 if (i2 != kItOmitted) {
2027 mask |= ToItMask(i3, firstcond0, 1);
2028 SetItCondition(i3, firstcond, 3);
2029 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002030 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002031 }
2032 }
2033 }
2034
2035 // Start at first condition.
2036 it_cond_index_ = 0;
2037 next_condition_ = it_conditions_[0];
2038 uint16_t encoding = B15 | B13 | B12 |
2039 B11 | B10 | B9 | B8 |
2040 firstcond << 4 |
2041 mask;
2042 Emit16(encoding);
2043}
2044
2045
2046void Thumb2Assembler::cbz(Register rn, Label* label) {
2047 CheckCondition(AL);
2048 if (label->IsBound()) {
2049 LOG(FATAL) << "cbz can only be used to branch forwards";
2050 } else {
2051 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2052 label->LinkTo(branchid);
2053 }
2054}
2055
2056
2057void Thumb2Assembler::cbnz(Register rn, Label* label) {
2058 CheckCondition(AL);
2059 if (label->IsBound()) {
2060 LOG(FATAL) << "cbnz can only be used to branch forwards";
2061 } else {
2062 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2063 label->LinkTo(branchid);
2064 }
2065}
2066
2067
2068void Thumb2Assembler::blx(Register rm, Condition cond) {
2069 CHECK_NE(rm, kNoRegister);
2070 CheckCondition(cond);
2071 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2072 Emit16(encoding);
2073}
2074
2075
2076void Thumb2Assembler::bx(Register rm, Condition cond) {
2077 CHECK_NE(rm, kNoRegister);
2078 CheckCondition(cond);
2079 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2080 Emit16(encoding);
2081}
2082
2083
2084void Thumb2Assembler::Push(Register rd, Condition cond) {
2085 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2086}
2087
2088
2089void Thumb2Assembler::Pop(Register rd, Condition cond) {
2090 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2091}
2092
2093
2094void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2095 stm(DB_W, SP, regs, cond);
2096}
2097
2098
2099void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2100 ldm(IA_W, SP, regs, cond);
2101}
2102
2103
2104void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2105 if (cond != AL || rd != rm) {
2106 mov(rd, ShifterOperand(rm), cond);
2107 }
2108}
2109
2110
2111// A branch has changed size. Make a hole for it.
2112void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2113 // Move the contents of the buffer using: Move(newposition, oldposition)
2114 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2115 buffer_.Move(location + delta, location);
2116}
2117
2118
2119void Thumb2Assembler::Bind(Label* label) {
2120 CHECK(!label->IsBound());
2121 uint32_t bound_pc = buffer_.Size();
2122 std::vector<Branch*> changed_branches;
2123
2124 while (label->IsLinked()) {
2125 uint16_t position = label->Position(); // Branch id for linked branch.
2126 Branch* branch = GetBranch(position); // Get the branch at this id.
2127 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2128 uint32_t branch_location = branch->GetLocation();
2129 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2130 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002131 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002132 MakeHoleForBranch(branch->GetLocation(), 2);
2133 if (branch->IsCompareAndBranch()) {
2134 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2135 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2136 // cmp rn, #0
2137 // b<eq|ne> target
2138 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2139 Condition cond = n ? NE : EQ;
2140 branch->Move(2); // Move the branch forward by 2 bytes.
2141 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2142 branch->ResetSize(Branch::k16Bit);
2143
2144 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002145 buffer_.Store<int16_t>(branch_location,
2146 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002147
2148 // Since have moved made a hole in the code we need to reload the
2149 // current pc.
2150 bound_pc = buffer_.Size();
2151
2152 // Now resolve the newly added branch.
2153 changed = branch->Resolve(bound_pc);
2154 if (changed) {
2155 MakeHoleForBranch(branch->GetLocation(), 2);
2156 changed_branches.push_back(branch);
2157 }
2158 } else {
2159 changed_branches.push_back(branch);
2160 }
2161 }
2162 label->position_ = next; // Move to next.
2163 }
2164 label->BindTo(bound_pc);
2165
2166 // Now relocate any changed branches. Do this until there are no more changes.
2167 std::vector<Branch*> branches_to_process = changed_branches;
2168 while (branches_to_process.size() != 0) {
2169 changed_branches.clear();
2170 for (auto& changed_branch : branches_to_process) {
2171 for (auto& branch : branches_) {
2172 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2173 if (changed) {
2174 changed_branches.push_back(branch);
2175 }
2176 }
2177 branches_to_process = changed_branches;
2178 }
2179 }
2180}
2181
2182
2183void Thumb2Assembler::EmitBranches() {
2184 for (auto& branch : branches_) {
2185 branch->Emit(&buffer_);
2186 }
2187}
2188
2189
2190void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002191 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002192 CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted.
Dave Allison45fdb932014-06-25 12:37:10 -07002193 CheckCondition(cond);
2194 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002195}
2196
2197
2198void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002199 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002200 CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted.
2201 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002202 CheckCondition(cond);
2203 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002204}
2205
2206
2207void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002208 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002209 CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted.
2210 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002211 CheckCondition(cond);
2212 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002213}
2214
2215
2216void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002217 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002218 CHECK_NE(shift_imm, 0u); // Use Rrx instruction.
Dave Allison45fdb932014-06-25 12:37:10 -07002219 CheckCondition(cond);
2220 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002221}
2222
2223
Dave Allison45fdb932014-06-25 12:37:10 -07002224void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2225 CheckCondition(cond);
2226 EmitShift(rd, rm, RRX, rm, setcc);
2227}
2228
2229
2230void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2231 bool setcc, Condition cond) {
2232 CheckCondition(cond);
2233 EmitShift(rd, rm, LSL, rn, setcc);
2234}
2235
2236
2237void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2238 bool setcc, Condition cond) {
2239 CheckCondition(cond);
2240 EmitShift(rd, rm, LSR, rn, setcc);
2241}
2242
2243
2244void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2245 bool setcc, Condition cond) {
2246 CheckCondition(cond);
2247 EmitShift(rd, rm, ASR, rn, setcc);
2248}
2249
2250
2251void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2252 bool setcc, Condition cond) {
2253 CheckCondition(cond);
2254 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002255}
2256
2257
2258int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2259 // The offset is off by 4 due to the way the ARM CPUs read PC.
2260 offset -= 4;
2261 offset >>= 1;
2262
2263 uint32_t value = 0;
2264 // There are two different encodings depending on the value of bit 12. In one case
2265 // intermediate values are calculated using the sign bit.
2266 if ((inst & B12) == B12) {
2267 // 25 bits of offset.
2268 uint32_t signbit = (offset >> 31) & 0x1;
2269 uint32_t i1 = (offset >> 22) & 0x1;
2270 uint32_t i2 = (offset >> 21) & 0x1;
2271 uint32_t imm10 = (offset >> 11) & 0x03ff;
2272 uint32_t imm11 = offset & 0x07ff;
2273 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2274 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2275 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2276 imm11;
2277 // Remove the offset from the current encoding.
2278 inst &= ~(0x3ff << 16 | 0x7ff);
2279 } else {
2280 uint32_t signbit = (offset >> 31) & 0x1;
2281 uint32_t imm6 = (offset >> 11) & 0x03f;
2282 uint32_t imm11 = offset & 0x07ff;
2283 uint32_t j1 = (offset >> 19) & 1;
2284 uint32_t j2 = (offset >> 17) & 1;
2285 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2286 imm11;
2287 // Remove the offset from the current encoding.
2288 inst &= ~(0x3f << 16 | 0x7ff);
2289 }
2290 // Mask out offset bits in current instruction.
2291 inst &= ~(B26 | B13 | B11);
2292 inst |= value;
2293 return inst;
2294}
2295
2296
2297int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2298 int32_t imm32;
2299 if ((instr & B12) == B12) {
2300 uint32_t S = (instr >> 26) & 1;
2301 uint32_t J2 = (instr >> 11) & 1;
2302 uint32_t J1 = (instr >> 13) & 1;
2303 uint32_t imm10 = (instr >> 16) & 0x3FF;
2304 uint32_t imm11 = instr & 0x7FF;
2305
2306 uint32_t I1 = ~(J1 ^ S) & 1;
2307 uint32_t I2 = ~(J2 ^ S) & 1;
2308 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2309 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2310 } else {
2311 uint32_t S = (instr >> 26) & 1;
2312 uint32_t J2 = (instr >> 11) & 1;
2313 uint32_t J1 = (instr >> 13) & 1;
2314 uint32_t imm6 = (instr >> 16) & 0x3F;
2315 uint32_t imm11 = instr & 0x7FF;
2316
2317 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2318 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2319 }
2320 imm32 += 4;
2321 return imm32;
2322}
2323
2324
2325void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2326 AddConstant(rd, rd, value, cond);
2327}
2328
2329
2330void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2331 Condition cond) {
2332 if (value == 0) {
2333 if (rd != rn) {
2334 mov(rd, ShifterOperand(rn), cond);
2335 }
2336 return;
2337 }
2338 // We prefer to select the shorter code sequence rather than selecting add for
2339 // positive values and sub for negatives ones, which would slightly improve
2340 // the readability of generated code for some constants.
2341 ShifterOperand shifter_op;
2342 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2343 add(rd, rn, shifter_op, cond);
2344 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2345 sub(rd, rn, shifter_op, cond);
2346 } else {
2347 CHECK(rn != IP);
2348 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2349 mvn(IP, shifter_op, cond);
2350 add(rd, rn, ShifterOperand(IP), cond);
2351 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2352 mvn(IP, shifter_op, cond);
2353 sub(rd, rn, ShifterOperand(IP), cond);
2354 } else {
2355 movw(IP, Low16Bits(value), cond);
2356 uint16_t value_high = High16Bits(value);
2357 if (value_high != 0) {
2358 movt(IP, value_high, cond);
2359 }
2360 add(rd, rn, ShifterOperand(IP), cond);
2361 }
2362 }
2363}
2364
2365
2366void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2367 Condition cond) {
2368 ShifterOperand shifter_op;
2369 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2370 adds(rd, rn, shifter_op, cond);
2371 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2372 subs(rd, rn, shifter_op, cond);
2373 } else {
2374 CHECK(rn != IP);
2375 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2376 mvn(IP, shifter_op, cond);
2377 adds(rd, rn, ShifterOperand(IP), cond);
2378 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2379 mvn(IP, shifter_op, cond);
2380 subs(rd, rn, ShifterOperand(IP), cond);
2381 } else {
2382 movw(IP, Low16Bits(value), cond);
2383 uint16_t value_high = High16Bits(value);
2384 if (value_high != 0) {
2385 movt(IP, value_high, cond);
2386 }
2387 adds(rd, rn, ShifterOperand(IP), cond);
2388 }
2389 }
2390}
2391
Dave Allison65fcc2c2014-04-28 13:45:27 -07002392void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2393 ShifterOperand shifter_op;
2394 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2395 mov(rd, shifter_op, cond);
2396 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2397 mvn(rd, shifter_op, cond);
2398 } else {
2399 movw(rd, Low16Bits(value), cond);
2400 uint16_t value_high = High16Bits(value);
2401 if (value_high != 0) {
2402 movt(rd, value_high, cond);
2403 }
2404 }
2405}
2406
2407// Implementation note: this method must emit at most one instruction when
2408// Address::CanHoldLoadOffsetThumb.
2409void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2410 Register reg,
2411 Register base,
2412 int32_t offset,
2413 Condition cond) {
2414 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002415 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002416 LoadImmediate(IP, offset, cond);
2417 add(IP, IP, ShifterOperand(base), cond);
2418 base = IP;
2419 offset = 0;
2420 }
2421 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2422 switch (type) {
2423 case kLoadSignedByte:
2424 ldrsb(reg, Address(base, offset), cond);
2425 break;
2426 case kLoadUnsignedByte:
2427 ldrb(reg, Address(base, offset), cond);
2428 break;
2429 case kLoadSignedHalfword:
2430 ldrsh(reg, Address(base, offset), cond);
2431 break;
2432 case kLoadUnsignedHalfword:
2433 ldrh(reg, Address(base, offset), cond);
2434 break;
2435 case kLoadWord:
2436 ldr(reg, Address(base, offset), cond);
2437 break;
2438 case kLoadWordPair:
2439 ldrd(reg, Address(base, offset), cond);
2440 break;
2441 default:
2442 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002443 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002444 }
2445}
2446
2447
2448// Implementation note: this method must emit at most one instruction when
2449// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2450void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2451 Register base,
2452 int32_t offset,
2453 Condition cond) {
2454 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2455 CHECK_NE(base, IP);
2456 LoadImmediate(IP, offset, cond);
2457 add(IP, IP, ShifterOperand(base), cond);
2458 base = IP;
2459 offset = 0;
2460 }
2461 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2462 vldrs(reg, Address(base, offset), cond);
2463}
2464
2465
2466// Implementation note: this method must emit at most one instruction when
2467// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2468void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2469 Register base,
2470 int32_t offset,
2471 Condition cond) {
2472 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2473 CHECK_NE(base, IP);
2474 LoadImmediate(IP, offset, cond);
2475 add(IP, IP, ShifterOperand(base), cond);
2476 base = IP;
2477 offset = 0;
2478 }
2479 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2480 vldrd(reg, Address(base, offset), cond);
2481}
2482
2483
2484// Implementation note: this method must emit at most one instruction when
2485// Address::CanHoldStoreOffsetThumb.
2486void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2487 Register reg,
2488 Register base,
2489 int32_t offset,
2490 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002491 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002492 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002493 CHECK_NE(base, IP);
2494 if (reg != IP) {
2495 tmp_reg = IP;
2496 } else {
2497 // Be careful not to use IP twice (for `reg` and to build the
2498 // Address object used by the store instruction(s) below).
2499 // Instead, save R5 on the stack (or R6 if R5 is not available),
2500 // use it as secondary temporary register, and restore it after
2501 // the store instruction has been emitted.
2502 tmp_reg = base != R5 ? R5 : R6;
2503 Push(tmp_reg);
2504 if (base == SP) {
2505 offset += kRegisterSize;
2506 }
2507 }
2508 LoadImmediate(tmp_reg, offset, cond);
2509 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2510 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002511 offset = 0;
2512 }
2513 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2514 switch (type) {
2515 case kStoreByte:
2516 strb(reg, Address(base, offset), cond);
2517 break;
2518 case kStoreHalfword:
2519 strh(reg, Address(base, offset), cond);
2520 break;
2521 case kStoreWord:
2522 str(reg, Address(base, offset), cond);
2523 break;
2524 case kStoreWordPair:
2525 strd(reg, Address(base, offset), cond);
2526 break;
2527 default:
2528 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002529 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002530 }
Roland Levillain775ef492014-11-04 17:43:11 +00002531 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2532 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2533 Pop(tmp_reg);
2534 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002535}
2536
2537
2538// Implementation note: this method must emit at most one instruction when
2539// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2540void Thumb2Assembler::StoreSToOffset(SRegister reg,
2541 Register base,
2542 int32_t offset,
2543 Condition cond) {
2544 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2545 CHECK_NE(base, IP);
2546 LoadImmediate(IP, offset, cond);
2547 add(IP, IP, ShifterOperand(base), cond);
2548 base = IP;
2549 offset = 0;
2550 }
2551 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2552 vstrs(reg, Address(base, offset), cond);
2553}
2554
2555
2556// Implementation note: this method must emit at most one instruction when
2557// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2558void Thumb2Assembler::StoreDToOffset(DRegister reg,
2559 Register base,
2560 int32_t offset,
2561 Condition cond) {
2562 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2563 CHECK_NE(base, IP);
2564 LoadImmediate(IP, offset, cond);
2565 add(IP, IP, ShifterOperand(base), cond);
2566 base = IP;
2567 offset = 0;
2568 }
2569 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2570 vstrd(reg, Address(base, offset), cond);
2571}
2572
2573
2574void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2575 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002576 dmb(SY);
2577}
2578
2579
2580void Thumb2Assembler::dmb(DmbOptions flavor) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002581#if ANDROID_SMP != 0
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002582 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2583 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002584#endif
2585}
2586
2587
2588void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002589 if (force_32bit_branches_) {
2590 cmp(r, ShifterOperand(0));
2591 b(label, EQ);
2592 } else {
2593 cbz(r, label);
2594 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002595}
2596
2597
2598void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002599 if (force_32bit_branches_) {
2600 cmp(r, ShifterOperand(0));
2601 b(label, NE);
2602 } else {
2603 cbnz(r, label);
2604 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002605}
2606} // namespace arm
2607} // namespace art