blob: 78ff31a061b8d7d83706d11eca263968585b7d80 [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
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100622 bool can_contain_high_register = (opcode == MOV)
623 || ((opcode == ADD || opcode == SUB) && (rn == rd));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700624
625 if (IsHighRegister(rd) || IsHighRegister(rn)) {
626 if (can_contain_high_register) {
627 // There are high register instructions available for this opcode.
628 // However, there is no RRX available.
629 if (so.IsShift() && so.GetShift() == RRX) {
630 return true;
631 }
632
633 // Check special case for SP relative ADD and SUB immediate.
634 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
635 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
636 if (rn == SP && rd != SP && IsHighRegister(rd)) {
637 return true;
638 }
639
640 uint32_t imm = so.GetImmediate();
641 // If the immediates are out of range use 32 bit.
642 if (rd == SP && rn == SP) {
643 if (imm > (1 << 9)) { // 9 bit immediate.
644 return true;
645 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700646 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
647 if (imm > (1 << 10)) {
648 return true;
649 }
650 } else if (opcode == SUB && rd != SP && rn == SP) {
651 // SUB rd, SP, #imm is always 32 bit.
652 return true;
653 }
654 }
655 }
656
657 // The ADD,SUB and MOV instructions that work with high registers don't have
658 // immediate variants.
659 if (so.IsImmediate()) {
660 return true;
661 }
662 }
663
664 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
665 return true;
666 }
667
668 // Check for MOV with an ROR.
669 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
670 if (so.GetImmediate() != 0) {
671 return true;
672 }
673 }
674
675 bool rn_is_valid = true;
676
677 // Check for single operand instructions and ADD/SUB.
678 switch (opcode) {
679 case CMP:
680 case MOV:
681 case TST:
682 case MVN:
683 rn_is_valid = false; // There is no Rn for these instructions.
684 break;
685 case TEQ:
686 return true;
687 break;
688 case ADD:
689 case SUB:
690 break;
691 default:
692 if (so.IsRegister() && rd != rn) {
693 return true;
694 }
695 }
696
697 if (so.IsImmediate()) {
698 if (rn_is_valid && rn != rd) {
699 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
700 // immediate must be 3 bits.
701 if (opcode != ADD && opcode != SUB) {
702 return true;
703 } else {
704 // Check that the immediate is 3 bits for ADD and SUB.
705 if (so.GetImmediate() >= 8) {
706 return true;
707 }
708 }
709 } else {
710 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
711 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
712 return true;
713 } else {
714 if (so.GetImmediate() > 255) {
715 return true;
716 }
717 }
718 }
719 }
720
721 // The instruction can be encoded in 16 bits.
722 return false;
723}
724
725
726void Thumb2Assembler::Emit32BitDataProcessing(Condition cond,
727 Opcode opcode,
728 int set_cc,
729 Register rn,
730 Register rd,
731 const ShifterOperand& so) {
732 uint8_t thumb_opcode = 0b11111111;
733 switch (opcode) {
734 case AND: thumb_opcode = 0b0000; break;
735 case EOR: thumb_opcode = 0b0100; break;
736 case SUB: thumb_opcode = 0b1101; break;
737 case RSB: thumb_opcode = 0b1110; break;
738 case ADD: thumb_opcode = 0b1000; break;
739 case ADC: thumb_opcode = 0b1010; break;
740 case SBC: thumb_opcode = 0b1011; break;
741 case RSC: break;
742 case TST: thumb_opcode = 0b0000; set_cc = true; rd = PC; break;
743 case TEQ: thumb_opcode = 0b0100; set_cc = true; rd = PC; break;
744 case CMP: thumb_opcode = 0b1101; set_cc = true; rd = PC; break;
745 case CMN: thumb_opcode = 0b1000; set_cc = true; rd = PC; break;
746 case ORR: thumb_opcode = 0b0010; break;
747 case MOV: thumb_opcode = 0b0010; rn = PC; break;
748 case BIC: thumb_opcode = 0b0001; break;
749 case MVN: thumb_opcode = 0b0011; rn = PC; break;
750 default:
751 break;
752 }
753
754 if (thumb_opcode == 0b11111111) {
755 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
756 }
757
758 int32_t encoding = 0;
759 if (so.IsImmediate()) {
760 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100761 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700762 if (opcode == SUB) {
763 thumb_opcode = 0b0101;
764 } else {
765 thumb_opcode = 0;
766 }
767 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700768
769 uint32_t i = (imm >> 11) & 1;
770 uint32_t imm3 = (imm >> 8) & 0b111;
771 uint32_t imm8 = imm & 0xff;
772
773 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700774 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100775 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700776 rd << 8 |
777 i << 26 |
778 imm3 << 12 |
779 imm8;
780 } else {
781 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700782 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700783 if (imm == kInvalidModifiedImmediate) {
784 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
785 }
786 encoding = B31 | B30 | B29 | B28 |
787 thumb_opcode << 21 |
788 set_cc << 20 |
789 rn << 16 |
790 rd << 8 |
791 imm;
792 }
793 } else if (so.IsRegister()) {
794 // Register (possibly shifted)
795 encoding = B31 | B30 | B29 | B27 | B25 |
796 thumb_opcode << 21 |
797 set_cc << 20 |
798 rn << 16 |
799 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700800 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700801 }
802 Emit32(encoding);
803}
804
805
806void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
807 Opcode opcode,
808 int set_cc,
809 Register rn,
810 Register rd,
811 const ShifterOperand& so) {
812 if (opcode == ADD || opcode == SUB) {
813 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
814 return;
815 }
816 uint8_t thumb_opcode = 0b11111111;
817 // Thumb1.
818 uint8_t dp_opcode = 0b01;
819 uint8_t opcode_shift = 6;
820 uint8_t rd_shift = 0;
821 uint8_t rn_shift = 3;
822 uint8_t immediate_shift = 0;
823 bool use_immediate = false;
824 uint8_t immediate = 0;
825
826 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
827 // Convert shifted mov operand2 into 16 bit opcodes.
828 dp_opcode = 0;
829 opcode_shift = 11;
830
831 use_immediate = true;
832 immediate = so.GetImmediate();
833 immediate_shift = 6;
834
835 rn = so.GetRegister();
836
837 switch (so.GetShift()) {
838 case LSL: thumb_opcode = 0b00; break;
839 case LSR: thumb_opcode = 0b01; break;
840 case ASR: thumb_opcode = 0b10; break;
841 case ROR:
842 // ROR doesn't allow immediates.
843 thumb_opcode = 0b111;
844 dp_opcode = 0b01;
845 opcode_shift = 6;
846 use_immediate = false;
847 break;
848 case RRX: break;
849 default:
850 break;
851 }
852 } else {
853 if (so.IsImmediate()) {
854 use_immediate = true;
855 immediate = so.GetImmediate();
856 }
857
858 switch (opcode) {
859 case AND: thumb_opcode = 0b0000; break;
860 case EOR: thumb_opcode = 0b0001; break;
861 case SUB: break;
862 case RSB: thumb_opcode = 0b1001; break;
863 case ADD: break;
864 case ADC: thumb_opcode = 0b0101; break;
865 case SBC: thumb_opcode = 0b0110; break;
866 case RSC: break;
867 case TST: thumb_opcode = 0b1000; rn = so.GetRegister(); break;
868 case TEQ: break;
869 case CMP:
870 if (use_immediate) {
871 // T2 encoding.
872 dp_opcode = 0;
873 opcode_shift = 11;
874 thumb_opcode = 0b101;
875 rd_shift = 8;
876 rn_shift = 8;
877 } else {
878 thumb_opcode = 0b1010;
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100879 rd = rn;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700880 rn = so.GetRegister();
881 }
882
883 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100884 case CMN: {
885 thumb_opcode = 0b1011;
886 rd = rn;
887 rn = so.GetRegister();
888 break;
889 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700890 case ORR: thumb_opcode = 0b1100; break;
891 case MOV:
892 dp_opcode = 0;
893 if (use_immediate) {
894 // T2 encoding.
895 opcode_shift = 11;
896 thumb_opcode = 0b100;
897 rd_shift = 8;
898 rn_shift = 8;
899 } else {
900 rn = so.GetRegister();
901 if (IsHighRegister(rn) || IsHighRegister(rd)) {
902 // Special mov for high registers.
903 dp_opcode = 0b01;
904 opcode_shift = 7;
905 // Put the top bit of rd into the bottom bit of the opcode.
906 thumb_opcode = 0b0001100 | static_cast<uint32_t>(rd) >> 3;
907 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 0b111);
908 } else {
909 thumb_opcode = 0;
910 }
911 }
912 break;
913 case BIC: thumb_opcode = 0b1110; break;
914 case MVN: thumb_opcode = 0b1111; rn = so.GetRegister(); break;
915 default:
916 break;
917 }
918 }
919
920 if (thumb_opcode == 0b11111111) {
921 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
922 }
923
924 int16_t encoding = dp_opcode << 14 |
925 (thumb_opcode << opcode_shift) |
926 rd << rd_shift |
927 rn << rn_shift |
928 (use_immediate ? (immediate << immediate_shift) : 0);
929
930 Emit16(encoding);
931}
932
933
934// ADD and SUB are complex enough to warrant their own emitter.
935void Thumb2Assembler::Emit16BitAddSub(Condition cond,
936 Opcode opcode,
937 int set_cc,
938 Register rn,
939 Register rd,
940 const ShifterOperand& so) {
941 uint8_t dp_opcode = 0;
942 uint8_t opcode_shift = 6;
943 uint8_t rd_shift = 0;
944 uint8_t rn_shift = 3;
945 uint8_t immediate_shift = 0;
946 bool use_immediate = false;
947 uint8_t immediate = 0;
948 uint8_t thumb_opcode;;
949
950 if (so.IsImmediate()) {
951 use_immediate = true;
952 immediate = so.GetImmediate();
953 }
954
955 switch (opcode) {
956 case ADD:
957 if (so.IsRegister()) {
958 Register rm = so.GetRegister();
959 if (rn == rd) {
960 // Can use T2 encoding (allows 4 bit registers)
961 dp_opcode = 0b01;
962 opcode_shift = 10;
963 thumb_opcode = 0b0001;
964 // Make Rn also contain the top bit of rd.
965 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
966 (static_cast<uint32_t>(rd) & 0b1000) << 1);
967 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 0b111);
968 } else {
969 // T1.
970 opcode_shift = 9;
971 thumb_opcode = 0b01100;
972 immediate = static_cast<uint32_t>(so.GetRegister());
973 use_immediate = true;
974 immediate_shift = 6;
975 }
976 } else {
977 // Immediate.
978 if (rd == SP && rn == SP) {
979 // ADD sp, sp, #imm
980 dp_opcode = 0b10;
981 thumb_opcode = 0b11;
982 opcode_shift = 12;
983 CHECK_LT(immediate, (1 << 9));
984 CHECK_EQ((immediate & 0b11), 0);
985
986 // Remove rd and rn from instruction by orring it with immed and clearing bits.
987 rn = R0;
988 rd = R0;
989 rd_shift = 0;
990 rn_shift = 0;
991 immediate >>= 2;
992 } else if (rd != SP && rn == SP) {
993 // ADD rd, SP, #imm
994 dp_opcode = 0b10;
995 thumb_opcode = 0b101;
996 opcode_shift = 11;
997 CHECK_LT(immediate, (1 << 10));
998 CHECK_EQ((immediate & 0b11), 0);
999
1000 // Remove rn from instruction.
1001 rn = R0;
1002 rn_shift = 0;
1003 rd_shift = 8;
1004 immediate >>= 2;
1005 } else if (rn != rd) {
1006 // Must use T1.
1007 opcode_shift = 9;
1008 thumb_opcode = 0b01110;
1009 immediate_shift = 6;
1010 } else {
1011 // T2 encoding.
1012 opcode_shift = 11;
1013 thumb_opcode = 0b110;
1014 rd_shift = 8;
1015 rn_shift = 8;
1016 }
1017 }
1018 break;
1019
1020 case SUB:
1021 if (so.IsRegister()) {
1022 // T1.
1023 opcode_shift = 9;
1024 thumb_opcode = 0b01101;
1025 immediate = static_cast<uint32_t>(so.GetRegister());
1026 use_immediate = true;
1027 immediate_shift = 6;
1028 } else {
1029 if (rd == SP && rn == SP) {
1030 // SUB sp, sp, #imm
1031 dp_opcode = 0b10;
1032 thumb_opcode = 0b1100001;
1033 opcode_shift = 7;
1034 CHECK_LT(immediate, (1 << 9));
1035 CHECK_EQ((immediate & 0b11), 0);
1036
1037 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1038 rn = R0;
1039 rd = R0;
1040 rd_shift = 0;
1041 rn_shift = 0;
1042 immediate >>= 2;
1043 } else if (rn != rd) {
1044 // Must use T1.
1045 opcode_shift = 9;
1046 thumb_opcode = 0b01111;
1047 immediate_shift = 6;
1048 } else {
1049 // T2 encoding.
1050 opcode_shift = 11;
1051 thumb_opcode = 0b111;
1052 rd_shift = 8;
1053 rn_shift = 8;
1054 }
1055 }
1056 break;
1057 default:
1058 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
1059 return;
1060 }
1061
1062 int16_t encoding = dp_opcode << 14 |
1063 (thumb_opcode << opcode_shift) |
1064 rd << rd_shift |
1065 rn << rn_shift |
1066 (use_immediate ? (immediate << immediate_shift) : 0);
1067
1068 Emit16(encoding);
1069}
1070
1071
1072void Thumb2Assembler::EmitDataProcessing(Condition cond,
1073 Opcode opcode,
1074 int set_cc,
1075 Register rn,
1076 Register rd,
1077 const ShifterOperand& so) {
1078 CHECK_NE(rd, kNoRegister);
1079 CheckCondition(cond);
1080
1081 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1082 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1083 } else {
1084 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1085 }
1086}
1087
Dave Allison45fdb932014-06-25 12:37:10 -07001088void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1089 CHECK_LT(amount, (1 << 5));
1090 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1091 uint16_t opcode = 0;
1092 switch (shift) {
1093 case LSL: opcode = 0b00; break;
1094 case LSR: opcode = 0b01; break;
1095 case ASR: opcode = 0b10; break;
1096 case ROR: opcode = 0b11; break;
1097 case RRX: opcode = 0b11; amount = 0; break;
1098 default:
1099 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1100 }
1101 // 32 bit.
1102 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1103 0xf << 16 | (setcc ? B20 : 0);
1104 uint32_t imm3 = amount >> 2;
1105 uint32_t imm2 = amount & 0b11;
1106 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1107 static_cast<int16_t>(rd) << 8 | opcode << 4;
1108 Emit32(encoding);
1109 } else {
1110 // 16 bit shift
1111 uint16_t opcode = 0;
1112 switch (shift) {
1113 case LSL: opcode = 0b00; break;
1114 case LSR: opcode = 0b01; break;
1115 case ASR: opcode = 0b10; break;
1116 default:
1117 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1118 }
1119 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1120 static_cast<int16_t>(rd);
1121 Emit16(encoding);
1122 }
1123}
1124
1125void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1126 CHECK_NE(shift, RRX);
1127 bool must_be_32bit = false;
1128 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1129 must_be_32bit = true;
1130 }
1131
1132 if (must_be_32bit) {
1133 uint16_t opcode = 0;
1134 switch (shift) {
1135 case LSL: opcode = 0b00; break;
1136 case LSR: opcode = 0b01; break;
1137 case ASR: opcode = 0b10; break;
1138 case ROR: opcode = 0b11; break;
1139 default:
1140 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1141 }
1142 // 32 bit.
1143 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1144 0xf << 12 | (setcc ? B20 : 0);
1145 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1146 static_cast<int16_t>(rd) << 8 | opcode << 21;
1147 Emit32(encoding);
1148 } else {
1149 uint16_t opcode = 0;
1150 switch (shift) {
1151 case LSL: opcode = 0b0010; break;
1152 case LSR: opcode = 0b0011; break;
1153 case ASR: opcode = 0b0100; break;
1154 default:
1155 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1156 }
1157 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1158 static_cast<int16_t>(rd);
1159 Emit16(encoding);
1160 }
1161}
1162
1163
Dave Allison65fcc2c2014-04-28 13:45:27 -07001164
1165void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1166 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1167 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1168 int32_t offset = target_ - location_;
1169
1170 if (size_ == k32Bit) {
1171 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1172 if (link) {
1173 // BL or BLX immediate.
1174 encoding |= B14;
1175 if (!x) {
1176 encoding |= B12;
1177 } else {
1178 // Bottom bit of offset must be 0.
1179 CHECK_EQ((offset & 1), 0);
1180 }
1181 } else {
1182 if (x) {
1183 LOG(FATAL) << "Invalid use of BX";
1184 } else {
1185 if (cond_ == AL) {
1186 // Can use the T4 encoding allowing a 24 bit offset.
1187 if (!x) {
1188 encoding |= B12;
1189 }
1190 } else {
1191 // Must be T3 encoding with a 20 bit offset.
1192 encoding |= cond_ << 22;
1193 }
1194 }
1195 }
1196 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1197 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1198 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1199 } else {
1200 if (IsCompareAndBranch()) {
1201 offset -= 4;
1202 uint16_t i = (offset >> 6) & 1;
1203 uint16_t imm5 = (offset >> 1) & 0b11111;
1204 int16_t encoding = B15 | B13 | B12 |
1205 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1206 static_cast<uint32_t>(rn_) |
1207 B8 |
1208 i << 9 |
1209 imm5 << 3;
1210 buffer->Store<int16_t>(location_, encoding);
1211 } else {
1212 offset -= 4; // Account for PC offset.
1213 int16_t encoding;
1214 // 16 bit.
1215 if (cond_ == AL) {
1216 encoding = B15 | B14 | B13 |
1217 ((offset >> 1) & 0x7ff);
1218 } else {
1219 encoding = B15 | B14 | B12 |
1220 cond_ << 8 | ((offset >> 1) & 0xff);
1221 }
1222 buffer->Store<int16_t>(location_, encoding);
1223 }
1224 }
1225}
1226
1227
1228uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1229 uint32_t location = buffer_.Size();
1230
1231 // This is always unresolved as it must be a forward branch.
1232 Emit16(prev); // Previous link.
1233 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1234 location, rn);
1235}
1236
1237
1238// NOTE: this only support immediate offsets, not [rx,ry].
1239// TODO: support [rx,ry] instructions.
1240void Thumb2Assembler::EmitLoadStore(Condition cond,
1241 bool load,
1242 bool byte,
1243 bool half,
1244 bool is_signed,
1245 Register rd,
1246 const Address& ad) {
1247 CHECK_NE(rd, kNoRegister);
1248 CheckCondition(cond);
1249 bool must_be_32bit = force_32bit_;
1250 if (IsHighRegister(rd)) {
1251 must_be_32bit = true;
1252 }
1253
1254 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001255 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001256 must_be_32bit = true;
1257 }
1258
1259 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1260 must_be_32bit = true;
1261 }
1262
Dave Allison45fdb932014-06-25 12:37:10 -07001263 if (ad.IsImmediate()) {
1264 // Immediate offset
1265 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001266
Dave Allison45fdb932014-06-25 12:37:10 -07001267 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001268 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001269 must_be_32bit = true;
1270 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001271
1272 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001273 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001274 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001275 must_be_32bit = true;
1276 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001277 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001278 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001279 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001280 must_be_32bit = true;
1281 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001282 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001283 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001284 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001285 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001286 }
1287 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001288
Dave Allison45fdb932014-06-25 12:37:10 -07001289 if (must_be_32bit) {
1290 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1291 (load ? B20 : 0) |
1292 (is_signed ? B24 : 0) |
1293 static_cast<uint32_t>(rd) << 12 |
1294 ad.encodingThumb(true) |
1295 (byte ? 0 : half ? B21 : B22);
1296 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001297 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001298 // 16 bit thumb1.
1299 uint8_t opA = 0;
1300 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001301
1302 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001303 opA = 0b0111;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001304 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001305 opA = 0b1000;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001306 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001307 if (rn == SP) {
1308 opA = 0b1001;
1309 sp_relative = true;
1310 } else {
1311 opA = 0b0110;
1312 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001313 }
Dave Allison45fdb932014-06-25 12:37:10 -07001314 int16_t encoding = opA << 12 |
1315 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001316
Dave Allison45fdb932014-06-25 12:37:10 -07001317 CHECK_GE(offset, 0);
1318 if (sp_relative) {
1319 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001320 CHECK_LT(offset, (1 << 10));
Dave Allison45fdb932014-06-25 12:37:10 -07001321 CHECK_EQ((offset & 0b11), 0);
1322 encoding |= rd << 8 | offset >> 2;
1323 } else {
1324 // No SP relative. The offset is shifted right depending on
1325 // the size of the load/store.
1326 encoding |= static_cast<uint32_t>(rd);
1327
1328 if (byte) {
1329 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001330 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001331 } else if (half) {
1332 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001333 CHECK_LT(offset, (1 << 6));
Dave Allison45fdb932014-06-25 12:37:10 -07001334 CHECK_EQ((offset & 0b1), 0);
1335 offset >>= 1;
1336 } else {
1337 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001338 CHECK_LT(offset, (1 << 7));
Dave Allison45fdb932014-06-25 12:37:10 -07001339 CHECK_EQ((offset & 0b11), 0);
1340 offset >>= 2;
1341 }
1342 encoding |= rn << 3 | offset << 6;
1343 }
1344
1345 Emit16(encoding);
1346 }
1347 } else {
1348 // Register shift.
1349 if (ad.GetRegister() == PC) {
1350 // PC relative literal encoding.
1351 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001352 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001353 int32_t up = B23;
1354 if (offset < 0) {
1355 offset = -offset;
1356 up = 0;
1357 }
1358 CHECK_LT(offset, (1 << 12));
1359 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1360 offset | up |
1361 static_cast<uint32_t>(rd) << 12;
1362 Emit32(encoding);
1363 } else {
1364 // 16 bit literal load.
1365 CHECK_GE(offset, 0);
1366 CHECK_LT(offset, (1 << 10));
1367 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1368 Emit16(encoding);
1369 }
1370 } else {
1371 if (ad.GetShiftCount() != 0) {
1372 // If there is a shift count this must be 32 bit.
1373 must_be_32bit = true;
1374 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1375 must_be_32bit = true;
1376 }
1377
1378 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001379 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001380 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001381 if (half) {
1382 encoding |= B21;
1383 } else if (!byte) {
1384 encoding |= B22;
1385 }
Dave Allison45fdb932014-06-25 12:37:10 -07001386 Emit32(encoding);
1387 } else {
1388 // 16 bit register offset.
1389 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1390 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001391 if (byte) {
1392 encoding |= B10;
1393 } else if (half) {
1394 encoding |= B9;
1395 }
Dave Allison45fdb932014-06-25 12:37:10 -07001396 Emit16(encoding);
1397 }
1398 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001399 }
1400}
1401
1402
1403void Thumb2Assembler::EmitMultiMemOp(Condition cond,
1404 BlockAddressMode am,
1405 bool load,
1406 Register base,
1407 RegList regs) {
1408 CHECK_NE(base, kNoRegister);
1409 CheckCondition(cond);
1410 bool must_be_32bit = force_32bit_;
1411
1412 if ((regs & 0xff00) != 0) {
1413 must_be_32bit = true;
1414 }
1415
1416 uint32_t w_bit = am == IA_W || am == DB_W || am == DA_W || am == IB_W;
1417 // 16 bit always uses writeback.
1418 if (!w_bit) {
1419 must_be_32bit = true;
1420 }
1421
1422 if (must_be_32bit) {
1423 uint32_t op = 0;
1424 switch (am) {
1425 case IA:
1426 case IA_W:
1427 op = 0b01;
1428 break;
1429 case DB:
1430 case DB_W:
1431 op = 0b10;
1432 break;
1433 case DA:
1434 case IB:
1435 case DA_W:
1436 case IB_W:
1437 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << am;
1438 }
1439 if (load) {
1440 // Cannot have SP in the list.
1441 CHECK_EQ((regs & (1 << SP)), 0);
1442 } else {
1443 // Cannot have PC or SP in the list.
1444 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1445 }
1446 int32_t encoding = B31 | B30 | B29 | B27 |
1447 (op << 23) |
1448 (load ? B20 : 0) |
1449 base << 16 |
1450 regs |
1451 (w_bit << 21);
1452 Emit32(encoding);
1453 } else {
1454 int16_t encoding = B15 | B14 |
1455 (load ? B11 : 0) |
1456 base << 8 |
1457 regs;
1458 Emit16(encoding);
1459 }
1460}
1461
1462
1463void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1464 uint32_t pc = buffer_.Size();
1465 Branch::Type branch_type;
1466 if (cond == AL) {
1467 if (link) {
1468 if (x) {
1469 branch_type = Branch::kUnconditionalLinkX; // BLX.
1470 } else {
1471 branch_type = Branch::kUnconditionalLink; // BX.
1472 }
1473 } else {
1474 branch_type = Branch::kUnconditional; // B.
1475 }
1476 } else {
1477 branch_type = Branch::kConditional; // B<cond>.
1478 }
1479
1480 if (label->IsBound()) {
1481 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1482
1483 // The branch is to a bound label which means that it's a backwards branch. We know the
1484 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1485 // branch the size may change if it so happens that other branches change size that change
1486 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1487 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001488 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001489 Emit16(0); // Space for a 16 bit branch.
1490 } else {
1491 Emit32(0); // Space for a 32 bit branch.
1492 }
1493 } else {
1494 // Branch is to an unbound label. Emit space for it.
1495 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001496 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001497 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1498 Emit16(0); // another 16 bits.
1499 } else {
1500 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1501 }
1502 label->LinkTo(branch_id); // Link to the branch ID.
1503 }
1504}
1505
1506
1507void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1508 CHECK_NE(rd, kNoRegister);
1509 CHECK_NE(rm, kNoRegister);
1510 CheckCondition(cond);
1511 CHECK_NE(rd, PC);
1512 CHECK_NE(rm, PC);
1513 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1514 B25 | B23 | B21 | B20 |
1515 static_cast<uint32_t>(rm) << 16 |
1516 0xf << 12 |
1517 static_cast<uint32_t>(rd) << 8 |
1518 B7 |
1519 static_cast<uint32_t>(rm);
1520 Emit32(encoding);
1521}
1522
1523
1524void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1525 CheckCondition(cond);
1526 bool must_be_32bit = force_32bit_;
1527 if (IsHighRegister(rd)|| imm16 >= 256u) {
1528 must_be_32bit = true;
1529 }
1530
1531 if (must_be_32bit) {
1532 // Use encoding T3.
1533 uint32_t imm4 = (imm16 >> 12) & 0b1111;
1534 uint32_t i = (imm16 >> 11) & 0b1;
1535 uint32_t imm3 = (imm16 >> 8) & 0b111;
1536 uint32_t imm8 = imm16 & 0xff;
1537 int32_t encoding = B31 | B30 | B29 | B28 |
1538 B25 | B22 |
1539 static_cast<uint32_t>(rd) << 8 |
1540 i << 26 |
1541 imm4 << 16 |
1542 imm3 << 12 |
1543 imm8;
1544 Emit32(encoding);
1545 } else {
1546 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1547 imm16;
1548 Emit16(encoding);
1549 }
1550}
1551
1552
1553void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1554 CheckCondition(cond);
1555 // Always 32 bits.
1556 uint32_t imm4 = (imm16 >> 12) & 0b1111;
1557 uint32_t i = (imm16 >> 11) & 0b1;
1558 uint32_t imm3 = (imm16 >> 8) & 0b111;
1559 uint32_t imm8 = imm16 & 0xff;
1560 int32_t encoding = B31 | B30 | B29 | B28 |
1561 B25 | B23 | B22 |
1562 static_cast<uint32_t>(rd) << 8 |
1563 i << 26 |
1564 imm4 << 16 |
1565 imm3 << 12 |
1566 imm8;
1567 Emit32(encoding);
1568}
1569
1570
1571void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1572 CHECK_NE(rn, kNoRegister);
1573 CHECK_NE(rt, kNoRegister);
1574 CheckCondition(cond);
1575 CHECK_NE(rn, kNoRegister);
1576 CHECK_NE(rt, kNoRegister);
1577 CheckCondition(cond);
1578 CHECK_LT(imm, (1u << 10));
1579
1580 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1581 static_cast<uint32_t>(rn) << 16 |
1582 static_cast<uint32_t>(rt) << 12 |
1583 0xf << 8 |
1584 imm >> 2;
1585 Emit32(encoding);
1586}
1587
1588
1589void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1590 ldrex(rt, rn, 0, cond);
1591}
1592
1593
1594void Thumb2Assembler::strex(Register rd,
1595 Register rt,
1596 Register rn,
1597 uint16_t imm,
1598 Condition cond) {
1599 CHECK_NE(rn, kNoRegister);
1600 CHECK_NE(rd, kNoRegister);
1601 CHECK_NE(rt, kNoRegister);
1602 CheckCondition(cond);
1603 CHECK_LT(imm, (1u << 10));
1604
1605 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1606 static_cast<uint32_t>(rn) << 16 |
1607 static_cast<uint32_t>(rt) << 12 |
1608 static_cast<uint32_t>(rd) << 8 |
1609 imm >> 2;
1610 Emit32(encoding);
1611}
1612
1613
1614void Thumb2Assembler::strex(Register rd,
1615 Register rt,
1616 Register rn,
1617 Condition cond) {
1618 strex(rd, rt, rn, 0, cond);
1619}
1620
1621
1622void Thumb2Assembler::clrex(Condition cond) {
1623 CheckCondition(cond);
1624 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1625 B21 | B20 |
1626 0xf << 16 |
1627 B15 |
1628 0xf << 8 |
1629 B5 |
1630 0xf;
1631 Emit32(encoding);
1632}
1633
1634
1635void Thumb2Assembler::nop(Condition cond) {
1636 CheckCondition(cond);
1637 int16_t encoding = B15 | B13 | B12 |
1638 B11 | B10 | B9 | B8;
1639 Emit16(encoding);
1640}
1641
1642
1643void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1644 CHECK_NE(sn, kNoSRegister);
1645 CHECK_NE(rt, kNoRegister);
1646 CHECK_NE(rt, SP);
1647 CHECK_NE(rt, PC);
1648 CheckCondition(cond);
1649 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1650 B27 | B26 | B25 |
1651 ((static_cast<int32_t>(sn) >> 1)*B16) |
1652 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1653 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1654 Emit32(encoding);
1655}
1656
1657
1658void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1659 CHECK_NE(sn, kNoSRegister);
1660 CHECK_NE(rt, kNoRegister);
1661 CHECK_NE(rt, SP);
1662 CHECK_NE(rt, PC);
1663 CheckCondition(cond);
1664 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1665 B27 | B26 | B25 | B20 |
1666 ((static_cast<int32_t>(sn) >> 1)*B16) |
1667 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1668 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1669 Emit32(encoding);
1670}
1671
1672
1673void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1674 Condition cond) {
1675 CHECK_NE(sm, kNoSRegister);
1676 CHECK_NE(sm, S31);
1677 CHECK_NE(rt, kNoRegister);
1678 CHECK_NE(rt, SP);
1679 CHECK_NE(rt, PC);
1680 CHECK_NE(rt2, kNoRegister);
1681 CHECK_NE(rt2, SP);
1682 CHECK_NE(rt2, PC);
1683 CheckCondition(cond);
1684 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1685 B27 | B26 | B22 |
1686 (static_cast<int32_t>(rt2)*B16) |
1687 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1688 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1689 (static_cast<int32_t>(sm) >> 1);
1690 Emit32(encoding);
1691}
1692
1693
1694void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1695 Condition cond) {
1696 CHECK_NE(sm, kNoSRegister);
1697 CHECK_NE(sm, S31);
1698 CHECK_NE(rt, kNoRegister);
1699 CHECK_NE(rt, SP);
1700 CHECK_NE(rt, PC);
1701 CHECK_NE(rt2, kNoRegister);
1702 CHECK_NE(rt2, SP);
1703 CHECK_NE(rt2, PC);
1704 CHECK_NE(rt, rt2);
1705 CheckCondition(cond);
1706 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1707 B27 | B26 | B22 | B20 |
1708 (static_cast<int32_t>(rt2)*B16) |
1709 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1710 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1711 (static_cast<int32_t>(sm) >> 1);
1712 Emit32(encoding);
1713}
1714
1715
1716void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1717 Condition cond) {
1718 CHECK_NE(dm, kNoDRegister);
1719 CHECK_NE(rt, kNoRegister);
1720 CHECK_NE(rt, SP);
1721 CHECK_NE(rt, PC);
1722 CHECK_NE(rt2, kNoRegister);
1723 CHECK_NE(rt2, SP);
1724 CHECK_NE(rt2, PC);
1725 CheckCondition(cond);
1726 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1727 B27 | B26 | B22 |
1728 (static_cast<int32_t>(rt2)*B16) |
1729 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1730 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1731 (static_cast<int32_t>(dm) & 0xf);
1732 Emit32(encoding);
1733}
1734
1735
1736void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1737 Condition cond) {
1738 CHECK_NE(dm, kNoDRegister);
1739 CHECK_NE(rt, kNoRegister);
1740 CHECK_NE(rt, SP);
1741 CHECK_NE(rt, PC);
1742 CHECK_NE(rt2, kNoRegister);
1743 CHECK_NE(rt2, SP);
1744 CHECK_NE(rt2, PC);
1745 CHECK_NE(rt, rt2);
1746 CheckCondition(cond);
1747 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1748 B27 | B26 | B22 | B20 |
1749 (static_cast<int32_t>(rt2)*B16) |
1750 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1751 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1752 (static_cast<int32_t>(dm) & 0xf);
1753 Emit32(encoding);
1754}
1755
1756
1757void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1758 const Address& addr = static_cast<const Address&>(ad);
1759 CHECK_NE(sd, kNoSRegister);
1760 CheckCondition(cond);
1761 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1762 B27 | B26 | B24 | B20 |
1763 ((static_cast<int32_t>(sd) & 1)*B22) |
1764 ((static_cast<int32_t>(sd) >> 1)*B12) |
1765 B11 | B9 | addr.vencoding();
1766 Emit32(encoding);
1767}
1768
1769
1770void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1771 const Address& addr = static_cast<const Address&>(ad);
1772 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1773 CHECK_NE(sd, kNoSRegister);
1774 CheckCondition(cond);
1775 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1776 B27 | B26 | B24 |
1777 ((static_cast<int32_t>(sd) & 1)*B22) |
1778 ((static_cast<int32_t>(sd) >> 1)*B12) |
1779 B11 | B9 | addr.vencoding();
1780 Emit32(encoding);
1781}
1782
1783
1784void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1785 const Address& addr = static_cast<const Address&>(ad);
1786 CHECK_NE(dd, kNoDRegister);
1787 CheckCondition(cond);
1788 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1789 B27 | B26 | B24 | B20 |
1790 ((static_cast<int32_t>(dd) >> 4)*B22) |
1791 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1792 B11 | B9 | B8 | addr.vencoding();
1793 Emit32(encoding);
1794}
1795
1796
1797void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1798 const Address& addr = static_cast<const Address&>(ad);
1799 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1800 CHECK_NE(dd, kNoDRegister);
1801 CheckCondition(cond);
1802 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1803 B27 | B26 | B24 |
1804 ((static_cast<int32_t>(dd) >> 4)*B22) |
1805 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1806 B11 | B9 | B8 | addr.vencoding();
1807 Emit32(encoding);
1808}
1809
1810
1811void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1812 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1813}
1814
1815
1816void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1817 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1818}
1819
1820
1821void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1822 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1823}
1824
1825
1826void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1827 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1828}
1829
1830
1831void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1832 CheckCondition(cond);
1833
1834 uint32_t D;
1835 uint32_t Vd;
1836 if (dbl) {
1837 // Encoded as D:Vd.
1838 D = (reg >> 4) & 1;
1839 Vd = reg & 0b1111;
1840 } else {
1841 // Encoded as Vd:D.
1842 D = reg & 1;
1843 Vd = (reg >> 1) & 0b1111;
1844 }
1845 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1846 B11 | B9 |
1847 (dbl ? B8 : 0) |
1848 (push ? B24 : (B23 | B20)) |
1849 0b1110 << 28 |
1850 nregs << (dbl ? 1 : 0) |
1851 D << 22 |
1852 Vd << 12;
1853 Emit32(encoding);
1854}
1855
1856
1857void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1858 SRegister sd, SRegister sn, SRegister sm) {
1859 CHECK_NE(sd, kNoSRegister);
1860 CHECK_NE(sn, kNoSRegister);
1861 CHECK_NE(sm, kNoSRegister);
1862 CheckCondition(cond);
1863 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1864 B27 | B26 | B25 | B11 | B9 | opcode |
1865 ((static_cast<int32_t>(sd) & 1)*B22) |
1866 ((static_cast<int32_t>(sn) >> 1)*B16) |
1867 ((static_cast<int32_t>(sd) >> 1)*B12) |
1868 ((static_cast<int32_t>(sn) & 1)*B7) |
1869 ((static_cast<int32_t>(sm) & 1)*B5) |
1870 (static_cast<int32_t>(sm) >> 1);
1871 Emit32(encoding);
1872}
1873
1874
1875void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1876 DRegister dd, DRegister dn, DRegister dm) {
1877 CHECK_NE(dd, kNoDRegister);
1878 CHECK_NE(dn, kNoDRegister);
1879 CHECK_NE(dm, kNoDRegister);
1880 CheckCondition(cond);
1881 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1882 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1883 ((static_cast<int32_t>(dd) >> 4)*B22) |
1884 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1885 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1886 ((static_cast<int32_t>(dn) >> 4)*B7) |
1887 ((static_cast<int32_t>(dm) >> 4)*B5) |
1888 (static_cast<int32_t>(dm) & 0xf);
1889 Emit32(encoding);
1890}
1891
1892
1893void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1894 SRegister sd, DRegister dm) {
1895 CHECK_NE(sd, kNoSRegister);
1896 CHECK_NE(dm, kNoDRegister);
1897 CheckCondition(cond);
1898 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1899 B27 | B26 | B25 | B11 | B9 | opcode |
1900 ((static_cast<int32_t>(sd) & 1)*B22) |
1901 ((static_cast<int32_t>(sd) >> 1)*B12) |
1902 ((static_cast<int32_t>(dm) >> 4)*B5) |
1903 (static_cast<int32_t>(dm) & 0xf);
1904 Emit32(encoding);
1905}
1906
1907
1908void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
1909 DRegister dd, SRegister sm) {
1910 CHECK_NE(dd, kNoDRegister);
1911 CHECK_NE(sm, kNoSRegister);
1912 CheckCondition(cond);
1913 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1914 B27 | B26 | B25 | B11 | B9 | opcode |
1915 ((static_cast<int32_t>(dd) >> 4)*B22) |
1916 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1917 ((static_cast<int32_t>(sm) & 1)*B5) |
1918 (static_cast<int32_t>(sm) >> 1);
1919 Emit32(encoding);
1920}
1921
1922
1923void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
1924 CheckCondition(cond);
1925 UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction";
1926}
1927
1928
1929void Thumb2Assembler::svc(uint32_t imm8) {
1930 CHECK(IsUint(8, imm8)) << imm8;
1931 int16_t encoding = B15 | B14 | B12 |
1932 B11 | B10 | B9 | B8 |
1933 imm8;
1934 Emit16(encoding);
1935}
1936
1937
1938void Thumb2Assembler::bkpt(uint16_t imm8) {
1939 CHECK(IsUint(8, imm8)) << imm8;
1940 int16_t encoding = B15 | B13 | B12 |
1941 B11 | B10 | B9 |
1942 imm8;
1943 Emit16(encoding);
1944}
1945
1946// Convert the given IT state to a mask bit given bit 0 of the first
1947// condition and a shift position.
1948static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
1949 switch (s) {
1950 case kItOmitted: return 1 << shift;
1951 case kItThen: return firstcond0 << shift;
1952 case kItElse: return !firstcond0 << shift;
1953 }
1954 return 0;
1955}
1956
1957
1958// Set the IT condition in the given position for the given state. This is used
1959// to check that conditional instructions match the preceding IT statement.
1960void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
1961 switch (s) {
1962 case kItOmitted: it_conditions_[index] = AL; break;
1963 case kItThen: it_conditions_[index] = cond; break;
1964 case kItElse:
1965 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
1966 break;
1967 }
1968}
1969
1970
1971void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
1972 CheckCondition(AL); // Not allowed in IT block.
1973 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
1974
1975 // All conditions to AL.
1976 for (uint8_t i = 0; i < 4; ++i) {
1977 it_conditions_[i] = AL;
1978 }
1979
1980 SetItCondition(kItThen, firstcond, 0);
1981 uint8_t mask = ToItMask(i1, firstcond0, 3);
1982 SetItCondition(i1, firstcond, 1);
1983
1984 if (i1 != kItOmitted) {
1985 mask |= ToItMask(i2, firstcond0, 2);
1986 SetItCondition(i2, firstcond, 2);
1987 if (i2 != kItOmitted) {
1988 mask |= ToItMask(i3, firstcond0, 1);
1989 SetItCondition(i3, firstcond, 3);
1990 if (i3 != kItOmitted) {
1991 mask |= 0b0001;
1992 }
1993 }
1994 }
1995
1996 // Start at first condition.
1997 it_cond_index_ = 0;
1998 next_condition_ = it_conditions_[0];
1999 uint16_t encoding = B15 | B13 | B12 |
2000 B11 | B10 | B9 | B8 |
2001 firstcond << 4 |
2002 mask;
2003 Emit16(encoding);
2004}
2005
2006
2007void Thumb2Assembler::cbz(Register rn, Label* label) {
2008 CheckCondition(AL);
2009 if (label->IsBound()) {
2010 LOG(FATAL) << "cbz can only be used to branch forwards";
2011 } else {
2012 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2013 label->LinkTo(branchid);
2014 }
2015}
2016
2017
2018void Thumb2Assembler::cbnz(Register rn, Label* label) {
2019 CheckCondition(AL);
2020 if (label->IsBound()) {
2021 LOG(FATAL) << "cbnz can only be used to branch forwards";
2022 } else {
2023 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2024 label->LinkTo(branchid);
2025 }
2026}
2027
2028
2029void Thumb2Assembler::blx(Register rm, Condition cond) {
2030 CHECK_NE(rm, kNoRegister);
2031 CheckCondition(cond);
2032 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2033 Emit16(encoding);
2034}
2035
2036
2037void Thumb2Assembler::bx(Register rm, Condition cond) {
2038 CHECK_NE(rm, kNoRegister);
2039 CheckCondition(cond);
2040 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2041 Emit16(encoding);
2042}
2043
2044
2045void Thumb2Assembler::Push(Register rd, Condition cond) {
2046 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2047}
2048
2049
2050void Thumb2Assembler::Pop(Register rd, Condition cond) {
2051 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2052}
2053
2054
2055void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2056 stm(DB_W, SP, regs, cond);
2057}
2058
2059
2060void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2061 ldm(IA_W, SP, regs, cond);
2062}
2063
2064
2065void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2066 if (cond != AL || rd != rm) {
2067 mov(rd, ShifterOperand(rm), cond);
2068 }
2069}
2070
2071
2072// A branch has changed size. Make a hole for it.
2073void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2074 // Move the contents of the buffer using: Move(newposition, oldposition)
2075 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2076 buffer_.Move(location + delta, location);
2077}
2078
2079
2080void Thumb2Assembler::Bind(Label* label) {
2081 CHECK(!label->IsBound());
2082 uint32_t bound_pc = buffer_.Size();
2083 std::vector<Branch*> changed_branches;
2084
2085 while (label->IsLinked()) {
2086 uint16_t position = label->Position(); // Branch id for linked branch.
2087 Branch* branch = GetBranch(position); // Get the branch at this id.
2088 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2089 uint32_t branch_location = branch->GetLocation();
2090 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2091 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002092 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002093 MakeHoleForBranch(branch->GetLocation(), 2);
2094 if (branch->IsCompareAndBranch()) {
2095 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2096 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2097 // cmp rn, #0
2098 // b<eq|ne> target
2099 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2100 Condition cond = n ? NE : EQ;
2101 branch->Move(2); // Move the branch forward by 2 bytes.
2102 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2103 branch->ResetSize(Branch::k16Bit);
2104
2105 // Now add a compare instruction in the place the branch was.
2106 int16_t cmp = B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8;
2107 buffer_.Store<int16_t>(branch_location, cmp);
2108
2109 // Since have moved made a hole in the code we need to reload the
2110 // current pc.
2111 bound_pc = buffer_.Size();
2112
2113 // Now resolve the newly added branch.
2114 changed = branch->Resolve(bound_pc);
2115 if (changed) {
2116 MakeHoleForBranch(branch->GetLocation(), 2);
2117 changed_branches.push_back(branch);
2118 }
2119 } else {
2120 changed_branches.push_back(branch);
2121 }
2122 }
2123 label->position_ = next; // Move to next.
2124 }
2125 label->BindTo(bound_pc);
2126
2127 // Now relocate any changed branches. Do this until there are no more changes.
2128 std::vector<Branch*> branches_to_process = changed_branches;
2129 while (branches_to_process.size() != 0) {
2130 changed_branches.clear();
2131 for (auto& changed_branch : branches_to_process) {
2132 for (auto& branch : branches_) {
2133 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2134 if (changed) {
2135 changed_branches.push_back(branch);
2136 }
2137 }
2138 branches_to_process = changed_branches;
2139 }
2140 }
2141}
2142
2143
2144void Thumb2Assembler::EmitBranches() {
2145 for (auto& branch : branches_) {
2146 branch->Emit(&buffer_);
2147 }
2148}
2149
2150
2151void Thumb2Assembler::Lsl(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 Lsl if no shift is wanted.
Dave Allison45fdb932014-06-25 12:37:10 -07002154 CheckCondition(cond);
2155 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002156}
2157
2158
2159void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002160 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002161 CHECK_NE(shift_imm, 0u); // Do not use Lsr if no shift is wanted.
2162 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002163 CheckCondition(cond);
2164 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002165}
2166
2167
2168void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002169 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002170 CHECK_NE(shift_imm, 0u); // Do not use Asr if no shift is wanted.
2171 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002172 CheckCondition(cond);
2173 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002174}
2175
2176
2177void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002178 bool setcc, Condition cond) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002179 CHECK_NE(shift_imm, 0u); // Use Rrx instruction.
Dave Allison45fdb932014-06-25 12:37:10 -07002180 CheckCondition(cond);
2181 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002182}
2183
2184
Dave Allison45fdb932014-06-25 12:37:10 -07002185void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2186 CheckCondition(cond);
2187 EmitShift(rd, rm, RRX, rm, setcc);
2188}
2189
2190
2191void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2192 bool setcc, Condition cond) {
2193 CheckCondition(cond);
2194 EmitShift(rd, rm, LSL, rn, setcc);
2195}
2196
2197
2198void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2199 bool setcc, Condition cond) {
2200 CheckCondition(cond);
2201 EmitShift(rd, rm, LSR, rn, setcc);
2202}
2203
2204
2205void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2206 bool setcc, Condition cond) {
2207 CheckCondition(cond);
2208 EmitShift(rd, rm, ASR, rn, setcc);
2209}
2210
2211
2212void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2213 bool setcc, Condition cond) {
2214 CheckCondition(cond);
2215 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002216}
2217
2218
2219int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2220 // The offset is off by 4 due to the way the ARM CPUs read PC.
2221 offset -= 4;
2222 offset >>= 1;
2223
2224 uint32_t value = 0;
2225 // There are two different encodings depending on the value of bit 12. In one case
2226 // intermediate values are calculated using the sign bit.
2227 if ((inst & B12) == B12) {
2228 // 25 bits of offset.
2229 uint32_t signbit = (offset >> 31) & 0x1;
2230 uint32_t i1 = (offset >> 22) & 0x1;
2231 uint32_t i2 = (offset >> 21) & 0x1;
2232 uint32_t imm10 = (offset >> 11) & 0x03ff;
2233 uint32_t imm11 = offset & 0x07ff;
2234 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2235 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2236 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2237 imm11;
2238 // Remove the offset from the current encoding.
2239 inst &= ~(0x3ff << 16 | 0x7ff);
2240 } else {
2241 uint32_t signbit = (offset >> 31) & 0x1;
2242 uint32_t imm6 = (offset >> 11) & 0x03f;
2243 uint32_t imm11 = offset & 0x07ff;
2244 uint32_t j1 = (offset >> 19) & 1;
2245 uint32_t j2 = (offset >> 17) & 1;
2246 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2247 imm11;
2248 // Remove the offset from the current encoding.
2249 inst &= ~(0x3f << 16 | 0x7ff);
2250 }
2251 // Mask out offset bits in current instruction.
2252 inst &= ~(B26 | B13 | B11);
2253 inst |= value;
2254 return inst;
2255}
2256
2257
2258int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2259 int32_t imm32;
2260 if ((instr & B12) == B12) {
2261 uint32_t S = (instr >> 26) & 1;
2262 uint32_t J2 = (instr >> 11) & 1;
2263 uint32_t J1 = (instr >> 13) & 1;
2264 uint32_t imm10 = (instr >> 16) & 0x3FF;
2265 uint32_t imm11 = instr & 0x7FF;
2266
2267 uint32_t I1 = ~(J1 ^ S) & 1;
2268 uint32_t I2 = ~(J2 ^ S) & 1;
2269 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2270 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2271 } else {
2272 uint32_t S = (instr >> 26) & 1;
2273 uint32_t J2 = (instr >> 11) & 1;
2274 uint32_t J1 = (instr >> 13) & 1;
2275 uint32_t imm6 = (instr >> 16) & 0x3F;
2276 uint32_t imm11 = instr & 0x7FF;
2277
2278 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2279 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2280 }
2281 imm32 += 4;
2282 return imm32;
2283}
2284
2285
2286void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2287 AddConstant(rd, rd, value, cond);
2288}
2289
2290
2291void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2292 Condition cond) {
2293 if (value == 0) {
2294 if (rd != rn) {
2295 mov(rd, ShifterOperand(rn), cond);
2296 }
2297 return;
2298 }
2299 // We prefer to select the shorter code sequence rather than selecting add for
2300 // positive values and sub for negatives ones, which would slightly improve
2301 // the readability of generated code for some constants.
2302 ShifterOperand shifter_op;
2303 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2304 add(rd, rn, shifter_op, cond);
2305 } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) {
2306 sub(rd, rn, shifter_op, cond);
2307 } else {
2308 CHECK(rn != IP);
2309 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2310 mvn(IP, shifter_op, cond);
2311 add(rd, rn, ShifterOperand(IP), cond);
2312 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2313 mvn(IP, shifter_op, cond);
2314 sub(rd, rn, ShifterOperand(IP), cond);
2315 } else {
2316 movw(IP, Low16Bits(value), cond);
2317 uint16_t value_high = High16Bits(value);
2318 if (value_high != 0) {
2319 movt(IP, value_high, cond);
2320 }
2321 add(rd, rn, ShifterOperand(IP), cond);
2322 }
2323 }
2324}
2325
2326
2327void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2328 Condition cond) {
2329 ShifterOperand shifter_op;
2330 if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) {
2331 adds(rd, rn, shifter_op, cond);
2332 } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) {
2333 subs(rd, rn, shifter_op, cond);
2334 } else {
2335 CHECK(rn != IP);
2336 if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) {
2337 mvn(IP, shifter_op, cond);
2338 adds(rd, rn, ShifterOperand(IP), cond);
2339 } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) {
2340 mvn(IP, shifter_op, cond);
2341 subs(rd, rn, ShifterOperand(IP), cond);
2342 } else {
2343 movw(IP, Low16Bits(value), cond);
2344 uint16_t value_high = High16Bits(value);
2345 if (value_high != 0) {
2346 movt(IP, value_high, cond);
2347 }
2348 adds(rd, rn, ShifterOperand(IP), cond);
2349 }
2350 }
2351}
2352
2353
2354void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2355 ShifterOperand shifter_op;
2356 if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) {
2357 mov(rd, shifter_op, cond);
2358 } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) {
2359 mvn(rd, shifter_op, cond);
2360 } else {
2361 movw(rd, Low16Bits(value), cond);
2362 uint16_t value_high = High16Bits(value);
2363 if (value_high != 0) {
2364 movt(rd, value_high, cond);
2365 }
2366 }
2367}
2368
2369// Implementation note: this method must emit at most one instruction when
2370// Address::CanHoldLoadOffsetThumb.
2371void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2372 Register reg,
2373 Register base,
2374 int32_t offset,
2375 Condition cond) {
2376 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
2377 CHECK(base != IP);
2378 LoadImmediate(IP, offset, cond);
2379 add(IP, IP, ShifterOperand(base), cond);
2380 base = IP;
2381 offset = 0;
2382 }
2383 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2384 switch (type) {
2385 case kLoadSignedByte:
2386 ldrsb(reg, Address(base, offset), cond);
2387 break;
2388 case kLoadUnsignedByte:
2389 ldrb(reg, Address(base, offset), cond);
2390 break;
2391 case kLoadSignedHalfword:
2392 ldrsh(reg, Address(base, offset), cond);
2393 break;
2394 case kLoadUnsignedHalfword:
2395 ldrh(reg, Address(base, offset), cond);
2396 break;
2397 case kLoadWord:
2398 ldr(reg, Address(base, offset), cond);
2399 break;
2400 case kLoadWordPair:
2401 ldrd(reg, Address(base, offset), cond);
2402 break;
2403 default:
2404 LOG(FATAL) << "UNREACHABLE";
2405 }
2406}
2407
2408
2409// Implementation note: this method must emit at most one instruction when
2410// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2411void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2412 Register base,
2413 int32_t offset,
2414 Condition cond) {
2415 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2416 CHECK_NE(base, IP);
2417 LoadImmediate(IP, offset, cond);
2418 add(IP, IP, ShifterOperand(base), cond);
2419 base = IP;
2420 offset = 0;
2421 }
2422 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2423 vldrs(reg, Address(base, offset), cond);
2424}
2425
2426
2427// Implementation note: this method must emit at most one instruction when
2428// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2429void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2430 Register base,
2431 int32_t offset,
2432 Condition cond) {
2433 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2434 CHECK_NE(base, IP);
2435 LoadImmediate(IP, offset, cond);
2436 add(IP, IP, ShifterOperand(base), cond);
2437 base = IP;
2438 offset = 0;
2439 }
2440 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2441 vldrd(reg, Address(base, offset), cond);
2442}
2443
2444
2445// Implementation note: this method must emit at most one instruction when
2446// Address::CanHoldStoreOffsetThumb.
2447void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2448 Register reg,
2449 Register base,
2450 int32_t offset,
2451 Condition cond) {
2452 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
2453 CHECK(reg != IP);
2454 CHECK(base != IP);
2455 LoadImmediate(IP, offset, cond);
2456 add(IP, IP, ShifterOperand(base), cond);
2457 base = IP;
2458 offset = 0;
2459 }
2460 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2461 switch (type) {
2462 case kStoreByte:
2463 strb(reg, Address(base, offset), cond);
2464 break;
2465 case kStoreHalfword:
2466 strh(reg, Address(base, offset), cond);
2467 break;
2468 case kStoreWord:
2469 str(reg, Address(base, offset), cond);
2470 break;
2471 case kStoreWordPair:
2472 strd(reg, Address(base, offset), cond);
2473 break;
2474 default:
2475 LOG(FATAL) << "UNREACHABLE";
2476 }
2477}
2478
2479
2480// Implementation note: this method must emit at most one instruction when
2481// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2482void Thumb2Assembler::StoreSToOffset(SRegister reg,
2483 Register base,
2484 int32_t offset,
2485 Condition cond) {
2486 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2487 CHECK_NE(base, IP);
2488 LoadImmediate(IP, offset, cond);
2489 add(IP, IP, ShifterOperand(base), cond);
2490 base = IP;
2491 offset = 0;
2492 }
2493 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2494 vstrs(reg, Address(base, offset), cond);
2495}
2496
2497
2498// Implementation note: this method must emit at most one instruction when
2499// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2500void Thumb2Assembler::StoreDToOffset(DRegister reg,
2501 Register base,
2502 int32_t offset,
2503 Condition cond) {
2504 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2505 CHECK_NE(base, IP);
2506 LoadImmediate(IP, offset, cond);
2507 add(IP, IP, ShifterOperand(base), cond);
2508 base = IP;
2509 offset = 0;
2510 }
2511 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2512 vstrd(reg, Address(base, offset), cond);
2513}
2514
2515
2516void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2517 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
2518#if ANDROID_SMP != 0
2519 int32_t encoding = 0xf3bf8f5f; // dmb in T1 encoding.
2520 Emit32(encoding);
2521#endif
2522}
2523
2524
2525void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002526 if (force_32bit_branches_) {
2527 cmp(r, ShifterOperand(0));
2528 b(label, EQ);
2529 } else {
2530 cbz(r, label);
2531 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002532}
2533
2534
2535void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002536 if (force_32bit_branches_) {
2537 cmp(r, ShifterOperand(0));
2538 b(label, NE);
2539 } else {
2540 cbnz(r, label);
2541 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002542}
2543} // namespace arm
2544} // namespace art