blob: 479186c5d76f5705260ba732184b749cb60069aa [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
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100701 bool can_contain_high_register = (opcode == MOV)
702 || ((opcode == ADD || opcode == SUB) && (rn == rd));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700703
704 if (IsHighRegister(rd) || IsHighRegister(rn)) {
705 if (can_contain_high_register) {
706 // There are high register instructions available for this opcode.
707 // However, there is no RRX available.
708 if (so.IsShift() && so.GetShift() == RRX) {
709 return true;
710 }
711
712 // Check special case for SP relative ADD and SUB immediate.
713 if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
714 // If rn is SP and rd is a high register we need to use a 32 bit encoding.
715 if (rn == SP && rd != SP && IsHighRegister(rd)) {
716 return true;
717 }
718
719 uint32_t imm = so.GetImmediate();
720 // If the immediates are out of range use 32 bit.
721 if (rd == SP && rn == SP) {
722 if (imm > (1 << 9)) { // 9 bit immediate.
723 return true;
724 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700725 } else if (opcode == ADD && rd != SP && rn == SP) { // 10 bit immediate.
726 if (imm > (1 << 10)) {
727 return true;
728 }
729 } else if (opcode == SUB && rd != SP && rn == SP) {
730 // SUB rd, SP, #imm is always 32 bit.
731 return true;
732 }
733 }
734 }
735
736 // The ADD,SUB and MOV instructions that work with high registers don't have
737 // immediate variants.
738 if (so.IsImmediate()) {
739 return true;
740 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100741
742 if (!can_contain_high_register) {
743 return true;
744 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700745 }
746
747 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
748 return true;
749 }
750
751 // Check for MOV with an ROR.
752 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
753 if (so.GetImmediate() != 0) {
754 return true;
755 }
756 }
757
758 bool rn_is_valid = true;
759
760 // Check for single operand instructions and ADD/SUB.
761 switch (opcode) {
762 case CMP:
763 case MOV:
764 case TST:
765 case MVN:
766 rn_is_valid = false; // There is no Rn for these instructions.
767 break;
768 case TEQ:
769 return true;
770 break;
771 case ADD:
772 case SUB:
773 break;
774 default:
775 if (so.IsRegister() && rd != rn) {
776 return true;
777 }
778 }
779
780 if (so.IsImmediate()) {
781 if (rn_is_valid && rn != rd) {
782 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
783 // immediate must be 3 bits.
784 if (opcode != ADD && opcode != SUB) {
785 return true;
786 } else {
787 // Check that the immediate is 3 bits for ADD and SUB.
788 if (so.GetImmediate() >= 8) {
789 return true;
790 }
791 }
792 } else {
793 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
794 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
795 return true;
796 } else {
797 if (so.GetImmediate() > 255) {
798 return true;
799 }
800 }
801 }
802 }
803
804 // The instruction can be encoded in 16 bits.
805 return false;
806}
807
808
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700809void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700810 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700811 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700812 Register rn,
813 Register rd,
814 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700815 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700816 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700817 case AND: thumb_opcode = 0U /* 0b0000 */; break;
818 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
819 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
820 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
821 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700822 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700823 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700824 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700825 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
826 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
827 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
828 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
829 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
830 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
831 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
832 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700833 default:
834 break;
835 }
836
Andreas Gampec8ccf682014-09-29 20:07:43 -0700837 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700838 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000839 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700840 }
841
842 int32_t encoding = 0;
843 if (so.IsImmediate()) {
844 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100845 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700846 if (opcode == SUB) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700847 thumb_opcode = 5U /* 0b0101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700848 } else {
849 thumb_opcode = 0;
850 }
851 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700852
853 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700854 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700855 uint32_t imm8 = imm & 0xff;
856
857 encoding = B31 | B30 | B29 | B28 | B25 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700858 thumb_opcode << 21 |
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100859 rn << 16 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700860 rd << 8 |
861 i << 26 |
862 imm3 << 12 |
863 imm8;
864 } else {
865 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700866 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700867 if (imm == kInvalidModifiedImmediate) {
868 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
Vladimir Markoe8469c12014-11-26 18:09:30 +0000869 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700870 }
871 encoding = B31 | B30 | B29 | B28 |
872 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700873 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700874 rn << 16 |
875 rd << 8 |
876 imm;
877 }
878 } else if (so.IsRegister()) {
879 // Register (possibly shifted)
880 encoding = B31 | B30 | B29 | B27 | B25 |
881 thumb_opcode << 21 |
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700882 (set_cc ? 1 : 0) << 20 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700883 rn << 16 |
884 rd << 8 |
Dave Allison45fdb932014-06-25 12:37:10 -0700885 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700886 }
887 Emit32(encoding);
888}
889
890
891void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
892 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700893 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700894 Register rn,
895 Register rd,
896 const ShifterOperand& so) {
897 if (opcode == ADD || opcode == SUB) {
898 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
899 return;
900 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700901 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700902 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700903 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700904 uint8_t opcode_shift = 6;
905 uint8_t rd_shift = 0;
906 uint8_t rn_shift = 3;
907 uint8_t immediate_shift = 0;
908 bool use_immediate = false;
909 uint8_t immediate = 0;
910
911 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
912 // Convert shifted mov operand2 into 16 bit opcodes.
913 dp_opcode = 0;
914 opcode_shift = 11;
915
916 use_immediate = true;
917 immediate = so.GetImmediate();
918 immediate_shift = 6;
919
920 rn = so.GetRegister();
921
922 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700923 case LSL: thumb_opcode = 0U /* 0b00 */; break;
924 case LSR: thumb_opcode = 1U /* 0b01 */; break;
925 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700926 case ROR:
927 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700928 thumb_opcode = 7U /* 0b111 */;
929 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700930 opcode_shift = 6;
931 use_immediate = false;
932 break;
933 case RRX: break;
934 default:
935 break;
936 }
937 } else {
938 if (so.IsImmediate()) {
939 use_immediate = true;
940 immediate = so.GetImmediate();
941 }
942
943 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700944 case AND: thumb_opcode = 0U /* 0b0000 */; break;
945 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700946 case SUB: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700947 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700948 case ADD: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700949 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
950 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700951 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700952 case TST: thumb_opcode = 8U /* 0b1000 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700953 case TEQ: break;
954 case CMP:
955 if (use_immediate) {
956 // T2 encoding.
957 dp_opcode = 0;
958 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700959 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700960 rd_shift = 8;
961 rn_shift = 8;
962 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700963 thumb_opcode = 10U /* 0b1010 */;
Nicolas Geoffray8d486732014-07-16 16:23:40 +0100964 rd = rn;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700965 rn = so.GetRegister();
966 }
967
968 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100969 case CMN: {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700970 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100971 rd = rn;
972 rn = so.GetRegister();
973 break;
974 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700975 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700976 case MOV:
977 dp_opcode = 0;
978 if (use_immediate) {
979 // T2 encoding.
980 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700981 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700982 rd_shift = 8;
983 rn_shift = 8;
984 } else {
985 rn = so.GetRegister();
986 if (IsHighRegister(rn) || IsHighRegister(rd)) {
987 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700988 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700989 opcode_shift = 7;
990 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700991 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
992 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700993 } else {
994 thumb_opcode = 0;
995 }
996 }
997 break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700998 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
999 case MVN: thumb_opcode = 15U /* 0b1111 */; rn = so.GetRegister(); break;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001000 default:
1001 break;
1002 }
1003 }
1004
Andreas Gampec8ccf682014-09-29 20:07:43 -07001005 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001006 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001007 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001008 }
1009
1010 int16_t encoding = dp_opcode << 14 |
1011 (thumb_opcode << opcode_shift) |
1012 rd << rd_shift |
1013 rn << rn_shift |
1014 (use_immediate ? (immediate << immediate_shift) : 0);
1015
1016 Emit16(encoding);
1017}
1018
1019
1020// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001021void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001022 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001023 bool set_cc ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001024 Register rn,
1025 Register rd,
1026 const ShifterOperand& so) {
1027 uint8_t dp_opcode = 0;
1028 uint8_t opcode_shift = 6;
1029 uint8_t rd_shift = 0;
1030 uint8_t rn_shift = 3;
1031 uint8_t immediate_shift = 0;
1032 bool use_immediate = false;
1033 uint8_t immediate = 0;
1034 uint8_t thumb_opcode;;
1035
1036 if (so.IsImmediate()) {
1037 use_immediate = true;
1038 immediate = so.GetImmediate();
1039 }
1040
1041 switch (opcode) {
1042 case ADD:
1043 if (so.IsRegister()) {
1044 Register rm = so.GetRegister();
1045 if (rn == rd) {
1046 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001047 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001048 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001049 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001050 // Make Rn also contain the top bit of rd.
1051 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001052 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1053 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001054 } else {
1055 // T1.
1056 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001057 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001058 immediate = static_cast<uint32_t>(so.GetRegister());
1059 use_immediate = true;
1060 immediate_shift = 6;
1061 }
1062 } else {
1063 // Immediate.
1064 if (rd == SP && rn == SP) {
1065 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001066 dp_opcode = 2U /* 0b10 */;
1067 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001068 opcode_shift = 12;
1069 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001070 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001071
1072 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1073 rn = R0;
1074 rd = R0;
1075 rd_shift = 0;
1076 rn_shift = 0;
1077 immediate >>= 2;
1078 } else if (rd != SP && rn == SP) {
1079 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001080 dp_opcode = 2U /* 0b10 */;
1081 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001082 opcode_shift = 11;
1083 CHECK_LT(immediate, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001084 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001085
1086 // Remove rn from instruction.
1087 rn = R0;
1088 rn_shift = 0;
1089 rd_shift = 8;
1090 immediate >>= 2;
1091 } else if (rn != rd) {
1092 // Must use T1.
1093 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001094 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001095 immediate_shift = 6;
1096 } else {
1097 // T2 encoding.
1098 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001099 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001100 rd_shift = 8;
1101 rn_shift = 8;
1102 }
1103 }
1104 break;
1105
1106 case SUB:
1107 if (so.IsRegister()) {
1108 // T1.
1109 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001110 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001111 immediate = static_cast<uint32_t>(so.GetRegister());
1112 use_immediate = true;
1113 immediate_shift = 6;
1114 } else {
1115 if (rd == SP && rn == SP) {
1116 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001117 dp_opcode = 2U /* 0b10 */;
1118 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001119 opcode_shift = 7;
1120 CHECK_LT(immediate, (1 << 9));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001121 CHECK_EQ((immediate & 3 /* 0b11 */), 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001122
1123 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1124 rn = R0;
1125 rd = R0;
1126 rd_shift = 0;
1127 rn_shift = 0;
1128 immediate >>= 2;
1129 } else if (rn != rd) {
1130 // Must use T1.
1131 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001132 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001133 immediate_shift = 6;
1134 } else {
1135 // T2 encoding.
1136 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001137 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001138 rd_shift = 8;
1139 rn_shift = 8;
1140 }
1141 }
1142 break;
1143 default:
1144 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001145 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001146 }
1147
1148 int16_t encoding = dp_opcode << 14 |
1149 (thumb_opcode << opcode_shift) |
1150 rd << rd_shift |
1151 rn << rn_shift |
1152 (use_immediate ? (immediate << immediate_shift) : 0);
1153
1154 Emit16(encoding);
1155}
1156
1157
1158void Thumb2Assembler::EmitDataProcessing(Condition cond,
1159 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001160 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001161 Register rn,
1162 Register rd,
1163 const ShifterOperand& so) {
1164 CHECK_NE(rd, kNoRegister);
1165 CheckCondition(cond);
1166
1167 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1168 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1169 } else {
1170 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1171 }
1172}
1173
Dave Allison45fdb932014-06-25 12:37:10 -07001174void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1175 CHECK_LT(amount, (1 << 5));
1176 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1177 uint16_t opcode = 0;
1178 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001179 case LSL: opcode = 0U /* 0b00 */; break;
1180 case LSR: opcode = 1U /* 0b01 */; break;
1181 case ASR: opcode = 2U /* 0b10 */; break;
1182 case ROR: opcode = 3U /* 0b11 */; break;
1183 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001184 default:
1185 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001186 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001187 }
1188 // 32 bit.
1189 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1190 0xf << 16 | (setcc ? B20 : 0);
1191 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001192 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001193 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1194 static_cast<int16_t>(rd) << 8 | opcode << 4;
1195 Emit32(encoding);
1196 } else {
1197 // 16 bit shift
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;
Dave Allison45fdb932014-06-25 12:37:10 -07001203 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001204 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1205 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001206 }
1207 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1208 static_cast<int16_t>(rd);
1209 Emit16(encoding);
1210 }
1211}
1212
1213void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1214 CHECK_NE(shift, RRX);
1215 bool must_be_32bit = false;
1216 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1217 must_be_32bit = true;
1218 }
1219
1220 if (must_be_32bit) {
1221 uint16_t opcode = 0;
1222 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001223 case LSL: opcode = 0U /* 0b00 */; break;
1224 case LSR: opcode = 1U /* 0b01 */; break;
1225 case ASR: opcode = 2U /* 0b10 */; break;
1226 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001227 default:
1228 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001229 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001230 }
1231 // 32 bit.
1232 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1233 0xf << 12 | (setcc ? B20 : 0);
1234 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1235 static_cast<int16_t>(rd) << 8 | opcode << 21;
1236 Emit32(encoding);
1237 } else {
1238 uint16_t opcode = 0;
1239 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001240 case LSL: opcode = 2U /* 0b0010 */; break;
1241 case LSR: opcode = 3U /* 0b0011 */; break;
1242 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001243 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001244 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1245 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001246 }
1247 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1248 static_cast<int16_t>(rd);
1249 Emit16(encoding);
1250 }
1251}
1252
1253
Dave Allison65fcc2c2014-04-28 13:45:27 -07001254
1255void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1256 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1257 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1258 int32_t offset = target_ - location_;
1259
1260 if (size_ == k32Bit) {
1261 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1262 if (link) {
1263 // BL or BLX immediate.
1264 encoding |= B14;
1265 if (!x) {
1266 encoding |= B12;
1267 } else {
1268 // Bottom bit of offset must be 0.
1269 CHECK_EQ((offset & 1), 0);
1270 }
1271 } else {
1272 if (x) {
1273 LOG(FATAL) << "Invalid use of BX";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001274 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001275 } else {
1276 if (cond_ == AL) {
1277 // Can use the T4 encoding allowing a 24 bit offset.
1278 if (!x) {
1279 encoding |= B12;
1280 }
1281 } else {
1282 // Must be T3 encoding with a 20 bit offset.
1283 encoding |= cond_ << 22;
1284 }
1285 }
1286 }
1287 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1288 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1289 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1290 } else {
1291 if (IsCompareAndBranch()) {
1292 offset -= 4;
1293 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001294 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001295 int16_t encoding = B15 | B13 | B12 |
1296 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1297 static_cast<uint32_t>(rn_) |
1298 B8 |
1299 i << 9 |
1300 imm5 << 3;
1301 buffer->Store<int16_t>(location_, encoding);
1302 } else {
1303 offset -= 4; // Account for PC offset.
1304 int16_t encoding;
1305 // 16 bit.
1306 if (cond_ == AL) {
1307 encoding = B15 | B14 | B13 |
1308 ((offset >> 1) & 0x7ff);
1309 } else {
1310 encoding = B15 | B14 | B12 |
1311 cond_ << 8 | ((offset >> 1) & 0xff);
1312 }
1313 buffer->Store<int16_t>(location_, encoding);
1314 }
1315 }
1316}
1317
1318
1319uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1320 uint32_t location = buffer_.Size();
1321
1322 // This is always unresolved as it must be a forward branch.
1323 Emit16(prev); // Previous link.
1324 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1325 location, rn);
1326}
1327
1328
1329// NOTE: this only support immediate offsets, not [rx,ry].
1330// TODO: support [rx,ry] instructions.
1331void Thumb2Assembler::EmitLoadStore(Condition cond,
1332 bool load,
1333 bool byte,
1334 bool half,
1335 bool is_signed,
1336 Register rd,
1337 const Address& ad) {
1338 CHECK_NE(rd, kNoRegister);
1339 CheckCondition(cond);
1340 bool must_be_32bit = force_32bit_;
1341 if (IsHighRegister(rd)) {
1342 must_be_32bit = true;
1343 }
1344
1345 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001346 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001347 must_be_32bit = true;
1348 }
1349
1350 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1351 must_be_32bit = true;
1352 }
1353
Dave Allison45fdb932014-06-25 12:37:10 -07001354 if (ad.IsImmediate()) {
1355 // Immediate offset
1356 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001357
Dave Allison45fdb932014-06-25 12:37:10 -07001358 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001359 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001360 must_be_32bit = true;
1361 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001362
1363 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001364 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001365 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001366 must_be_32bit = true;
1367 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001368 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001369 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001370 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001371 must_be_32bit = true;
1372 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001373 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001374 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001375 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001376 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001377 }
1378 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001379
Dave Allison45fdb932014-06-25 12:37:10 -07001380 if (must_be_32bit) {
1381 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1382 (load ? B20 : 0) |
1383 (is_signed ? B24 : 0) |
1384 static_cast<uint32_t>(rd) << 12 |
1385 ad.encodingThumb(true) |
1386 (byte ? 0 : half ? B21 : B22);
1387 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001388 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001389 // 16 bit thumb1.
1390 uint8_t opA = 0;
1391 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001392
1393 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001394 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001395 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001396 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001397 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001398 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001399 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001400 sp_relative = true;
1401 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001402 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001403 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001404 }
Dave Allison45fdb932014-06-25 12:37:10 -07001405 int16_t encoding = opA << 12 |
1406 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001407
Dave Allison45fdb932014-06-25 12:37:10 -07001408 CHECK_GE(offset, 0);
1409 if (sp_relative) {
1410 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001411 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001412 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001413 encoding |= rd << 8 | offset >> 2;
1414 } else {
1415 // No SP relative. The offset is shifted right depending on
1416 // the size of the load/store.
1417 encoding |= static_cast<uint32_t>(rd);
1418
1419 if (byte) {
1420 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001421 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001422 } else if (half) {
1423 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001424 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001425 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001426 offset >>= 1;
1427 } else {
1428 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001429 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001430 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001431 offset >>= 2;
1432 }
1433 encoding |= rn << 3 | offset << 6;
1434 }
1435
1436 Emit16(encoding);
1437 }
1438 } else {
1439 // Register shift.
1440 if (ad.GetRegister() == PC) {
1441 // PC relative literal encoding.
1442 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001443 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001444 int32_t up = B23;
1445 if (offset < 0) {
1446 offset = -offset;
1447 up = 0;
1448 }
1449 CHECK_LT(offset, (1 << 12));
1450 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1451 offset | up |
1452 static_cast<uint32_t>(rd) << 12;
1453 Emit32(encoding);
1454 } else {
1455 // 16 bit literal load.
1456 CHECK_GE(offset, 0);
1457 CHECK_LT(offset, (1 << 10));
1458 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1459 Emit16(encoding);
1460 }
1461 } else {
1462 if (ad.GetShiftCount() != 0) {
1463 // If there is a shift count this must be 32 bit.
1464 must_be_32bit = true;
1465 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1466 must_be_32bit = true;
1467 }
1468
1469 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001470 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001471 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001472 if (half) {
1473 encoding |= B21;
1474 } else if (!byte) {
1475 encoding |= B22;
1476 }
Dave Allison45fdb932014-06-25 12:37:10 -07001477 Emit32(encoding);
1478 } else {
1479 // 16 bit register offset.
1480 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1481 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001482 if (byte) {
1483 encoding |= B10;
1484 } else if (half) {
1485 encoding |= B9;
1486 }
Dave Allison45fdb932014-06-25 12:37:10 -07001487 Emit16(encoding);
1488 }
1489 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001490 }
1491}
1492
1493
1494void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001495 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001496 bool load,
1497 Register base,
1498 RegList regs) {
1499 CHECK_NE(base, kNoRegister);
1500 CheckCondition(cond);
1501 bool must_be_32bit = force_32bit_;
1502
Vladimir Markoe8469c12014-11-26 18:09:30 +00001503 if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
1504 (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
1505 // Use 16-bit PUSH/POP.
1506 int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
1507 ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
1508 Emit16(encoding);
1509 return;
1510 }
1511
Dave Allison65fcc2c2014-04-28 13:45:27 -07001512 if ((regs & 0xff00) != 0) {
1513 must_be_32bit = true;
1514 }
1515
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001516 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001517 // 16 bit always uses writeback.
1518 if (!w_bit) {
1519 must_be_32bit = true;
1520 }
1521
1522 if (must_be_32bit) {
1523 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001524 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001525 case IA:
1526 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001527 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001528 break;
1529 case DB:
1530 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001531 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001532 break;
1533 case DA:
1534 case IB:
1535 case DA_W:
1536 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001537 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001538 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001539 }
1540 if (load) {
1541 // Cannot have SP in the list.
1542 CHECK_EQ((regs & (1 << SP)), 0);
1543 } else {
1544 // Cannot have PC or SP in the list.
1545 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1546 }
1547 int32_t encoding = B31 | B30 | B29 | B27 |
1548 (op << 23) |
1549 (load ? B20 : 0) |
1550 base << 16 |
1551 regs |
1552 (w_bit << 21);
1553 Emit32(encoding);
1554 } else {
1555 int16_t encoding = B15 | B14 |
1556 (load ? B11 : 0) |
1557 base << 8 |
1558 regs;
1559 Emit16(encoding);
1560 }
1561}
1562
1563
1564void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1565 uint32_t pc = buffer_.Size();
1566 Branch::Type branch_type;
1567 if (cond == AL) {
1568 if (link) {
1569 if (x) {
1570 branch_type = Branch::kUnconditionalLinkX; // BLX.
1571 } else {
1572 branch_type = Branch::kUnconditionalLink; // BX.
1573 }
1574 } else {
1575 branch_type = Branch::kUnconditional; // B.
1576 }
1577 } else {
1578 branch_type = Branch::kConditional; // B<cond>.
1579 }
1580
1581 if (label->IsBound()) {
1582 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1583
1584 // The branch is to a bound label which means that it's a backwards branch. We know the
1585 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1586 // branch the size may change if it so happens that other branches change size that change
1587 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1588 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001589 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001590 Emit16(0); // Space for a 16 bit branch.
1591 } else {
1592 Emit32(0); // Space for a 32 bit branch.
1593 }
1594 } else {
1595 // Branch is to an unbound label. Emit space for it.
1596 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001597 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001598 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1599 Emit16(0); // another 16 bits.
1600 } else {
1601 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1602 }
1603 label->LinkTo(branch_id); // Link to the branch ID.
1604 }
1605}
1606
1607
1608void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1609 CHECK_NE(rd, kNoRegister);
1610 CHECK_NE(rm, kNoRegister);
1611 CheckCondition(cond);
1612 CHECK_NE(rd, PC);
1613 CHECK_NE(rm, PC);
1614 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1615 B25 | B23 | B21 | B20 |
1616 static_cast<uint32_t>(rm) << 16 |
1617 0xf << 12 |
1618 static_cast<uint32_t>(rd) << 8 |
1619 B7 |
1620 static_cast<uint32_t>(rm);
1621 Emit32(encoding);
1622}
1623
1624
1625void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1626 CheckCondition(cond);
1627 bool must_be_32bit = force_32bit_;
1628 if (IsHighRegister(rd)|| imm16 >= 256u) {
1629 must_be_32bit = true;
1630 }
1631
1632 if (must_be_32bit) {
1633 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001634 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1635 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1636 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001637 uint32_t imm8 = imm16 & 0xff;
1638 int32_t encoding = B31 | B30 | B29 | B28 |
1639 B25 | B22 |
1640 static_cast<uint32_t>(rd) << 8 |
1641 i << 26 |
1642 imm4 << 16 |
1643 imm3 << 12 |
1644 imm8;
1645 Emit32(encoding);
1646 } else {
1647 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1648 imm16;
1649 Emit16(encoding);
1650 }
1651}
1652
1653
1654void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1655 CheckCondition(cond);
1656 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001657 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1658 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1659 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001660 uint32_t imm8 = imm16 & 0xff;
1661 int32_t encoding = B31 | B30 | B29 | B28 |
1662 B25 | B23 | B22 |
1663 static_cast<uint32_t>(rd) << 8 |
1664 i << 26 |
1665 imm4 << 16 |
1666 imm3 << 12 |
1667 imm8;
1668 Emit32(encoding);
1669}
1670
1671
1672void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1673 CHECK_NE(rn, kNoRegister);
1674 CHECK_NE(rt, kNoRegister);
1675 CheckCondition(cond);
1676 CHECK_NE(rn, kNoRegister);
1677 CHECK_NE(rt, kNoRegister);
1678 CheckCondition(cond);
1679 CHECK_LT(imm, (1u << 10));
1680
1681 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1682 static_cast<uint32_t>(rn) << 16 |
1683 static_cast<uint32_t>(rt) << 12 |
1684 0xf << 8 |
1685 imm >> 2;
1686 Emit32(encoding);
1687}
1688
1689
1690void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1691 ldrex(rt, rn, 0, cond);
1692}
1693
1694
1695void Thumb2Assembler::strex(Register rd,
1696 Register rt,
1697 Register rn,
1698 uint16_t imm,
1699 Condition cond) {
1700 CHECK_NE(rn, kNoRegister);
1701 CHECK_NE(rd, kNoRegister);
1702 CHECK_NE(rt, kNoRegister);
1703 CheckCondition(cond);
1704 CHECK_LT(imm, (1u << 10));
1705
1706 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1707 static_cast<uint32_t>(rn) << 16 |
1708 static_cast<uint32_t>(rt) << 12 |
1709 static_cast<uint32_t>(rd) << 8 |
1710 imm >> 2;
1711 Emit32(encoding);
1712}
1713
1714
1715void Thumb2Assembler::strex(Register rd,
1716 Register rt,
1717 Register rn,
1718 Condition cond) {
1719 strex(rd, rt, rn, 0, cond);
1720}
1721
1722
1723void Thumb2Assembler::clrex(Condition cond) {
1724 CheckCondition(cond);
1725 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1726 B21 | B20 |
1727 0xf << 16 |
1728 B15 |
1729 0xf << 8 |
1730 B5 |
1731 0xf;
1732 Emit32(encoding);
1733}
1734
1735
1736void Thumb2Assembler::nop(Condition cond) {
1737 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001738 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001739 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001740 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001741}
1742
1743
1744void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1745 CHECK_NE(sn, kNoSRegister);
1746 CHECK_NE(rt, kNoRegister);
1747 CHECK_NE(rt, SP);
1748 CHECK_NE(rt, PC);
1749 CheckCondition(cond);
1750 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1751 B27 | B26 | B25 |
1752 ((static_cast<int32_t>(sn) >> 1)*B16) |
1753 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1754 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1755 Emit32(encoding);
1756}
1757
1758
1759void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1760 CHECK_NE(sn, kNoSRegister);
1761 CHECK_NE(rt, kNoRegister);
1762 CHECK_NE(rt, SP);
1763 CHECK_NE(rt, PC);
1764 CheckCondition(cond);
1765 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1766 B27 | B26 | B25 | B20 |
1767 ((static_cast<int32_t>(sn) >> 1)*B16) |
1768 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1769 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1770 Emit32(encoding);
1771}
1772
1773
1774void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1775 Condition cond) {
1776 CHECK_NE(sm, kNoSRegister);
1777 CHECK_NE(sm, S31);
1778 CHECK_NE(rt, kNoRegister);
1779 CHECK_NE(rt, SP);
1780 CHECK_NE(rt, PC);
1781 CHECK_NE(rt2, kNoRegister);
1782 CHECK_NE(rt2, SP);
1783 CHECK_NE(rt2, PC);
1784 CheckCondition(cond);
1785 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1786 B27 | B26 | B22 |
1787 (static_cast<int32_t>(rt2)*B16) |
1788 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1789 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1790 (static_cast<int32_t>(sm) >> 1);
1791 Emit32(encoding);
1792}
1793
1794
1795void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1796 Condition cond) {
1797 CHECK_NE(sm, kNoSRegister);
1798 CHECK_NE(sm, S31);
1799 CHECK_NE(rt, kNoRegister);
1800 CHECK_NE(rt, SP);
1801 CHECK_NE(rt, PC);
1802 CHECK_NE(rt2, kNoRegister);
1803 CHECK_NE(rt2, SP);
1804 CHECK_NE(rt2, PC);
1805 CHECK_NE(rt, rt2);
1806 CheckCondition(cond);
1807 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1808 B27 | B26 | B22 | B20 |
1809 (static_cast<int32_t>(rt2)*B16) |
1810 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1811 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1812 (static_cast<int32_t>(sm) >> 1);
1813 Emit32(encoding);
1814}
1815
1816
1817void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1818 Condition cond) {
1819 CHECK_NE(dm, kNoDRegister);
1820 CHECK_NE(rt, kNoRegister);
1821 CHECK_NE(rt, SP);
1822 CHECK_NE(rt, PC);
1823 CHECK_NE(rt2, kNoRegister);
1824 CHECK_NE(rt2, SP);
1825 CHECK_NE(rt2, PC);
1826 CheckCondition(cond);
1827 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1828 B27 | B26 | B22 |
1829 (static_cast<int32_t>(rt2)*B16) |
1830 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1831 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1832 (static_cast<int32_t>(dm) & 0xf);
1833 Emit32(encoding);
1834}
1835
1836
1837void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1838 Condition cond) {
1839 CHECK_NE(dm, kNoDRegister);
1840 CHECK_NE(rt, kNoRegister);
1841 CHECK_NE(rt, SP);
1842 CHECK_NE(rt, PC);
1843 CHECK_NE(rt2, kNoRegister);
1844 CHECK_NE(rt2, SP);
1845 CHECK_NE(rt2, PC);
1846 CHECK_NE(rt, rt2);
1847 CheckCondition(cond);
1848 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1849 B27 | B26 | B22 | B20 |
1850 (static_cast<int32_t>(rt2)*B16) |
1851 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1852 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1853 (static_cast<int32_t>(dm) & 0xf);
1854 Emit32(encoding);
1855}
1856
1857
1858void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1859 const Address& addr = static_cast<const Address&>(ad);
1860 CHECK_NE(sd, kNoSRegister);
1861 CheckCondition(cond);
1862 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1863 B27 | B26 | B24 | B20 |
1864 ((static_cast<int32_t>(sd) & 1)*B22) |
1865 ((static_cast<int32_t>(sd) >> 1)*B12) |
1866 B11 | B9 | addr.vencoding();
1867 Emit32(encoding);
1868}
1869
1870
1871void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1872 const Address& addr = static_cast<const Address&>(ad);
1873 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1874 CHECK_NE(sd, kNoSRegister);
1875 CheckCondition(cond);
1876 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1877 B27 | B26 | B24 |
1878 ((static_cast<int32_t>(sd) & 1)*B22) |
1879 ((static_cast<int32_t>(sd) >> 1)*B12) |
1880 B11 | B9 | addr.vencoding();
1881 Emit32(encoding);
1882}
1883
1884
1885void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1886 const Address& addr = static_cast<const Address&>(ad);
1887 CHECK_NE(dd, kNoDRegister);
1888 CheckCondition(cond);
1889 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1890 B27 | B26 | B24 | B20 |
1891 ((static_cast<int32_t>(dd) >> 4)*B22) |
1892 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1893 B11 | B9 | B8 | addr.vencoding();
1894 Emit32(encoding);
1895}
1896
1897
1898void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1899 const Address& addr = static_cast<const Address&>(ad);
1900 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1901 CHECK_NE(dd, kNoDRegister);
1902 CheckCondition(cond);
1903 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1904 B27 | B26 | B24 |
1905 ((static_cast<int32_t>(dd) >> 4)*B22) |
1906 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1907 B11 | B9 | B8 | addr.vencoding();
1908 Emit32(encoding);
1909}
1910
1911
1912void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1913 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1914}
1915
1916
1917void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1918 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1919}
1920
1921
1922void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1923 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1924}
1925
1926
1927void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1928 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1929}
1930
1931
1932void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1933 CheckCondition(cond);
1934
1935 uint32_t D;
1936 uint32_t Vd;
1937 if (dbl) {
1938 // Encoded as D:Vd.
1939 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001940 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001941 } else {
1942 // Encoded as Vd:D.
1943 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001944 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001945 }
1946 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1947 B11 | B9 |
1948 (dbl ? B8 : 0) |
1949 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001950 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001951 nregs << (dbl ? 1 : 0) |
1952 D << 22 |
1953 Vd << 12;
1954 Emit32(encoding);
1955}
1956
1957
1958void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
1959 SRegister sd, SRegister sn, SRegister sm) {
1960 CHECK_NE(sd, kNoSRegister);
1961 CHECK_NE(sn, kNoSRegister);
1962 CHECK_NE(sm, kNoSRegister);
1963 CheckCondition(cond);
1964 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1965 B27 | B26 | B25 | B11 | B9 | opcode |
1966 ((static_cast<int32_t>(sd) & 1)*B22) |
1967 ((static_cast<int32_t>(sn) >> 1)*B16) |
1968 ((static_cast<int32_t>(sd) >> 1)*B12) |
1969 ((static_cast<int32_t>(sn) & 1)*B7) |
1970 ((static_cast<int32_t>(sm) & 1)*B5) |
1971 (static_cast<int32_t>(sm) >> 1);
1972 Emit32(encoding);
1973}
1974
1975
1976void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
1977 DRegister dd, DRegister dn, DRegister dm) {
1978 CHECK_NE(dd, kNoDRegister);
1979 CHECK_NE(dn, kNoDRegister);
1980 CHECK_NE(dm, kNoDRegister);
1981 CheckCondition(cond);
1982 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1983 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
1984 ((static_cast<int32_t>(dd) >> 4)*B22) |
1985 ((static_cast<int32_t>(dn) & 0xf)*B16) |
1986 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1987 ((static_cast<int32_t>(dn) >> 4)*B7) |
1988 ((static_cast<int32_t>(dm) >> 4)*B5) |
1989 (static_cast<int32_t>(dm) & 0xf);
1990 Emit32(encoding);
1991}
1992
1993
1994void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1995 SRegister sd, DRegister dm) {
1996 CHECK_NE(sd, kNoSRegister);
1997 CHECK_NE(dm, kNoDRegister);
1998 CheckCondition(cond);
1999 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2000 B27 | B26 | B25 | B11 | B9 | opcode |
2001 ((static_cast<int32_t>(sd) & 1)*B22) |
2002 ((static_cast<int32_t>(sd) >> 1)*B12) |
2003 ((static_cast<int32_t>(dm) >> 4)*B5) |
2004 (static_cast<int32_t>(dm) & 0xf);
2005 Emit32(encoding);
2006}
2007
2008
2009void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
2010 DRegister dd, SRegister sm) {
2011 CHECK_NE(dd, kNoDRegister);
2012 CHECK_NE(sm, kNoSRegister);
2013 CheckCondition(cond);
2014 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2015 B27 | B26 | B25 | B11 | B9 | opcode |
2016 ((static_cast<int32_t>(dd) >> 4)*B22) |
2017 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2018 ((static_cast<int32_t>(sm) & 1)*B5) |
2019 (static_cast<int32_t>(sm) >> 1);
2020 Emit32(encoding);
2021}
2022
2023
2024void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00002025 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002026 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00002027 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2028 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
2029 (static_cast<int32_t>(PC)*B12) |
2030 B11 | B9 | B4;
2031 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002032}
2033
2034
2035void Thumb2Assembler::svc(uint32_t imm8) {
2036 CHECK(IsUint(8, imm8)) << imm8;
2037 int16_t encoding = B15 | B14 | B12 |
2038 B11 | B10 | B9 | B8 |
2039 imm8;
2040 Emit16(encoding);
2041}
2042
2043
2044void Thumb2Assembler::bkpt(uint16_t imm8) {
2045 CHECK(IsUint(8, imm8)) << imm8;
2046 int16_t encoding = B15 | B13 | B12 |
2047 B11 | B10 | B9 |
2048 imm8;
2049 Emit16(encoding);
2050}
2051
2052// Convert the given IT state to a mask bit given bit 0 of the first
2053// condition and a shift position.
2054static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2055 switch (s) {
2056 case kItOmitted: return 1 << shift;
2057 case kItThen: return firstcond0 << shift;
2058 case kItElse: return !firstcond0 << shift;
2059 }
2060 return 0;
2061}
2062
2063
2064// Set the IT condition in the given position for the given state. This is used
2065// to check that conditional instructions match the preceding IT statement.
2066void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2067 switch (s) {
2068 case kItOmitted: it_conditions_[index] = AL; break;
2069 case kItThen: it_conditions_[index] = cond; break;
2070 case kItElse:
2071 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2072 break;
2073 }
2074}
2075
2076
2077void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2078 CheckCondition(AL); // Not allowed in IT block.
2079 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2080
2081 // All conditions to AL.
2082 for (uint8_t i = 0; i < 4; ++i) {
2083 it_conditions_[i] = AL;
2084 }
2085
2086 SetItCondition(kItThen, firstcond, 0);
2087 uint8_t mask = ToItMask(i1, firstcond0, 3);
2088 SetItCondition(i1, firstcond, 1);
2089
2090 if (i1 != kItOmitted) {
2091 mask |= ToItMask(i2, firstcond0, 2);
2092 SetItCondition(i2, firstcond, 2);
2093 if (i2 != kItOmitted) {
2094 mask |= ToItMask(i3, firstcond0, 1);
2095 SetItCondition(i3, firstcond, 3);
2096 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002097 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002098 }
2099 }
2100 }
2101
2102 // Start at first condition.
2103 it_cond_index_ = 0;
2104 next_condition_ = it_conditions_[0];
2105 uint16_t encoding = B15 | B13 | B12 |
2106 B11 | B10 | B9 | B8 |
2107 firstcond << 4 |
2108 mask;
2109 Emit16(encoding);
2110}
2111
2112
2113void Thumb2Assembler::cbz(Register rn, Label* label) {
2114 CheckCondition(AL);
2115 if (label->IsBound()) {
2116 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002117 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002118 } else {
2119 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2120 label->LinkTo(branchid);
2121 }
2122}
2123
2124
2125void Thumb2Assembler::cbnz(Register rn, Label* label) {
2126 CheckCondition(AL);
2127 if (label->IsBound()) {
2128 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002129 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002130 } else {
2131 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2132 label->LinkTo(branchid);
2133 }
2134}
2135
2136
2137void Thumb2Assembler::blx(Register rm, Condition cond) {
2138 CHECK_NE(rm, kNoRegister);
2139 CheckCondition(cond);
2140 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2141 Emit16(encoding);
2142}
2143
2144
2145void Thumb2Assembler::bx(Register rm, Condition cond) {
2146 CHECK_NE(rm, kNoRegister);
2147 CheckCondition(cond);
2148 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2149 Emit16(encoding);
2150}
2151
2152
2153void Thumb2Assembler::Push(Register rd, Condition cond) {
2154 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2155}
2156
2157
2158void Thumb2Assembler::Pop(Register rd, Condition cond) {
2159 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2160}
2161
2162
2163void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2164 stm(DB_W, SP, regs, cond);
2165}
2166
2167
2168void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2169 ldm(IA_W, SP, regs, cond);
2170}
2171
2172
2173void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2174 if (cond != AL || rd != rm) {
2175 mov(rd, ShifterOperand(rm), cond);
2176 }
2177}
2178
2179
2180// A branch has changed size. Make a hole for it.
2181void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2182 // Move the contents of the buffer using: Move(newposition, oldposition)
2183 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2184 buffer_.Move(location + delta, location);
2185}
2186
2187
2188void Thumb2Assembler::Bind(Label* label) {
2189 CHECK(!label->IsBound());
2190 uint32_t bound_pc = buffer_.Size();
2191 std::vector<Branch*> changed_branches;
2192
2193 while (label->IsLinked()) {
2194 uint16_t position = label->Position(); // Branch id for linked branch.
2195 Branch* branch = GetBranch(position); // Get the branch at this id.
2196 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2197 uint32_t branch_location = branch->GetLocation();
2198 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2199 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002200 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002201 MakeHoleForBranch(branch->GetLocation(), 2);
2202 if (branch->IsCompareAndBranch()) {
2203 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2204 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2205 // cmp rn, #0
2206 // b<eq|ne> target
2207 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2208 Condition cond = n ? NE : EQ;
2209 branch->Move(2); // Move the branch forward by 2 bytes.
2210 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2211 branch->ResetSize(Branch::k16Bit);
2212
2213 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002214 buffer_.Store<int16_t>(branch_location,
2215 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002216
2217 // Since have moved made a hole in the code we need to reload the
2218 // current pc.
2219 bound_pc = buffer_.Size();
2220
2221 // Now resolve the newly added branch.
2222 changed = branch->Resolve(bound_pc);
2223 if (changed) {
2224 MakeHoleForBranch(branch->GetLocation(), 2);
2225 changed_branches.push_back(branch);
2226 }
2227 } else {
2228 changed_branches.push_back(branch);
2229 }
2230 }
2231 label->position_ = next; // Move to next.
2232 }
2233 label->BindTo(bound_pc);
2234
2235 // Now relocate any changed branches. Do this until there are no more changes.
2236 std::vector<Branch*> branches_to_process = changed_branches;
2237 while (branches_to_process.size() != 0) {
2238 changed_branches.clear();
2239 for (auto& changed_branch : branches_to_process) {
2240 for (auto& branch : branches_) {
2241 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2242 if (changed) {
2243 changed_branches.push_back(branch);
2244 }
2245 }
2246 branches_to_process = changed_branches;
2247 }
2248 }
2249}
2250
2251
2252void Thumb2Assembler::EmitBranches() {
2253 for (auto& branch : branches_) {
2254 branch->Emit(&buffer_);
2255 }
2256}
2257
2258
2259void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002260 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002261 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002262 CheckCondition(cond);
2263 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002264}
2265
2266
2267void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002268 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002269 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002270 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002271 CheckCondition(cond);
2272 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002273}
2274
2275
2276void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002277 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002278 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002279 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002280 CheckCondition(cond);
2281 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002282}
2283
2284
2285void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002286 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002287 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002288 CheckCondition(cond);
2289 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002290}
2291
2292
Dave Allison45fdb932014-06-25 12:37:10 -07002293void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2294 CheckCondition(cond);
2295 EmitShift(rd, rm, RRX, rm, setcc);
2296}
2297
2298
2299void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2300 bool setcc, Condition cond) {
2301 CheckCondition(cond);
2302 EmitShift(rd, rm, LSL, rn, setcc);
2303}
2304
2305
2306void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2307 bool setcc, Condition cond) {
2308 CheckCondition(cond);
2309 EmitShift(rd, rm, LSR, rn, setcc);
2310}
2311
2312
2313void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2314 bool setcc, Condition cond) {
2315 CheckCondition(cond);
2316 EmitShift(rd, rm, ASR, rn, setcc);
2317}
2318
2319
2320void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2321 bool setcc, Condition cond) {
2322 CheckCondition(cond);
2323 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002324}
2325
2326
2327int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2328 // The offset is off by 4 due to the way the ARM CPUs read PC.
2329 offset -= 4;
2330 offset >>= 1;
2331
2332 uint32_t value = 0;
2333 // There are two different encodings depending on the value of bit 12. In one case
2334 // intermediate values are calculated using the sign bit.
2335 if ((inst & B12) == B12) {
2336 // 25 bits of offset.
2337 uint32_t signbit = (offset >> 31) & 0x1;
2338 uint32_t i1 = (offset >> 22) & 0x1;
2339 uint32_t i2 = (offset >> 21) & 0x1;
2340 uint32_t imm10 = (offset >> 11) & 0x03ff;
2341 uint32_t imm11 = offset & 0x07ff;
2342 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2343 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2344 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2345 imm11;
2346 // Remove the offset from the current encoding.
2347 inst &= ~(0x3ff << 16 | 0x7ff);
2348 } else {
2349 uint32_t signbit = (offset >> 31) & 0x1;
2350 uint32_t imm6 = (offset >> 11) & 0x03f;
2351 uint32_t imm11 = offset & 0x07ff;
2352 uint32_t j1 = (offset >> 19) & 1;
2353 uint32_t j2 = (offset >> 17) & 1;
2354 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2355 imm11;
2356 // Remove the offset from the current encoding.
2357 inst &= ~(0x3f << 16 | 0x7ff);
2358 }
2359 // Mask out offset bits in current instruction.
2360 inst &= ~(B26 | B13 | B11);
2361 inst |= value;
2362 return inst;
2363}
2364
2365
2366int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2367 int32_t imm32;
2368 if ((instr & B12) == B12) {
2369 uint32_t S = (instr >> 26) & 1;
2370 uint32_t J2 = (instr >> 11) & 1;
2371 uint32_t J1 = (instr >> 13) & 1;
2372 uint32_t imm10 = (instr >> 16) & 0x3FF;
2373 uint32_t imm11 = instr & 0x7FF;
2374
2375 uint32_t I1 = ~(J1 ^ S) & 1;
2376 uint32_t I2 = ~(J2 ^ S) & 1;
2377 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2378 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2379 } else {
2380 uint32_t S = (instr >> 26) & 1;
2381 uint32_t J2 = (instr >> 11) & 1;
2382 uint32_t J1 = (instr >> 13) & 1;
2383 uint32_t imm6 = (instr >> 16) & 0x3F;
2384 uint32_t imm11 = instr & 0x7FF;
2385
2386 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2387 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2388 }
2389 imm32 += 4;
2390 return imm32;
2391}
2392
2393
2394void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2395 AddConstant(rd, rd, value, cond);
2396}
2397
2398
2399void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2400 Condition cond) {
2401 if (value == 0) {
2402 if (rd != rn) {
2403 mov(rd, ShifterOperand(rn), cond);
2404 }
2405 return;
2406 }
2407 // We prefer to select the shorter code sequence rather than selecting add for
2408 // positive values and sub for negatives ones, which would slightly improve
2409 // the readability of generated code for some constants.
2410 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002411 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002412 add(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002413 } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002414 sub(rd, rn, shifter_op, cond);
2415 } else {
2416 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002417 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002418 mvn(IP, shifter_op, cond);
2419 add(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002420 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002421 mvn(IP, shifter_op, cond);
2422 sub(rd, rn, ShifterOperand(IP), cond);
2423 } else {
2424 movw(IP, Low16Bits(value), cond);
2425 uint16_t value_high = High16Bits(value);
2426 if (value_high != 0) {
2427 movt(IP, value_high, cond);
2428 }
2429 add(rd, rn, ShifterOperand(IP), cond);
2430 }
2431 }
2432}
2433
2434
2435void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2436 Condition cond) {
2437 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002438 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002439 adds(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002440 } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002441 subs(rd, rn, shifter_op, cond);
2442 } else {
2443 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002444 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002445 mvn(IP, shifter_op, cond);
2446 adds(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002447 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002448 mvn(IP, shifter_op, cond);
2449 subs(rd, rn, ShifterOperand(IP), cond);
2450 } else {
2451 movw(IP, Low16Bits(value), cond);
2452 uint16_t value_high = High16Bits(value);
2453 if (value_high != 0) {
2454 movt(IP, value_high, cond);
2455 }
2456 adds(rd, rn, ShifterOperand(IP), cond);
2457 }
2458 }
2459}
2460
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002461
Dave Allison65fcc2c2014-04-28 13:45:27 -07002462void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2463 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002464 if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002465 mov(rd, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002466 } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002467 mvn(rd, shifter_op, cond);
2468 } else {
2469 movw(rd, Low16Bits(value), cond);
2470 uint16_t value_high = High16Bits(value);
2471 if (value_high != 0) {
2472 movt(rd, value_high, cond);
2473 }
2474 }
2475}
2476
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002477
Dave Allison65fcc2c2014-04-28 13:45:27 -07002478// Implementation note: this method must emit at most one instruction when
2479// Address::CanHoldLoadOffsetThumb.
2480void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2481 Register reg,
2482 Register base,
2483 int32_t offset,
2484 Condition cond) {
2485 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002486 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002487 LoadImmediate(IP, offset, cond);
2488 add(IP, IP, ShifterOperand(base), cond);
2489 base = IP;
2490 offset = 0;
2491 }
2492 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2493 switch (type) {
2494 case kLoadSignedByte:
2495 ldrsb(reg, Address(base, offset), cond);
2496 break;
2497 case kLoadUnsignedByte:
2498 ldrb(reg, Address(base, offset), cond);
2499 break;
2500 case kLoadSignedHalfword:
2501 ldrsh(reg, Address(base, offset), cond);
2502 break;
2503 case kLoadUnsignedHalfword:
2504 ldrh(reg, Address(base, offset), cond);
2505 break;
2506 case kLoadWord:
2507 ldr(reg, Address(base, offset), cond);
2508 break;
2509 case kLoadWordPair:
2510 ldrd(reg, Address(base, offset), cond);
2511 break;
2512 default:
2513 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002514 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002515 }
2516}
2517
2518
2519// Implementation note: this method must emit at most one instruction when
2520// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2521void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2522 Register base,
2523 int32_t offset,
2524 Condition cond) {
2525 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2526 CHECK_NE(base, IP);
2527 LoadImmediate(IP, offset, cond);
2528 add(IP, IP, ShifterOperand(base), cond);
2529 base = IP;
2530 offset = 0;
2531 }
2532 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2533 vldrs(reg, Address(base, offset), cond);
2534}
2535
2536
2537// Implementation note: this method must emit at most one instruction when
2538// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2539void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2540 Register base,
2541 int32_t offset,
2542 Condition cond) {
2543 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2544 CHECK_NE(base, IP);
2545 LoadImmediate(IP, offset, cond);
2546 add(IP, IP, ShifterOperand(base), cond);
2547 base = IP;
2548 offset = 0;
2549 }
2550 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2551 vldrd(reg, Address(base, offset), cond);
2552}
2553
2554
2555// Implementation note: this method must emit at most one instruction when
2556// Address::CanHoldStoreOffsetThumb.
2557void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2558 Register reg,
2559 Register base,
2560 int32_t offset,
2561 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002562 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002563 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002564 CHECK_NE(base, IP);
2565 if (reg != IP) {
2566 tmp_reg = IP;
2567 } else {
2568 // Be careful not to use IP twice (for `reg` and to build the
2569 // Address object used by the store instruction(s) below).
2570 // Instead, save R5 on the stack (or R6 if R5 is not available),
2571 // use it as secondary temporary register, and restore it after
2572 // the store instruction has been emitted.
2573 tmp_reg = base != R5 ? R5 : R6;
2574 Push(tmp_reg);
2575 if (base == SP) {
2576 offset += kRegisterSize;
2577 }
2578 }
2579 LoadImmediate(tmp_reg, offset, cond);
2580 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2581 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002582 offset = 0;
2583 }
2584 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2585 switch (type) {
2586 case kStoreByte:
2587 strb(reg, Address(base, offset), cond);
2588 break;
2589 case kStoreHalfword:
2590 strh(reg, Address(base, offset), cond);
2591 break;
2592 case kStoreWord:
2593 str(reg, Address(base, offset), cond);
2594 break;
2595 case kStoreWordPair:
2596 strd(reg, Address(base, offset), cond);
2597 break;
2598 default:
2599 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002600 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002601 }
Roland Levillain775ef492014-11-04 17:43:11 +00002602 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2603 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2604 Pop(tmp_reg);
2605 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002606}
2607
2608
2609// Implementation note: this method must emit at most one instruction when
2610// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2611void Thumb2Assembler::StoreSToOffset(SRegister reg,
2612 Register base,
2613 int32_t offset,
2614 Condition cond) {
2615 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2616 CHECK_NE(base, IP);
2617 LoadImmediate(IP, offset, cond);
2618 add(IP, IP, ShifterOperand(base), cond);
2619 base = IP;
2620 offset = 0;
2621 }
2622 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2623 vstrs(reg, Address(base, offset), cond);
2624}
2625
2626
2627// Implementation note: this method must emit at most one instruction when
2628// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2629void Thumb2Assembler::StoreDToOffset(DRegister reg,
2630 Register base,
2631 int32_t offset,
2632 Condition cond) {
2633 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2634 CHECK_NE(base, IP);
2635 LoadImmediate(IP, offset, cond);
2636 add(IP, IP, ShifterOperand(base), cond);
2637 base = IP;
2638 offset = 0;
2639 }
2640 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2641 vstrd(reg, Address(base, offset), cond);
2642}
2643
2644
2645void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2646 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002647 dmb(SY);
2648}
2649
2650
2651void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002652 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2653 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002654}
2655
2656
2657void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002658 if (force_32bit_branches_) {
2659 cmp(r, ShifterOperand(0));
2660 b(label, EQ);
2661 } else {
2662 cbz(r, label);
2663 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002664}
2665
2666
2667void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002668 if (force_32bit_branches_) {
2669 cmp(r, ShifterOperand(0));
2670 b(label, NE);
2671 } else {
2672 cbnz(r, label);
2673 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002674}
2675} // namespace arm
2676} // namespace art