blob: 30aa6254b64d137b4ebb297ec3cc0c50086a2894 [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) {
155 if (rd == rm && !IsHighRegister(rd) && !IsHighRegister(rn) && !force_32bit_) {
156 // 16 bit.
157 int16_t encoding = B14 | B9 | B8 | B6 |
158 rn << 3 | rd;
159 Emit16(encoding);
160 } else {
161 // 32 bit.
162 uint32_t op1 = 0b000;
163 uint32_t op2 = 0b00;
164 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
165 op1 << 20 |
166 B15 | B14 | B13 | B12 |
167 op2 << 4 |
168 static_cast<uint32_t>(rd) << 8 |
169 static_cast<uint32_t>(rn) << 16 |
170 static_cast<uint32_t>(rm);
171
172 Emit32(encoding);
173 }
174}
175
176
177void Thumb2Assembler::mla(Register rd, Register rn, Register rm, Register ra,
178 Condition cond) {
179 uint32_t op1 = 0b000;
180 uint32_t op2 = 0b00;
181 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
182 op1 << 20 |
183 op2 << 4 |
184 static_cast<uint32_t>(rd) << 8 |
185 static_cast<uint32_t>(ra) << 12 |
186 static_cast<uint32_t>(rn) << 16 |
187 static_cast<uint32_t>(rm);
188
189 Emit32(encoding);
190}
191
192
193void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra,
194 Condition cond) {
195 uint32_t op1 = 0b000;
196 uint32_t op2 = 0b01;
197 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
198 op1 << 20 |
199 op2 << 4 |
200 static_cast<uint32_t>(rd) << 8 |
201 static_cast<uint32_t>(ra) << 12 |
202 static_cast<uint32_t>(rn) << 16 |
203 static_cast<uint32_t>(rm);
204
205 Emit32(encoding);
206}
207
208
209void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
210 Register rm, Condition cond) {
211 uint32_t op1 = 0b010;
212 uint32_t op2 = 0b0000;
213 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
214 op1 << 20 |
215 op2 << 4 |
216 static_cast<uint32_t>(rd_lo) << 12 |
217 static_cast<uint32_t>(rd_hi) << 8 |
218 static_cast<uint32_t>(rn) << 16 |
219 static_cast<uint32_t>(rm);
220
221 Emit32(encoding);
222}
223
224
225void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
226 uint32_t op1 = 0b001;
227 uint32_t op2 = 0b1111;
228 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 |
229 op1 << 20 |
230 op2 << 4 |
231 0xf << 12 |
232 static_cast<uint32_t>(rd) << 8 |
233 static_cast<uint32_t>(rn) << 16 |
234 static_cast<uint32_t>(rm);
235
236 Emit32(encoding);
237}
238
239
240void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
241 uint32_t op1 = 0b001;
242 uint32_t op2 = 0b1111;
243 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 |
244 op1 << 20 |
245 op2 << 4 |
246 0xf << 12 |
247 static_cast<uint32_t>(rd) << 8 |
248 static_cast<uint32_t>(rn) << 16 |
249 static_cast<uint32_t>(rm);
250
251 Emit32(encoding);
252}
253
254
255void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
256 EmitLoadStore(cond, true, false, false, false, rd, ad);
257}
258
259
260void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
261 EmitLoadStore(cond, false, false, false, false, rd, ad);
262}
263
264
265void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
266 EmitLoadStore(cond, true, true, false, false, rd, ad);
267}
268
269
270void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
271 EmitLoadStore(cond, false, true, false, false, rd, ad);
272}
273
274
275void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
276 EmitLoadStore(cond, true, false, true, false, rd, ad);
277}
278
279
280void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
281 EmitLoadStore(cond, false, false, true, false, rd, ad);
282}
283
284
285void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
286 EmitLoadStore(cond, true, true, false, true, rd, ad);
287}
288
289
290void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
291 EmitLoadStore(cond, true, false, true, true, rd, ad);
292}
293
294
295void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
296 CHECK_EQ(rd % 2, 0);
297 // This is different from other loads. The encoding is like ARM.
298 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
299 static_cast<int32_t>(rd) << 12 |
300 (static_cast<int32_t>(rd) + 1) << 8 |
301 ad.encodingThumbLdrdStrd();
302 Emit32(encoding);
303}
304
305
306void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
307 CHECK_EQ(rd % 2, 0);
308 // This is different from other loads. The encoding is like ARM.
309 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
310 static_cast<int32_t>(rd) << 12 |
311 (static_cast<int32_t>(rd) + 1) << 8 |
312 ad.encodingThumbLdrdStrd();
313 Emit32(encoding);
314}
315
316
317void Thumb2Assembler::ldm(BlockAddressMode am,
318 Register base,
319 RegList regs,
320 Condition cond) {
321 if (__builtin_popcount(regs) == 1) {
322 // Thumb doesn't support one reg in the list.
323 // Find the register number.
324 int reg = 0;
325 while (reg < 16) {
326 if ((regs & (1 << reg)) != 0) {
327 break;
328 }
329 ++reg;
330 }
331 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700332 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700333 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
334 } else {
335 EmitMultiMemOp(cond, am, true, base, regs);
336 }
337}
338
339
340void Thumb2Assembler::stm(BlockAddressMode am,
341 Register base,
342 RegList regs,
343 Condition cond) {
344 if (__builtin_popcount(regs) == 1) {
345 // Thumb doesn't support one reg in the list.
346 // Find the register number.
347 int reg = 0;
348 while (reg < 16) {
349 if ((regs & (1 << reg)) != 0) {
350 break;
351 }
352 ++reg;
353 }
354 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700355 CHECK(am == IA || am == IA_W);
356 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700357 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
358 } else {
359 EmitMultiMemOp(cond, am, false, base, regs);
360 }
361}
362
363
364bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
365 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
366 if (((imm32 & ((1 << 19) - 1)) == 0) &&
367 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
368 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
369 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
370 ((imm32 >> 19) & ((1 << 6) -1));
371 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
372 sd, S0, S0);
373 return true;
374 }
375 return false;
376}
377
378
379bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
380 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
381 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
382 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
383 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
384 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
385 ((imm64 >> 48) & ((1 << 6) -1));
386 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
387 dd, D0, D0);
388 return true;
389 }
390 return false;
391}
392
393
394void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
395 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
396}
397
398
399void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
400 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
401}
402
403
404void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
405 Condition cond) {
406 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
407}
408
409
410void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
411 Condition cond) {
412 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
413}
414
415
416void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
417 Condition cond) {
418 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
419}
420
421
422void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
423 Condition cond) {
424 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
425}
426
427
428void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
429 Condition cond) {
430 EmitVFPsss(cond, B21, sd, sn, sm);
431}
432
433
434void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
435 Condition cond) {
436 EmitVFPddd(cond, B21, dd, dn, dm);
437}
438
439
440void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
441 Condition cond) {
442 EmitVFPsss(cond, 0, sd, sn, sm);
443}
444
445
446void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
447 Condition cond) {
448 EmitVFPddd(cond, 0, dd, dn, dm);
449}
450
451
452void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
453 Condition cond) {
454 EmitVFPsss(cond, B6, sd, sn, sm);
455}
456
457
458void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
459 Condition cond) {
460 EmitVFPddd(cond, B6, dd, dn, dm);
461}
462
463
464void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
465 Condition cond) {
466 EmitVFPsss(cond, B23, sd, sn, sm);
467}
468
469
470void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
471 Condition cond) {
472 EmitVFPddd(cond, B23, dd, dn, dm);
473}
474
475
476void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
477 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
478}
479
480
481void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
482 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
483}
484
485
486void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
487 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
488}
489
490
491void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
492 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
493}
494
495
496void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
497 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
498}
499
500void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
501 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
502}
503
504
505void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
506 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
507}
508
509
510void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
511 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
512}
513
514
515void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
516 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
517}
518
519
520void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
521 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
522}
523
524
525void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
526 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
527}
528
529
530void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
531 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
532}
533
534
535void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
536 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
537}
538
539
540void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
541 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
542}
543
544
545void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
546 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
547}
548
549
550void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
551 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
552}
553
554
555void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
556 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
557}
558
559
560void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
561 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
562}
563
564
565void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
566 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
567}
568
569
570void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
571 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
572}
573
574void Thumb2Assembler::b(Label* label, Condition cond) {
575 EmitBranch(cond, label, false, false);
576}
577
578
579void Thumb2Assembler::bl(Label* label, Condition cond) {
580 CheckCondition(cond);
581 EmitBranch(cond, label, true, false);
582}
583
584
585void Thumb2Assembler::blx(Label* label) {
586 EmitBranch(AL, label, true, true);
587}
588
589
590void Thumb2Assembler::MarkExceptionHandler(Label* label) {
591 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
592 Label l;
593 b(&l);
594 EmitBranch(AL, label, false, false);
595 Bind(&l);
596}
597
598
599void Thumb2Assembler::Emit32(int32_t value) {
600 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
601 buffer_.Emit<int16_t>(value >> 16);
602 buffer_.Emit<int16_t>(value & 0xffff);
603}
604
605
606void Thumb2Assembler::Emit16(int16_t value) {
607 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
608 buffer_.Emit<int16_t>(value);
609}
610
611
612bool Thumb2Assembler::Is32BitDataProcessing(Condition cond,
613 Opcode opcode,
614 int set_cc,
615 Register rn,
616 Register rd,
617 const ShifterOperand& so) {
618 if (force_32bit_) {
619 return true;
620 }
621
622 bool can_contain_high_register = opcode == MOV || opcode == ADD || opcode == SUB;
623
624 if (IsHighRegister(rd) || IsHighRegister(rn)) {
625 if (can_contain_high_register) {
626 // There are high register instructions available for this opcode.
627 // However, there is no RRX available.
628 if (so.IsShift() && so.GetShift() == RRX) {
629 return true;
630 }
631
632 // Check special case for SP relative ADD and SUB immediate.
633 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
634 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
635 if (rn == SP && rd != SP && IsHighRegister(rd)) {
636 return true;
637 }
638
639 uint32_t imm = so.GetImmediate();
640 // If the immediates are out of range use 32 bit.
641 if (rd == SP && rn == SP) {
642 if (imm > (1 << 9)) { // 9 bit immediate.
643 return true;
644 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700645 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
646 if (imm > (1 << 10)) {
647 return true;
648 }
649 } else if (opcode == SUB && rd != SP && rn == SP) {
650 // SUB rd, SP, #imm is always 32 bit.
651 return true;
652 }
653 }
654 }
655
656 // The ADD,SUB and MOV instructions that work with high registers don't have
657 // immediate variants.
658 if (so.IsImmediate()) {
659 return true;
660 }
661 }
662
663 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
664 return true;
665 }
666
667 // Check for MOV with an ROR.
668 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
669 if (so.GetImmediate() != 0) {
670 return true;
671 }
672 }
673
674 bool rn_is_valid = true;
675
676 // Check for single operand instructions and ADD/SUB.
677 switch (opcode) {
678 case CMP:
679 case MOV:
680 case TST:
681 case MVN:
682 rn_is_valid = false; // There is no Rn for these instructions.
683 break;
684 case TEQ:
685 return true;
686 break;
687 case ADD:
688 case SUB:
689 break;
690 default:
691 if (so.IsRegister() && rd != rn) {
692 return true;
693 }
694 }
695
696 if (so.IsImmediate()) {
697 if (rn_is_valid && rn != rd) {
698 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
699 // immediate must be 3 bits.
700 if (opcode != ADD && opcode != SUB) {
701 return true;
702 } else {
703 // Check that the immediate is 3 bits for ADD and SUB.
704 if (so.GetImmediate() >= 8) {
705 return true;
706 }
707 }
708 } else {
709 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
710 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
711 return true;
712 } else {
713 if (so.GetImmediate() > 255) {
714 return true;
715 }
716 }
717 }
718 }
719
720 // The instruction can be encoded in 16 bits.
721 return false;
722}
723
724
725void Thumb2Assembler::Emit32BitDataProcessing(Condition cond,
726 Opcode opcode,
727 int set_cc,
728 Register rn,
729 Register rd,
730 const ShifterOperand& so) {
731 uint8_t thumb_opcode = 0b11111111;
732 switch (opcode) {
733 case AND: thumb_opcode = 0b0000; break;
734 case EOR: thumb_opcode = 0b0100; break;
735 case SUB: thumb_opcode = 0b1101; break;
736 case RSB: thumb_opcode = 0b1110; break;
737 case ADD: thumb_opcode = 0b1000; break;
738 case ADC: thumb_opcode = 0b1010; break;
739 case SBC: thumb_opcode = 0b1011; break;
740 case RSC: break;
741 case TST: thumb_opcode = 0b0000; set_cc = true; rd = PC; break;
742 case TEQ: thumb_opcode = 0b0100; set_cc = true; rd = PC; break;
743 case CMP: thumb_opcode = 0b1101; set_cc = true; rd = PC; break;
744 case CMN: thumb_opcode = 0b1000; set_cc = true; rd = PC; break;
745 case ORR: thumb_opcode = 0b0010; break;
746 case MOV: thumb_opcode = 0b0010; rn = PC; break;
747 case BIC: thumb_opcode = 0b0001; break;
748 case MVN: thumb_opcode = 0b0011; rn = PC; break;
749 default:
750 break;
751 }
752
753 if (thumb_opcode == 0b11111111) {
754 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
755 }
756
757 int32_t encoding = 0;
758 if (so.IsImmediate()) {
759 // Check special cases.
760 if ((opcode == SUB || opcode == ADD) && rn == SP) {
761 // There are special ADD/SUB rd, SP, #imm12 instructions.
762 if (opcode == SUB) {
763 thumb_opcode = 0b0101;
764 } else {
765 thumb_opcode = 0;
766 }
767 uint32_t imm = so.GetImmediate();
768 CHECK_LT(imm, (1u << 12));
769
770 uint32_t i = (imm >> 11) & 1;
771 uint32_t imm3 = (imm >> 8) & 0b111;
772 uint32_t imm8 = imm & 0xff;
773
774 encoding = B31 | B30 | B29 | B28 | B25 |
775 B19 | B18 | B16 |
776 thumb_opcode << 21 |
777 rd << 8 |
778 i << 26 |
779 imm3 << 12 |
780 imm8;
781 } else {
782 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700783 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700784 if (imm == kInvalidModifiedImmediate) {
785 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
786 }
787 encoding = B31 | B30 | B29 | B28 |
788 thumb_opcode << 21 |
789 set_cc << 20 |
790 rn << 16 |
791 rd << 8 |
792 imm;
793 }
794 } else if (so.IsRegister()) {
795 // Register (possibly shifted)
796 encoding = B31 | B30 | B29 | B27 | B25 |
797 thumb_opcode << 21 |
798 set_cc << 20 |
799 rn << 16 |
800 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700801 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700802 }
803 Emit32(encoding);
804}
805
806
807void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
808 Opcode opcode,
809 int set_cc,
810 Register rn,
811 Register rd,
812 const ShifterOperand& so) {
813 if (opcode == ADD || opcode == SUB) {
814 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
815 return;
816 }
817 uint8_t thumb_opcode = 0b11111111;
818 // Thumb1.
819 uint8_t dp_opcode = 0b01;
820 uint8_t opcode_shift = 6;
821 uint8_t rd_shift = 0;
822 uint8_t rn_shift = 3;
823 uint8_t immediate_shift = 0;
824 bool use_immediate = false;
825 uint8_t immediate = 0;
826
827 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
828 // Convert shifted mov operand2 into 16 bit opcodes.
829 dp_opcode = 0;
830 opcode_shift = 11;
831
832 use_immediate = true;
833 immediate = so.GetImmediate();
834 immediate_shift = 6;
835
836 rn = so.GetRegister();
837
838 switch (so.GetShift()) {
839 case LSL: thumb_opcode = 0b00; break;
840 case LSR: thumb_opcode = 0b01; break;
841 case ASR: thumb_opcode = 0b10; break;
842 case ROR:
843 // ROR doesn't allow immediates.
844 thumb_opcode = 0b111;
845 dp_opcode = 0b01;
846 opcode_shift = 6;
847 use_immediate = false;
848 break;
849 case RRX: break;
850 default:
851 break;
852 }
853 } else {
854 if (so.IsImmediate()) {
855 use_immediate = true;
856 immediate = so.GetImmediate();
857 }
858
859 switch (opcode) {
860 case AND: thumb_opcode = 0b0000; break;
861 case EOR: thumb_opcode = 0b0001; break;
862 case SUB: break;
863 case RSB: thumb_opcode = 0b1001; break;
864 case ADD: break;
865 case ADC: thumb_opcode = 0b0101; break;
866 case SBC: thumb_opcode = 0b0110; break;
867 case RSC: break;
868 case TST: thumb_opcode = 0b1000; rn = so.GetRegister(); break;
869 case TEQ: break;
870 case CMP:
871 if (use_immediate) {
872 // T2 encoding.
873 dp_opcode = 0;
874 opcode_shift = 11;
875 thumb_opcode = 0b101;
876 rd_shift = 8;
877 rn_shift = 8;
878 } else {
879 thumb_opcode = 0b1010;
880 rn = so.GetRegister();
881 }
882
883 break;
884 case CMN: thumb_opcode = 0b1011; rn = so.GetRegister(); break;
885 case ORR: thumb_opcode = 0b1100; break;
886 case MOV:
887 dp_opcode = 0;
888 if (use_immediate) {
889 // T2 encoding.
890 opcode_shift = 11;
891 thumb_opcode = 0b100;
892 rd_shift = 8;
893 rn_shift = 8;
894 } else {
895 rn = so.GetRegister();
896 if (IsHighRegister(rn) || IsHighRegister(rd)) {
897 // Special mov for high registers.
898 dp_opcode = 0b01;
899 opcode_shift = 7;
900 // Put the top bit of rd into the bottom bit of the opcode.
901 thumb_opcode = 0b0001100 | static_cast<uint32_t>(rd) >> 3;
902 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 0b111);
903 } else {
904 thumb_opcode = 0;
905 }
906 }
907 break;
908 case BIC: thumb_opcode = 0b1110; break;
909 case MVN: thumb_opcode = 0b1111; rn = so.GetRegister(); break;
910 default:
911 break;
912 }
913 }
914
915 if (thumb_opcode == 0b11111111) {
916 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
917 }
918
919 int16_t encoding = dp_opcode << 14 |
920 (thumb_opcode << opcode_shift) |
921 rd << rd_shift |
922 rn << rn_shift |
923 (use_immediate ? (immediate << immediate_shift) : 0);
924
925 Emit16(encoding);
926}
927
928
929// ADD and SUB are complex enough to warrant their own emitter.
930void Thumb2Assembler::Emit16BitAddSub(Condition cond,
931 Opcode opcode,
932 int set_cc,
933 Register rn,
934 Register rd,
935 const ShifterOperand& so) {
936 uint8_t dp_opcode = 0;
937 uint8_t opcode_shift = 6;
938 uint8_t rd_shift = 0;
939 uint8_t rn_shift = 3;
940 uint8_t immediate_shift = 0;
941 bool use_immediate = false;
942 uint8_t immediate = 0;
943 uint8_t thumb_opcode;;
944
945 if (so.IsImmediate()) {
946 use_immediate = true;
947 immediate = so.GetImmediate();
948 }
949
950 switch (opcode) {
951 case ADD:
952 if (so.IsRegister()) {
953 Register rm = so.GetRegister();
954 if (rn == rd) {
955 // Can use T2 encoding (allows 4 bit registers)
956 dp_opcode = 0b01;
957 opcode_shift = 10;
958 thumb_opcode = 0b0001;
959 // Make Rn also contain the top bit of rd.
960 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
961 (static_cast<uint32_t>(rd) & 0b1000) << 1);
962 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 0b111);
963 } else {
964 // T1.
965 opcode_shift = 9;
966 thumb_opcode = 0b01100;
967 immediate = static_cast<uint32_t>(so.GetRegister());
968 use_immediate = true;
969 immediate_shift = 6;
970 }
971 } else {
972 // Immediate.
973 if (rd == SP && rn == SP) {
974 // ADD sp, sp, #imm
975 dp_opcode = 0b10;
976 thumb_opcode = 0b11;
977 opcode_shift = 12;
978 CHECK_LT(immediate, (1 << 9));
979 CHECK_EQ((immediate & 0b11), 0);
980
981 // Remove rd and rn from instruction by orring it with immed and clearing bits.
982 rn = R0;
983 rd = R0;
984 rd_shift = 0;
985 rn_shift = 0;
986 immediate >>= 2;
987 } else if (rd != SP && rn == SP) {
988 // ADD rd, SP, #imm
989 dp_opcode = 0b10;
990 thumb_opcode = 0b101;
991 opcode_shift = 11;
992 CHECK_LT(immediate, (1 << 10));
993 CHECK_EQ((immediate & 0b11), 0);
994
995 // Remove rn from instruction.
996 rn = R0;
997 rn_shift = 0;
998 rd_shift = 8;
999 immediate >>= 2;
1000 } else if (rn != rd) {
1001 // Must use T1.
1002 opcode_shift = 9;
1003 thumb_opcode = 0b01110;
1004 immediate_shift = 6;
1005 } else {
1006 // T2 encoding.
1007 opcode_shift = 11;
1008 thumb_opcode = 0b110;
1009 rd_shift = 8;
1010 rn_shift = 8;
1011 }
1012 }
1013 break;
1014
1015 case SUB:
1016 if (so.IsRegister()) {
1017 // T1.
1018 opcode_shift = 9;
1019 thumb_opcode = 0b01101;
1020 immediate = static_cast<uint32_t>(so.GetRegister());
1021 use_immediate = true;
1022 immediate_shift = 6;
1023 } else {
1024 if (rd == SP && rn == SP) {
1025 // SUB sp, sp, #imm
1026 dp_opcode = 0b10;
1027 thumb_opcode = 0b1100001;
1028 opcode_shift = 7;
1029 CHECK_LT(immediate, (1 << 9));
1030 CHECK_EQ((immediate & 0b11), 0);
1031
1032 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1033 rn = R0;
1034 rd = R0;
1035 rd_shift = 0;
1036 rn_shift = 0;
1037 immediate >>= 2;
1038 } else if (rn != rd) {
1039 // Must use T1.
1040 opcode_shift = 9;
1041 thumb_opcode = 0b01111;
1042 immediate_shift = 6;
1043 } else {
1044 // T2 encoding.
1045 opcode_shift = 11;
1046 thumb_opcode = 0b111;
1047 rd_shift = 8;
1048 rn_shift = 8;
1049 }
1050 }
1051 break;
1052 default:
1053 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
1054 return;
1055 }
1056
1057 int16_t encoding = dp_opcode << 14 |
1058 (thumb_opcode << opcode_shift) |
1059 rd << rd_shift |
1060 rn << rn_shift |
1061 (use_immediate ? (immediate << immediate_shift) : 0);
1062
1063 Emit16(encoding);
1064}
1065
1066
1067void Thumb2Assembler::EmitDataProcessing(Condition cond,
1068 Opcode opcode,
1069 int set_cc,
1070 Register rn,
1071 Register rd,
1072 const ShifterOperand& so) {
1073 CHECK_NE(rd, kNoRegister);
1074 CheckCondition(cond);
1075
1076 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1077 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1078 } else {
1079 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1080 }
1081}
1082
Dave Allison45fdb932014-06-25 12:37:10 -07001083void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1084 CHECK_LT(amount, (1 << 5));
1085 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1086 uint16_t opcode = 0;
1087 switch (shift) {
1088 case LSL: opcode = 0b00; break;
1089 case LSR: opcode = 0b01; break;
1090 case ASR: opcode = 0b10; break;
1091 case ROR: opcode = 0b11; break;
1092 case RRX: opcode = 0b11; amount = 0; break;
1093 default:
1094 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1095 }
1096 // 32 bit.
1097 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1098 0xf << 16 | (setcc ? B20 : 0);
1099 uint32_t imm3 = amount >> 2;
1100 uint32_t imm2 = amount & 0b11;
1101 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1102 static_cast<int16_t>(rd) << 8 | opcode << 4;
1103 Emit32(encoding);
1104 } else {
1105 // 16 bit shift
1106 uint16_t opcode = 0;
1107 switch (shift) {
1108 case LSL: opcode = 0b00; break;
1109 case LSR: opcode = 0b01; break;
1110 case ASR: opcode = 0b10; break;
1111 default:
1112 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1113 }
1114 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1115 static_cast<int16_t>(rd);
1116 Emit16(encoding);
1117 }
1118}
1119
1120void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1121 CHECK_NE(shift, RRX);
1122 bool must_be_32bit = false;
1123 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1124 must_be_32bit = true;
1125 }
1126
1127 if (must_be_32bit) {
1128 uint16_t opcode = 0;
1129 switch (shift) {
1130 case LSL: opcode = 0b00; break;
1131 case LSR: opcode = 0b01; break;
1132 case ASR: opcode = 0b10; break;
1133 case ROR: opcode = 0b11; break;
1134 default:
1135 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1136 }
1137 // 32 bit.
1138 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1139 0xf << 12 | (setcc ? B20 : 0);
1140 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1141 static_cast<int16_t>(rd) << 8 | opcode << 21;
1142 Emit32(encoding);
1143 } else {
1144 uint16_t opcode = 0;
1145 switch (shift) {
1146 case LSL: opcode = 0b0010; break;
1147 case LSR: opcode = 0b0011; break;
1148 case ASR: opcode = 0b0100; break;
1149 default:
1150 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1151 }
1152 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1153 static_cast<int16_t>(rd);
1154 Emit16(encoding);
1155 }
1156}
1157
1158
Dave Allison65fcc2c2014-04-28 13:45:27 -07001159
1160void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1161 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1162 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1163 int32_t offset = target_ - location_;
1164
1165 if (size_ == k32Bit) {
1166 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1167 if (link) {
1168 // BL or BLX immediate.
1169 encoding |= B14;
1170 if (!x) {
1171 encoding |= B12;
1172 } else {
1173 // Bottom bit of offset must be 0.
1174 CHECK_EQ((offset & 1), 0);
1175 }
1176 } else {
1177 if (x) {
1178 LOG(FATAL) << "Invalid use of BX";
1179 } else {
1180 if (cond_ == AL) {
1181 // Can use the T4 encoding allowing a 24 bit offset.
1182 if (!x) {
1183 encoding |= B12;
1184 }
1185 } else {
1186 // Must be T3 encoding with a 20 bit offset.
1187 encoding |= cond_ << 22;
1188 }
1189 }
1190 }
1191 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1192 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1193 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1194 } else {
1195 if (IsCompareAndBranch()) {
1196 offset -= 4;
1197 uint16_t i = (offset >> 6) & 1;
1198 uint16_t imm5 = (offset >> 1) & 0b11111;
1199 int16_t encoding = B15 | B13 | B12 |
1200 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1201 static_cast<uint32_t>(rn_) |
1202 B8 |
1203 i << 9 |
1204 imm5 << 3;
1205 buffer->Store<int16_t>(location_, encoding);
1206 } else {
1207 offset -= 4; // Account for PC offset.
1208 int16_t encoding;
1209 // 16 bit.
1210 if (cond_ == AL) {
1211 encoding = B15 | B14 | B13 |
1212 ((offset >> 1) & 0x7ff);
1213 } else {
1214 encoding = B15 | B14 | B12 |
1215 cond_ << 8 | ((offset >> 1) & 0xff);
1216 }
1217 buffer->Store<int16_t>(location_, encoding);
1218 }
1219 }
1220}
1221
1222
1223uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1224 uint32_t location = buffer_.Size();
1225
1226 // This is always unresolved as it must be a forward branch.
1227 Emit16(prev); // Previous link.
1228 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1229 location, rn);
1230}
1231
1232
1233// NOTE: this only support immediate offsets, not [rx,ry].
1234// TODO: support [rx,ry] instructions.
1235void Thumb2Assembler::EmitLoadStore(Condition cond,
1236 bool load,
1237 bool byte,
1238 bool half,
1239 bool is_signed,
1240 Register rd,
1241 const Address& ad) {
1242 CHECK_NE(rd, kNoRegister);
1243 CheckCondition(cond);
1244 bool must_be_32bit = force_32bit_;
1245 if (IsHighRegister(rd)) {
1246 must_be_32bit = true;
1247 }
1248
1249 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001250 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001251 must_be_32bit = true;
1252 }
1253
1254 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1255 must_be_32bit = true;
1256 }
1257
Dave Allison45fdb932014-06-25 12:37:10 -07001258 if (ad.IsImmediate()) {
1259 // Immediate offset
1260 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001261
Dave Allison45fdb932014-06-25 12:37:10 -07001262 // The 16 bit SP relative instruction can only have a 10 bit offset.
1263 if (rn == SP && offset > 1024) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001264 must_be_32bit = true;
1265 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001266
1267 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001268 // 5 bit offset, no shift.
1269 if (offset > 32) {
1270 must_be_32bit = true;
1271 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001272 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001273 // 6 bit offset, shifted by 1.
1274 if (offset > 64) {
1275 must_be_32bit = true;
1276 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001277 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001278 // 7 bit offset, shifted by 2.
1279 if (offset > 128) {
1280 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001281 }
1282 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001283
Dave Allison45fdb932014-06-25 12:37:10 -07001284 if (must_be_32bit) {
1285 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1286 (load ? B20 : 0) |
1287 (is_signed ? B24 : 0) |
1288 static_cast<uint32_t>(rd) << 12 |
1289 ad.encodingThumb(true) |
1290 (byte ? 0 : half ? B21 : B22);
1291 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001292 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001293 // 16 bit thumb1.
1294 uint8_t opA = 0;
1295 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001296
1297 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001298 opA = 0b0111;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001299 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001300 opA = 0b1000;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001301 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001302 if (rn == SP) {
1303 opA = 0b1001;
1304 sp_relative = true;
1305 } else {
1306 opA = 0b0110;
1307 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001308 }
Dave Allison45fdb932014-06-25 12:37:10 -07001309 int16_t encoding = opA << 12 |
1310 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001311
Dave Allison45fdb932014-06-25 12:37:10 -07001312 CHECK_GE(offset, 0);
1313 if (sp_relative) {
1314 // SP relative, 10 bit offset.
1315 CHECK_LT(offset, 1024);
1316 CHECK_EQ((offset & 0b11), 0);
1317 encoding |= rd << 8 | offset >> 2;
1318 } else {
1319 // No SP relative. The offset is shifted right depending on
1320 // the size of the load/store.
1321 encoding |= static_cast<uint32_t>(rd);
1322
1323 if (byte) {
1324 // 5 bit offset, no shift.
1325 CHECK_LT(offset, 32);
1326 } else if (half) {
1327 // 6 bit offset, shifted by 1.
1328 CHECK_LT(offset, 64);
1329 CHECK_EQ((offset & 0b1), 0);
1330 offset >>= 1;
1331 } else {
1332 // 7 bit offset, shifted by 2.
1333 CHECK_LT(offset, 128);
1334 CHECK_EQ((offset & 0b11), 0);
1335 offset >>= 2;
1336 }
1337 encoding |= rn << 3 | offset << 6;
1338 }
1339
1340 Emit16(encoding);
1341 }
1342 } else {
1343 // Register shift.
1344 if (ad.GetRegister() == PC) {
1345 // PC relative literal encoding.
1346 int32_t offset = ad.GetOffset();
1347 if (must_be_32bit || offset < 0 || offset > (1 << 10) || !load) {
1348 int32_t up = B23;
1349 if (offset < 0) {
1350 offset = -offset;
1351 up = 0;
1352 }
1353 CHECK_LT(offset, (1 << 12));
1354 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1355 offset | up |
1356 static_cast<uint32_t>(rd) << 12;
1357 Emit32(encoding);
1358 } else {
1359 // 16 bit literal load.
1360 CHECK_GE(offset, 0);
1361 CHECK_LT(offset, (1 << 10));
1362 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1363 Emit16(encoding);
1364 }
1365 } else {
1366 if (ad.GetShiftCount() != 0) {
1367 // If there is a shift count this must be 32 bit.
1368 must_be_32bit = true;
1369 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1370 must_be_32bit = true;
1371 }
1372
1373 if (must_be_32bit) {
1374 int32_t encoding = 0x1f << 27 | B22 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
1375 ad.encodingThumb(true);
1376 Emit32(encoding);
1377 } else {
1378 // 16 bit register offset.
1379 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1380 ad.encodingThumb(false);
1381 Emit16(encoding);
1382 }
1383 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001384 }
1385}
1386
1387
1388void Thumb2Assembler::EmitMultiMemOp(Condition cond,
1389 BlockAddressMode am,
1390 bool load,
1391 Register base,
1392 RegList regs) {
1393 CHECK_NE(base, kNoRegister);
1394 CheckCondition(cond);
1395 bool must_be_32bit = force_32bit_;
1396
1397 if ((regs & 0xff00) != 0) {
1398 must_be_32bit = true;
1399 }
1400
1401 uint32_t w_bit = am == IA_W || am == DB_W || am == DA_W || am == IB_W;
1402 // 16 bit always uses writeback.
1403 if (!w_bit) {
1404 must_be_32bit = true;
1405 }
1406
1407 if (must_be_32bit) {
1408 uint32_t op = 0;
1409 switch (am) {
1410 case IA:
1411 case IA_W:
1412 op = 0b01;
1413 break;
1414 case DB:
1415 case DB_W:
1416 op = 0b10;
1417 break;
1418 case DA:
1419 case IB:
1420 case DA_W:
1421 case IB_W:
1422 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << am;
1423 }
1424 if (load) {
1425 // Cannot have SP in the list.
1426 CHECK_EQ((regs & (1 << SP)), 0);
1427 } else {
1428 // Cannot have PC or SP in the list.
1429 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1430 }
1431 int32_t encoding = B31 | B30 | B29 | B27 |
1432 (op << 23) |
1433 (load ? B20 : 0) |
1434 base << 16 |
1435 regs |
1436 (w_bit << 21);
1437 Emit32(encoding);
1438 } else {
1439 int16_t encoding = B15 | B14 |
1440 (load ? B11 : 0) |
1441 base << 8 |
1442 regs;
1443 Emit16(encoding);
1444 }
1445}
1446
1447
1448void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1449 uint32_t pc = buffer_.Size();
1450 Branch::Type branch_type;
1451 if (cond == AL) {
1452 if (link) {
1453 if (x) {
1454 branch_type = Branch::kUnconditionalLinkX; // BLX.
1455 } else {
1456 branch_type = Branch::kUnconditionalLink; // BX.
1457 }
1458 } else {
1459 branch_type = Branch::kUnconditional; // B.
1460 }
1461 } else {
1462 branch_type = Branch::kConditional; // B<cond>.
1463 }
1464
1465 if (label->IsBound()) {
1466 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1467
1468 // The branch is to a bound label which means that it's a backwards branch. We know the
1469 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1470 // branch the size may change if it so happens that other branches change size that change
1471 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1472 if (size == Branch::k16Bit) {
1473 Emit16(0); // Space for a 16 bit branch.
1474 } else {
1475 Emit32(0); // Space for a 32 bit branch.
1476 }
1477 } else {
1478 // Branch is to an unbound label. Emit space for it.
1479 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
1480 if (force_32bit_) {
1481 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1482 Emit16(0); // another 16 bits.
1483 } else {
1484 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1485 }
1486 label->LinkTo(branch_id); // Link to the branch ID.
1487 }
1488}
1489
1490
1491void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1492 CHECK_NE(rd, kNoRegister);
1493 CHECK_NE(rm, kNoRegister);
1494 CheckCondition(cond);
1495 CHECK_NE(rd, PC);
1496 CHECK_NE(rm, PC);
1497 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1498 B25 | B23 | B21 | B20 |
1499 static_cast<uint32_t>(rm) << 16 |
1500 0xf << 12 |
1501 static_cast<uint32_t>(rd) << 8 |
1502 B7 |
1503 static_cast<uint32_t>(rm);
1504 Emit32(encoding);
1505}
1506
1507
1508void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1509 CheckCondition(cond);
1510 bool must_be_32bit = force_32bit_;
1511 if (IsHighRegister(rd)|| imm16 >= 256u) {
1512 must_be_32bit = true;
1513 }
1514
1515 if (must_be_32bit) {
1516 // Use encoding T3.
1517 uint32_t imm4 = (imm16 >> 12) & 0b1111;
1518 uint32_t i = (imm16 >> 11) & 0b1;
1519 uint32_t imm3 = (imm16 >> 8) & 0b111;
1520 uint32_t imm8 = imm16 & 0xff;
1521 int32_t encoding = B31 | B30 | B29 | B28 |
1522 B25 | B22 |
1523 static_cast<uint32_t>(rd) << 8 |
1524 i << 26 |
1525 imm4 << 16 |
1526 imm3 << 12 |
1527 imm8;
1528 Emit32(encoding);
1529 } else {
1530 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1531 imm16;
1532 Emit16(encoding);
1533 }
1534}
1535
1536
1537void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1538 CheckCondition(cond);
1539 // Always 32 bits.
1540 uint32_t imm4 = (imm16 >> 12) & 0b1111;
1541 uint32_t i = (imm16 >> 11) & 0b1;
1542 uint32_t imm3 = (imm16 >> 8) & 0b111;
1543 uint32_t imm8 = imm16 & 0xff;
1544 int32_t encoding = B31 | B30 | B29 | B28 |
1545 B25 | B23 | B22 |
1546 static_cast<uint32_t>(rd) << 8 |
1547 i << 26 |
1548 imm4 << 16 |
1549 imm3 << 12 |
1550 imm8;
1551 Emit32(encoding);
1552}
1553
1554
1555void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1556 CHECK_NE(rn, kNoRegister);
1557 CHECK_NE(rt, kNoRegister);
1558 CheckCondition(cond);
1559 CHECK_NE(rn, kNoRegister);
1560 CHECK_NE(rt, kNoRegister);
1561 CheckCondition(cond);
1562 CHECK_LT(imm, (1u << 10));
1563
1564 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1565 static_cast<uint32_t>(rn) << 16 |
1566 static_cast<uint32_t>(rt) << 12 |
1567 0xf << 8 |
1568 imm >> 2;
1569 Emit32(encoding);
1570}
1571
1572
1573void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1574 ldrex(rt, rn, 0, cond);
1575}
1576
1577
1578void Thumb2Assembler::strex(Register rd,
1579 Register rt,
1580 Register rn,
1581 uint16_t imm,
1582 Condition cond) {
1583 CHECK_NE(rn, kNoRegister);
1584 CHECK_NE(rd, kNoRegister);
1585 CHECK_NE(rt, kNoRegister);
1586 CheckCondition(cond);
1587 CHECK_LT(imm, (1u << 10));
1588
1589 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1590 static_cast<uint32_t>(rn) << 16 |
1591 static_cast<uint32_t>(rt) << 12 |
1592 static_cast<uint32_t>(rd) << 8 |
1593 imm >> 2;
1594 Emit32(encoding);
1595}
1596
1597
1598void Thumb2Assembler::strex(Register rd,
1599 Register rt,
1600 Register rn,
1601 Condition cond) {
1602 strex(rd, rt, rn, 0, cond);
1603}
1604
1605
1606void Thumb2Assembler::clrex(Condition cond) {
1607 CheckCondition(cond);
1608 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1609 B21 | B20 |
1610 0xf << 16 |
1611 B15 |
1612 0xf << 8 |
1613 B5 |
1614 0xf;
1615 Emit32(encoding);
1616}
1617
1618
1619void Thumb2Assembler::nop(Condition cond) {
1620 CheckCondition(cond);
1621 int16_t encoding = B15 | B13 | B12 |
1622 B11 | B10 | B9 | B8;
1623 Emit16(encoding);
1624}
1625
1626
1627void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1628 CHECK_NE(sn, kNoSRegister);
1629 CHECK_NE(rt, kNoRegister);
1630 CHECK_NE(rt, SP);
1631 CHECK_NE(rt, PC);
1632 CheckCondition(cond);
1633 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1634 B27 | B26 | B25 |
1635 ((static_cast<int32_t>(sn) >> 1)*B16) |
1636 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1637 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1638 Emit32(encoding);
1639}
1640
1641
1642void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1643 CHECK_NE(sn, kNoSRegister);
1644 CHECK_NE(rt, kNoRegister);
1645 CHECK_NE(rt, SP);
1646 CHECK_NE(rt, PC);
1647 CheckCondition(cond);
1648 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1649 B27 | B26 | B25 | B20 |
1650 ((static_cast<int32_t>(sn) >> 1)*B16) |
1651 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1652 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1653 Emit32(encoding);
1654}
1655
1656
1657void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1658 Condition cond) {
1659 CHECK_NE(sm, kNoSRegister);
1660 CHECK_NE(sm, S31);
1661 CHECK_NE(rt, kNoRegister);
1662 CHECK_NE(rt, SP);
1663 CHECK_NE(rt, PC);
1664 CHECK_NE(rt2, kNoRegister);
1665 CHECK_NE(rt2, SP);
1666 CHECK_NE(rt2, PC);
1667 CheckCondition(cond);
1668 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1669 B27 | B26 | B22 |
1670 (static_cast<int32_t>(rt2)*B16) |
1671 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1672 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1673 (static_cast<int32_t>(sm) >> 1);
1674 Emit32(encoding);
1675}
1676
1677
1678void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1679 Condition cond) {
1680 CHECK_NE(sm, kNoSRegister);
1681 CHECK_NE(sm, S31);
1682 CHECK_NE(rt, kNoRegister);
1683 CHECK_NE(rt, SP);
1684 CHECK_NE(rt, PC);
1685 CHECK_NE(rt2, kNoRegister);
1686 CHECK_NE(rt2, SP);
1687 CHECK_NE(rt2, PC);
1688 CHECK_NE(rt, rt2);
1689 CheckCondition(cond);
1690 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1691 B27 | B26 | B22 | B20 |
1692 (static_cast<int32_t>(rt2)*B16) |
1693 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1694 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1695 (static_cast<int32_t>(sm) >> 1);
1696 Emit32(encoding);
1697}
1698
1699
1700void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1701 Condition cond) {
1702 CHECK_NE(dm, kNoDRegister);
1703 CHECK_NE(rt, kNoRegister);
1704 CHECK_NE(rt, SP);
1705 CHECK_NE(rt, PC);
1706 CHECK_NE(rt2, kNoRegister);
1707 CHECK_NE(rt2, SP);
1708 CHECK_NE(rt2, PC);
1709 CheckCondition(cond);
1710 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1711 B27 | B26 | B22 |
1712 (static_cast<int32_t>(rt2)*B16) |
1713 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1714 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1715 (static_cast<int32_t>(dm) & 0xf);
1716 Emit32(encoding);
1717}
1718
1719
1720void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1721 Condition cond) {
1722 CHECK_NE(dm, kNoDRegister);
1723 CHECK_NE(rt, kNoRegister);
1724 CHECK_NE(rt, SP);
1725 CHECK_NE(rt, PC);
1726 CHECK_NE(rt2, kNoRegister);
1727 CHECK_NE(rt2, SP);
1728 CHECK_NE(rt2, PC);
1729 CHECK_NE(rt, rt2);
1730 CheckCondition(cond);
1731 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1732 B27 | B26 | B22 | B20 |
1733 (static_cast<int32_t>(rt2)*B16) |
1734 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1735 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1736 (static_cast<int32_t>(dm) & 0xf);
1737 Emit32(encoding);
1738}
1739
1740
1741void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1742 const Address& addr = static_cast<const Address&>(ad);
1743 CHECK_NE(sd, kNoSRegister);
1744 CheckCondition(cond);
1745 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1746 B27 | B26 | B24 | B20 |
1747 ((static_cast<int32_t>(sd) & 1)*B22) |
1748 ((static_cast<int32_t>(sd) >> 1)*B12) |
1749 B11 | B9 | addr.vencoding();
1750 Emit32(encoding);
1751}
1752
1753
1754void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1755 const Address& addr = static_cast<const Address&>(ad);
1756 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1757 CHECK_NE(sd, kNoSRegister);
1758 CheckCondition(cond);
1759 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1760 B27 | B26 | B24 |
1761 ((static_cast<int32_t>(sd) & 1)*B22) |
1762 ((static_cast<int32_t>(sd) >> 1)*B12) |
1763 B11 | B9 | addr.vencoding();
1764 Emit32(encoding);
1765}
1766
1767
1768void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1769 const Address& addr = static_cast<const Address&>(ad);
1770 CHECK_NE(dd, kNoDRegister);
1771 CheckCondition(cond);
1772 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1773 B27 | B26 | B24 | B20 |
1774 ((static_cast<int32_t>(dd) >> 4)*B22) |
1775 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1776 B11 | B9 | B8 | addr.vencoding();
1777 Emit32(encoding);
1778}
1779
1780
1781void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1782 const Address& addr = static_cast<const Address&>(ad);
1783 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1784 CHECK_NE(dd, kNoDRegister);
1785 CheckCondition(cond);
1786 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1787 B27 | B26 | B24 |
1788 ((static_cast<int32_t>(dd) >> 4)*B22) |
1789 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1790 B11 | B9 | B8 | addr.vencoding();
1791 Emit32(encoding);
1792}
1793
1794
1795void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1796 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1797}
1798
1799
1800void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1801 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1802}
1803
1804
1805void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1806 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1807}
1808
1809
1810void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1811 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1812}
1813
1814
1815void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1816 CheckCondition(cond);
1817
1818 uint32_t D;
1819 uint32_t Vd;
1820 if (dbl) {
1821 // Encoded as D:Vd.
1822 D = (reg >> 4) & 1;
1823 Vd = reg & 0b1111;
1824 } else {
1825 // Encoded as Vd:D.
1826 D = reg & 1;
1827 Vd = (reg >> 1) & 0b1111;
1828 }
1829 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1830 B11 | B9 |
1831 (dbl ? B8 : 0) |
1832 (push ? B24 : (B23 | B20)) |
1833 0b1110 << 28 |
1834 nregs << (dbl ? 1 : 0) |
1835 D << 22 |
1836 Vd << 12;
1837 Emit32(encoding);
1838}
1839
1840
1841void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1842 SRegister sd, SRegister sn, SRegister sm) {
1843 CHECK_NE(sd, kNoSRegister);
1844 CHECK_NE(sn, kNoSRegister);
1845 CHECK_NE(sm, kNoSRegister);
1846 CheckCondition(cond);
1847 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1848 B27 | B26 | B25 | B11 | B9 | opcode |
1849 ((static_cast<int32_t>(sd) & 1)*B22) |
1850 ((static_cast<int32_t>(sn) >> 1)*B16) |
1851 ((static_cast<int32_t>(sd) >> 1)*B12) |
1852 ((static_cast<int32_t>(sn) & 1)*B7) |
1853 ((static_cast<int32_t>(sm) & 1)*B5) |
1854 (static_cast<int32_t>(sm) >> 1);
1855 Emit32(encoding);
1856}
1857
1858
1859void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1860 DRegister dd, DRegister dn, DRegister dm) {
1861 CHECK_NE(dd, kNoDRegister);
1862 CHECK_NE(dn, kNoDRegister);
1863 CHECK_NE(dm, kNoDRegister);
1864 CheckCondition(cond);
1865 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1866 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1867 ((static_cast<int32_t>(dd) >> 4)*B22) |
1868 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1869 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1870 ((static_cast<int32_t>(dn) >> 4)*B7) |
1871 ((static_cast<int32_t>(dm) >> 4)*B5) |
1872 (static_cast<int32_t>(dm) & 0xf);
1873 Emit32(encoding);
1874}
1875
1876
1877void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1878 SRegister sd, DRegister dm) {
1879 CHECK_NE(sd, kNoSRegister);
1880 CHECK_NE(dm, kNoDRegister);
1881 CheckCondition(cond);
1882 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1883 B27 | B26 | B25 | B11 | B9 | opcode |
1884 ((static_cast<int32_t>(sd) & 1)*B22) |
1885 ((static_cast<int32_t>(sd) >> 1)*B12) |
1886 ((static_cast<int32_t>(dm) >> 4)*B5) |
1887 (static_cast<int32_t>(dm) & 0xf);
1888 Emit32(encoding);
1889}
1890
1891
1892void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
1893 DRegister dd, SRegister sm) {
1894 CHECK_NE(dd, kNoDRegister);
1895 CHECK_NE(sm, kNoSRegister);
1896 CheckCondition(cond);
1897 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1898 B27 | B26 | B25 | B11 | B9 | opcode |
1899 ((static_cast<int32_t>(dd) >> 4)*B22) |
1900 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1901 ((static_cast<int32_t>(sm) & 1)*B5) |
1902 (static_cast<int32_t>(sm) >> 1);
1903 Emit32(encoding);
1904}
1905
1906
1907void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
1908 CheckCondition(cond);
1909 UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
1910}
1911
1912
1913void Thumb2Assembler::svc(uint32_t imm8) {
1914 CHECK(IsUint(8, imm8)) << imm8;
1915 int16_t encoding = B15 | B14 | B12 |
1916 B11 | B10 | B9 | B8 |
1917 imm8;
1918 Emit16(encoding);
1919}
1920
1921
1922void Thumb2Assembler::bkpt(uint16_t imm8) {
1923 CHECK(IsUint(8, imm8)) << imm8;
1924 int16_t encoding = B15 | B13 | B12 |
1925 B11 | B10 | B9 |
1926 imm8;
1927 Emit16(encoding);
1928}
1929
1930// Convert the given IT state to a mask bit given bit 0 of the first
1931// condition and a shift position.
1932static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
1933 switch (s) {
1934 case kItOmitted: return 1 << shift;
1935 case kItThen: return firstcond0 << shift;
1936 case kItElse: return !firstcond0 << shift;
1937 }
1938 return 0;
1939}
1940
1941
1942// Set the IT condition in the given position for the given state. This is used
1943// to check that conditional instructions match the preceding IT statement.
1944void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
1945 switch (s) {
1946 case kItOmitted: it_conditions_[index] = AL; break;
1947 case kItThen: it_conditions_[index] = cond; break;
1948 case kItElse:
1949 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
1950 break;
1951 }
1952}
1953
1954
1955void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
1956 CheckCondition(AL); // Not allowed in IT block.
1957 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
1958
1959 // All conditions to AL.
1960 for (uint8_t i = 0; i < 4; ++i) {
1961 it_conditions_[i] = AL;
1962 }
1963
1964 SetItCondition(kItThen, firstcond, 0);
1965 uint8_t mask = ToItMask(i1, firstcond0, 3);
1966 SetItCondition(i1, firstcond, 1);
1967
1968 if (i1 != kItOmitted) {
1969 mask |= ToItMask(i2, firstcond0, 2);
1970 SetItCondition(i2, firstcond, 2);
1971 if (i2 != kItOmitted) {
1972 mask |= ToItMask(i3, firstcond0, 1);
1973 SetItCondition(i3, firstcond, 3);
1974 if (i3 != kItOmitted) {
1975 mask |= 0b0001;
1976 }
1977 }
1978 }
1979
1980 // Start at first condition.
1981 it_cond_index_ = 0;
1982 next_condition_ = it_conditions_[0];
1983 uint16_t encoding = B15 | B13 | B12 |
1984 B11 | B10 | B9 | B8 |
1985 firstcond << 4 |
1986 mask;
1987 Emit16(encoding);
1988}
1989
1990
1991void Thumb2Assembler::cbz(Register rn, Label* label) {
1992 CheckCondition(AL);
1993 if (label->IsBound()) {
1994 LOG(FATAL) << "cbz can only be used to branch forwards";
1995 } else {
1996 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
1997 label->LinkTo(branchid);
1998 }
1999}
2000
2001
2002void Thumb2Assembler::cbnz(Register rn, Label* label) {
2003 CheckCondition(AL);
2004 if (label->IsBound()) {
2005 LOG(FATAL) << "cbnz can only be used to branch forwards";
2006 } else {
2007 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2008 label->LinkTo(branchid);
2009 }
2010}
2011
2012
2013void Thumb2Assembler::blx(Register rm, Condition cond) {
2014 CHECK_NE(rm, kNoRegister);
2015 CheckCondition(cond);
2016 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2017 Emit16(encoding);
2018}
2019
2020
2021void Thumb2Assembler::bx(Register rm, Condition cond) {
2022 CHECK_NE(rm, kNoRegister);
2023 CheckCondition(cond);
2024 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2025 Emit16(encoding);
2026}
2027
2028
2029void Thumb2Assembler::Push(Register rd, Condition cond) {
2030 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2031}
2032
2033
2034void Thumb2Assembler::Pop(Register rd, Condition cond) {
2035 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2036}
2037
2038
2039void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2040 stm(DB_W, SP, regs, cond);
2041}
2042
2043
2044void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2045 ldm(IA_W, SP, regs, cond);
2046}
2047
2048
2049void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2050 if (cond != AL || rd != rm) {
2051 mov(rd, ShifterOperand(rm), cond);
2052 }
2053}
2054
2055
2056// A branch has changed size. Make a hole for it.
2057void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2058 // Move the contents of the buffer using: Move(newposition, oldposition)
2059 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2060 buffer_.Move(location + delta, location);
2061}
2062
2063
2064void Thumb2Assembler::Bind(Label* label) {
2065 CHECK(!label->IsBound());
2066 uint32_t bound_pc = buffer_.Size();
2067 std::vector<Branch*> changed_branches;
2068
2069 while (label->IsLinked()) {
2070 uint16_t position = label->Position(); // Branch id for linked branch.
2071 Branch* branch = GetBranch(position); // Get the branch at this id.
2072 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2073 uint32_t branch_location = branch->GetLocation();
2074 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2075 if (changed) {
2076 MakeHoleForBranch(branch->GetLocation(), 2);
2077 if (branch->IsCompareAndBranch()) {
2078 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2079 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2080 // cmp rn, #0
2081 // b<eq|ne> target
2082 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2083 Condition cond = n ? NE : EQ;
2084 branch->Move(2); // Move the branch forward by 2 bytes.
2085 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2086 branch->ResetSize(Branch::k16Bit);
2087
2088 // Now add a compare instruction in the place the branch was.
2089 int16_t cmp = B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8;
2090 buffer_.Store<int16_t>(branch_location, cmp);
2091
2092 // Since have moved made a hole in the code we need to reload the
2093 // current pc.
2094 bound_pc = buffer_.Size();
2095
2096 // Now resolve the newly added branch.
2097 changed = branch->Resolve(bound_pc);
2098 if (changed) {
2099 MakeHoleForBranch(branch->GetLocation(), 2);
2100 changed_branches.push_back(branch);
2101 }
2102 } else {
2103 changed_branches.push_back(branch);
2104 }
2105 }
2106 label->position_ = next; // Move to next.
2107 }
2108 label->BindTo(bound_pc);
2109
2110 // Now relocate any changed branches. Do this until there are no more changes.
2111 std::vector<Branch*> branches_to_process = changed_branches;
2112 while (branches_to_process.size() != 0) {
2113 changed_branches.clear();
2114 for (auto& changed_branch : branches_to_process) {
2115 for (auto& branch : branches_) {
2116 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2117 if (changed) {
2118 changed_branches.push_back(branch);
2119 }
2120 }
2121 branches_to_process = changed_branches;
2122 }
2123 }
2124}
2125
2126
2127void Thumb2Assembler::EmitBranches() {
2128 for (auto& branch : branches_) {
2129 branch->Emit(&buffer_);
2130 }
2131}
2132
2133
2134void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002135 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002136 CHECK_NE(shift_imm, 0u); // Do not use Lsl if no shift is wanted.
Dave Allison45fdb932014-06-25 12:37:10 -07002137 CheckCondition(cond);
2138 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002139}
2140
2141
2142void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002143 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002144 CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted.
2145 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002146 CheckCondition(cond);
2147 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002148}
2149
2150
2151void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002152 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002153 CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted.
2154 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002155 CheckCondition(cond);
2156 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002157}
2158
2159
2160void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002161 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002162 CHECK_NE(shift_imm, 0u); // Use Rrx instruction.
Dave Allison45fdb932014-06-25 12:37:10 -07002163 CheckCondition(cond);
2164 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002165}
2166
2167
Dave Allison45fdb932014-06-25 12:37:10 -07002168void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2169 CheckCondition(cond);
2170 EmitShift(rd, rm, RRX, rm, setcc);
2171}
2172
2173
2174void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2175 bool setcc, Condition cond) {
2176 CheckCondition(cond);
2177 EmitShift(rd, rm, LSL, rn, setcc);
2178}
2179
2180
2181void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2182 bool setcc, Condition cond) {
2183 CheckCondition(cond);
2184 EmitShift(rd, rm, LSR, rn, setcc);
2185}
2186
2187
2188void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2189 bool setcc, Condition cond) {
2190 CheckCondition(cond);
2191 EmitShift(rd, rm, ASR, rn, setcc);
2192}
2193
2194
2195void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2196 bool setcc, Condition cond) {
2197 CheckCondition(cond);
2198 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002199}
2200
2201
2202int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2203 // The offset is off by 4 due to the way the ARM CPUs read PC.
2204 offset -= 4;
2205 offset >>= 1;
2206
2207 uint32_t value = 0;
2208 // There are two different encodings depending on the value of bit 12. In one case
2209 // intermediate values are calculated using the sign bit.
2210 if ((inst & B12) == B12) {
2211 // 25 bits of offset.
2212 uint32_t signbit = (offset >> 31) & 0x1;
2213 uint32_t i1 = (offset >> 22) & 0x1;
2214 uint32_t i2 = (offset >> 21) & 0x1;
2215 uint32_t imm10 = (offset >> 11) & 0x03ff;
2216 uint32_t imm11 = offset & 0x07ff;
2217 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2218 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2219 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2220 imm11;
2221 // Remove the offset from the current encoding.
2222 inst &= ~(0x3ff << 16 | 0x7ff);
2223 } else {
2224 uint32_t signbit = (offset >> 31) & 0x1;
2225 uint32_t imm6 = (offset >> 11) & 0x03f;
2226 uint32_t imm11 = offset & 0x07ff;
2227 uint32_t j1 = (offset >> 19) & 1;
2228 uint32_t j2 = (offset >> 17) & 1;
2229 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2230 imm11;
2231 // Remove the offset from the current encoding.
2232 inst &= ~(0x3f << 16 | 0x7ff);
2233 }
2234 // Mask out offset bits in current instruction.
2235 inst &= ~(B26 | B13 | B11);
2236 inst |= value;
2237 return inst;
2238}
2239
2240
2241int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2242 int32_t imm32;
2243 if ((instr & B12) == B12) {
2244 uint32_t S = (instr >> 26) & 1;
2245 uint32_t J2 = (instr >> 11) & 1;
2246 uint32_t J1 = (instr >> 13) & 1;
2247 uint32_t imm10 = (instr >> 16) & 0x3FF;
2248 uint32_t imm11 = instr & 0x7FF;
2249
2250 uint32_t I1 = ~(J1 ^ S) & 1;
2251 uint32_t I2 = ~(J2 ^ S) & 1;
2252 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2253 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2254 } else {
2255 uint32_t S = (instr >> 26) & 1;
2256 uint32_t J2 = (instr >> 11) & 1;
2257 uint32_t J1 = (instr >> 13) & 1;
2258 uint32_t imm6 = (instr >> 16) & 0x3F;
2259 uint32_t imm11 = instr & 0x7FF;
2260
2261 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2262 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2263 }
2264 imm32 += 4;
2265 return imm32;
2266}
2267
2268
2269void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2270 AddConstant(rd, rd, value, cond);
2271}
2272
2273
2274void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2275 Condition cond) {
2276 if (value == 0) {
2277 if (rd != rn) {
2278 mov(rd, ShifterOperand(rn), cond);
2279 }
2280 return;
2281 }
2282 // We prefer to select the shorter code sequence rather than selecting add for
2283 // positive values and sub for negatives ones, which would slightly improve
2284 // the readability of generated code for some constants.
2285 ShifterOperand shifter_op;
2286 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2287 add(rd, rn, shifter_op, cond);
2288 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2289 sub(rd, rn, shifter_op, cond);
2290 } else {
2291 CHECK(rn != IP);
2292 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2293 mvn(IP, shifter_op, cond);
2294 add(rd, rn, ShifterOperand(IP), cond);
2295 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2296 mvn(IP, shifter_op, cond);
2297 sub(rd, rn, ShifterOperand(IP), cond);
2298 } else {
2299 movw(IP, Low16Bits(value), cond);
2300 uint16_t value_high = High16Bits(value);
2301 if (value_high != 0) {
2302 movt(IP, value_high, cond);
2303 }
2304 add(rd, rn, ShifterOperand(IP), cond);
2305 }
2306 }
2307}
2308
2309
2310void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2311 Condition cond) {
2312 ShifterOperand shifter_op;
2313 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2314 adds(rd, rn, shifter_op, cond);
2315 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2316 subs(rd, rn, shifter_op, cond);
2317 } else {
2318 CHECK(rn != IP);
2319 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2320 mvn(IP, shifter_op, cond);
2321 adds(rd, rn, ShifterOperand(IP), cond);
2322 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2323 mvn(IP, shifter_op, cond);
2324 subs(rd, rn, ShifterOperand(IP), cond);
2325 } else {
2326 movw(IP, Low16Bits(value), cond);
2327 uint16_t value_high = High16Bits(value);
2328 if (value_high != 0) {
2329 movt(IP, value_high, cond);
2330 }
2331 adds(rd, rn, ShifterOperand(IP), cond);
2332 }
2333 }
2334}
2335
2336
2337void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2338 ShifterOperand shifter_op;
2339 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2340 mov(rd, shifter_op, cond);
2341 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2342 mvn(rd, shifter_op, cond);
2343 } else {
2344 movw(rd, Low16Bits(value), cond);
2345 uint16_t value_high = High16Bits(value);
2346 if (value_high != 0) {
2347 movt(rd, value_high, cond);
2348 }
2349 }
2350}
2351
2352// Implementation note: this method must emit at most one instruction when
2353// Address::CanHoldLoadOffsetThumb.
2354void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2355 Register reg,
2356 Register base,
2357 int32_t offset,
2358 Condition cond) {
2359 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
2360 CHECK(base != IP);
2361 LoadImmediate(IP, offset, cond);
2362 add(IP, IP, ShifterOperand(base), cond);
2363 base = IP;
2364 offset = 0;
2365 }
2366 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2367 switch (type) {
2368 case kLoadSignedByte:
2369 ldrsb(reg, Address(base, offset), cond);
2370 break;
2371 case kLoadUnsignedByte:
2372 ldrb(reg, Address(base, offset), cond);
2373 break;
2374 case kLoadSignedHalfword:
2375 ldrsh(reg, Address(base, offset), cond);
2376 break;
2377 case kLoadUnsignedHalfword:
2378 ldrh(reg, Address(base, offset), cond);
2379 break;
2380 case kLoadWord:
2381 ldr(reg, Address(base, offset), cond);
2382 break;
2383 case kLoadWordPair:
2384 ldrd(reg, Address(base, offset), cond);
2385 break;
2386 default:
2387 LOG(FATAL) << "UNREACHABLE";
2388 }
2389}
2390
2391
2392// Implementation note: this method must emit at most one instruction when
2393// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2394void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2395 Register base,
2396 int32_t offset,
2397 Condition cond) {
2398 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2399 CHECK_NE(base, IP);
2400 LoadImmediate(IP, offset, cond);
2401 add(IP, IP, ShifterOperand(base), cond);
2402 base = IP;
2403 offset = 0;
2404 }
2405 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2406 vldrs(reg, Address(base, offset), cond);
2407}
2408
2409
2410// Implementation note: this method must emit at most one instruction when
2411// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2412void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2413 Register base,
2414 int32_t offset,
2415 Condition cond) {
2416 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2417 CHECK_NE(base, IP);
2418 LoadImmediate(IP, offset, cond);
2419 add(IP, IP, ShifterOperand(base), cond);
2420 base = IP;
2421 offset = 0;
2422 }
2423 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2424 vldrd(reg, Address(base, offset), cond);
2425}
2426
2427
2428// Implementation note: this method must emit at most one instruction when
2429// Address::CanHoldStoreOffsetThumb.
2430void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2431 Register reg,
2432 Register base,
2433 int32_t offset,
2434 Condition cond) {
2435 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
2436 CHECK(reg != IP);
2437 CHECK(base != IP);
2438 LoadImmediate(IP, offset, cond);
2439 add(IP, IP, ShifterOperand(base), cond);
2440 base = IP;
2441 offset = 0;
2442 }
2443 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2444 switch (type) {
2445 case kStoreByte:
2446 strb(reg, Address(base, offset), cond);
2447 break;
2448 case kStoreHalfword:
2449 strh(reg, Address(base, offset), cond);
2450 break;
2451 case kStoreWord:
2452 str(reg, Address(base, offset), cond);
2453 break;
2454 case kStoreWordPair:
2455 strd(reg, Address(base, offset), cond);
2456 break;
2457 default:
2458 LOG(FATAL) << "UNREACHABLE";
2459 }
2460}
2461
2462
2463// Implementation note: this method must emit at most one instruction when
2464// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2465void Thumb2Assembler::StoreSToOffset(SRegister reg,
2466 Register base,
2467 int32_t offset,
2468 Condition cond) {
2469 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2470 CHECK_NE(base, IP);
2471 LoadImmediate(IP, offset, cond);
2472 add(IP, IP, ShifterOperand(base), cond);
2473 base = IP;
2474 offset = 0;
2475 }
2476 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2477 vstrs(reg, Address(base, offset), cond);
2478}
2479
2480
2481// Implementation note: this method must emit at most one instruction when
2482// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2483void Thumb2Assembler::StoreDToOffset(DRegister reg,
2484 Register base,
2485 int32_t offset,
2486 Condition cond) {
2487 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2488 CHECK_NE(base, IP);
2489 LoadImmediate(IP, offset, cond);
2490 add(IP, IP, ShifterOperand(base), cond);
2491 base = IP;
2492 offset = 0;
2493 }
2494 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2495 vstrd(reg, Address(base, offset), cond);
2496}
2497
2498
2499void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2500 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
2501#if ANDROID_SMP != 0
2502 int32_t encoding = 0xf3bf8f5f; // dmb in T1 encoding.
2503 Emit32(encoding);
2504#endif
2505}
2506
2507
2508void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
2509 cbz(r, label);
2510}
2511
2512
2513void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
2514 cbnz(r, label);
2515}
2516} // namespace arm
2517} // namespace art