blob: 0920a3f59f006d8020b24526dc04bf343f274732 [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
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +000028bool Thumb2Assembler::ShifterOperandCanHold(Register rd,
29 Register rn,
30 Opcode opcode,
31 uint32_t immediate,
32 ShifterOperand* shifter_op) {
33 shifter_op->type_ = ShifterOperand::kImmediate;
34 shifter_op->immed_ = immediate;
35 shifter_op->is_shift_ = false;
36 shifter_op->is_rotate_ = false;
37 switch (opcode) {
38 case ADD:
39 case SUB:
40 if (rn == SP) {
41 if (rd == SP) {
42 return immediate < (1 << 9); // 9 bits allowed.
43 } else {
44 return immediate < (1 << 12); // 12 bits.
45 }
46 }
47 if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done.
48 return true;
49 }
50 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
51
52 case MOV:
53 // TODO: Support less than or equal to 12bits.
54 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
55 case MVN:
56 default:
57 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
58 }
59}
60
Dave Allison65fcc2c2014-04-28 13:45:27 -070061void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so,
62 Condition cond) {
63 EmitDataProcessing(cond, AND, 0, rn, rd, so);
64}
65
66
67void Thumb2Assembler::eor(Register rd, Register rn, const ShifterOperand& so,
68 Condition cond) {
69 EmitDataProcessing(cond, EOR, 0, rn, rd, so);
70}
71
72
73void Thumb2Assembler::sub(Register rd, Register rn, const ShifterOperand& so,
74 Condition cond) {
75 EmitDataProcessing(cond, SUB, 0, rn, rd, so);
76}
77
78
79void Thumb2Assembler::rsb(Register rd, Register rn, const ShifterOperand& so,
80 Condition cond) {
81 EmitDataProcessing(cond, RSB, 0, rn, rd, so);
82}
83
84
85void Thumb2Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so,
86 Condition cond) {
87 EmitDataProcessing(cond, RSB, 1, rn, rd, so);
88}
89
90
91void Thumb2Assembler::add(Register rd, Register rn, const ShifterOperand& so,
92 Condition cond) {
93 EmitDataProcessing(cond, ADD, 0, rn, rd, so);
94}
95
96
97void Thumb2Assembler::adds(Register rd, Register rn, const ShifterOperand& so,
98 Condition cond) {
99 EmitDataProcessing(cond, ADD, 1, rn, rd, so);
100}
101
102
103void Thumb2Assembler::subs(Register rd, Register rn, const ShifterOperand& so,
104 Condition cond) {
105 EmitDataProcessing(cond, SUB, 1, rn, rd, so);
106}
107
108
109void Thumb2Assembler::adc(Register rd, Register rn, const ShifterOperand& so,
110 Condition cond) {
111 EmitDataProcessing(cond, ADC, 0, rn, rd, so);
112}
113
114
115void Thumb2Assembler::sbc(Register rd, Register rn, const ShifterOperand& so,
116 Condition cond) {
117 EmitDataProcessing(cond, SBC, 0, rn, rd, so);
118}
119
120
121void Thumb2Assembler::rsc(Register rd, Register rn, const ShifterOperand& so,
122 Condition cond) {
123 EmitDataProcessing(cond, RSC, 0, rn, rd, so);
124}
125
126
127void Thumb2Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) {
128 CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker.
129 EmitDataProcessing(cond, TST, 1, rn, R0, so);
130}
131
132
133void Thumb2Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) {
134 CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker.
135 EmitDataProcessing(cond, TEQ, 1, rn, R0, so);
136}
137
138
139void Thumb2Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) {
140 EmitDataProcessing(cond, CMP, 1, rn, R0, so);
141}
142
143
144void Thumb2Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) {
145 EmitDataProcessing(cond, CMN, 1, rn, R0, so);
146}
147
148
149void Thumb2Assembler::orr(Register rd, Register rn,
150 const ShifterOperand& so, Condition cond) {
151 EmitDataProcessing(cond, ORR, 0, rn, rd, so);
152}
153
154
155void Thumb2Assembler::orrs(Register rd, Register rn,
156 const ShifterOperand& so, Condition cond) {
157 EmitDataProcessing(cond, ORR, 1, rn, rd, so);
158}
159
160
161void Thumb2Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) {
162 EmitDataProcessing(cond, MOV, 0, R0, rd, so);
163}
164
165
166void Thumb2Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) {
167 EmitDataProcessing(cond, MOV, 1, R0, rd, so);
168}
169
170
171void Thumb2Assembler::bic(Register rd, Register rn, const ShifterOperand& so,
172 Condition cond) {
173 EmitDataProcessing(cond, BIC, 0, rn, rd, so);
174}
175
176
177void Thumb2Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) {
178 EmitDataProcessing(cond, MVN, 0, R0, rd, so);
179}
180
181
182void Thumb2Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) {
183 EmitDataProcessing(cond, MVN, 1, R0, rd, so);
184}
185
186
187void Thumb2Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700188 CheckCondition(cond);
189
Dave Allison65fcc2c2014-04-28 13:45:27 -0700190 if (rd == rm && !IsHighRegister(rd) && !IsHighRegister(rn) && !force_32bit_) {
191 // 16 bit.
192 int16_t encoding = B14 | B9 | B8 | B6 |
193 rn << 3 | rd;
194 Emit16(encoding);
195 } else {
196 // 32 bit.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700197 uint32_t op1 = 0U /* 0b000 */;
198 uint32_t op2 = 0U /* 0b00 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700199 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
200 op1 << 20 |
201 B15 | B14 | B13 | B12 |
202 op2 << 4 |
203 static_cast<uint32_t>(rd) << 8 |
204 static_cast<uint32_t>(rn) << 16 |
205 static_cast<uint32_t>(rm);
206
207 Emit32(encoding);
208 }
209}
210
211
212void Thumb2Assembler::mla(Register rd, Register rn, Register rm, Register ra,
213 Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700214 CheckCondition(cond);
215
Andreas Gampec8ccf682014-09-29 20:07:43 -0700216 uint32_t op1 = 0U /* 0b000 */;
217 uint32_t op2 = 0U /* 0b00 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700218 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
219 op1 << 20 |
220 op2 << 4 |
221 static_cast<uint32_t>(rd) << 8 |
222 static_cast<uint32_t>(ra) << 12 |
223 static_cast<uint32_t>(rn) << 16 |
224 static_cast<uint32_t>(rm);
225
226 Emit32(encoding);
227}
228
229
230void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra,
231 Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700232 CheckCondition(cond);
233
Andreas Gampec8ccf682014-09-29 20:07:43 -0700234 uint32_t op1 = 0U /* 0b000 */;
235 uint32_t op2 = 01 /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700236 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
237 op1 << 20 |
238 op2 << 4 |
239 static_cast<uint32_t>(rd) << 8 |
240 static_cast<uint32_t>(ra) << 12 |
241 static_cast<uint32_t>(rn) << 16 |
242 static_cast<uint32_t>(rm);
243
244 Emit32(encoding);
245}
246
247
248void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
249 Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700250 CheckCondition(cond);
251
Andreas Gampec8ccf682014-09-29 20:07:43 -0700252 uint32_t op1 = 2U /* 0b010; */;
253 uint32_t op2 = 0U /* 0b0000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700254 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
255 op1 << 20 |
256 op2 << 4 |
257 static_cast<uint32_t>(rd_lo) << 12 |
258 static_cast<uint32_t>(rd_hi) << 8 |
259 static_cast<uint32_t>(rn) << 16 |
260 static_cast<uint32_t>(rm);
261
262 Emit32(encoding);
263}
264
265
266void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700267 CheckCondition(cond);
268
Andreas Gampec8ccf682014-09-29 20:07:43 -0700269 uint32_t op1 = 1U /* 0b001 */;
270 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700271 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 |
272 op1 << 20 |
273 op2 << 4 |
274 0xf << 12 |
275 static_cast<uint32_t>(rd) << 8 |
276 static_cast<uint32_t>(rn) << 16 |
277 static_cast<uint32_t>(rm);
278
279 Emit32(encoding);
280}
281
282
283void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700284 CheckCondition(cond);
285
Andreas Gampec8ccf682014-09-29 20:07:43 -0700286 uint32_t op1 = 1U /* 0b001 */;
287 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700288 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 |
289 op1 << 20 |
290 op2 << 4 |
291 0xf << 12 |
292 static_cast<uint32_t>(rd) << 8 |
293 static_cast<uint32_t>(rn) << 16 |
294 static_cast<uint32_t>(rm);
295
296 Emit32(encoding);
297}
298
299
Roland Levillain51d3fc42014-11-13 14:11:42 +0000300void Thumb2Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
301 CheckCondition(cond);
302 CHECK_LE(lsb, 31U);
303 CHECK(1U <= width && width <= 32U) << width;
304 uint32_t widthminus1 = width - 1;
305 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
306 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
307
308 uint32_t op = 20U /* 0b10100 */;
309 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
310 op << 20 |
311 static_cast<uint32_t>(rn) << 16 |
312 imm3 << 12 |
313 static_cast<uint32_t>(rd) << 8 |
314 imm2 << 6 |
315 widthminus1;
316
317 Emit32(encoding);
318}
319
320
Roland Levillain981e4542014-11-14 11:47:14 +0000321void Thumb2Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
322 CheckCondition(cond);
323 CHECK_LE(lsb, 31U);
324 CHECK(1U <= width && width <= 32U) << width;
325 uint32_t widthminus1 = width - 1;
326 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
327 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
328
329 uint32_t op = 28U /* 0b11100 */;
330 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
331 op << 20 |
332 static_cast<uint32_t>(rn) << 16 |
333 imm3 << 12 |
334 static_cast<uint32_t>(rd) << 8 |
335 imm2 << 6 |
336 widthminus1;
337
338 Emit32(encoding);
339}
340
341
Dave Allison65fcc2c2014-04-28 13:45:27 -0700342void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
343 EmitLoadStore(cond, true, false, false, false, rd, ad);
344}
345
346
347void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
348 EmitLoadStore(cond, false, false, false, false, rd, ad);
349}
350
351
352void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
353 EmitLoadStore(cond, true, true, false, false, rd, ad);
354}
355
356
357void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
358 EmitLoadStore(cond, false, true, false, false, rd, ad);
359}
360
361
362void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
363 EmitLoadStore(cond, true, false, true, false, rd, ad);
364}
365
366
367void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
368 EmitLoadStore(cond, false, false, true, false, rd, ad);
369}
370
371
372void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
373 EmitLoadStore(cond, true, true, false, true, rd, ad);
374}
375
376
377void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
378 EmitLoadStore(cond, true, false, true, true, rd, ad);
379}
380
381
382void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700383 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700384 CHECK_EQ(rd % 2, 0);
385 // This is different from other loads. The encoding is like ARM.
386 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
387 static_cast<int32_t>(rd) << 12 |
388 (static_cast<int32_t>(rd) + 1) << 8 |
389 ad.encodingThumbLdrdStrd();
390 Emit32(encoding);
391}
392
393
394void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700395 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700396 CHECK_EQ(rd % 2, 0);
397 // This is different from other loads. The encoding is like ARM.
398 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
399 static_cast<int32_t>(rd) << 12 |
400 (static_cast<int32_t>(rd) + 1) << 8 |
401 ad.encodingThumbLdrdStrd();
402 Emit32(encoding);
403}
404
405
406void Thumb2Assembler::ldm(BlockAddressMode am,
407 Register base,
408 RegList regs,
409 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000410 CHECK_NE(regs, 0u); // Do not use ldm if there's nothing to load.
411 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700412 // Thumb doesn't support one reg in the list.
413 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000414 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700415 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700416 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700417 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
418 } else {
419 EmitMultiMemOp(cond, am, true, base, regs);
420 }
421}
422
423
424void Thumb2Assembler::stm(BlockAddressMode am,
425 Register base,
426 RegList regs,
427 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000428 CHECK_NE(regs, 0u); // Do not use stm if there's nothing to store.
429 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700430 // Thumb doesn't support one reg in the list.
431 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000432 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700433 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700434 CHECK(am == IA || am == IA_W);
435 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700436 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
437 } else {
438 EmitMultiMemOp(cond, am, false, base, regs);
439 }
440}
441
442
443bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
444 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
445 if (((imm32 & ((1 << 19) - 1)) == 0) &&
446 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
447 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
448 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
449 ((imm32 >> 19) & ((1 << 6) -1));
450 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
451 sd, S0, S0);
452 return true;
453 }
454 return false;
455}
456
457
458bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
459 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
460 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
461 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
462 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
463 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
464 ((imm64 >> 48) & ((1 << 6) -1));
465 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
466 dd, D0, D0);
467 return true;
468 }
469 return false;
470}
471
472
473void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
474 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
475}
476
477
478void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
479 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
480}
481
482
483void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
484 Condition cond) {
485 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
486}
487
488
489void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
490 Condition cond) {
491 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
492}
493
494
495void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
496 Condition cond) {
497 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
498}
499
500
501void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
502 Condition cond) {
503 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
504}
505
506
507void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
508 Condition cond) {
509 EmitVFPsss(cond, B21, sd, sn, sm);
510}
511
512
513void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
514 Condition cond) {
515 EmitVFPddd(cond, B21, dd, dn, dm);
516}
517
518
519void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
520 Condition cond) {
521 EmitVFPsss(cond, 0, sd, sn, sm);
522}
523
524
525void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
526 Condition cond) {
527 EmitVFPddd(cond, 0, dd, dn, dm);
528}
529
530
531void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
532 Condition cond) {
533 EmitVFPsss(cond, B6, sd, sn, sm);
534}
535
536
537void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
538 Condition cond) {
539 EmitVFPddd(cond, B6, dd, dn, dm);
540}
541
542
543void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
544 Condition cond) {
545 EmitVFPsss(cond, B23, sd, sn, sm);
546}
547
548
549void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
550 Condition cond) {
551 EmitVFPddd(cond, B23, dd, dn, dm);
552}
553
554
555void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
556 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
557}
558
559
560void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
561 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
562}
563
564
565void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
566 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
567}
568
569
570void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
571 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
572}
573
574
575void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
576 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
577}
578
579void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
580 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
581}
582
583
584void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
585 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
586}
587
588
589void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
590 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
591}
592
593
594void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
595 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
596}
597
598
599void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
600 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
601}
602
603
604void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
605 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
606}
607
608
609void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
610 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
611}
612
613
614void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
615 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
616}
617
618
619void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
620 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
621}
622
623
624void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
625 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
626}
627
628
629void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
630 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
631}
632
633
634void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
635 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
636}
637
638
639void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
640 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
641}
642
643
644void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
645 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
646}
647
648
649void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
650 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
651}
652
653void Thumb2Assembler::b(Label* label, Condition cond) {
654 EmitBranch(cond, label, false, false);
655}
656
657
658void Thumb2Assembler::bl(Label* label, Condition cond) {
659 CheckCondition(cond);
660 EmitBranch(cond, label, true, false);
661}
662
663
664void Thumb2Assembler::blx(Label* label) {
665 EmitBranch(AL, label, true, true);
666}
667
668
669void Thumb2Assembler::MarkExceptionHandler(Label* label) {
670 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
671 Label l;
672 b(&l);
673 EmitBranch(AL, label, false, false);
674 Bind(&l);
675}
676
677
678void Thumb2Assembler::Emit32(int32_t value) {
679 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
680 buffer_.Emit<int16_t>(value >> 16);
681 buffer_.Emit<int16_t>(value & 0xffff);
682}
683
684
685void Thumb2Assembler::Emit16(int16_t value) {
686 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
687 buffer_.Emit<int16_t>(value);
688}
689
690
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700691bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700692 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700693 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700694 Register rn,
695 Register rd,
696 const ShifterOperand& so) {
697 if (force_32bit_) {
698 return true;
699 }
700
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000701 // Check special case for SP relative ADD and SUB immediate.
702 if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) {
703 // If the immediate is in range, use 16 bit.
704 if (rd == SP) {
705 if (so.GetImmediate() < (1 << 9)) { // 9 bit immediate.
706 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700707 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000708 } else if (!IsHighRegister(rd) && opcode == ADD) {
709 if (so.GetImmediate() < (1 << 10)) { // 10 bit immediate.
710 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700711 }
712 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000713 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700714
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000715 bool can_contain_high_register = (opcode == MOV)
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800716 || ((opcode == ADD) && (rn == rd) && !set_cc);
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000717
718 if (IsHighRegister(rd) || IsHighRegister(rn)) {
719 if (!can_contain_high_register) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700720 return true;
721 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100722
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000723 // There are high register instructions available for this opcode.
724 // However, there is no actual shift available, neither for ADD nor for MOV (ASR/LSR/LSL/ROR).
725 if (so.IsShift() && (so.GetShift() == RRX || so.GetImmediate() != 0u)) {
726 return true;
727 }
728
729 // The ADD and MOV instructions that work with high registers don't have 16-bit
730 // immediate variants.
731 if (so.IsImmediate()) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100732 return true;
733 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700734 }
735
736 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
737 return true;
738 }
739
740 // Check for MOV with an ROR.
741 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
742 if (so.GetImmediate() != 0) {
743 return true;
744 }
745 }
746
747 bool rn_is_valid = true;
748
749 // Check for single operand instructions and ADD/SUB.
750 switch (opcode) {
751 case CMP:
752 case MOV:
753 case TST:
754 case MVN:
755 rn_is_valid = false; // There is no Rn for these instructions.
756 break;
757 case TEQ:
758 return true;
759 break;
760 case ADD:
761 case SUB:
762 break;
763 default:
764 if (so.IsRegister() && rd != rn) {
765 return true;
766 }
767 }
768
769 if (so.IsImmediate()) {
770 if (rn_is_valid && rn != rd) {
771 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
772 // immediate must be 3 bits.
773 if (opcode != ADD && opcode != SUB) {
774 return true;
775 } else {
776 // Check that the immediate is 3 bits for ADD and SUB.
777 if (so.GetImmediate() >= 8) {
778 return true;
779 }
780 }
781 } else {
782 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
783 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
784 return true;
785 } else {
786 if (so.GetImmediate() > 255) {
787 return true;
788 }
789 }
790 }
791 }
792
793 // The instruction can be encoded in 16 bits.
794 return false;
795}
796
797
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700798void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700799 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700800 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700801 Register rn,
802 Register rd,
803 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700804 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700805 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700806 case AND: thumb_opcode = 0U /* 0b0000 */; break;
807 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
808 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
809 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
810 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700811 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700812 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700813 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700814 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
815 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
816 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
817 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
818 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
819 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
820 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
821 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700822 default:
823 break;
824 }
825
Andreas Gampec8ccf682014-09-29 20:07:43 -0700826 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700827 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000828 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700829 }
830
831 int32_t encoding = 0;
832 if (so.IsImmediate()) {
833 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100834 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700835 if (opcode == SUB) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700836 thumb_opcode = 5U /* 0b0101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700837 } else {
838 thumb_opcode = 0;
839 }
840 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700841
842 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700843 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700844 uint32_t imm8 = imm & 0xff;
845
846 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700847 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100848 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700849 rd << 8 |
850 i << 26 |
851 imm3 << 12 |
852 imm8;
853 } else {
854 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700855 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700856 if (imm == kInvalidModifiedImmediate) {
857 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
Vladimir Markoe8469c12014-11-26 18:09:30 +0000858 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700859 }
860 encoding = B31 | B30 | B29 | B28 |
861 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700862 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700863 rn << 16 |
864 rd << 8 |
865 imm;
866 }
867 } else if (so.IsRegister()) {
868 // Register (possibly shifted)
869 encoding = B31 | B30 | B29 | B27 | B25 |
870 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700871 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700872 rn << 16 |
873 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700874 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700875 }
876 Emit32(encoding);
877}
878
879
880void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
881 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700882 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700883 Register rn,
884 Register rd,
885 const ShifterOperand& so) {
886 if (opcode == ADD || opcode == SUB) {
887 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
888 return;
889 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700890 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700891 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700892 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700893 uint8_t opcode_shift = 6;
894 uint8_t rd_shift = 0;
895 uint8_t rn_shift = 3;
896 uint8_t immediate_shift = 0;
897 bool use_immediate = false;
898 uint8_t immediate = 0;
899
900 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
901 // Convert shifted mov operand2 into 16 bit opcodes.
902 dp_opcode = 0;
903 opcode_shift = 11;
904
905 use_immediate = true;
906 immediate = so.GetImmediate();
907 immediate_shift = 6;
908
909 rn = so.GetRegister();
910
911 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700912 case LSL: thumb_opcode = 0U /* 0b00 */; break;
913 case LSR: thumb_opcode = 1U /* 0b01 */; break;
914 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700915 case ROR:
916 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700917 thumb_opcode = 7U /* 0b111 */;
918 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700919 opcode_shift = 6;
920 use_immediate = false;
921 break;
922 case RRX: break;
923 default:
924 break;
925 }
926 } else {
927 if (so.IsImmediate()) {
928 use_immediate = true;
929 immediate = so.GetImmediate();
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800930 } else {
931 // Adjust rn and rd: only two registers will be emitted.
932 switch (opcode) {
933 case AND:
934 case ORR:
935 case EOR:
936 case RSB:
937 case ADC:
938 case SBC:
939 case BIC: {
940 if (rn == rd) {
941 rn = so.GetRegister();
942 } else {
943 CHECK_EQ(rd, so.GetRegister());
944 }
945 break;
946 }
947 case CMP:
948 case CMN: {
949 CHECK_EQ(rd, 0);
950 rd = rn;
951 rn = so.GetRegister();
952 break;
953 }
Andreas Gampe7b7e5242015-02-02 19:17:11 -0800954 case TST:
955 case TEQ:
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800956 case MVN: {
957 CHECK_EQ(rn, 0);
958 rn = so.GetRegister();
959 break;
960 }
961 default:
962 break;
963 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700964 }
965
966 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700967 case AND: thumb_opcode = 0U /* 0b0000 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800968 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700969 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700970 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700971 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
972 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800973 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
974 case TST: thumb_opcode = 8U /* 0b1000 */; CHECK(!use_immediate); break;
975 case MVN: thumb_opcode = 15U /* 0b1111 */; CHECK(!use_immediate); break;
976 case CMP: {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700977 if (use_immediate) {
978 // T2 encoding.
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800979 dp_opcode = 0;
980 opcode_shift = 11;
981 thumb_opcode = 5U /* 0b101 */;
982 rd_shift = 8;
983 rn_shift = 8;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700984 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700985 thumb_opcode = 10U /* 0b1010 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700986 }
987
988 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800989 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100990 case CMN: {
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800991 CHECK(!use_immediate);
Andreas Gampec8ccf682014-09-29 20:07:43 -0700992 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100993 break;
994 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700995 case MOV:
996 dp_opcode = 0;
997 if (use_immediate) {
998 // T2 encoding.
999 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001000 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001001 rd_shift = 8;
1002 rn_shift = 8;
1003 } else {
1004 rn = so.GetRegister();
1005 if (IsHighRegister(rn) || IsHighRegister(rd)) {
1006 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001007 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001008 opcode_shift = 7;
1009 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001010 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
1011 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001012 } else {
1013 thumb_opcode = 0;
1014 }
1015 }
1016 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001017
1018 case TEQ:
1019 case RSC:
Dave Allison65fcc2c2014-04-28 13:45:27 -07001020 default:
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001021 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001022 break;
1023 }
1024 }
1025
Andreas Gampec8ccf682014-09-29 20:07:43 -07001026 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001027 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001028 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001029 }
1030
1031 int16_t encoding = dp_opcode << 14 |
1032 (thumb_opcode << opcode_shift) |
1033 rd << rd_shift |
1034 rn << rn_shift |
1035 (use_immediate ? (immediate << immediate_shift) : 0);
1036
1037 Emit16(encoding);
1038}
1039
1040
1041// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001042void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001043 Opcode opcode,
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001044 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001045 Register rn,
1046 Register rd,
1047 const ShifterOperand& so) {
1048 uint8_t dp_opcode = 0;
1049 uint8_t opcode_shift = 6;
1050 uint8_t rd_shift = 0;
1051 uint8_t rn_shift = 3;
1052 uint8_t immediate_shift = 0;
1053 bool use_immediate = false;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001054 uint32_t immediate = 0; // Should be at most 9 bits but keep the full immediate for CHECKs.
Dave Allison65fcc2c2014-04-28 13:45:27 -07001055 uint8_t thumb_opcode;;
1056
1057 if (so.IsImmediate()) {
1058 use_immediate = true;
1059 immediate = so.GetImmediate();
1060 }
1061
1062 switch (opcode) {
1063 case ADD:
1064 if (so.IsRegister()) {
1065 Register rm = so.GetRegister();
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001066 if (rn == rd && !set_cc) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001067 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001068 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001069 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001070 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001071 // Make Rn also contain the top bit of rd.
1072 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001073 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1074 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001075 } else {
1076 // T1.
1077 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001078 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001079 immediate = static_cast<uint32_t>(so.GetRegister());
1080 use_immediate = true;
1081 immediate_shift = 6;
1082 }
1083 } else {
1084 // Immediate.
1085 if (rd == SP && rn == SP) {
1086 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001087 dp_opcode = 2U /* 0b10 */;
1088 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001089 opcode_shift = 12;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001090 CHECK_LT(immediate, (1u << 9));
1091 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001092
1093 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1094 rn = R0;
1095 rd = R0;
1096 rd_shift = 0;
1097 rn_shift = 0;
1098 immediate >>= 2;
1099 } else if (rd != SP && rn == SP) {
1100 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001101 dp_opcode = 2U /* 0b10 */;
1102 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001103 opcode_shift = 11;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001104 CHECK_LT(immediate, (1u << 10));
1105 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001106
1107 // Remove rn from instruction.
1108 rn = R0;
1109 rn_shift = 0;
1110 rd_shift = 8;
1111 immediate >>= 2;
1112 } else if (rn != rd) {
1113 // Must use T1.
1114 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001115 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001116 immediate_shift = 6;
1117 } else {
1118 // T2 encoding.
1119 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001120 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001121 rd_shift = 8;
1122 rn_shift = 8;
1123 }
1124 }
1125 break;
1126
1127 case SUB:
1128 if (so.IsRegister()) {
1129 // T1.
1130 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001131 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001132 immediate = static_cast<uint32_t>(so.GetRegister());
1133 use_immediate = true;
1134 immediate_shift = 6;
1135 } else {
1136 if (rd == SP && rn == SP) {
1137 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001138 dp_opcode = 2U /* 0b10 */;
1139 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001140 opcode_shift = 7;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001141 CHECK_LT(immediate, (1u << 9));
1142 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001143
1144 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1145 rn = R0;
1146 rd = R0;
1147 rd_shift = 0;
1148 rn_shift = 0;
1149 immediate >>= 2;
1150 } else if (rn != rd) {
1151 // Must use T1.
1152 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001153 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001154 immediate_shift = 6;
1155 } else {
1156 // T2 encoding.
1157 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001158 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001159 rd_shift = 8;
1160 rn_shift = 8;
1161 }
1162 }
1163 break;
1164 default:
1165 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001166 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001167 }
1168
1169 int16_t encoding = dp_opcode << 14 |
1170 (thumb_opcode << opcode_shift) |
1171 rd << rd_shift |
1172 rn << rn_shift |
1173 (use_immediate ? (immediate << immediate_shift) : 0);
1174
1175 Emit16(encoding);
1176}
1177
1178
1179void Thumb2Assembler::EmitDataProcessing(Condition cond,
1180 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001181 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001182 Register rn,
1183 Register rd,
1184 const ShifterOperand& so) {
1185 CHECK_NE(rd, kNoRegister);
1186 CheckCondition(cond);
1187
1188 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1189 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1190 } else {
1191 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1192 }
1193}
1194
Dave Allison45fdb932014-06-25 12:37:10 -07001195void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1196 CHECK_LT(amount, (1 << 5));
1197 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1198 uint16_t opcode = 0;
1199 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001200 case LSL: opcode = 0U /* 0b00 */; break;
1201 case LSR: opcode = 1U /* 0b01 */; break;
1202 case ASR: opcode = 2U /* 0b10 */; break;
1203 case ROR: opcode = 3U /* 0b11 */; break;
1204 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001205 default:
1206 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001207 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001208 }
1209 // 32 bit.
1210 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1211 0xf << 16 | (setcc ? B20 : 0);
1212 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001213 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001214 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1215 static_cast<int16_t>(rd) << 8 | opcode << 4;
1216 Emit32(encoding);
1217 } else {
1218 // 16 bit shift
1219 uint16_t opcode = 0;
1220 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001221 case LSL: opcode = 0U /* 0b00 */; break;
1222 case LSR: opcode = 1U /* 0b01 */; break;
1223 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001224 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001225 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1226 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001227 }
1228 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1229 static_cast<int16_t>(rd);
1230 Emit16(encoding);
1231 }
1232}
1233
1234void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1235 CHECK_NE(shift, RRX);
1236 bool must_be_32bit = false;
1237 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1238 must_be_32bit = true;
1239 }
1240
1241 if (must_be_32bit) {
1242 uint16_t opcode = 0;
1243 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001244 case LSL: opcode = 0U /* 0b00 */; break;
1245 case LSR: opcode = 1U /* 0b01 */; break;
1246 case ASR: opcode = 2U /* 0b10 */; break;
1247 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001248 default:
1249 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001250 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001251 }
1252 // 32 bit.
1253 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1254 0xf << 12 | (setcc ? B20 : 0);
1255 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1256 static_cast<int16_t>(rd) << 8 | opcode << 21;
1257 Emit32(encoding);
1258 } else {
1259 uint16_t opcode = 0;
1260 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001261 case LSL: opcode = 2U /* 0b0010 */; break;
1262 case LSR: opcode = 3U /* 0b0011 */; break;
1263 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001264 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001265 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1266 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001267 }
1268 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1269 static_cast<int16_t>(rd);
1270 Emit16(encoding);
1271 }
1272}
1273
1274
Dave Allison65fcc2c2014-04-28 13:45:27 -07001275
1276void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1277 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1278 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1279 int32_t offset = target_ - location_;
1280
1281 if (size_ == k32Bit) {
1282 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1283 if (link) {
1284 // BL or BLX immediate.
1285 encoding |= B14;
1286 if (!x) {
1287 encoding |= B12;
1288 } else {
1289 // Bottom bit of offset must be 0.
1290 CHECK_EQ((offset & 1), 0);
1291 }
1292 } else {
1293 if (x) {
1294 LOG(FATAL) << "Invalid use of BX";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001295 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001296 } else {
1297 if (cond_ == AL) {
1298 // Can use the T4 encoding allowing a 24 bit offset.
1299 if (!x) {
1300 encoding |= B12;
1301 }
1302 } else {
1303 // Must be T3 encoding with a 20 bit offset.
1304 encoding |= cond_ << 22;
1305 }
1306 }
1307 }
1308 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1309 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1310 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1311 } else {
1312 if (IsCompareAndBranch()) {
1313 offset -= 4;
1314 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001315 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001316 int16_t encoding = B15 | B13 | B12 |
1317 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1318 static_cast<uint32_t>(rn_) |
1319 B8 |
1320 i << 9 |
1321 imm5 << 3;
1322 buffer->Store<int16_t>(location_, encoding);
1323 } else {
1324 offset -= 4; // Account for PC offset.
1325 int16_t encoding;
1326 // 16 bit.
1327 if (cond_ == AL) {
1328 encoding = B15 | B14 | B13 |
1329 ((offset >> 1) & 0x7ff);
1330 } else {
1331 encoding = B15 | B14 | B12 |
1332 cond_ << 8 | ((offset >> 1) & 0xff);
1333 }
1334 buffer->Store<int16_t>(location_, encoding);
1335 }
1336 }
1337}
1338
1339
1340uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1341 uint32_t location = buffer_.Size();
1342
1343 // This is always unresolved as it must be a forward branch.
1344 Emit16(prev); // Previous link.
1345 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1346 location, rn);
1347}
1348
1349
1350// NOTE: this only support immediate offsets, not [rx,ry].
1351// TODO: support [rx,ry] instructions.
1352void Thumb2Assembler::EmitLoadStore(Condition cond,
1353 bool load,
1354 bool byte,
1355 bool half,
1356 bool is_signed,
1357 Register rd,
1358 const Address& ad) {
1359 CHECK_NE(rd, kNoRegister);
1360 CheckCondition(cond);
1361 bool must_be_32bit = force_32bit_;
1362 if (IsHighRegister(rd)) {
1363 must_be_32bit = true;
1364 }
1365
1366 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001367 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001368 must_be_32bit = true;
1369 }
1370
1371 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1372 must_be_32bit = true;
1373 }
1374
Dave Allison45fdb932014-06-25 12:37:10 -07001375 if (ad.IsImmediate()) {
1376 // Immediate offset
1377 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001378
Dave Allison45fdb932014-06-25 12:37:10 -07001379 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001380 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001381 must_be_32bit = true;
1382 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001383
1384 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001385 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001386 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001387 must_be_32bit = true;
1388 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001389 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001390 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001391 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001392 must_be_32bit = true;
1393 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001394 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001395 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001396 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001397 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001398 }
1399 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001400
Dave Allison45fdb932014-06-25 12:37:10 -07001401 if (must_be_32bit) {
1402 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1403 (load ? B20 : 0) |
1404 (is_signed ? B24 : 0) |
1405 static_cast<uint32_t>(rd) << 12 |
1406 ad.encodingThumb(true) |
1407 (byte ? 0 : half ? B21 : B22);
1408 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001409 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001410 // 16 bit thumb1.
1411 uint8_t opA = 0;
1412 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001413
1414 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001415 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001416 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001417 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001418 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001419 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001420 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001421 sp_relative = true;
1422 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001423 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001424 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001425 }
Dave Allison45fdb932014-06-25 12:37:10 -07001426 int16_t encoding = opA << 12 |
1427 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001428
Dave Allison45fdb932014-06-25 12:37:10 -07001429 CHECK_GE(offset, 0);
1430 if (sp_relative) {
1431 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001432 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001433 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001434 encoding |= rd << 8 | offset >> 2;
1435 } else {
1436 // No SP relative. The offset is shifted right depending on
1437 // the size of the load/store.
1438 encoding |= static_cast<uint32_t>(rd);
1439
1440 if (byte) {
1441 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001442 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001443 } else if (half) {
1444 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001445 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001446 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001447 offset >>= 1;
1448 } else {
1449 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001450 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001451 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001452 offset >>= 2;
1453 }
1454 encoding |= rn << 3 | offset << 6;
1455 }
1456
1457 Emit16(encoding);
1458 }
1459 } else {
1460 // Register shift.
1461 if (ad.GetRegister() == PC) {
1462 // PC relative literal encoding.
1463 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001464 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001465 int32_t up = B23;
1466 if (offset < 0) {
1467 offset = -offset;
1468 up = 0;
1469 }
1470 CHECK_LT(offset, (1 << 12));
1471 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1472 offset | up |
1473 static_cast<uint32_t>(rd) << 12;
1474 Emit32(encoding);
1475 } else {
1476 // 16 bit literal load.
1477 CHECK_GE(offset, 0);
1478 CHECK_LT(offset, (1 << 10));
1479 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1480 Emit16(encoding);
1481 }
1482 } else {
1483 if (ad.GetShiftCount() != 0) {
1484 // If there is a shift count this must be 32 bit.
1485 must_be_32bit = true;
1486 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1487 must_be_32bit = true;
1488 }
1489
1490 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001491 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001492 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001493 if (half) {
1494 encoding |= B21;
1495 } else if (!byte) {
1496 encoding |= B22;
1497 }
Dave Allison45fdb932014-06-25 12:37:10 -07001498 Emit32(encoding);
1499 } else {
1500 // 16 bit register offset.
1501 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1502 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001503 if (byte) {
1504 encoding |= B10;
1505 } else if (half) {
1506 encoding |= B9;
1507 }
Dave Allison45fdb932014-06-25 12:37:10 -07001508 Emit16(encoding);
1509 }
1510 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001511 }
1512}
1513
1514
1515void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001516 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001517 bool load,
1518 Register base,
1519 RegList regs) {
1520 CHECK_NE(base, kNoRegister);
1521 CheckCondition(cond);
1522 bool must_be_32bit = force_32bit_;
1523
Vladimir Markoe8469c12014-11-26 18:09:30 +00001524 if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
1525 (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
1526 // Use 16-bit PUSH/POP.
1527 int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
1528 ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
1529 Emit16(encoding);
1530 return;
1531 }
1532
Dave Allison65fcc2c2014-04-28 13:45:27 -07001533 if ((regs & 0xff00) != 0) {
1534 must_be_32bit = true;
1535 }
1536
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001537 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001538 // 16 bit always uses writeback.
1539 if (!w_bit) {
1540 must_be_32bit = true;
1541 }
1542
1543 if (must_be_32bit) {
1544 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001545 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001546 case IA:
1547 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001548 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001549 break;
1550 case DB:
1551 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001552 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001553 break;
1554 case DA:
1555 case IB:
1556 case DA_W:
1557 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001558 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001559 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001560 }
1561 if (load) {
1562 // Cannot have SP in the list.
1563 CHECK_EQ((regs & (1 << SP)), 0);
1564 } else {
1565 // Cannot have PC or SP in the list.
1566 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1567 }
1568 int32_t encoding = B31 | B30 | B29 | B27 |
1569 (op << 23) |
1570 (load ? B20 : 0) |
1571 base << 16 |
1572 regs |
1573 (w_bit << 21);
1574 Emit32(encoding);
1575 } else {
1576 int16_t encoding = B15 | B14 |
1577 (load ? B11 : 0) |
1578 base << 8 |
1579 regs;
1580 Emit16(encoding);
1581 }
1582}
1583
1584
1585void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1586 uint32_t pc = buffer_.Size();
1587 Branch::Type branch_type;
1588 if (cond == AL) {
1589 if (link) {
1590 if (x) {
1591 branch_type = Branch::kUnconditionalLinkX; // BLX.
1592 } else {
1593 branch_type = Branch::kUnconditionalLink; // BX.
1594 }
1595 } else {
1596 branch_type = Branch::kUnconditional; // B.
1597 }
1598 } else {
1599 branch_type = Branch::kConditional; // B<cond>.
1600 }
1601
1602 if (label->IsBound()) {
1603 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1604
1605 // The branch is to a bound label which means that it's a backwards branch. We know the
1606 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1607 // branch the size may change if it so happens that other branches change size that change
1608 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1609 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001610 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001611 Emit16(0); // Space for a 16 bit branch.
1612 } else {
1613 Emit32(0); // Space for a 32 bit branch.
1614 }
1615 } else {
1616 // Branch is to an unbound label. Emit space for it.
1617 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001618 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001619 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1620 Emit16(0); // another 16 bits.
1621 } else {
1622 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1623 }
1624 label->LinkTo(branch_id); // Link to the branch ID.
1625 }
1626}
1627
1628
1629void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1630 CHECK_NE(rd, kNoRegister);
1631 CHECK_NE(rm, kNoRegister);
1632 CheckCondition(cond);
1633 CHECK_NE(rd, PC);
1634 CHECK_NE(rm, PC);
1635 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1636 B25 | B23 | B21 | B20 |
1637 static_cast<uint32_t>(rm) << 16 |
1638 0xf << 12 |
1639 static_cast<uint32_t>(rd) << 8 |
1640 B7 |
1641 static_cast<uint32_t>(rm);
1642 Emit32(encoding);
1643}
1644
1645
1646void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1647 CheckCondition(cond);
1648 bool must_be_32bit = force_32bit_;
1649 if (IsHighRegister(rd)|| imm16 >= 256u) {
1650 must_be_32bit = true;
1651 }
1652
1653 if (must_be_32bit) {
1654 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001655 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1656 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1657 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001658 uint32_t imm8 = imm16 & 0xff;
1659 int32_t encoding = B31 | B30 | B29 | B28 |
1660 B25 | B22 |
1661 static_cast<uint32_t>(rd) << 8 |
1662 i << 26 |
1663 imm4 << 16 |
1664 imm3 << 12 |
1665 imm8;
1666 Emit32(encoding);
1667 } else {
1668 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1669 imm16;
1670 Emit16(encoding);
1671 }
1672}
1673
1674
1675void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1676 CheckCondition(cond);
1677 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001678 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1679 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1680 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001681 uint32_t imm8 = imm16 & 0xff;
1682 int32_t encoding = B31 | B30 | B29 | B28 |
1683 B25 | B23 | B22 |
1684 static_cast<uint32_t>(rd) << 8 |
1685 i << 26 |
1686 imm4 << 16 |
1687 imm3 << 12 |
1688 imm8;
1689 Emit32(encoding);
1690}
1691
1692
1693void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1694 CHECK_NE(rn, kNoRegister);
1695 CHECK_NE(rt, kNoRegister);
1696 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001697 CHECK_LT(imm, (1u << 10));
1698
1699 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1700 static_cast<uint32_t>(rn) << 16 |
1701 static_cast<uint32_t>(rt) << 12 |
1702 0xf << 8 |
1703 imm >> 2;
1704 Emit32(encoding);
1705}
1706
1707
1708void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1709 ldrex(rt, rn, 0, cond);
1710}
1711
1712
1713void Thumb2Assembler::strex(Register rd,
1714 Register rt,
1715 Register rn,
1716 uint16_t imm,
1717 Condition cond) {
1718 CHECK_NE(rn, kNoRegister);
1719 CHECK_NE(rd, kNoRegister);
1720 CHECK_NE(rt, kNoRegister);
1721 CheckCondition(cond);
1722 CHECK_LT(imm, (1u << 10));
1723
1724 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1725 static_cast<uint32_t>(rn) << 16 |
1726 static_cast<uint32_t>(rt) << 12 |
1727 static_cast<uint32_t>(rd) << 8 |
1728 imm >> 2;
1729 Emit32(encoding);
1730}
1731
1732
Calin Juravle52c48962014-12-16 17:02:57 +00001733void Thumb2Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
1734 CHECK_NE(rn, kNoRegister);
1735 CHECK_NE(rt, kNoRegister);
1736 CHECK_NE(rt2, kNoRegister);
1737 CHECK_NE(rt, rt2);
1738 CheckCondition(cond);
1739
1740 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 | B20 |
1741 static_cast<uint32_t>(rn) << 16 |
1742 static_cast<uint32_t>(rt) << 12 |
1743 static_cast<uint32_t>(rt2) << 8 |
1744 B6 | B5 | B4 | B3 | B2 | B1 | B0;
1745 Emit32(encoding);
1746}
1747
1748
Dave Allison65fcc2c2014-04-28 13:45:27 -07001749void Thumb2Assembler::strex(Register rd,
1750 Register rt,
1751 Register rn,
1752 Condition cond) {
1753 strex(rd, rt, rn, 0, cond);
1754}
1755
1756
Calin Juravle52c48962014-12-16 17:02:57 +00001757void Thumb2Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
1758 CHECK_NE(rd, kNoRegister);
1759 CHECK_NE(rn, kNoRegister);
1760 CHECK_NE(rt, kNoRegister);
1761 CHECK_NE(rt2, kNoRegister);
1762 CHECK_NE(rt, rt2);
1763 CHECK_NE(rd, rt);
1764 CHECK_NE(rd, rt2);
1765 CheckCondition(cond);
1766
1767 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 |
1768 static_cast<uint32_t>(rn) << 16 |
1769 static_cast<uint32_t>(rt) << 12 |
1770 static_cast<uint32_t>(rt2) << 8 |
1771 B6 | B5 | B4 |
1772 static_cast<uint32_t>(rd);
1773 Emit32(encoding);
1774}
1775
1776
Dave Allison65fcc2c2014-04-28 13:45:27 -07001777void Thumb2Assembler::clrex(Condition cond) {
1778 CheckCondition(cond);
1779 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1780 B21 | B20 |
1781 0xf << 16 |
1782 B15 |
1783 0xf << 8 |
1784 B5 |
1785 0xf;
1786 Emit32(encoding);
1787}
1788
1789
1790void Thumb2Assembler::nop(Condition cond) {
1791 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001792 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001793 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001794 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001795}
1796
1797
1798void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1799 CHECK_NE(sn, kNoSRegister);
1800 CHECK_NE(rt, kNoRegister);
1801 CHECK_NE(rt, SP);
1802 CHECK_NE(rt, PC);
1803 CheckCondition(cond);
1804 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1805 B27 | B26 | B25 |
1806 ((static_cast<int32_t>(sn) >> 1)*B16) |
1807 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1808 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1809 Emit32(encoding);
1810}
1811
1812
1813void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1814 CHECK_NE(sn, kNoSRegister);
1815 CHECK_NE(rt, kNoRegister);
1816 CHECK_NE(rt, SP);
1817 CHECK_NE(rt, PC);
1818 CheckCondition(cond);
1819 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1820 B27 | B26 | B25 | B20 |
1821 ((static_cast<int32_t>(sn) >> 1)*B16) |
1822 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1823 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1824 Emit32(encoding);
1825}
1826
1827
1828void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1829 Condition cond) {
1830 CHECK_NE(sm, kNoSRegister);
1831 CHECK_NE(sm, S31);
1832 CHECK_NE(rt, kNoRegister);
1833 CHECK_NE(rt, SP);
1834 CHECK_NE(rt, PC);
1835 CHECK_NE(rt2, kNoRegister);
1836 CHECK_NE(rt2, SP);
1837 CHECK_NE(rt2, PC);
1838 CheckCondition(cond);
1839 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1840 B27 | B26 | B22 |
1841 (static_cast<int32_t>(rt2)*B16) |
1842 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1843 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1844 (static_cast<int32_t>(sm) >> 1);
1845 Emit32(encoding);
1846}
1847
1848
1849void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1850 Condition cond) {
1851 CHECK_NE(sm, kNoSRegister);
1852 CHECK_NE(sm, S31);
1853 CHECK_NE(rt, kNoRegister);
1854 CHECK_NE(rt, SP);
1855 CHECK_NE(rt, PC);
1856 CHECK_NE(rt2, kNoRegister);
1857 CHECK_NE(rt2, SP);
1858 CHECK_NE(rt2, PC);
1859 CHECK_NE(rt, rt2);
1860 CheckCondition(cond);
1861 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1862 B27 | B26 | B22 | B20 |
1863 (static_cast<int32_t>(rt2)*B16) |
1864 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1865 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1866 (static_cast<int32_t>(sm) >> 1);
1867 Emit32(encoding);
1868}
1869
1870
1871void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1872 Condition cond) {
1873 CHECK_NE(dm, kNoDRegister);
1874 CHECK_NE(rt, kNoRegister);
1875 CHECK_NE(rt, SP);
1876 CHECK_NE(rt, PC);
1877 CHECK_NE(rt2, kNoRegister);
1878 CHECK_NE(rt2, SP);
1879 CHECK_NE(rt2, PC);
1880 CheckCondition(cond);
1881 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1882 B27 | B26 | B22 |
1883 (static_cast<int32_t>(rt2)*B16) |
1884 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1885 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1886 (static_cast<int32_t>(dm) & 0xf);
1887 Emit32(encoding);
1888}
1889
1890
1891void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1892 Condition cond) {
1893 CHECK_NE(dm, kNoDRegister);
1894 CHECK_NE(rt, kNoRegister);
1895 CHECK_NE(rt, SP);
1896 CHECK_NE(rt, PC);
1897 CHECK_NE(rt2, kNoRegister);
1898 CHECK_NE(rt2, SP);
1899 CHECK_NE(rt2, PC);
1900 CHECK_NE(rt, rt2);
1901 CheckCondition(cond);
1902 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1903 B27 | B26 | B22 | B20 |
1904 (static_cast<int32_t>(rt2)*B16) |
1905 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1906 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1907 (static_cast<int32_t>(dm) & 0xf);
1908 Emit32(encoding);
1909}
1910
1911
1912void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1913 const Address& addr = static_cast<const Address&>(ad);
1914 CHECK_NE(sd, kNoSRegister);
1915 CheckCondition(cond);
1916 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1917 B27 | B26 | B24 | B20 |
1918 ((static_cast<int32_t>(sd) & 1)*B22) |
1919 ((static_cast<int32_t>(sd) >> 1)*B12) |
1920 B11 | B9 | addr.vencoding();
1921 Emit32(encoding);
1922}
1923
1924
1925void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1926 const Address& addr = static_cast<const Address&>(ad);
1927 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1928 CHECK_NE(sd, kNoSRegister);
1929 CheckCondition(cond);
1930 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1931 B27 | B26 | B24 |
1932 ((static_cast<int32_t>(sd) & 1)*B22) |
1933 ((static_cast<int32_t>(sd) >> 1)*B12) |
1934 B11 | B9 | addr.vencoding();
1935 Emit32(encoding);
1936}
1937
1938
1939void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1940 const Address& addr = static_cast<const Address&>(ad);
1941 CHECK_NE(dd, kNoDRegister);
1942 CheckCondition(cond);
1943 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1944 B27 | B26 | B24 | B20 |
1945 ((static_cast<int32_t>(dd) >> 4)*B22) |
1946 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1947 B11 | B9 | B8 | addr.vencoding();
1948 Emit32(encoding);
1949}
1950
1951
1952void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1953 const Address& addr = static_cast<const Address&>(ad);
1954 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1955 CHECK_NE(dd, kNoDRegister);
1956 CheckCondition(cond);
1957 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1958 B27 | B26 | B24 |
1959 ((static_cast<int32_t>(dd) >> 4)*B22) |
1960 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1961 B11 | B9 | B8 | addr.vencoding();
1962 Emit32(encoding);
1963}
1964
1965
1966void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1967 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1968}
1969
1970
1971void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1972 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1973}
1974
1975
1976void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1977 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1978}
1979
1980
1981void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1982 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1983}
1984
1985
1986void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1987 CheckCondition(cond);
1988
1989 uint32_t D;
1990 uint32_t Vd;
1991 if (dbl) {
1992 // Encoded as D:Vd.
1993 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001994 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001995 } else {
1996 // Encoded as Vd:D.
1997 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001998 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001999 }
2000 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
2001 B11 | B9 |
2002 (dbl ? B8 : 0) |
2003 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07002004 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07002005 nregs << (dbl ? 1 : 0) |
2006 D << 22 |
2007 Vd << 12;
2008 Emit32(encoding);
2009}
2010
2011
2012void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
2013 SRegister sd, SRegister sn, SRegister sm) {
2014 CHECK_NE(sd, kNoSRegister);
2015 CHECK_NE(sn, kNoSRegister);
2016 CHECK_NE(sm, kNoSRegister);
2017 CheckCondition(cond);
2018 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2019 B27 | B26 | B25 | B11 | B9 | opcode |
2020 ((static_cast<int32_t>(sd) & 1)*B22) |
2021 ((static_cast<int32_t>(sn) >> 1)*B16) |
2022 ((static_cast<int32_t>(sd) >> 1)*B12) |
2023 ((static_cast<int32_t>(sn) & 1)*B7) |
2024 ((static_cast<int32_t>(sm) & 1)*B5) |
2025 (static_cast<int32_t>(sm) >> 1);
2026 Emit32(encoding);
2027}
2028
2029
2030void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
2031 DRegister dd, DRegister dn, DRegister dm) {
2032 CHECK_NE(dd, kNoDRegister);
2033 CHECK_NE(dn, kNoDRegister);
2034 CHECK_NE(dm, kNoDRegister);
2035 CheckCondition(cond);
2036 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2037 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
2038 ((static_cast<int32_t>(dd) >> 4)*B22) |
2039 ((static_cast<int32_t>(dn) & 0xf)*B16) |
2040 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2041 ((static_cast<int32_t>(dn) >> 4)*B7) |
2042 ((static_cast<int32_t>(dm) >> 4)*B5) |
2043 (static_cast<int32_t>(dm) & 0xf);
2044 Emit32(encoding);
2045}
2046
2047
2048void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
2049 SRegister sd, DRegister dm) {
2050 CHECK_NE(sd, kNoSRegister);
2051 CHECK_NE(dm, kNoDRegister);
2052 CheckCondition(cond);
2053 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2054 B27 | B26 | B25 | B11 | B9 | opcode |
2055 ((static_cast<int32_t>(sd) & 1)*B22) |
2056 ((static_cast<int32_t>(sd) >> 1)*B12) |
2057 ((static_cast<int32_t>(dm) >> 4)*B5) |
2058 (static_cast<int32_t>(dm) & 0xf);
2059 Emit32(encoding);
2060}
2061
2062
2063void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
2064 DRegister dd, SRegister sm) {
2065 CHECK_NE(dd, kNoDRegister);
2066 CHECK_NE(sm, kNoSRegister);
2067 CheckCondition(cond);
2068 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2069 B27 | B26 | B25 | B11 | B9 | opcode |
2070 ((static_cast<int32_t>(dd) >> 4)*B22) |
2071 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2072 ((static_cast<int32_t>(sm) & 1)*B5) |
2073 (static_cast<int32_t>(sm) >> 1);
2074 Emit32(encoding);
2075}
2076
2077
2078void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00002079 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002080 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00002081 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2082 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
2083 (static_cast<int32_t>(PC)*B12) |
2084 B11 | B9 | B4;
2085 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002086}
2087
2088
2089void Thumb2Assembler::svc(uint32_t imm8) {
2090 CHECK(IsUint(8, imm8)) << imm8;
2091 int16_t encoding = B15 | B14 | B12 |
2092 B11 | B10 | B9 | B8 |
2093 imm8;
2094 Emit16(encoding);
2095}
2096
2097
2098void Thumb2Assembler::bkpt(uint16_t imm8) {
2099 CHECK(IsUint(8, imm8)) << imm8;
2100 int16_t encoding = B15 | B13 | B12 |
2101 B11 | B10 | B9 |
2102 imm8;
2103 Emit16(encoding);
2104}
2105
2106// Convert the given IT state to a mask bit given bit 0 of the first
2107// condition and a shift position.
2108static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2109 switch (s) {
2110 case kItOmitted: return 1 << shift;
2111 case kItThen: return firstcond0 << shift;
2112 case kItElse: return !firstcond0 << shift;
2113 }
2114 return 0;
2115}
2116
2117
2118// Set the IT condition in the given position for the given state. This is used
2119// to check that conditional instructions match the preceding IT statement.
2120void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2121 switch (s) {
2122 case kItOmitted: it_conditions_[index] = AL; break;
2123 case kItThen: it_conditions_[index] = cond; break;
2124 case kItElse:
2125 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2126 break;
2127 }
2128}
2129
2130
2131void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2132 CheckCondition(AL); // Not allowed in IT block.
2133 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2134
2135 // All conditions to AL.
2136 for (uint8_t i = 0; i < 4; ++i) {
2137 it_conditions_[i] = AL;
2138 }
2139
2140 SetItCondition(kItThen, firstcond, 0);
2141 uint8_t mask = ToItMask(i1, firstcond0, 3);
2142 SetItCondition(i1, firstcond, 1);
2143
2144 if (i1 != kItOmitted) {
2145 mask |= ToItMask(i2, firstcond0, 2);
2146 SetItCondition(i2, firstcond, 2);
2147 if (i2 != kItOmitted) {
2148 mask |= ToItMask(i3, firstcond0, 1);
2149 SetItCondition(i3, firstcond, 3);
2150 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002151 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002152 }
2153 }
2154 }
2155
2156 // Start at first condition.
2157 it_cond_index_ = 0;
2158 next_condition_ = it_conditions_[0];
2159 uint16_t encoding = B15 | B13 | B12 |
2160 B11 | B10 | B9 | B8 |
2161 firstcond << 4 |
2162 mask;
2163 Emit16(encoding);
2164}
2165
2166
2167void Thumb2Assembler::cbz(Register rn, Label* label) {
2168 CheckCondition(AL);
2169 if (label->IsBound()) {
2170 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002171 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002172 } else {
2173 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2174 label->LinkTo(branchid);
2175 }
2176}
2177
2178
2179void Thumb2Assembler::cbnz(Register rn, Label* label) {
2180 CheckCondition(AL);
2181 if (label->IsBound()) {
2182 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002183 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002184 } else {
2185 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2186 label->LinkTo(branchid);
2187 }
2188}
2189
2190
2191void Thumb2Assembler::blx(Register rm, Condition cond) {
2192 CHECK_NE(rm, kNoRegister);
2193 CheckCondition(cond);
2194 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2195 Emit16(encoding);
2196}
2197
2198
2199void Thumb2Assembler::bx(Register rm, Condition cond) {
2200 CHECK_NE(rm, kNoRegister);
2201 CheckCondition(cond);
2202 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2203 Emit16(encoding);
2204}
2205
2206
2207void Thumb2Assembler::Push(Register rd, Condition cond) {
2208 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2209}
2210
2211
2212void Thumb2Assembler::Pop(Register rd, Condition cond) {
2213 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2214}
2215
2216
2217void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2218 stm(DB_W, SP, regs, cond);
2219}
2220
2221
2222void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2223 ldm(IA_W, SP, regs, cond);
2224}
2225
2226
2227void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2228 if (cond != AL || rd != rm) {
2229 mov(rd, ShifterOperand(rm), cond);
2230 }
2231}
2232
2233
2234// A branch has changed size. Make a hole for it.
2235void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2236 // Move the contents of the buffer using: Move(newposition, oldposition)
2237 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2238 buffer_.Move(location + delta, location);
2239}
2240
2241
2242void Thumb2Assembler::Bind(Label* label) {
2243 CHECK(!label->IsBound());
2244 uint32_t bound_pc = buffer_.Size();
2245 std::vector<Branch*> changed_branches;
2246
2247 while (label->IsLinked()) {
2248 uint16_t position = label->Position(); // Branch id for linked branch.
2249 Branch* branch = GetBranch(position); // Get the branch at this id.
2250 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2251 uint32_t branch_location = branch->GetLocation();
2252 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2253 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002254 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002255 MakeHoleForBranch(branch->GetLocation(), 2);
2256 if (branch->IsCompareAndBranch()) {
2257 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2258 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2259 // cmp rn, #0
2260 // b<eq|ne> target
2261 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2262 Condition cond = n ? NE : EQ;
2263 branch->Move(2); // Move the branch forward by 2 bytes.
2264 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2265 branch->ResetSize(Branch::k16Bit);
2266
2267 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002268 buffer_.Store<int16_t>(branch_location,
2269 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002270
2271 // Since have moved made a hole in the code we need to reload the
2272 // current pc.
2273 bound_pc = buffer_.Size();
2274
2275 // Now resolve the newly added branch.
2276 changed = branch->Resolve(bound_pc);
2277 if (changed) {
2278 MakeHoleForBranch(branch->GetLocation(), 2);
2279 changed_branches.push_back(branch);
2280 }
2281 } else {
2282 changed_branches.push_back(branch);
2283 }
2284 }
2285 label->position_ = next; // Move to next.
2286 }
2287 label->BindTo(bound_pc);
2288
2289 // Now relocate any changed branches. Do this until there are no more changes.
2290 std::vector<Branch*> branches_to_process = changed_branches;
2291 while (branches_to_process.size() != 0) {
2292 changed_branches.clear();
2293 for (auto& changed_branch : branches_to_process) {
2294 for (auto& branch : branches_) {
2295 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2296 if (changed) {
2297 changed_branches.push_back(branch);
2298 }
2299 }
2300 branches_to_process = changed_branches;
2301 }
2302 }
2303}
2304
2305
2306void Thumb2Assembler::EmitBranches() {
2307 for (auto& branch : branches_) {
2308 branch->Emit(&buffer_);
2309 }
2310}
2311
2312
2313void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002314 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002315 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002316 CheckCondition(cond);
2317 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002318}
2319
2320
2321void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002322 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002323 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002324 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002325 CheckCondition(cond);
2326 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002327}
2328
2329
2330void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002331 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002332 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002333 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002334 CheckCondition(cond);
2335 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002336}
2337
2338
2339void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002340 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002341 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002342 CheckCondition(cond);
2343 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002344}
2345
2346
Dave Allison45fdb932014-06-25 12:37:10 -07002347void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2348 CheckCondition(cond);
2349 EmitShift(rd, rm, RRX, rm, setcc);
2350}
2351
2352
2353void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2354 bool setcc, Condition cond) {
2355 CheckCondition(cond);
2356 EmitShift(rd, rm, LSL, rn, setcc);
2357}
2358
2359
2360void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2361 bool setcc, Condition cond) {
2362 CheckCondition(cond);
2363 EmitShift(rd, rm, LSR, rn, setcc);
2364}
2365
2366
2367void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2368 bool setcc, Condition cond) {
2369 CheckCondition(cond);
2370 EmitShift(rd, rm, ASR, rn, setcc);
2371}
2372
2373
2374void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2375 bool setcc, Condition cond) {
2376 CheckCondition(cond);
2377 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002378}
2379
2380
2381int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2382 // The offset is off by 4 due to the way the ARM CPUs read PC.
2383 offset -= 4;
2384 offset >>= 1;
2385
2386 uint32_t value = 0;
2387 // There are two different encodings depending on the value of bit 12. In one case
2388 // intermediate values are calculated using the sign bit.
2389 if ((inst & B12) == B12) {
2390 // 25 bits of offset.
2391 uint32_t signbit = (offset >> 31) & 0x1;
2392 uint32_t i1 = (offset >> 22) & 0x1;
2393 uint32_t i2 = (offset >> 21) & 0x1;
2394 uint32_t imm10 = (offset >> 11) & 0x03ff;
2395 uint32_t imm11 = offset & 0x07ff;
2396 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2397 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2398 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2399 imm11;
2400 // Remove the offset from the current encoding.
2401 inst &= ~(0x3ff << 16 | 0x7ff);
2402 } else {
2403 uint32_t signbit = (offset >> 31) & 0x1;
2404 uint32_t imm6 = (offset >> 11) & 0x03f;
2405 uint32_t imm11 = offset & 0x07ff;
2406 uint32_t j1 = (offset >> 19) & 1;
2407 uint32_t j2 = (offset >> 17) & 1;
2408 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2409 imm11;
2410 // Remove the offset from the current encoding.
2411 inst &= ~(0x3f << 16 | 0x7ff);
2412 }
2413 // Mask out offset bits in current instruction.
2414 inst &= ~(B26 | B13 | B11);
2415 inst |= value;
2416 return inst;
2417}
2418
2419
2420int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2421 int32_t imm32;
2422 if ((instr & B12) == B12) {
2423 uint32_t S = (instr >> 26) & 1;
2424 uint32_t J2 = (instr >> 11) & 1;
2425 uint32_t J1 = (instr >> 13) & 1;
2426 uint32_t imm10 = (instr >> 16) & 0x3FF;
2427 uint32_t imm11 = instr & 0x7FF;
2428
2429 uint32_t I1 = ~(J1 ^ S) & 1;
2430 uint32_t I2 = ~(J2 ^ S) & 1;
2431 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2432 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2433 } else {
2434 uint32_t S = (instr >> 26) & 1;
2435 uint32_t J2 = (instr >> 11) & 1;
2436 uint32_t J1 = (instr >> 13) & 1;
2437 uint32_t imm6 = (instr >> 16) & 0x3F;
2438 uint32_t imm11 = instr & 0x7FF;
2439
2440 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2441 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2442 }
2443 imm32 += 4;
2444 return imm32;
2445}
2446
2447
2448void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2449 AddConstant(rd, rd, value, cond);
2450}
2451
2452
2453void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2454 Condition cond) {
2455 if (value == 0) {
2456 if (rd != rn) {
2457 mov(rd, ShifterOperand(rn), cond);
2458 }
2459 return;
2460 }
2461 // We prefer to select the shorter code sequence rather than selecting add for
2462 // positive values and sub for negatives ones, which would slightly improve
2463 // the readability of generated code for some constants.
2464 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002465 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002466 add(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002467 } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002468 sub(rd, rn, shifter_op, cond);
2469 } else {
2470 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002471 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002472 mvn(IP, shifter_op, cond);
2473 add(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002474 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002475 mvn(IP, shifter_op, cond);
2476 sub(rd, rn, ShifterOperand(IP), cond);
2477 } else {
2478 movw(IP, Low16Bits(value), cond);
2479 uint16_t value_high = High16Bits(value);
2480 if (value_high != 0) {
2481 movt(IP, value_high, cond);
2482 }
2483 add(rd, rn, ShifterOperand(IP), cond);
2484 }
2485 }
2486}
2487
2488
2489void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2490 Condition cond) {
2491 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002492 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002493 adds(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002494 } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002495 subs(rd, rn, shifter_op, cond);
2496 } else {
2497 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002498 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002499 mvn(IP, shifter_op, cond);
2500 adds(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002501 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002502 mvn(IP, shifter_op, cond);
2503 subs(rd, rn, ShifterOperand(IP), cond);
2504 } else {
2505 movw(IP, Low16Bits(value), cond);
2506 uint16_t value_high = High16Bits(value);
2507 if (value_high != 0) {
2508 movt(IP, value_high, cond);
2509 }
2510 adds(rd, rn, ShifterOperand(IP), cond);
2511 }
2512 }
2513}
2514
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002515
Dave Allison65fcc2c2014-04-28 13:45:27 -07002516void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2517 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002518 if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002519 mov(rd, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002520 } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002521 mvn(rd, shifter_op, cond);
2522 } else {
2523 movw(rd, Low16Bits(value), cond);
2524 uint16_t value_high = High16Bits(value);
2525 if (value_high != 0) {
2526 movt(rd, value_high, cond);
2527 }
2528 }
2529}
2530
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002531
Dave Allison65fcc2c2014-04-28 13:45:27 -07002532// Implementation note: this method must emit at most one instruction when
2533// Address::CanHoldLoadOffsetThumb.
2534void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2535 Register reg,
2536 Register base,
2537 int32_t offset,
2538 Condition cond) {
2539 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002540 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002541 LoadImmediate(IP, offset, cond);
2542 add(IP, IP, ShifterOperand(base), cond);
2543 base = IP;
2544 offset = 0;
2545 }
2546 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2547 switch (type) {
2548 case kLoadSignedByte:
2549 ldrsb(reg, Address(base, offset), cond);
2550 break;
2551 case kLoadUnsignedByte:
2552 ldrb(reg, Address(base, offset), cond);
2553 break;
2554 case kLoadSignedHalfword:
2555 ldrsh(reg, Address(base, offset), cond);
2556 break;
2557 case kLoadUnsignedHalfword:
2558 ldrh(reg, Address(base, offset), cond);
2559 break;
2560 case kLoadWord:
2561 ldr(reg, Address(base, offset), cond);
2562 break;
2563 case kLoadWordPair:
2564 ldrd(reg, Address(base, offset), cond);
2565 break;
2566 default:
2567 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002568 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002569 }
2570}
2571
2572
2573// Implementation note: this method must emit at most one instruction when
2574// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2575void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2576 Register base,
2577 int32_t offset,
2578 Condition cond) {
2579 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2580 CHECK_NE(base, IP);
2581 LoadImmediate(IP, offset, cond);
2582 add(IP, IP, ShifterOperand(base), cond);
2583 base = IP;
2584 offset = 0;
2585 }
2586 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2587 vldrs(reg, Address(base, offset), cond);
2588}
2589
2590
2591// Implementation note: this method must emit at most one instruction when
2592// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2593void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2594 Register base,
2595 int32_t offset,
2596 Condition cond) {
2597 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2598 CHECK_NE(base, IP);
2599 LoadImmediate(IP, offset, cond);
2600 add(IP, IP, ShifterOperand(base), cond);
2601 base = IP;
2602 offset = 0;
2603 }
2604 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2605 vldrd(reg, Address(base, offset), cond);
2606}
2607
2608
2609// Implementation note: this method must emit at most one instruction when
2610// Address::CanHoldStoreOffsetThumb.
2611void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2612 Register reg,
2613 Register base,
2614 int32_t offset,
2615 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002616 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002617 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002618 CHECK_NE(base, IP);
2619 if (reg != IP) {
2620 tmp_reg = IP;
2621 } else {
2622 // Be careful not to use IP twice (for `reg` and to build the
2623 // Address object used by the store instruction(s) below).
2624 // Instead, save R5 on the stack (or R6 if R5 is not available),
2625 // use it as secondary temporary register, and restore it after
2626 // the store instruction has been emitted.
2627 tmp_reg = base != R5 ? R5 : R6;
2628 Push(tmp_reg);
2629 if (base == SP) {
2630 offset += kRegisterSize;
2631 }
2632 }
2633 LoadImmediate(tmp_reg, offset, cond);
2634 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2635 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002636 offset = 0;
2637 }
2638 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2639 switch (type) {
2640 case kStoreByte:
2641 strb(reg, Address(base, offset), cond);
2642 break;
2643 case kStoreHalfword:
2644 strh(reg, Address(base, offset), cond);
2645 break;
2646 case kStoreWord:
2647 str(reg, Address(base, offset), cond);
2648 break;
2649 case kStoreWordPair:
2650 strd(reg, Address(base, offset), cond);
2651 break;
2652 default:
2653 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002654 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002655 }
Roland Levillain775ef492014-11-04 17:43:11 +00002656 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2657 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2658 Pop(tmp_reg);
2659 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002660}
2661
2662
2663// Implementation note: this method must emit at most one instruction when
2664// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2665void Thumb2Assembler::StoreSToOffset(SRegister reg,
2666 Register base,
2667 int32_t offset,
2668 Condition cond) {
2669 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2670 CHECK_NE(base, IP);
2671 LoadImmediate(IP, offset, cond);
2672 add(IP, IP, ShifterOperand(base), cond);
2673 base = IP;
2674 offset = 0;
2675 }
2676 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2677 vstrs(reg, Address(base, offset), cond);
2678}
2679
2680
2681// Implementation note: this method must emit at most one instruction when
2682// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2683void Thumb2Assembler::StoreDToOffset(DRegister reg,
2684 Register base,
2685 int32_t offset,
2686 Condition cond) {
2687 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2688 CHECK_NE(base, IP);
2689 LoadImmediate(IP, offset, cond);
2690 add(IP, IP, ShifterOperand(base), cond);
2691 base = IP;
2692 offset = 0;
2693 }
2694 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2695 vstrd(reg, Address(base, offset), cond);
2696}
2697
2698
2699void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2700 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002701 dmb(SY);
2702}
2703
2704
2705void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002706 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2707 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002708}
2709
2710
2711void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002712 if (force_32bit_branches_) {
2713 cmp(r, ShifterOperand(0));
2714 b(label, EQ);
2715 } else {
2716 cbz(r, label);
2717 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002718}
2719
2720
2721void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002722 if (force_32bit_branches_) {
2723 cmp(r, ShifterOperand(0));
2724 b(label, NE);
2725 } else {
2726 cbnz(r, label);
2727 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002728}
2729} // namespace arm
2730} // namespace art