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