blob: 6286b106aa280945d16f278fc5cb265d3fa18862 [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 Geoffray3d1e7882015-02-03 13:59:52 +000028bool Thumb2Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED,
29 Register rn ATTRIBUTE_UNUSED,
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +000030 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:
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +000040 if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done.
41 return true;
42 }
43 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
44
45 case MOV:
46 // TODO: Support less than or equal to 12bits.
47 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
48 case MVN:
49 default:
50 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
51 }
52}
53
Dave Allison65fcc2c2014-04-28 13:45:27 -070054void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so,
55 Condition cond) {
56 EmitDataProcessing(cond, AND, 0, rn, rd, so);
57}
58
59
60void Thumb2Assembler::eor(Register rd, Register rn, const ShifterOperand& so,
61 Condition cond) {
62 EmitDataProcessing(cond, EOR, 0, rn, rd, so);
63}
64
65
66void Thumb2Assembler::sub(Register rd, Register rn, const ShifterOperand& so,
67 Condition cond) {
68 EmitDataProcessing(cond, SUB, 0, rn, rd, so);
69}
70
71
72void Thumb2Assembler::rsb(Register rd, Register rn, const ShifterOperand& so,
73 Condition cond) {
74 EmitDataProcessing(cond, RSB, 0, rn, rd, so);
75}
76
77
78void Thumb2Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so,
79 Condition cond) {
80 EmitDataProcessing(cond, RSB, 1, rn, rd, so);
81}
82
83
84void Thumb2Assembler::add(Register rd, Register rn, const ShifterOperand& so,
85 Condition cond) {
86 EmitDataProcessing(cond, ADD, 0, rn, rd, so);
87}
88
89
90void Thumb2Assembler::adds(Register rd, Register rn, const ShifterOperand& so,
91 Condition cond) {
92 EmitDataProcessing(cond, ADD, 1, rn, rd, so);
93}
94
95
96void Thumb2Assembler::subs(Register rd, Register rn, const ShifterOperand& so,
97 Condition cond) {
98 EmitDataProcessing(cond, SUB, 1, rn, rd, so);
99}
100
101
102void Thumb2Assembler::adc(Register rd, Register rn, const ShifterOperand& so,
103 Condition cond) {
104 EmitDataProcessing(cond, ADC, 0, rn, rd, so);
105}
106
107
108void Thumb2Assembler::sbc(Register rd, Register rn, const ShifterOperand& so,
109 Condition cond) {
110 EmitDataProcessing(cond, SBC, 0, rn, rd, so);
111}
112
113
114void Thumb2Assembler::rsc(Register rd, Register rn, const ShifterOperand& so,
115 Condition cond) {
116 EmitDataProcessing(cond, RSC, 0, rn, rd, so);
117}
118
119
120void Thumb2Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) {
121 CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker.
122 EmitDataProcessing(cond, TST, 1, rn, R0, so);
123}
124
125
126void Thumb2Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) {
127 CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker.
128 EmitDataProcessing(cond, TEQ, 1, rn, R0, so);
129}
130
131
132void Thumb2Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) {
133 EmitDataProcessing(cond, CMP, 1, rn, R0, so);
134}
135
136
137void Thumb2Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) {
138 EmitDataProcessing(cond, CMN, 1, rn, R0, so);
139}
140
141
142void Thumb2Assembler::orr(Register rd, Register rn,
143 const ShifterOperand& so, Condition cond) {
144 EmitDataProcessing(cond, ORR, 0, rn, rd, so);
145}
146
147
148void Thumb2Assembler::orrs(Register rd, Register rn,
149 const ShifterOperand& so, Condition cond) {
150 EmitDataProcessing(cond, ORR, 1, rn, rd, so);
151}
152
153
154void Thumb2Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) {
155 EmitDataProcessing(cond, MOV, 0, R0, rd, so);
156}
157
158
159void Thumb2Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) {
160 EmitDataProcessing(cond, MOV, 1, R0, rd, so);
161}
162
163
164void Thumb2Assembler::bic(Register rd, Register rn, const ShifterOperand& so,
165 Condition cond) {
166 EmitDataProcessing(cond, BIC, 0, rn, rd, so);
167}
168
169
170void Thumb2Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) {
171 EmitDataProcessing(cond, MVN, 0, R0, rd, so);
172}
173
174
175void Thumb2Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) {
176 EmitDataProcessing(cond, MVN, 1, R0, rd, so);
177}
178
179
180void Thumb2Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700181 CheckCondition(cond);
182
Dave Allison65fcc2c2014-04-28 13:45:27 -0700183 if (rd == rm && !IsHighRegister(rd) && !IsHighRegister(rn) && !force_32bit_) {
184 // 16 bit.
185 int16_t encoding = B14 | B9 | B8 | B6 |
186 rn << 3 | rd;
187 Emit16(encoding);
188 } else {
189 // 32 bit.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700190 uint32_t op1 = 0U /* 0b000 */;
191 uint32_t op2 = 0U /* 0b00 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700192 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
193 op1 << 20 |
194 B15 | B14 | B13 | B12 |
195 op2 << 4 |
196 static_cast<uint32_t>(rd) << 8 |
197 static_cast<uint32_t>(rn) << 16 |
198 static_cast<uint32_t>(rm);
199
200 Emit32(encoding);
201 }
202}
203
204
205void Thumb2Assembler::mla(Register rd, Register rn, Register rm, Register ra,
206 Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700207 CheckCondition(cond);
208
Andreas Gampec8ccf682014-09-29 20:07:43 -0700209 uint32_t op1 = 0U /* 0b000 */;
210 uint32_t op2 = 0U /* 0b00 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700211 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
212 op1 << 20 |
213 op2 << 4 |
214 static_cast<uint32_t>(rd) << 8 |
215 static_cast<uint32_t>(ra) << 12 |
216 static_cast<uint32_t>(rn) << 16 |
217 static_cast<uint32_t>(rm);
218
219 Emit32(encoding);
220}
221
222
223void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra,
224 Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700225 CheckCondition(cond);
226
Andreas Gampec8ccf682014-09-29 20:07:43 -0700227 uint32_t op1 = 0U /* 0b000 */;
228 uint32_t op2 = 01 /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700229 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 |
230 op1 << 20 |
231 op2 << 4 |
232 static_cast<uint32_t>(rd) << 8 |
233 static_cast<uint32_t>(ra) << 12 |
234 static_cast<uint32_t>(rn) << 16 |
235 static_cast<uint32_t>(rm);
236
237 Emit32(encoding);
238}
239
240
241void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
242 Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700243 CheckCondition(cond);
244
Andreas Gampec8ccf682014-09-29 20:07:43 -0700245 uint32_t op1 = 2U /* 0b010; */;
246 uint32_t op2 = 0U /* 0b0000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700247 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
248 op1 << 20 |
249 op2 << 4 |
250 static_cast<uint32_t>(rd_lo) << 12 |
251 static_cast<uint32_t>(rd_hi) << 8 |
252 static_cast<uint32_t>(rn) << 16 |
253 static_cast<uint32_t>(rm);
254
255 Emit32(encoding);
256}
257
258
259void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700260 CheckCondition(cond);
261
Andreas Gampec8ccf682014-09-29 20:07:43 -0700262 uint32_t op1 = 1U /* 0b001 */;
263 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700264 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 |
265 op1 << 20 |
266 op2 << 4 |
267 0xf << 12 |
268 static_cast<uint32_t>(rd) << 8 |
269 static_cast<uint32_t>(rn) << 16 |
270 static_cast<uint32_t>(rm);
271
272 Emit32(encoding);
273}
274
275
276void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700277 CheckCondition(cond);
278
Andreas Gampec8ccf682014-09-29 20:07:43 -0700279 uint32_t op1 = 1U /* 0b001 */;
280 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700281 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 |
282 op1 << 20 |
283 op2 << 4 |
284 0xf << 12 |
285 static_cast<uint32_t>(rd) << 8 |
286 static_cast<uint32_t>(rn) << 16 |
287 static_cast<uint32_t>(rm);
288
289 Emit32(encoding);
290}
291
292
Roland Levillain51d3fc42014-11-13 14:11:42 +0000293void Thumb2Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
294 CheckCondition(cond);
295 CHECK_LE(lsb, 31U);
296 CHECK(1U <= width && width <= 32U) << width;
297 uint32_t widthminus1 = width - 1;
298 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
299 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
300
301 uint32_t op = 20U /* 0b10100 */;
302 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
303 op << 20 |
304 static_cast<uint32_t>(rn) << 16 |
305 imm3 << 12 |
306 static_cast<uint32_t>(rd) << 8 |
307 imm2 << 6 |
308 widthminus1;
309
310 Emit32(encoding);
311}
312
313
Roland Levillain981e4542014-11-14 11:47:14 +0000314void Thumb2Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
315 CheckCondition(cond);
316 CHECK_LE(lsb, 31U);
317 CHECK(1U <= width && width <= 32U) << width;
318 uint32_t widthminus1 = width - 1;
319 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
320 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
321
322 uint32_t op = 28U /* 0b11100 */;
323 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
324 op << 20 |
325 static_cast<uint32_t>(rn) << 16 |
326 imm3 << 12 |
327 static_cast<uint32_t>(rd) << 8 |
328 imm2 << 6 |
329 widthminus1;
330
331 Emit32(encoding);
332}
333
334
Dave Allison65fcc2c2014-04-28 13:45:27 -0700335void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
336 EmitLoadStore(cond, true, false, false, false, rd, ad);
337}
338
339
340void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
341 EmitLoadStore(cond, false, false, false, false, rd, ad);
342}
343
344
345void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
346 EmitLoadStore(cond, true, true, false, false, rd, ad);
347}
348
349
350void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
351 EmitLoadStore(cond, false, true, false, false, rd, ad);
352}
353
354
355void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
356 EmitLoadStore(cond, true, false, true, false, rd, ad);
357}
358
359
360void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
361 EmitLoadStore(cond, false, false, true, false, rd, ad);
362}
363
364
365void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
366 EmitLoadStore(cond, true, true, false, true, rd, ad);
367}
368
369
370void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
371 EmitLoadStore(cond, true, false, true, true, rd, ad);
372}
373
374
375void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700376 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700377 CHECK_EQ(rd % 2, 0);
378 // This is different from other loads. The encoding is like ARM.
379 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
380 static_cast<int32_t>(rd) << 12 |
381 (static_cast<int32_t>(rd) + 1) << 8 |
382 ad.encodingThumbLdrdStrd();
383 Emit32(encoding);
384}
385
386
387void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700388 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700389 CHECK_EQ(rd % 2, 0);
390 // This is different from other loads. The encoding is like ARM.
391 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
392 static_cast<int32_t>(rd) << 12 |
393 (static_cast<int32_t>(rd) + 1) << 8 |
394 ad.encodingThumbLdrdStrd();
395 Emit32(encoding);
396}
397
398
399void Thumb2Assembler::ldm(BlockAddressMode am,
400 Register base,
401 RegList regs,
402 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000403 CHECK_NE(regs, 0u); // Do not use ldm if there's nothing to load.
404 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700405 // Thumb doesn't support one reg in the list.
406 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000407 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700408 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700409 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700410 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
411 } else {
412 EmitMultiMemOp(cond, am, true, base, regs);
413 }
414}
415
416
417void Thumb2Assembler::stm(BlockAddressMode am,
418 Register base,
419 RegList regs,
420 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000421 CHECK_NE(regs, 0u); // Do not use stm if there's nothing to store.
422 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700423 // Thumb doesn't support one reg in the list.
424 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000425 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700426 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700427 CHECK(am == IA || am == IA_W);
428 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700429 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
430 } else {
431 EmitMultiMemOp(cond, am, false, base, regs);
432 }
433}
434
435
436bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
437 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
438 if (((imm32 & ((1 << 19) - 1)) == 0) &&
439 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
440 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
441 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
442 ((imm32 >> 19) & ((1 << 6) -1));
443 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
444 sd, S0, S0);
445 return true;
446 }
447 return false;
448}
449
450
451bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
452 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
453 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
454 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
455 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
456 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
457 ((imm64 >> 48) & ((1 << 6) -1));
458 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
459 dd, D0, D0);
460 return true;
461 }
462 return false;
463}
464
465
466void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
467 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
468}
469
470
471void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
472 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
473}
474
475
476void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
477 Condition cond) {
478 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
479}
480
481
482void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
483 Condition cond) {
484 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
485}
486
487
488void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
489 Condition cond) {
490 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
491}
492
493
494void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
495 Condition cond) {
496 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
497}
498
499
500void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
501 Condition cond) {
502 EmitVFPsss(cond, B21, sd, sn, sm);
503}
504
505
506void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
507 Condition cond) {
508 EmitVFPddd(cond, B21, dd, dn, dm);
509}
510
511
512void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
513 Condition cond) {
514 EmitVFPsss(cond, 0, sd, sn, sm);
515}
516
517
518void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
519 Condition cond) {
520 EmitVFPddd(cond, 0, dd, dn, dm);
521}
522
523
524void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
525 Condition cond) {
526 EmitVFPsss(cond, B6, sd, sn, sm);
527}
528
529
530void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
531 Condition cond) {
532 EmitVFPddd(cond, B6, dd, dn, dm);
533}
534
535
536void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
537 Condition cond) {
538 EmitVFPsss(cond, B23, sd, sn, sm);
539}
540
541
542void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
543 Condition cond) {
544 EmitVFPddd(cond, B23, dd, dn, dm);
545}
546
547
548void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
549 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
550}
551
552
553void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
554 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
555}
556
557
558void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
559 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
560}
561
562
563void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
564 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
565}
566
567
568void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
569 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
570}
571
572void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
573 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
574}
575
576
577void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
578 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
579}
580
581
582void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
583 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
584}
585
586
587void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
588 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
589}
590
591
592void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
593 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
594}
595
596
597void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
598 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
599}
600
601
602void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
603 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
604}
605
606
607void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
608 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
609}
610
611
612void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
613 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
614}
615
616
617void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
618 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
619}
620
621
622void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
623 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
624}
625
626
627void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
628 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
629}
630
631
632void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
633 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
634}
635
636
637void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
638 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
639}
640
641
642void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
643 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
644}
645
646void Thumb2Assembler::b(Label* label, Condition cond) {
647 EmitBranch(cond, label, false, false);
648}
649
650
651void Thumb2Assembler::bl(Label* label, Condition cond) {
652 CheckCondition(cond);
653 EmitBranch(cond, label, true, false);
654}
655
656
657void Thumb2Assembler::blx(Label* label) {
658 EmitBranch(AL, label, true, true);
659}
660
661
662void Thumb2Assembler::MarkExceptionHandler(Label* label) {
663 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
664 Label l;
665 b(&l);
666 EmitBranch(AL, label, false, false);
667 Bind(&l);
668}
669
670
671void Thumb2Assembler::Emit32(int32_t value) {
672 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
673 buffer_.Emit<int16_t>(value >> 16);
674 buffer_.Emit<int16_t>(value & 0xffff);
675}
676
677
678void Thumb2Assembler::Emit16(int16_t value) {
679 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
680 buffer_.Emit<int16_t>(value);
681}
682
683
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700684bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700685 Opcode opcode,
Andreas Gampeca714582015-04-03 19:41:34 -0700686 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700687 Register rn,
688 Register rd,
689 const ShifterOperand& so) {
690 if (force_32bit_) {
691 return true;
692 }
693
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000694 // Check special case for SP relative ADD and SUB immediate.
695 if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) {
696 // If the immediate is in range, use 16 bit.
697 if (rd == SP) {
698 if (so.GetImmediate() < (1 << 9)) { // 9 bit immediate.
699 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700700 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000701 } else if (!IsHighRegister(rd) && opcode == ADD) {
702 if (so.GetImmediate() < (1 << 10)) { // 10 bit immediate.
703 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700704 }
705 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000706 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700707
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000708 bool can_contain_high_register = (opcode == MOV)
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800709 || ((opcode == ADD) && (rn == rd) && !set_cc);
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000710
711 if (IsHighRegister(rd) || IsHighRegister(rn)) {
712 if (!can_contain_high_register) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700713 return true;
714 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100715
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000716 // There are high register instructions available for this opcode.
717 // However, there is no actual shift available, neither for ADD nor for MOV (ASR/LSR/LSL/ROR).
718 if (so.IsShift() && (so.GetShift() == RRX || so.GetImmediate() != 0u)) {
719 return true;
720 }
721
722 // The ADD and MOV instructions that work with high registers don't have 16-bit
723 // immediate variants.
724 if (so.IsImmediate()) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100725 return true;
726 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700727 }
728
729 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
730 return true;
731 }
732
733 // Check for MOV with an ROR.
734 if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
735 if (so.GetImmediate() != 0) {
736 return true;
737 }
738 }
739
740 bool rn_is_valid = true;
741
742 // Check for single operand instructions and ADD/SUB.
743 switch (opcode) {
744 case CMP:
745 case MOV:
746 case TST:
747 case MVN:
748 rn_is_valid = false; // There is no Rn for these instructions.
749 break;
750 case TEQ:
751 return true;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700752 case ADD:
753 case SUB:
754 break;
755 default:
756 if (so.IsRegister() && rd != rn) {
757 return true;
758 }
759 }
760
761 if (so.IsImmediate()) {
762 if (rn_is_valid && rn != rd) {
763 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
764 // immediate must be 3 bits.
765 if (opcode != ADD && opcode != SUB) {
766 return true;
767 } else {
768 // Check that the immediate is 3 bits for ADD and SUB.
769 if (so.GetImmediate() >= 8) {
770 return true;
771 }
772 }
773 } else {
774 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
775 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
776 return true;
777 } else {
778 if (so.GetImmediate() > 255) {
779 return true;
780 }
781 }
782 }
783 }
784
785 // The instruction can be encoded in 16 bits.
786 return false;
787}
788
789
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700790void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700791 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700792 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700793 Register rn,
794 Register rd,
795 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700796 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700797 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700798 case AND: thumb_opcode = 0U /* 0b0000 */; break;
799 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
800 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
801 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
802 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700803 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700804 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700805 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700806 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
807 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
808 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
809 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
810 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
811 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
812 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
813 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700814 default:
815 break;
816 }
817
Andreas Gampec8ccf682014-09-29 20:07:43 -0700818 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700819 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000820 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700821 }
822
823 int32_t encoding = 0;
824 if (so.IsImmediate()) {
825 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100826 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000827 if (!set_cc) {
828 if (opcode == SUB) {
829 thumb_opcode = 5U;
830 } else if (opcode == ADD) {
831 thumb_opcode = 0U;
832 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700833 }
834 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700835
836 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700837 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700838 uint32_t imm8 = imm & 0xff;
839
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000840 encoding = B31 | B30 | B29 | B28 |
841 (set_cc ? B20 : B25) |
842 thumb_opcode << 21 |
843 rn << 16 |
844 rd << 8 |
845 i << 26 |
846 imm3 << 12 |
847 imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700848 } else {
849 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700850 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700851 if (imm == kInvalidModifiedImmediate) {
852 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
Vladimir Markoe8469c12014-11-26 18:09:30 +0000853 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700854 }
855 encoding = B31 | B30 | B29 | B28 |
856 thumb_opcode << 21 |
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000857 (set_cc ? B20 : 0) |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700858 rn << 16 |
859 rd << 8 |
860 imm;
861 }
862 } else if (so.IsRegister()) {
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000863 // Register (possibly shifted)
864 encoding = B31 | B30 | B29 | B27 | B25 |
865 thumb_opcode << 21 |
866 (set_cc ? B20 : 0) |
867 rn << 16 |
868 rd << 8 |
869 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700870 }
871 Emit32(encoding);
872}
873
874
875void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
876 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700877 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700878 Register rn,
879 Register rd,
880 const ShifterOperand& so) {
881 if (opcode == ADD || opcode == SUB) {
882 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
883 return;
884 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700885 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700886 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700887 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700888 uint8_t opcode_shift = 6;
889 uint8_t rd_shift = 0;
890 uint8_t rn_shift = 3;
891 uint8_t immediate_shift = 0;
892 bool use_immediate = false;
893 uint8_t immediate = 0;
894
895 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
896 // Convert shifted mov operand2 into 16 bit opcodes.
897 dp_opcode = 0;
898 opcode_shift = 11;
899
900 use_immediate = true;
901 immediate = so.GetImmediate();
902 immediate_shift = 6;
903
904 rn = so.GetRegister();
905
906 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700907 case LSL: thumb_opcode = 0U /* 0b00 */; break;
908 case LSR: thumb_opcode = 1U /* 0b01 */; break;
909 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700910 case ROR:
911 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700912 thumb_opcode = 7U /* 0b111 */;
913 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700914 opcode_shift = 6;
915 use_immediate = false;
916 break;
917 case RRX: break;
918 default:
919 break;
920 }
921 } else {
922 if (so.IsImmediate()) {
923 use_immediate = true;
924 immediate = so.GetImmediate();
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800925 } else {
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000926 CHECK(!(so.IsRegister() && so.IsShift() && so.GetSecondRegister() != kNoRegister))
927 << "No register-shifted register instruction available in thumb";
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800928 // Adjust rn and rd: only two registers will be emitted.
929 switch (opcode) {
930 case AND:
931 case ORR:
932 case EOR:
933 case RSB:
934 case ADC:
935 case SBC:
936 case BIC: {
937 if (rn == rd) {
938 rn = so.GetRegister();
939 } else {
940 CHECK_EQ(rd, so.GetRegister());
941 }
942 break;
943 }
944 case CMP:
945 case CMN: {
946 CHECK_EQ(rd, 0);
947 rd = rn;
948 rn = so.GetRegister();
949 break;
950 }
Andreas Gampe7b7e5242015-02-02 19:17:11 -0800951 case TST:
952 case TEQ:
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800953 case MVN: {
954 CHECK_EQ(rn, 0);
955 rn = so.GetRegister();
956 break;
957 }
958 default:
959 break;
960 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700961 }
962
963 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700964 case AND: thumb_opcode = 0U /* 0b0000 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800965 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700966 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700967 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700968 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
969 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800970 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
971 case TST: thumb_opcode = 8U /* 0b1000 */; CHECK(!use_immediate); break;
972 case MVN: thumb_opcode = 15U /* 0b1111 */; CHECK(!use_immediate); break;
973 case CMP: {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700974 if (use_immediate) {
975 // T2 encoding.
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800976 dp_opcode = 0;
977 opcode_shift = 11;
978 thumb_opcode = 5U /* 0b101 */;
979 rd_shift = 8;
980 rn_shift = 8;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700981 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700982 thumb_opcode = 10U /* 0b1010 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700983 }
984
985 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800986 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100987 case CMN: {
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800988 CHECK(!use_immediate);
Andreas Gampec8ccf682014-09-29 20:07:43 -0700989 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100990 break;
991 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700992 case MOV:
993 dp_opcode = 0;
994 if (use_immediate) {
995 // T2 encoding.
996 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700997 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700998 rd_shift = 8;
999 rn_shift = 8;
1000 } else {
1001 rn = so.GetRegister();
1002 if (IsHighRegister(rn) || IsHighRegister(rd)) {
1003 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001004 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001005 opcode_shift = 7;
1006 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001007 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
1008 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001009 } else {
1010 thumb_opcode = 0;
1011 }
1012 }
1013 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001014
1015 case TEQ:
1016 case RSC:
Dave Allison65fcc2c2014-04-28 13:45:27 -07001017 default:
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001018 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001019 break;
1020 }
1021 }
1022
Andreas Gampec8ccf682014-09-29 20:07:43 -07001023 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001024 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001025 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001026 }
1027
1028 int16_t encoding = dp_opcode << 14 |
1029 (thumb_opcode << opcode_shift) |
1030 rd << rd_shift |
1031 rn << rn_shift |
1032 (use_immediate ? (immediate << immediate_shift) : 0);
1033
1034 Emit16(encoding);
1035}
1036
1037
1038// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001039void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001040 Opcode opcode,
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001041 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001042 Register rn,
1043 Register rd,
1044 const ShifterOperand& so) {
1045 uint8_t dp_opcode = 0;
1046 uint8_t opcode_shift = 6;
1047 uint8_t rd_shift = 0;
1048 uint8_t rn_shift = 3;
1049 uint8_t immediate_shift = 0;
1050 bool use_immediate = false;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001051 uint32_t immediate = 0; // Should be at most 9 bits but keep the full immediate for CHECKs.
Dave Allison65fcc2c2014-04-28 13:45:27 -07001052 uint8_t thumb_opcode;;
1053
1054 if (so.IsImmediate()) {
1055 use_immediate = true;
1056 immediate = so.GetImmediate();
1057 }
1058
1059 switch (opcode) {
1060 case ADD:
1061 if (so.IsRegister()) {
1062 Register rm = so.GetRegister();
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001063 if (rn == rd && !set_cc) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001064 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001065 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001066 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001067 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001068 // Make Rn also contain the top bit of rd.
1069 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001070 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1071 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001072 } else {
1073 // T1.
1074 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001075 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001076 immediate = static_cast<uint32_t>(so.GetRegister());
1077 use_immediate = true;
1078 immediate_shift = 6;
1079 }
1080 } else {
1081 // Immediate.
1082 if (rd == SP && rn == SP) {
1083 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001084 dp_opcode = 2U /* 0b10 */;
1085 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001086 opcode_shift = 12;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001087 CHECK_LT(immediate, (1u << 9));
1088 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001089
1090 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1091 rn = R0;
1092 rd = R0;
1093 rd_shift = 0;
1094 rn_shift = 0;
1095 immediate >>= 2;
1096 } else if (rd != SP && rn == SP) {
1097 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001098 dp_opcode = 2U /* 0b10 */;
1099 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001100 opcode_shift = 11;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001101 CHECK_LT(immediate, (1u << 10));
1102 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001103
1104 // Remove rn from instruction.
1105 rn = R0;
1106 rn_shift = 0;
1107 rd_shift = 8;
1108 immediate >>= 2;
1109 } else if (rn != rd) {
1110 // Must use T1.
1111 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001112 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001113 immediate_shift = 6;
1114 } else {
1115 // T2 encoding.
1116 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001117 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001118 rd_shift = 8;
1119 rn_shift = 8;
1120 }
1121 }
1122 break;
1123
1124 case SUB:
1125 if (so.IsRegister()) {
1126 // T1.
1127 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001128 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001129 immediate = static_cast<uint32_t>(so.GetRegister());
1130 use_immediate = true;
1131 immediate_shift = 6;
1132 } else {
1133 if (rd == SP && rn == SP) {
1134 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001135 dp_opcode = 2U /* 0b10 */;
1136 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001137 opcode_shift = 7;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001138 CHECK_LT(immediate, (1u << 9));
1139 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001140
1141 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1142 rn = R0;
1143 rd = R0;
1144 rd_shift = 0;
1145 rn_shift = 0;
1146 immediate >>= 2;
1147 } else if (rn != rd) {
1148 // Must use T1.
1149 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001150 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001151 immediate_shift = 6;
1152 } else {
1153 // T2 encoding.
1154 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001155 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001156 rd_shift = 8;
1157 rn_shift = 8;
1158 }
1159 }
1160 break;
1161 default:
1162 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001163 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001164 }
1165
1166 int16_t encoding = dp_opcode << 14 |
1167 (thumb_opcode << opcode_shift) |
1168 rd << rd_shift |
1169 rn << rn_shift |
1170 (use_immediate ? (immediate << immediate_shift) : 0);
1171
1172 Emit16(encoding);
1173}
1174
1175
1176void Thumb2Assembler::EmitDataProcessing(Condition cond,
1177 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001178 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001179 Register rn,
1180 Register rd,
1181 const ShifterOperand& so) {
1182 CHECK_NE(rd, kNoRegister);
1183 CheckCondition(cond);
1184
1185 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1186 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1187 } else {
1188 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1189 }
1190}
1191
Dave Allison45fdb932014-06-25 12:37:10 -07001192void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1193 CHECK_LT(amount, (1 << 5));
1194 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1195 uint16_t opcode = 0;
1196 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001197 case LSL: opcode = 0U /* 0b00 */; break;
1198 case LSR: opcode = 1U /* 0b01 */; break;
1199 case ASR: opcode = 2U /* 0b10 */; break;
1200 case ROR: opcode = 3U /* 0b11 */; break;
1201 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001202 default:
1203 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001204 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001205 }
1206 // 32 bit.
1207 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1208 0xf << 16 | (setcc ? B20 : 0);
1209 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001210 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001211 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1212 static_cast<int16_t>(rd) << 8 | opcode << 4;
1213 Emit32(encoding);
1214 } else {
1215 // 16 bit shift
1216 uint16_t opcode = 0;
1217 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001218 case LSL: opcode = 0U /* 0b00 */; break;
1219 case LSR: opcode = 1U /* 0b01 */; break;
1220 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001221 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001222 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1223 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001224 }
1225 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1226 static_cast<int16_t>(rd);
1227 Emit16(encoding);
1228 }
1229}
1230
1231void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1232 CHECK_NE(shift, RRX);
1233 bool must_be_32bit = false;
1234 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1235 must_be_32bit = true;
1236 }
1237
1238 if (must_be_32bit) {
1239 uint16_t opcode = 0;
1240 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001241 case LSL: opcode = 0U /* 0b00 */; break;
1242 case LSR: opcode = 1U /* 0b01 */; break;
1243 case ASR: opcode = 2U /* 0b10 */; break;
1244 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001245 default:
1246 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001247 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001248 }
1249 // 32 bit.
1250 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1251 0xf << 12 | (setcc ? B20 : 0);
1252 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1253 static_cast<int16_t>(rd) << 8 | opcode << 21;
1254 Emit32(encoding);
1255 } else {
1256 uint16_t opcode = 0;
1257 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001258 case LSL: opcode = 2U /* 0b0010 */; break;
1259 case LSR: opcode = 3U /* 0b0011 */; break;
1260 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001261 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001262 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1263 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001264 }
1265 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1266 static_cast<int16_t>(rd);
1267 Emit16(encoding);
1268 }
1269}
1270
1271
Dave Allison65fcc2c2014-04-28 13:45:27 -07001272
1273void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1274 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1275 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1276 int32_t offset = target_ - location_;
1277
1278 if (size_ == k32Bit) {
1279 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1280 if (link) {
1281 // BL or BLX immediate.
1282 encoding |= B14;
1283 if (!x) {
1284 encoding |= B12;
1285 } else {
1286 // Bottom bit of offset must be 0.
1287 CHECK_EQ((offset & 1), 0);
1288 }
1289 } else {
1290 if (x) {
1291 LOG(FATAL) << "Invalid use of BX";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001292 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001293 } else {
1294 if (cond_ == AL) {
1295 // Can use the T4 encoding allowing a 24 bit offset.
1296 if (!x) {
1297 encoding |= B12;
1298 }
1299 } else {
1300 // Must be T3 encoding with a 20 bit offset.
1301 encoding |= cond_ << 22;
1302 }
1303 }
1304 }
1305 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1306 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1307 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1308 } else {
1309 if (IsCompareAndBranch()) {
1310 offset -= 4;
1311 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001312 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001313 int16_t encoding = B15 | B13 | B12 |
1314 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1315 static_cast<uint32_t>(rn_) |
1316 B8 |
1317 i << 9 |
1318 imm5 << 3;
1319 buffer->Store<int16_t>(location_, encoding);
1320 } else {
1321 offset -= 4; // Account for PC offset.
1322 int16_t encoding;
1323 // 16 bit.
1324 if (cond_ == AL) {
1325 encoding = B15 | B14 | B13 |
1326 ((offset >> 1) & 0x7ff);
1327 } else {
1328 encoding = B15 | B14 | B12 |
1329 cond_ << 8 | ((offset >> 1) & 0xff);
1330 }
1331 buffer->Store<int16_t>(location_, encoding);
1332 }
1333 }
1334}
1335
1336
1337uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1338 uint32_t location = buffer_.Size();
1339
1340 // This is always unresolved as it must be a forward branch.
1341 Emit16(prev); // Previous link.
1342 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1343 location, rn);
1344}
1345
1346
1347// NOTE: this only support immediate offsets, not [rx,ry].
1348// TODO: support [rx,ry] instructions.
1349void Thumb2Assembler::EmitLoadStore(Condition cond,
1350 bool load,
1351 bool byte,
1352 bool half,
1353 bool is_signed,
1354 Register rd,
1355 const Address& ad) {
1356 CHECK_NE(rd, kNoRegister);
1357 CheckCondition(cond);
1358 bool must_be_32bit = force_32bit_;
1359 if (IsHighRegister(rd)) {
1360 must_be_32bit = true;
1361 }
1362
1363 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001364 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001365 must_be_32bit = true;
1366 }
1367
1368 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1369 must_be_32bit = true;
1370 }
1371
Dave Allison45fdb932014-06-25 12:37:10 -07001372 if (ad.IsImmediate()) {
1373 // Immediate offset
1374 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001375
Dave Allison45fdb932014-06-25 12:37:10 -07001376 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001377 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001378 must_be_32bit = true;
1379 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001380
1381 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001382 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001383 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001384 must_be_32bit = true;
1385 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001386 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001387 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001388 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001389 must_be_32bit = true;
1390 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001391 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001392 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001393 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001394 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001395 }
1396 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001397
Dave Allison45fdb932014-06-25 12:37:10 -07001398 if (must_be_32bit) {
1399 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1400 (load ? B20 : 0) |
1401 (is_signed ? B24 : 0) |
1402 static_cast<uint32_t>(rd) << 12 |
1403 ad.encodingThumb(true) |
1404 (byte ? 0 : half ? B21 : B22);
1405 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001406 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001407 // 16 bit thumb1.
1408 uint8_t opA = 0;
1409 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001410
1411 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001412 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001413 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001414 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001415 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001416 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001417 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001418 sp_relative = true;
1419 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001420 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001421 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001422 }
Dave Allison45fdb932014-06-25 12:37:10 -07001423 int16_t encoding = opA << 12 |
1424 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001425
Dave Allison45fdb932014-06-25 12:37:10 -07001426 CHECK_GE(offset, 0);
1427 if (sp_relative) {
1428 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001429 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001430 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001431 encoding |= rd << 8 | offset >> 2;
1432 } else {
1433 // No SP relative. The offset is shifted right depending on
1434 // the size of the load/store.
1435 encoding |= static_cast<uint32_t>(rd);
1436
1437 if (byte) {
1438 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001439 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001440 } else if (half) {
1441 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001442 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001443 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001444 offset >>= 1;
1445 } else {
1446 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001447 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001448 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001449 offset >>= 2;
1450 }
1451 encoding |= rn << 3 | offset << 6;
1452 }
1453
1454 Emit16(encoding);
1455 }
1456 } else {
1457 // Register shift.
1458 if (ad.GetRegister() == PC) {
1459 // PC relative literal encoding.
1460 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001461 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001462 int32_t up = B23;
1463 if (offset < 0) {
1464 offset = -offset;
1465 up = 0;
1466 }
1467 CHECK_LT(offset, (1 << 12));
1468 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1469 offset | up |
1470 static_cast<uint32_t>(rd) << 12;
1471 Emit32(encoding);
1472 } else {
1473 // 16 bit literal load.
1474 CHECK_GE(offset, 0);
1475 CHECK_LT(offset, (1 << 10));
1476 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1477 Emit16(encoding);
1478 }
1479 } else {
1480 if (ad.GetShiftCount() != 0) {
1481 // If there is a shift count this must be 32 bit.
1482 must_be_32bit = true;
1483 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1484 must_be_32bit = true;
1485 }
1486
1487 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001488 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001489 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001490 if (half) {
1491 encoding |= B21;
1492 } else if (!byte) {
1493 encoding |= B22;
1494 }
Dave Allison45fdb932014-06-25 12:37:10 -07001495 Emit32(encoding);
1496 } else {
1497 // 16 bit register offset.
1498 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1499 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001500 if (byte) {
1501 encoding |= B10;
1502 } else if (half) {
1503 encoding |= B9;
1504 }
Dave Allison45fdb932014-06-25 12:37:10 -07001505 Emit16(encoding);
1506 }
1507 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001508 }
1509}
1510
1511
1512void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001513 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001514 bool load,
1515 Register base,
1516 RegList regs) {
1517 CHECK_NE(base, kNoRegister);
1518 CheckCondition(cond);
1519 bool must_be_32bit = force_32bit_;
1520
Vladimir Markoe8469c12014-11-26 18:09:30 +00001521 if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
1522 (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
1523 // Use 16-bit PUSH/POP.
1524 int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
1525 ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
1526 Emit16(encoding);
1527 return;
1528 }
1529
Dave Allison65fcc2c2014-04-28 13:45:27 -07001530 if ((regs & 0xff00) != 0) {
1531 must_be_32bit = true;
1532 }
1533
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001534 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001535 // 16 bit always uses writeback.
1536 if (!w_bit) {
1537 must_be_32bit = true;
1538 }
1539
1540 if (must_be_32bit) {
1541 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001542 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001543 case IA:
1544 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001545 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001546 break;
1547 case DB:
1548 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001549 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001550 break;
1551 case DA:
1552 case IB:
1553 case DA_W:
1554 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001555 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001556 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001557 }
1558 if (load) {
1559 // Cannot have SP in the list.
1560 CHECK_EQ((regs & (1 << SP)), 0);
1561 } else {
1562 // Cannot have PC or SP in the list.
1563 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1564 }
1565 int32_t encoding = B31 | B30 | B29 | B27 |
1566 (op << 23) |
1567 (load ? B20 : 0) |
1568 base << 16 |
1569 regs |
1570 (w_bit << 21);
1571 Emit32(encoding);
1572 } else {
1573 int16_t encoding = B15 | B14 |
1574 (load ? B11 : 0) |
1575 base << 8 |
1576 regs;
1577 Emit16(encoding);
1578 }
1579}
1580
1581
1582void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1583 uint32_t pc = buffer_.Size();
1584 Branch::Type branch_type;
1585 if (cond == AL) {
1586 if (link) {
1587 if (x) {
1588 branch_type = Branch::kUnconditionalLinkX; // BLX.
1589 } else {
1590 branch_type = Branch::kUnconditionalLink; // BX.
1591 }
1592 } else {
1593 branch_type = Branch::kUnconditional; // B.
1594 }
1595 } else {
1596 branch_type = Branch::kConditional; // B<cond>.
1597 }
1598
1599 if (label->IsBound()) {
1600 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1601
1602 // The branch is to a bound label which means that it's a backwards branch. We know the
1603 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1604 // branch the size may change if it so happens that other branches change size that change
1605 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1606 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001607 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001608 Emit16(0); // Space for a 16 bit branch.
1609 } else {
1610 Emit32(0); // Space for a 32 bit branch.
1611 }
1612 } else {
1613 // Branch is to an unbound label. Emit space for it.
1614 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001615 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001616 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1617 Emit16(0); // another 16 bits.
1618 } else {
1619 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1620 }
1621 label->LinkTo(branch_id); // Link to the branch ID.
1622 }
1623}
1624
1625
1626void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1627 CHECK_NE(rd, kNoRegister);
1628 CHECK_NE(rm, kNoRegister);
1629 CheckCondition(cond);
1630 CHECK_NE(rd, PC);
1631 CHECK_NE(rm, PC);
1632 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1633 B25 | B23 | B21 | B20 |
1634 static_cast<uint32_t>(rm) << 16 |
1635 0xf << 12 |
1636 static_cast<uint32_t>(rd) << 8 |
1637 B7 |
1638 static_cast<uint32_t>(rm);
1639 Emit32(encoding);
1640}
1641
1642
1643void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1644 CheckCondition(cond);
1645 bool must_be_32bit = force_32bit_;
1646 if (IsHighRegister(rd)|| imm16 >= 256u) {
1647 must_be_32bit = true;
1648 }
1649
1650 if (must_be_32bit) {
1651 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001652 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1653 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1654 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001655 uint32_t imm8 = imm16 & 0xff;
1656 int32_t encoding = B31 | B30 | B29 | B28 |
1657 B25 | B22 |
1658 static_cast<uint32_t>(rd) << 8 |
1659 i << 26 |
1660 imm4 << 16 |
1661 imm3 << 12 |
1662 imm8;
1663 Emit32(encoding);
1664 } else {
1665 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1666 imm16;
1667 Emit16(encoding);
1668 }
1669}
1670
1671
1672void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1673 CheckCondition(cond);
1674 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001675 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1676 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1677 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001678 uint32_t imm8 = imm16 & 0xff;
1679 int32_t encoding = B31 | B30 | B29 | B28 |
1680 B25 | B23 | B22 |
1681 static_cast<uint32_t>(rd) << 8 |
1682 i << 26 |
1683 imm4 << 16 |
1684 imm3 << 12 |
1685 imm8;
1686 Emit32(encoding);
1687}
1688
1689
1690void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1691 CHECK_NE(rn, kNoRegister);
1692 CHECK_NE(rt, kNoRegister);
1693 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001694 CHECK_LT(imm, (1u << 10));
1695
1696 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1697 static_cast<uint32_t>(rn) << 16 |
1698 static_cast<uint32_t>(rt) << 12 |
1699 0xf << 8 |
1700 imm >> 2;
1701 Emit32(encoding);
1702}
1703
1704
1705void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1706 ldrex(rt, rn, 0, cond);
1707}
1708
1709
1710void Thumb2Assembler::strex(Register rd,
1711 Register rt,
1712 Register rn,
1713 uint16_t imm,
1714 Condition cond) {
1715 CHECK_NE(rn, kNoRegister);
1716 CHECK_NE(rd, kNoRegister);
1717 CHECK_NE(rt, kNoRegister);
1718 CheckCondition(cond);
1719 CHECK_LT(imm, (1u << 10));
1720
1721 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1722 static_cast<uint32_t>(rn) << 16 |
1723 static_cast<uint32_t>(rt) << 12 |
1724 static_cast<uint32_t>(rd) << 8 |
1725 imm >> 2;
1726 Emit32(encoding);
1727}
1728
1729
Calin Juravle52c48962014-12-16 17:02:57 +00001730void Thumb2Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
1731 CHECK_NE(rn, kNoRegister);
1732 CHECK_NE(rt, kNoRegister);
1733 CHECK_NE(rt2, kNoRegister);
1734 CHECK_NE(rt, rt2);
1735 CheckCondition(cond);
1736
1737 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 | B20 |
1738 static_cast<uint32_t>(rn) << 16 |
1739 static_cast<uint32_t>(rt) << 12 |
1740 static_cast<uint32_t>(rt2) << 8 |
1741 B6 | B5 | B4 | B3 | B2 | B1 | B0;
1742 Emit32(encoding);
1743}
1744
1745
Dave Allison65fcc2c2014-04-28 13:45:27 -07001746void Thumb2Assembler::strex(Register rd,
1747 Register rt,
1748 Register rn,
1749 Condition cond) {
1750 strex(rd, rt, rn, 0, cond);
1751}
1752
1753
Calin Juravle52c48962014-12-16 17:02:57 +00001754void Thumb2Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
1755 CHECK_NE(rd, kNoRegister);
1756 CHECK_NE(rn, kNoRegister);
1757 CHECK_NE(rt, kNoRegister);
1758 CHECK_NE(rt2, kNoRegister);
1759 CHECK_NE(rt, rt2);
1760 CHECK_NE(rd, rt);
1761 CHECK_NE(rd, rt2);
1762 CheckCondition(cond);
1763
1764 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 |
1765 static_cast<uint32_t>(rn) << 16 |
1766 static_cast<uint32_t>(rt) << 12 |
1767 static_cast<uint32_t>(rt2) << 8 |
1768 B6 | B5 | B4 |
1769 static_cast<uint32_t>(rd);
1770 Emit32(encoding);
1771}
1772
1773
Dave Allison65fcc2c2014-04-28 13:45:27 -07001774void Thumb2Assembler::clrex(Condition cond) {
1775 CheckCondition(cond);
1776 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1777 B21 | B20 |
1778 0xf << 16 |
1779 B15 |
1780 0xf << 8 |
1781 B5 |
1782 0xf;
1783 Emit32(encoding);
1784}
1785
1786
1787void Thumb2Assembler::nop(Condition cond) {
1788 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001789 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001790 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001791 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001792}
1793
1794
1795void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1796 CHECK_NE(sn, kNoSRegister);
1797 CHECK_NE(rt, kNoRegister);
1798 CHECK_NE(rt, SP);
1799 CHECK_NE(rt, PC);
1800 CheckCondition(cond);
1801 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1802 B27 | B26 | B25 |
1803 ((static_cast<int32_t>(sn) >> 1)*B16) |
1804 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1805 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1806 Emit32(encoding);
1807}
1808
1809
1810void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1811 CHECK_NE(sn, kNoSRegister);
1812 CHECK_NE(rt, kNoRegister);
1813 CHECK_NE(rt, SP);
1814 CHECK_NE(rt, PC);
1815 CheckCondition(cond);
1816 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1817 B27 | B26 | B25 | B20 |
1818 ((static_cast<int32_t>(sn) >> 1)*B16) |
1819 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1820 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1821 Emit32(encoding);
1822}
1823
1824
1825void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1826 Condition cond) {
1827 CHECK_NE(sm, kNoSRegister);
1828 CHECK_NE(sm, S31);
1829 CHECK_NE(rt, kNoRegister);
1830 CHECK_NE(rt, SP);
1831 CHECK_NE(rt, PC);
1832 CHECK_NE(rt2, kNoRegister);
1833 CHECK_NE(rt2, SP);
1834 CHECK_NE(rt2, PC);
1835 CheckCondition(cond);
1836 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1837 B27 | B26 | B22 |
1838 (static_cast<int32_t>(rt2)*B16) |
1839 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1840 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1841 (static_cast<int32_t>(sm) >> 1);
1842 Emit32(encoding);
1843}
1844
1845
1846void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1847 Condition cond) {
1848 CHECK_NE(sm, kNoSRegister);
1849 CHECK_NE(sm, S31);
1850 CHECK_NE(rt, kNoRegister);
1851 CHECK_NE(rt, SP);
1852 CHECK_NE(rt, PC);
1853 CHECK_NE(rt2, kNoRegister);
1854 CHECK_NE(rt2, SP);
1855 CHECK_NE(rt2, PC);
1856 CHECK_NE(rt, rt2);
1857 CheckCondition(cond);
1858 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1859 B27 | B26 | B22 | B20 |
1860 (static_cast<int32_t>(rt2)*B16) |
1861 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1862 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1863 (static_cast<int32_t>(sm) >> 1);
1864 Emit32(encoding);
1865}
1866
1867
1868void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1869 Condition cond) {
1870 CHECK_NE(dm, kNoDRegister);
1871 CHECK_NE(rt, kNoRegister);
1872 CHECK_NE(rt, SP);
1873 CHECK_NE(rt, PC);
1874 CHECK_NE(rt2, kNoRegister);
1875 CHECK_NE(rt2, SP);
1876 CHECK_NE(rt2, PC);
1877 CheckCondition(cond);
1878 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1879 B27 | B26 | B22 |
1880 (static_cast<int32_t>(rt2)*B16) |
1881 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1882 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1883 (static_cast<int32_t>(dm) & 0xf);
1884 Emit32(encoding);
1885}
1886
1887
1888void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1889 Condition cond) {
1890 CHECK_NE(dm, kNoDRegister);
1891 CHECK_NE(rt, kNoRegister);
1892 CHECK_NE(rt, SP);
1893 CHECK_NE(rt, PC);
1894 CHECK_NE(rt2, kNoRegister);
1895 CHECK_NE(rt2, SP);
1896 CHECK_NE(rt2, PC);
1897 CHECK_NE(rt, rt2);
1898 CheckCondition(cond);
1899 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1900 B27 | B26 | B22 | B20 |
1901 (static_cast<int32_t>(rt2)*B16) |
1902 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1903 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1904 (static_cast<int32_t>(dm) & 0xf);
1905 Emit32(encoding);
1906}
1907
1908
1909void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1910 const Address& addr = static_cast<const Address&>(ad);
1911 CHECK_NE(sd, kNoSRegister);
1912 CheckCondition(cond);
1913 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1914 B27 | B26 | B24 | B20 |
1915 ((static_cast<int32_t>(sd) & 1)*B22) |
1916 ((static_cast<int32_t>(sd) >> 1)*B12) |
1917 B11 | B9 | addr.vencoding();
1918 Emit32(encoding);
1919}
1920
1921
1922void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1923 const Address& addr = static_cast<const Address&>(ad);
1924 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1925 CHECK_NE(sd, kNoSRegister);
1926 CheckCondition(cond);
1927 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1928 B27 | B26 | B24 |
1929 ((static_cast<int32_t>(sd) & 1)*B22) |
1930 ((static_cast<int32_t>(sd) >> 1)*B12) |
1931 B11 | B9 | addr.vencoding();
1932 Emit32(encoding);
1933}
1934
1935
1936void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1937 const Address& addr = static_cast<const Address&>(ad);
1938 CHECK_NE(dd, kNoDRegister);
1939 CheckCondition(cond);
1940 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1941 B27 | B26 | B24 | B20 |
1942 ((static_cast<int32_t>(dd) >> 4)*B22) |
1943 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1944 B11 | B9 | B8 | addr.vencoding();
1945 Emit32(encoding);
1946}
1947
1948
1949void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1950 const Address& addr = static_cast<const Address&>(ad);
1951 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1952 CHECK_NE(dd, kNoDRegister);
1953 CheckCondition(cond);
1954 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1955 B27 | B26 | B24 |
1956 ((static_cast<int32_t>(dd) >> 4)*B22) |
1957 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1958 B11 | B9 | B8 | addr.vencoding();
1959 Emit32(encoding);
1960}
1961
1962
1963void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1964 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1965}
1966
1967
1968void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
1969 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
1970}
1971
1972
1973void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
1974 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
1975}
1976
1977
1978void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
1979 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
1980}
1981
1982
1983void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
1984 CheckCondition(cond);
1985
1986 uint32_t D;
1987 uint32_t Vd;
1988 if (dbl) {
1989 // Encoded as D:Vd.
1990 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001991 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001992 } else {
1993 // Encoded as Vd:D.
1994 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001995 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001996 }
1997 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
1998 B11 | B9 |
1999 (dbl ? B8 : 0) |
2000 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07002001 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07002002 nregs << (dbl ? 1 : 0) |
2003 D << 22 |
2004 Vd << 12;
2005 Emit32(encoding);
2006}
2007
2008
2009void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
2010 SRegister sd, SRegister sn, SRegister sm) {
2011 CHECK_NE(sd, kNoSRegister);
2012 CHECK_NE(sn, kNoSRegister);
2013 CHECK_NE(sm, kNoSRegister);
2014 CheckCondition(cond);
2015 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2016 B27 | B26 | B25 | B11 | B9 | opcode |
2017 ((static_cast<int32_t>(sd) & 1)*B22) |
2018 ((static_cast<int32_t>(sn) >> 1)*B16) |
2019 ((static_cast<int32_t>(sd) >> 1)*B12) |
2020 ((static_cast<int32_t>(sn) & 1)*B7) |
2021 ((static_cast<int32_t>(sm) & 1)*B5) |
2022 (static_cast<int32_t>(sm) >> 1);
2023 Emit32(encoding);
2024}
2025
2026
2027void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
2028 DRegister dd, DRegister dn, DRegister dm) {
2029 CHECK_NE(dd, kNoDRegister);
2030 CHECK_NE(dn, kNoDRegister);
2031 CHECK_NE(dm, kNoDRegister);
2032 CheckCondition(cond);
2033 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2034 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
2035 ((static_cast<int32_t>(dd) >> 4)*B22) |
2036 ((static_cast<int32_t>(dn) & 0xf)*B16) |
2037 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2038 ((static_cast<int32_t>(dn) >> 4)*B7) |
2039 ((static_cast<int32_t>(dm) >> 4)*B5) |
2040 (static_cast<int32_t>(dm) & 0xf);
2041 Emit32(encoding);
2042}
2043
2044
2045void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
2046 SRegister sd, DRegister dm) {
2047 CHECK_NE(sd, kNoSRegister);
2048 CHECK_NE(dm, kNoDRegister);
2049 CheckCondition(cond);
2050 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2051 B27 | B26 | B25 | B11 | B9 | opcode |
2052 ((static_cast<int32_t>(sd) & 1)*B22) |
2053 ((static_cast<int32_t>(sd) >> 1)*B12) |
2054 ((static_cast<int32_t>(dm) >> 4)*B5) |
2055 (static_cast<int32_t>(dm) & 0xf);
2056 Emit32(encoding);
2057}
2058
2059
2060void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
2061 DRegister dd, SRegister sm) {
2062 CHECK_NE(dd, kNoDRegister);
2063 CHECK_NE(sm, kNoSRegister);
2064 CheckCondition(cond);
2065 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2066 B27 | B26 | B25 | B11 | B9 | opcode |
2067 ((static_cast<int32_t>(dd) >> 4)*B22) |
2068 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2069 ((static_cast<int32_t>(sm) & 1)*B5) |
2070 (static_cast<int32_t>(sm) >> 1);
2071 Emit32(encoding);
2072}
2073
2074
2075void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00002076 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002077 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00002078 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2079 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
2080 (static_cast<int32_t>(PC)*B12) |
2081 B11 | B9 | B4;
2082 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002083}
2084
2085
2086void Thumb2Assembler::svc(uint32_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002087 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002088 int16_t encoding = B15 | B14 | B12 |
2089 B11 | B10 | B9 | B8 |
2090 imm8;
2091 Emit16(encoding);
2092}
2093
2094
2095void Thumb2Assembler::bkpt(uint16_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002096 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002097 int16_t encoding = B15 | B13 | B12 |
2098 B11 | B10 | B9 |
2099 imm8;
2100 Emit16(encoding);
2101}
2102
2103// Convert the given IT state to a mask bit given bit 0 of the first
2104// condition and a shift position.
2105static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2106 switch (s) {
2107 case kItOmitted: return 1 << shift;
2108 case kItThen: return firstcond0 << shift;
2109 case kItElse: return !firstcond0 << shift;
2110 }
2111 return 0;
2112}
2113
2114
2115// Set the IT condition in the given position for the given state. This is used
2116// to check that conditional instructions match the preceding IT statement.
2117void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2118 switch (s) {
2119 case kItOmitted: it_conditions_[index] = AL; break;
2120 case kItThen: it_conditions_[index] = cond; break;
2121 case kItElse:
2122 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2123 break;
2124 }
2125}
2126
2127
2128void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2129 CheckCondition(AL); // Not allowed in IT block.
2130 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2131
2132 // All conditions to AL.
2133 for (uint8_t i = 0; i < 4; ++i) {
2134 it_conditions_[i] = AL;
2135 }
2136
2137 SetItCondition(kItThen, firstcond, 0);
2138 uint8_t mask = ToItMask(i1, firstcond0, 3);
2139 SetItCondition(i1, firstcond, 1);
2140
2141 if (i1 != kItOmitted) {
2142 mask |= ToItMask(i2, firstcond0, 2);
2143 SetItCondition(i2, firstcond, 2);
2144 if (i2 != kItOmitted) {
2145 mask |= ToItMask(i3, firstcond0, 1);
2146 SetItCondition(i3, firstcond, 3);
2147 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002148 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002149 }
2150 }
2151 }
2152
2153 // Start at first condition.
2154 it_cond_index_ = 0;
2155 next_condition_ = it_conditions_[0];
2156 uint16_t encoding = B15 | B13 | B12 |
2157 B11 | B10 | B9 | B8 |
2158 firstcond << 4 |
2159 mask;
2160 Emit16(encoding);
2161}
2162
2163
2164void Thumb2Assembler::cbz(Register rn, Label* label) {
2165 CheckCondition(AL);
2166 if (label->IsBound()) {
2167 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002168 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002169 } else {
2170 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2171 label->LinkTo(branchid);
2172 }
2173}
2174
2175
2176void Thumb2Assembler::cbnz(Register rn, Label* label) {
2177 CheckCondition(AL);
2178 if (label->IsBound()) {
2179 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002180 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002181 } else {
2182 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2183 label->LinkTo(branchid);
2184 }
2185}
2186
2187
2188void Thumb2Assembler::blx(Register rm, Condition cond) {
2189 CHECK_NE(rm, kNoRegister);
2190 CheckCondition(cond);
2191 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2192 Emit16(encoding);
2193}
2194
2195
2196void Thumb2Assembler::bx(Register rm, Condition cond) {
2197 CHECK_NE(rm, kNoRegister);
2198 CheckCondition(cond);
2199 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2200 Emit16(encoding);
2201}
2202
2203
2204void Thumb2Assembler::Push(Register rd, Condition cond) {
2205 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2206}
2207
2208
2209void Thumb2Assembler::Pop(Register rd, Condition cond) {
2210 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2211}
2212
2213
2214void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2215 stm(DB_W, SP, regs, cond);
2216}
2217
2218
2219void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2220 ldm(IA_W, SP, regs, cond);
2221}
2222
2223
2224void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2225 if (cond != AL || rd != rm) {
2226 mov(rd, ShifterOperand(rm), cond);
2227 }
2228}
2229
2230
2231// A branch has changed size. Make a hole for it.
2232void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2233 // Move the contents of the buffer using: Move(newposition, oldposition)
2234 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2235 buffer_.Move(location + delta, location);
2236}
2237
2238
2239void Thumb2Assembler::Bind(Label* label) {
2240 CHECK(!label->IsBound());
2241 uint32_t bound_pc = buffer_.Size();
2242 std::vector<Branch*> changed_branches;
2243
2244 while (label->IsLinked()) {
2245 uint16_t position = label->Position(); // Branch id for linked branch.
2246 Branch* branch = GetBranch(position); // Get the branch at this id.
2247 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2248 uint32_t branch_location = branch->GetLocation();
2249 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2250 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002251 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002252 MakeHoleForBranch(branch->GetLocation(), 2);
2253 if (branch->IsCompareAndBranch()) {
2254 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2255 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2256 // cmp rn, #0
2257 // b<eq|ne> target
2258 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2259 Condition cond = n ? NE : EQ;
2260 branch->Move(2); // Move the branch forward by 2 bytes.
2261 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2262 branch->ResetSize(Branch::k16Bit);
2263
2264 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002265 buffer_.Store<int16_t>(branch_location,
2266 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002267
2268 // Since have moved made a hole in the code we need to reload the
2269 // current pc.
2270 bound_pc = buffer_.Size();
2271
2272 // Now resolve the newly added branch.
2273 changed = branch->Resolve(bound_pc);
2274 if (changed) {
2275 MakeHoleForBranch(branch->GetLocation(), 2);
2276 changed_branches.push_back(branch);
2277 }
2278 } else {
2279 changed_branches.push_back(branch);
2280 }
2281 }
2282 label->position_ = next; // Move to next.
2283 }
2284 label->BindTo(bound_pc);
2285
2286 // Now relocate any changed branches. Do this until there are no more changes.
2287 std::vector<Branch*> branches_to_process = changed_branches;
2288 while (branches_to_process.size() != 0) {
2289 changed_branches.clear();
2290 for (auto& changed_branch : branches_to_process) {
2291 for (auto& branch : branches_) {
2292 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2293 if (changed) {
2294 changed_branches.push_back(branch);
2295 }
2296 }
2297 branches_to_process = changed_branches;
2298 }
2299 }
2300}
2301
2302
2303void Thumb2Assembler::EmitBranches() {
2304 for (auto& branch : branches_) {
2305 branch->Emit(&buffer_);
2306 }
2307}
2308
2309
2310void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002311 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002312 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002313 CheckCondition(cond);
2314 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002315}
2316
2317
2318void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002319 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002320 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002321 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002322 CheckCondition(cond);
2323 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002324}
2325
2326
2327void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002328 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002329 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002330 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002331 CheckCondition(cond);
2332 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002333}
2334
2335
2336void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002337 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002338 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002339 CheckCondition(cond);
2340 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002341}
2342
2343
Dave Allison45fdb932014-06-25 12:37:10 -07002344void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2345 CheckCondition(cond);
2346 EmitShift(rd, rm, RRX, rm, setcc);
2347}
2348
2349
2350void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2351 bool setcc, Condition cond) {
2352 CheckCondition(cond);
2353 EmitShift(rd, rm, LSL, rn, setcc);
2354}
2355
2356
2357void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2358 bool setcc, Condition cond) {
2359 CheckCondition(cond);
2360 EmitShift(rd, rm, LSR, rn, setcc);
2361}
2362
2363
2364void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2365 bool setcc, Condition cond) {
2366 CheckCondition(cond);
2367 EmitShift(rd, rm, ASR, rn, setcc);
2368}
2369
2370
2371void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2372 bool setcc, Condition cond) {
2373 CheckCondition(cond);
2374 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002375}
2376
2377
2378int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2379 // The offset is off by 4 due to the way the ARM CPUs read PC.
2380 offset -= 4;
2381 offset >>= 1;
2382
2383 uint32_t value = 0;
2384 // There are two different encodings depending on the value of bit 12. In one case
2385 // intermediate values are calculated using the sign bit.
2386 if ((inst & B12) == B12) {
2387 // 25 bits of offset.
2388 uint32_t signbit = (offset >> 31) & 0x1;
2389 uint32_t i1 = (offset >> 22) & 0x1;
2390 uint32_t i2 = (offset >> 21) & 0x1;
2391 uint32_t imm10 = (offset >> 11) & 0x03ff;
2392 uint32_t imm11 = offset & 0x07ff;
2393 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2394 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2395 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2396 imm11;
2397 // Remove the offset from the current encoding.
2398 inst &= ~(0x3ff << 16 | 0x7ff);
2399 } else {
2400 uint32_t signbit = (offset >> 31) & 0x1;
2401 uint32_t imm6 = (offset >> 11) & 0x03f;
2402 uint32_t imm11 = offset & 0x07ff;
2403 uint32_t j1 = (offset >> 19) & 1;
2404 uint32_t j2 = (offset >> 17) & 1;
2405 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2406 imm11;
2407 // Remove the offset from the current encoding.
2408 inst &= ~(0x3f << 16 | 0x7ff);
2409 }
2410 // Mask out offset bits in current instruction.
2411 inst &= ~(B26 | B13 | B11);
2412 inst |= value;
2413 return inst;
2414}
2415
2416
2417int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2418 int32_t imm32;
2419 if ((instr & B12) == B12) {
2420 uint32_t S = (instr >> 26) & 1;
2421 uint32_t J2 = (instr >> 11) & 1;
2422 uint32_t J1 = (instr >> 13) & 1;
2423 uint32_t imm10 = (instr >> 16) & 0x3FF;
2424 uint32_t imm11 = instr & 0x7FF;
2425
2426 uint32_t I1 = ~(J1 ^ S) & 1;
2427 uint32_t I2 = ~(J2 ^ S) & 1;
2428 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2429 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2430 } else {
2431 uint32_t S = (instr >> 26) & 1;
2432 uint32_t J2 = (instr >> 11) & 1;
2433 uint32_t J1 = (instr >> 13) & 1;
2434 uint32_t imm6 = (instr >> 16) & 0x3F;
2435 uint32_t imm11 = instr & 0x7FF;
2436
2437 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2438 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2439 }
2440 imm32 += 4;
2441 return imm32;
2442}
2443
2444
2445void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2446 AddConstant(rd, rd, value, cond);
2447}
2448
2449
2450void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2451 Condition cond) {
2452 if (value == 0) {
2453 if (rd != rn) {
2454 mov(rd, ShifterOperand(rn), cond);
2455 }
2456 return;
2457 }
2458 // We prefer to select the shorter code sequence rather than selecting add for
2459 // positive values and sub for negatives ones, which would slightly improve
2460 // the readability of generated code for some constants.
2461 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002462 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002463 add(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002464 } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002465 sub(rd, rn, shifter_op, cond);
2466 } else {
2467 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002468 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002469 mvn(IP, shifter_op, cond);
2470 add(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002471 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002472 mvn(IP, shifter_op, cond);
2473 sub(rd, rn, ShifterOperand(IP), cond);
2474 } else {
2475 movw(IP, Low16Bits(value), cond);
2476 uint16_t value_high = High16Bits(value);
2477 if (value_high != 0) {
2478 movt(IP, value_high, cond);
2479 }
2480 add(rd, rn, ShifterOperand(IP), cond);
2481 }
2482 }
2483}
2484
2485
2486void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2487 Condition cond) {
2488 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002489 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002490 adds(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002491 } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002492 subs(rd, rn, shifter_op, cond);
2493 } else {
2494 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002495 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002496 mvn(IP, shifter_op, cond);
2497 adds(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002498 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002499 mvn(IP, shifter_op, cond);
2500 subs(rd, rn, ShifterOperand(IP), cond);
2501 } else {
2502 movw(IP, Low16Bits(value), cond);
2503 uint16_t value_high = High16Bits(value);
2504 if (value_high != 0) {
2505 movt(IP, value_high, cond);
2506 }
2507 adds(rd, rn, ShifterOperand(IP), cond);
2508 }
2509 }
2510}
2511
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002512
Dave Allison65fcc2c2014-04-28 13:45:27 -07002513void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2514 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002515 if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002516 mov(rd, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002517 } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002518 mvn(rd, shifter_op, cond);
2519 } else {
2520 movw(rd, Low16Bits(value), cond);
2521 uint16_t value_high = High16Bits(value);
2522 if (value_high != 0) {
2523 movt(rd, value_high, cond);
2524 }
2525 }
2526}
2527
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002528
Dave Allison65fcc2c2014-04-28 13:45:27 -07002529// Implementation note: this method must emit at most one instruction when
2530// Address::CanHoldLoadOffsetThumb.
2531void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2532 Register reg,
2533 Register base,
2534 int32_t offset,
2535 Condition cond) {
2536 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002537 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002538 LoadImmediate(IP, offset, cond);
2539 add(IP, IP, ShifterOperand(base), cond);
2540 base = IP;
2541 offset = 0;
2542 }
2543 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2544 switch (type) {
2545 case kLoadSignedByte:
2546 ldrsb(reg, Address(base, offset), cond);
2547 break;
2548 case kLoadUnsignedByte:
2549 ldrb(reg, Address(base, offset), cond);
2550 break;
2551 case kLoadSignedHalfword:
2552 ldrsh(reg, Address(base, offset), cond);
2553 break;
2554 case kLoadUnsignedHalfword:
2555 ldrh(reg, Address(base, offset), cond);
2556 break;
2557 case kLoadWord:
2558 ldr(reg, Address(base, offset), cond);
2559 break;
2560 case kLoadWordPair:
2561 ldrd(reg, Address(base, offset), cond);
2562 break;
2563 default:
2564 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002565 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002566 }
2567}
2568
2569
2570// Implementation note: this method must emit at most one instruction when
2571// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2572void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2573 Register base,
2574 int32_t offset,
2575 Condition cond) {
2576 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2577 CHECK_NE(base, IP);
2578 LoadImmediate(IP, offset, cond);
2579 add(IP, IP, ShifterOperand(base), cond);
2580 base = IP;
2581 offset = 0;
2582 }
2583 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2584 vldrs(reg, Address(base, offset), cond);
2585}
2586
2587
2588// Implementation note: this method must emit at most one instruction when
2589// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2590void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2591 Register base,
2592 int32_t offset,
2593 Condition cond) {
2594 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2595 CHECK_NE(base, IP);
2596 LoadImmediate(IP, offset, cond);
2597 add(IP, IP, ShifterOperand(base), cond);
2598 base = IP;
2599 offset = 0;
2600 }
2601 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2602 vldrd(reg, Address(base, offset), cond);
2603}
2604
2605
2606// Implementation note: this method must emit at most one instruction when
2607// Address::CanHoldStoreOffsetThumb.
2608void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2609 Register reg,
2610 Register base,
2611 int32_t offset,
2612 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002613 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002614 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002615 CHECK_NE(base, IP);
2616 if (reg != IP) {
2617 tmp_reg = IP;
2618 } else {
2619 // Be careful not to use IP twice (for `reg` and to build the
2620 // Address object used by the store instruction(s) below).
2621 // Instead, save R5 on the stack (or R6 if R5 is not available),
2622 // use it as secondary temporary register, and restore it after
2623 // the store instruction has been emitted.
2624 tmp_reg = base != R5 ? R5 : R6;
2625 Push(tmp_reg);
2626 if (base == SP) {
2627 offset += kRegisterSize;
2628 }
2629 }
2630 LoadImmediate(tmp_reg, offset, cond);
2631 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2632 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002633 offset = 0;
2634 }
2635 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2636 switch (type) {
2637 case kStoreByte:
2638 strb(reg, Address(base, offset), cond);
2639 break;
2640 case kStoreHalfword:
2641 strh(reg, Address(base, offset), cond);
2642 break;
2643 case kStoreWord:
2644 str(reg, Address(base, offset), cond);
2645 break;
2646 case kStoreWordPair:
2647 strd(reg, Address(base, offset), cond);
2648 break;
2649 default:
2650 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002651 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002652 }
Roland Levillain775ef492014-11-04 17:43:11 +00002653 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2654 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2655 Pop(tmp_reg);
2656 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002657}
2658
2659
2660// Implementation note: this method must emit at most one instruction when
2661// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2662void Thumb2Assembler::StoreSToOffset(SRegister reg,
2663 Register base,
2664 int32_t offset,
2665 Condition cond) {
2666 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2667 CHECK_NE(base, IP);
2668 LoadImmediate(IP, offset, cond);
2669 add(IP, IP, ShifterOperand(base), cond);
2670 base = IP;
2671 offset = 0;
2672 }
2673 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2674 vstrs(reg, Address(base, offset), cond);
2675}
2676
2677
2678// Implementation note: this method must emit at most one instruction when
2679// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2680void Thumb2Assembler::StoreDToOffset(DRegister reg,
2681 Register base,
2682 int32_t offset,
2683 Condition cond) {
2684 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2685 CHECK_NE(base, IP);
2686 LoadImmediate(IP, offset, cond);
2687 add(IP, IP, ShifterOperand(base), cond);
2688 base = IP;
2689 offset = 0;
2690 }
2691 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2692 vstrd(reg, Address(base, offset), cond);
2693}
2694
2695
2696void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2697 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002698 dmb(SY);
2699}
2700
2701
2702void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002703 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2704 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002705}
2706
2707
2708void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002709 if (force_32bit_branches_) {
2710 cmp(r, ShifterOperand(0));
2711 b(label, EQ);
2712 } else {
2713 cbz(r, label);
2714 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002715}
2716
2717
2718void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002719 if (force_32bit_branches_) {
2720 cmp(r, ShifterOperand(0));
2721 b(label, NE);
2722 } else {
2723 cbnz(r, label);
2724 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002725}
2726} // namespace arm
2727} // namespace art