blob: 4ff3aeb45bcb925f615845f3436e831a3324ec98 [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
Zheng Xuc6667102015-05-15 16:08:45 +0800241void Thumb2Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
242 Register rm, Condition cond) {
243 CheckCondition(cond);
244
245 uint32_t op1 = 0U /* 0b000; */;
246 uint32_t op2 = 0U /* 0b0000 */;
247 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
Dave Allison65fcc2c2014-04-28 13:45:27 -0700259void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
260 Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700261 CheckCondition(cond);
262
Andreas Gampec8ccf682014-09-29 20:07:43 -0700263 uint32_t op1 = 2U /* 0b010; */;
264 uint32_t op2 = 0U /* 0b0000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700265 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
266 op1 << 20 |
267 op2 << 4 |
268 static_cast<uint32_t>(rd_lo) << 12 |
269 static_cast<uint32_t>(rd_hi) << 8 |
270 static_cast<uint32_t>(rn) << 16 |
271 static_cast<uint32_t>(rm);
272
273 Emit32(encoding);
274}
275
276
277void Thumb2Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700278 CheckCondition(cond);
279
Andreas Gampec8ccf682014-09-29 20:07:43 -0700280 uint32_t op1 = 1U /* 0b001 */;
281 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700282 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B20 |
283 op1 << 20 |
284 op2 << 4 |
285 0xf << 12 |
286 static_cast<uint32_t>(rd) << 8 |
287 static_cast<uint32_t>(rn) << 16 |
288 static_cast<uint32_t>(rm);
289
290 Emit32(encoding);
291}
292
293
294void Thumb2Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700295 CheckCondition(cond);
296
Andreas Gampec8ccf682014-09-29 20:07:43 -0700297 uint32_t op1 = 1U /* 0b001 */;
298 uint32_t op2 = 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700299 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | B21 | B20 |
300 op1 << 20 |
301 op2 << 4 |
302 0xf << 12 |
303 static_cast<uint32_t>(rd) << 8 |
304 static_cast<uint32_t>(rn) << 16 |
305 static_cast<uint32_t>(rm);
306
307 Emit32(encoding);
308}
309
310
Roland Levillain51d3fc42014-11-13 14:11:42 +0000311void Thumb2Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
312 CheckCondition(cond);
313 CHECK_LE(lsb, 31U);
314 CHECK(1U <= width && width <= 32U) << width;
315 uint32_t widthminus1 = width - 1;
316 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
317 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
318
319 uint32_t op = 20U /* 0b10100 */;
320 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
321 op << 20 |
322 static_cast<uint32_t>(rn) << 16 |
323 imm3 << 12 |
324 static_cast<uint32_t>(rd) << 8 |
325 imm2 << 6 |
326 widthminus1;
327
328 Emit32(encoding);
329}
330
331
Roland Levillain981e4542014-11-14 11:47:14 +0000332void Thumb2Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
333 CheckCondition(cond);
334 CHECK_LE(lsb, 31U);
335 CHECK(1U <= width && width <= 32U) << width;
336 uint32_t widthminus1 = width - 1;
337 uint32_t imm2 = lsb & (B1 | B0); // Bits 0-1 of `lsb`.
338 uint32_t imm3 = (lsb & (B4 | B3 | B2)) >> 2; // Bits 2-4 of `lsb`.
339
340 uint32_t op = 28U /* 0b11100 */;
341 int32_t encoding = B31 | B30 | B29 | B28 | B25 |
342 op << 20 |
343 static_cast<uint32_t>(rn) << 16 |
344 imm3 << 12 |
345 static_cast<uint32_t>(rd) << 8 |
346 imm2 << 6 |
347 widthminus1;
348
349 Emit32(encoding);
350}
351
352
Dave Allison65fcc2c2014-04-28 13:45:27 -0700353void Thumb2Assembler::ldr(Register rd, const Address& ad, Condition cond) {
354 EmitLoadStore(cond, true, false, false, false, rd, ad);
355}
356
357
358void Thumb2Assembler::str(Register rd, const Address& ad, Condition cond) {
359 EmitLoadStore(cond, false, false, false, false, rd, ad);
360}
361
362
363void Thumb2Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
364 EmitLoadStore(cond, true, true, false, false, rd, ad);
365}
366
367
368void Thumb2Assembler::strb(Register rd, const Address& ad, Condition cond) {
369 EmitLoadStore(cond, false, true, false, false, rd, ad);
370}
371
372
373void Thumb2Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
374 EmitLoadStore(cond, true, false, true, false, rd, ad);
375}
376
377
378void Thumb2Assembler::strh(Register rd, const Address& ad, Condition cond) {
379 EmitLoadStore(cond, false, false, true, false, rd, ad);
380}
381
382
383void Thumb2Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
384 EmitLoadStore(cond, true, true, false, true, rd, ad);
385}
386
387
388void Thumb2Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
389 EmitLoadStore(cond, true, false, true, true, rd, ad);
390}
391
392
393void Thumb2Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
Roland Levillain4af147e2015-04-07 13:54:49 +0100394 ldrd(rd, Register(rd + 1), ad, cond);
395}
396
397
398void Thumb2Assembler::ldrd(Register rd, Register rd2, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700399 CheckCondition(cond);
Roland Levillain4af147e2015-04-07 13:54:49 +0100400 // Encoding T1.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700401 // This is different from other loads. The encoding is like ARM.
402 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
403 static_cast<int32_t>(rd) << 12 |
Roland Levillain4af147e2015-04-07 13:54:49 +0100404 static_cast<int32_t>(rd2) << 8 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700405 ad.encodingThumbLdrdStrd();
406 Emit32(encoding);
407}
408
409
410void Thumb2Assembler::strd(Register rd, const Address& ad, Condition cond) {
Roland Levillain4af147e2015-04-07 13:54:49 +0100411 strd(rd, Register(rd + 1), ad, cond);
412}
413
414
415void Thumb2Assembler::strd(Register rd, Register rd2, const Address& ad, Condition cond) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700416 CheckCondition(cond);
Roland Levillain4af147e2015-04-07 13:54:49 +0100417 // Encoding T1.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700418 // This is different from other loads. The encoding is like ARM.
419 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
420 static_cast<int32_t>(rd) << 12 |
Roland Levillain4af147e2015-04-07 13:54:49 +0100421 static_cast<int32_t>(rd2) << 8 |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700422 ad.encodingThumbLdrdStrd();
423 Emit32(encoding);
424}
425
426
427void Thumb2Assembler::ldm(BlockAddressMode am,
428 Register base,
429 RegList regs,
430 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000431 CHECK_NE(regs, 0u); // Do not use ldm if there's nothing to load.
432 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700433 // Thumb doesn't support one reg in the list.
434 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000435 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700436 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700437 CHECK(am == DB_W); // Only writeback is supported.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700438 ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond);
439 } else {
440 EmitMultiMemOp(cond, am, true, base, regs);
441 }
442}
443
444
445void Thumb2Assembler::stm(BlockAddressMode am,
446 Register base,
447 RegList regs,
448 Condition cond) {
Vladimir Markoe8469c12014-11-26 18:09:30 +0000449 CHECK_NE(regs, 0u); // Do not use stm if there's nothing to store.
450 if (IsPowerOfTwo(regs)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700451 // Thumb doesn't support one reg in the list.
452 // Find the register number.
Vladimir Markoe8469c12014-11-26 18:09:30 +0000453 int reg = CTZ(static_cast<uint32_t>(regs));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700454 CHECK_LT(reg, 16);
Dave Allison45fdb932014-06-25 12:37:10 -0700455 CHECK(am == IA || am == IA_W);
456 Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700457 str(static_cast<Register>(reg), Address(base, -kRegisterSize, strmode), cond);
458 } else {
459 EmitMultiMemOp(cond, am, false, base, regs);
460 }
461}
462
463
464bool Thumb2Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
465 uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
466 if (((imm32 & ((1 << 19) - 1)) == 0) &&
467 ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
468 (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
469 uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
470 ((imm32 >> 19) & ((1 << 6) -1));
471 EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
472 sd, S0, S0);
473 return true;
474 }
475 return false;
476}
477
478
479bool Thumb2Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
480 uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
481 if (((imm64 & ((1LL << 48) - 1)) == 0) &&
482 ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
483 (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
484 uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
485 ((imm64 >> 48) & ((1 << 6) -1));
486 EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
487 dd, D0, D0);
488 return true;
489 }
490 return false;
491}
492
493
494void Thumb2Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
495 EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
496}
497
498
499void Thumb2Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
500 EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
501}
502
503
504void Thumb2Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
505 Condition cond) {
506 EmitVFPsss(cond, B21 | B20, sd, sn, sm);
507}
508
509
510void Thumb2Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
511 Condition cond) {
512 EmitVFPddd(cond, B21 | B20, dd, dn, dm);
513}
514
515
516void Thumb2Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
517 Condition cond) {
518 EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
519}
520
521
522void Thumb2Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
523 Condition cond) {
524 EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
525}
526
527
528void Thumb2Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
529 Condition cond) {
530 EmitVFPsss(cond, B21, sd, sn, sm);
531}
532
533
534void Thumb2Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
535 Condition cond) {
536 EmitVFPddd(cond, B21, dd, dn, dm);
537}
538
539
540void Thumb2Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
541 Condition cond) {
542 EmitVFPsss(cond, 0, sd, sn, sm);
543}
544
545
546void Thumb2Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
547 Condition cond) {
548 EmitVFPddd(cond, 0, dd, dn, dm);
549}
550
551
552void Thumb2Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
553 Condition cond) {
554 EmitVFPsss(cond, B6, sd, sn, sm);
555}
556
557
558void Thumb2Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
559 Condition cond) {
560 EmitVFPddd(cond, B6, dd, dn, dm);
561}
562
563
564void Thumb2Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
565 Condition cond) {
566 EmitVFPsss(cond, B23, sd, sn, sm);
567}
568
569
570void Thumb2Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
571 Condition cond) {
572 EmitVFPddd(cond, B23, dd, dn, dm);
573}
574
575
576void Thumb2Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
577 EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
578}
579
580
581void Thumb2Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
582 EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
583}
584
585
586void Thumb2Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
587 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
588}
589
590
591void Thumb2Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
592 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
593}
594
595
596void Thumb2Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
597 EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
598}
599
600void Thumb2Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
601 EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
602}
603
604
605void Thumb2Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
606 EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
607}
608
609
610void Thumb2Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
611 EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
612}
613
614
615void Thumb2Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
616 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
617}
618
619
620void Thumb2Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
621 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
622}
623
624
625void Thumb2Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
626 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
627}
628
629
630void Thumb2Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
631 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
632}
633
634
635void Thumb2Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
636 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
637}
638
639
640void Thumb2Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
641 EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
642}
643
644
645void Thumb2Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
646 EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
647}
648
649
650void Thumb2Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
651 EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
652}
653
654
655void Thumb2Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
656 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
657}
658
659
660void Thumb2Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
661 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
662}
663
664
665void Thumb2Assembler::vcmpsz(SRegister sd, Condition cond) {
666 EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
667}
668
669
670void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
671 EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
672}
673
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +0000674
Dave Allison65fcc2c2014-04-28 13:45:27 -0700675void Thumb2Assembler::b(Label* label, Condition cond) {
676 EmitBranch(cond, label, false, false);
677}
678
679
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +0000680void Thumb2Assembler::b(NearLabel* label, Condition cond) {
681 EmitBranch(cond, label, false, false, /* is_near */ true);
682}
683
684
Dave Allison65fcc2c2014-04-28 13:45:27 -0700685void Thumb2Assembler::bl(Label* label, Condition cond) {
686 CheckCondition(cond);
687 EmitBranch(cond, label, true, false);
688}
689
690
691void Thumb2Assembler::blx(Label* label) {
692 EmitBranch(AL, label, true, true);
693}
694
695
696void Thumb2Assembler::MarkExceptionHandler(Label* label) {
697 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
698 Label l;
699 b(&l);
700 EmitBranch(AL, label, false, false);
701 Bind(&l);
702}
703
704
705void Thumb2Assembler::Emit32(int32_t value) {
706 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
707 buffer_.Emit<int16_t>(value >> 16);
708 buffer_.Emit<int16_t>(value & 0xffff);
709}
710
711
712void Thumb2Assembler::Emit16(int16_t value) {
713 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
714 buffer_.Emit<int16_t>(value);
715}
716
717
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700718bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700719 Opcode opcode,
Andreas Gampeca714582015-04-03 19:41:34 -0700720 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700721 Register rn,
722 Register rd,
723 const ShifterOperand& so) {
724 if (force_32bit_) {
725 return true;
726 }
727
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000728 // Check special case for SP relative ADD and SUB immediate.
729 if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) {
730 // If the immediate is in range, use 16 bit.
731 if (rd == SP) {
732 if (so.GetImmediate() < (1 << 9)) { // 9 bit immediate.
733 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700734 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000735 } else if (!IsHighRegister(rd) && opcode == ADD) {
736 if (so.GetImmediate() < (1 << 10)) { // 10 bit immediate.
737 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700738 }
739 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000740 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700741
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000742 bool can_contain_high_register = (opcode == MOV)
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800743 || ((opcode == ADD) && (rn == rd) && !set_cc);
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000744
745 if (IsHighRegister(rd) || IsHighRegister(rn)) {
746 if (!can_contain_high_register) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700747 return true;
748 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100749
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000750 // There are high register instructions available for this opcode.
751 // However, there is no actual shift available, neither for ADD nor for MOV (ASR/LSR/LSL/ROR).
752 if (so.IsShift() && (so.GetShift() == RRX || so.GetImmediate() != 0u)) {
753 return true;
754 }
755
756 // The ADD and MOV instructions that work with high registers don't have 16-bit
757 // immediate variants.
758 if (so.IsImmediate()) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100759 return true;
760 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700761 }
762
763 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
764 return true;
765 }
766
Dave Allison65fcc2c2014-04-28 13:45:27 -0700767 bool rn_is_valid = true;
768
769 // Check for single operand instructions and ADD/SUB.
770 switch (opcode) {
771 case CMP:
772 case MOV:
773 case TST:
774 case MVN:
775 rn_is_valid = false; // There is no Rn for these instructions.
776 break;
777 case TEQ:
778 return true;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700779 case ADD:
780 case SUB:
781 break;
782 default:
783 if (so.IsRegister() && rd != rn) {
784 return true;
785 }
786 }
787
788 if (so.IsImmediate()) {
789 if (rn_is_valid && rn != rd) {
790 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
791 // immediate must be 3 bits.
792 if (opcode != ADD && opcode != SUB) {
793 return true;
794 } else {
795 // Check that the immediate is 3 bits for ADD and SUB.
796 if (so.GetImmediate() >= 8) {
797 return true;
798 }
799 }
800 } else {
801 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
802 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
803 return true;
804 } else {
805 if (so.GetImmediate() > 255) {
806 return true;
807 }
808 }
809 }
810 }
811
Zheng Xuc6667102015-05-15 16:08:45 +0800812 // Check for register shift operand.
813 if (so.IsRegister() && so.IsShift()) {
814 if (opcode != MOV) {
815 return true;
816 }
817 // Check for MOV with an ROR.
818 if (so.GetShift() == ROR) {
819 if (so.GetImmediate() != 0) {
820 return true;
821 }
822 }
823 }
824
Dave Allison65fcc2c2014-04-28 13:45:27 -0700825 // The instruction can be encoded in 16 bits.
826 return false;
827}
828
829
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700830void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700831 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700832 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700833 Register rn,
834 Register rd,
835 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700836 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700837 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700838 case AND: thumb_opcode = 0U /* 0b0000 */; break;
839 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
840 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
841 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
842 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700843 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700844 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700845 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700846 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
847 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
848 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
849 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
850 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
851 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
852 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
853 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700854 default:
855 break;
856 }
857
Andreas Gampec8ccf682014-09-29 20:07:43 -0700858 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700859 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000860 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700861 }
862
863 int32_t encoding = 0;
864 if (so.IsImmediate()) {
865 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100866 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000867 if (!set_cc) {
868 if (opcode == SUB) {
869 thumb_opcode = 5U;
870 } else if (opcode == ADD) {
871 thumb_opcode = 0U;
872 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700873 }
874 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700875
876 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700877 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700878 uint32_t imm8 = imm & 0xff;
879
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000880 encoding = B31 | B30 | B29 | B28 |
881 (set_cc ? B20 : B25) |
882 thumb_opcode << 21 |
883 rn << 16 |
884 rd << 8 |
885 i << 26 |
886 imm3 << 12 |
887 imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700888 } else {
889 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700890 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700891 if (imm == kInvalidModifiedImmediate) {
892 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
Vladimir Markoe8469c12014-11-26 18:09:30 +0000893 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700894 }
895 encoding = B31 | B30 | B29 | B28 |
896 thumb_opcode << 21 |
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000897 (set_cc ? B20 : 0) |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700898 rn << 16 |
899 rd << 8 |
900 imm;
901 }
902 } else if (so.IsRegister()) {
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000903 // Register (possibly shifted)
904 encoding = B31 | B30 | B29 | B27 | B25 |
905 thumb_opcode << 21 |
906 (set_cc ? B20 : 0) |
907 rn << 16 |
908 rd << 8 |
909 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700910 }
911 Emit32(encoding);
912}
913
914
915void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
916 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700917 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700918 Register rn,
919 Register rd,
920 const ShifterOperand& so) {
921 if (opcode == ADD || opcode == SUB) {
922 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
923 return;
924 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700925 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700926 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700927 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700928 uint8_t opcode_shift = 6;
929 uint8_t rd_shift = 0;
930 uint8_t rn_shift = 3;
931 uint8_t immediate_shift = 0;
932 bool use_immediate = false;
933 uint8_t immediate = 0;
934
935 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
936 // Convert shifted mov operand2 into 16 bit opcodes.
937 dp_opcode = 0;
938 opcode_shift = 11;
939
940 use_immediate = true;
941 immediate = so.GetImmediate();
942 immediate_shift = 6;
943
944 rn = so.GetRegister();
945
946 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700947 case LSL: thumb_opcode = 0U /* 0b00 */; break;
948 case LSR: thumb_opcode = 1U /* 0b01 */; break;
949 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700950 case ROR:
951 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700952 thumb_opcode = 7U /* 0b111 */;
953 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700954 opcode_shift = 6;
955 use_immediate = false;
956 break;
957 case RRX: break;
958 default:
959 break;
960 }
961 } else {
962 if (so.IsImmediate()) {
963 use_immediate = true;
964 immediate = so.GetImmediate();
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800965 } else {
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000966 CHECK(!(so.IsRegister() && so.IsShift() && so.GetSecondRegister() != kNoRegister))
967 << "No register-shifted register instruction available in thumb";
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800968 // Adjust rn and rd: only two registers will be emitted.
969 switch (opcode) {
970 case AND:
971 case ORR:
972 case EOR:
973 case RSB:
974 case ADC:
975 case SBC:
976 case BIC: {
977 if (rn == rd) {
978 rn = so.GetRegister();
979 } else {
980 CHECK_EQ(rd, so.GetRegister());
981 }
982 break;
983 }
984 case CMP:
985 case CMN: {
986 CHECK_EQ(rd, 0);
987 rd = rn;
988 rn = so.GetRegister();
989 break;
990 }
Andreas Gampe7b7e5242015-02-02 19:17:11 -0800991 case TST:
992 case TEQ:
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800993 case MVN: {
994 CHECK_EQ(rn, 0);
995 rn = so.GetRegister();
996 break;
997 }
998 default:
999 break;
1000 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001001 }
1002
1003 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001004 case AND: thumb_opcode = 0U /* 0b0000 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001005 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001006 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001007 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001008 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
1009 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001010 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
1011 case TST: thumb_opcode = 8U /* 0b1000 */; CHECK(!use_immediate); break;
1012 case MVN: thumb_opcode = 15U /* 0b1111 */; CHECK(!use_immediate); break;
1013 case CMP: {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001014 if (use_immediate) {
1015 // T2 encoding.
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001016 dp_opcode = 0;
1017 opcode_shift = 11;
1018 thumb_opcode = 5U /* 0b101 */;
1019 rd_shift = 8;
1020 rn_shift = 8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001021 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001022 thumb_opcode = 10U /* 0b1010 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001023 }
1024
1025 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001026 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001027 case CMN: {
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001028 CHECK(!use_immediate);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001029 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001030 break;
1031 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001032 case MOV:
1033 dp_opcode = 0;
1034 if (use_immediate) {
1035 // T2 encoding.
1036 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001037 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001038 rd_shift = 8;
1039 rn_shift = 8;
1040 } else {
1041 rn = so.GetRegister();
1042 if (IsHighRegister(rn) || IsHighRegister(rd)) {
1043 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001044 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001045 opcode_shift = 7;
1046 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001047 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
1048 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001049 } else {
1050 thumb_opcode = 0;
1051 }
1052 }
1053 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001054
1055 case TEQ:
1056 case RSC:
Dave Allison65fcc2c2014-04-28 13:45:27 -07001057 default:
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001058 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001059 break;
1060 }
1061 }
1062
Andreas Gampec8ccf682014-09-29 20:07:43 -07001063 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001064 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001065 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001066 }
1067
1068 int16_t encoding = dp_opcode << 14 |
1069 (thumb_opcode << opcode_shift) |
1070 rd << rd_shift |
1071 rn << rn_shift |
1072 (use_immediate ? (immediate << immediate_shift) : 0);
1073
1074 Emit16(encoding);
1075}
1076
1077
1078// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001079void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001080 Opcode opcode,
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001081 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001082 Register rn,
1083 Register rd,
1084 const ShifterOperand& so) {
1085 uint8_t dp_opcode = 0;
1086 uint8_t opcode_shift = 6;
1087 uint8_t rd_shift = 0;
1088 uint8_t rn_shift = 3;
1089 uint8_t immediate_shift = 0;
1090 bool use_immediate = false;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001091 uint32_t immediate = 0; // Should be at most 9 bits but keep the full immediate for CHECKs.
Dave Allison65fcc2c2014-04-28 13:45:27 -07001092 uint8_t thumb_opcode;;
1093
1094 if (so.IsImmediate()) {
1095 use_immediate = true;
1096 immediate = so.GetImmediate();
1097 }
1098
1099 switch (opcode) {
1100 case ADD:
1101 if (so.IsRegister()) {
1102 Register rm = so.GetRegister();
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001103 if (rn == rd && !set_cc) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001104 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001105 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001106 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001107 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001108 // Make Rn also contain the top bit of rd.
1109 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001110 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1111 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001112 } else {
1113 // T1.
1114 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001115 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001116 immediate = static_cast<uint32_t>(so.GetRegister());
1117 use_immediate = true;
1118 immediate_shift = 6;
1119 }
1120 } else {
1121 // Immediate.
1122 if (rd == SP && rn == SP) {
1123 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001124 dp_opcode = 2U /* 0b10 */;
1125 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001126 opcode_shift = 12;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001127 CHECK_LT(immediate, (1u << 9));
1128 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001129
1130 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1131 rn = R0;
1132 rd = R0;
1133 rd_shift = 0;
1134 rn_shift = 0;
1135 immediate >>= 2;
1136 } else if (rd != SP && rn == SP) {
1137 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001138 dp_opcode = 2U /* 0b10 */;
1139 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001140 opcode_shift = 11;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001141 CHECK_LT(immediate, (1u << 10));
1142 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001143
1144 // Remove rn from instruction.
1145 rn = R0;
1146 rn_shift = 0;
1147 rd_shift = 8;
1148 immediate >>= 2;
1149 } else if (rn != rd) {
1150 // Must use T1.
1151 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001152 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001153 immediate_shift = 6;
1154 } else {
1155 // T2 encoding.
1156 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001157 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001158 rd_shift = 8;
1159 rn_shift = 8;
1160 }
1161 }
1162 break;
1163
1164 case SUB:
1165 if (so.IsRegister()) {
1166 // T1.
1167 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001168 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001169 immediate = static_cast<uint32_t>(so.GetRegister());
1170 use_immediate = true;
1171 immediate_shift = 6;
1172 } else {
1173 if (rd == SP && rn == SP) {
1174 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001175 dp_opcode = 2U /* 0b10 */;
1176 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001177 opcode_shift = 7;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001178 CHECK_LT(immediate, (1u << 9));
1179 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001180
1181 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1182 rn = R0;
1183 rd = R0;
1184 rd_shift = 0;
1185 rn_shift = 0;
1186 immediate >>= 2;
1187 } else if (rn != rd) {
1188 // Must use T1.
1189 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001190 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001191 immediate_shift = 6;
1192 } else {
1193 // T2 encoding.
1194 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001195 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001196 rd_shift = 8;
1197 rn_shift = 8;
1198 }
1199 }
1200 break;
1201 default:
1202 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001203 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001204 }
1205
1206 int16_t encoding = dp_opcode << 14 |
1207 (thumb_opcode << opcode_shift) |
1208 rd << rd_shift |
1209 rn << rn_shift |
1210 (use_immediate ? (immediate << immediate_shift) : 0);
1211
1212 Emit16(encoding);
1213}
1214
1215
1216void Thumb2Assembler::EmitDataProcessing(Condition cond,
1217 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001218 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001219 Register rn,
1220 Register rd,
1221 const ShifterOperand& so) {
1222 CHECK_NE(rd, kNoRegister);
1223 CheckCondition(cond);
1224
1225 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1226 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1227 } else {
1228 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1229 }
1230}
1231
Dave Allison45fdb932014-06-25 12:37:10 -07001232void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1233 CHECK_LT(amount, (1 << 5));
1234 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1235 uint16_t opcode = 0;
1236 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001237 case LSL: opcode = 0U /* 0b00 */; break;
1238 case LSR: opcode = 1U /* 0b01 */; break;
1239 case ASR: opcode = 2U /* 0b10 */; break;
1240 case ROR: opcode = 3U /* 0b11 */; break;
1241 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001242 default:
1243 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001244 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001245 }
1246 // 32 bit.
1247 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1248 0xf << 16 | (setcc ? B20 : 0);
1249 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001250 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001251 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1252 static_cast<int16_t>(rd) << 8 | opcode << 4;
1253 Emit32(encoding);
1254 } else {
1255 // 16 bit shift
1256 uint16_t opcode = 0;
1257 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001258 case LSL: opcode = 0U /* 0b00 */; break;
1259 case LSR: opcode = 1U /* 0b01 */; break;
1260 case ASR: opcode = 2U /* 0b10 */; 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 = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1266 static_cast<int16_t>(rd);
1267 Emit16(encoding);
1268 }
1269}
1270
1271void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1272 CHECK_NE(shift, RRX);
1273 bool must_be_32bit = false;
1274 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1275 must_be_32bit = true;
1276 }
1277
1278 if (must_be_32bit) {
1279 uint16_t opcode = 0;
1280 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001281 case LSL: opcode = 0U /* 0b00 */; break;
1282 case LSR: opcode = 1U /* 0b01 */; break;
1283 case ASR: opcode = 2U /* 0b10 */; break;
1284 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001285 default:
1286 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001287 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001288 }
1289 // 32 bit.
1290 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1291 0xf << 12 | (setcc ? B20 : 0);
1292 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1293 static_cast<int16_t>(rd) << 8 | opcode << 21;
1294 Emit32(encoding);
1295 } else {
1296 uint16_t opcode = 0;
1297 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001298 case LSL: opcode = 2U /* 0b0010 */; break;
1299 case LSR: opcode = 3U /* 0b0011 */; break;
1300 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001301 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001302 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1303 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001304 }
1305 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1306 static_cast<int16_t>(rd);
1307 Emit16(encoding);
1308 }
1309}
1310
1311
Dave Allison65fcc2c2014-04-28 13:45:27 -07001312
1313void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1314 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1315 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1316 int32_t offset = target_ - location_;
1317
1318 if (size_ == k32Bit) {
1319 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1320 if (link) {
1321 // BL or BLX immediate.
1322 encoding |= B14;
1323 if (!x) {
1324 encoding |= B12;
1325 } else {
1326 // Bottom bit of offset must be 0.
1327 CHECK_EQ((offset & 1), 0);
1328 }
1329 } else {
1330 if (x) {
1331 LOG(FATAL) << "Invalid use of BX";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001332 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001333 } else {
1334 if (cond_ == AL) {
1335 // Can use the T4 encoding allowing a 24 bit offset.
1336 if (!x) {
1337 encoding |= B12;
1338 }
1339 } else {
1340 // Must be T3 encoding with a 20 bit offset.
1341 encoding |= cond_ << 22;
1342 }
1343 }
1344 }
1345 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1346 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1347 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1348 } else {
1349 if (IsCompareAndBranch()) {
1350 offset -= 4;
1351 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001352 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001353 int16_t encoding = B15 | B13 | B12 |
1354 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1355 static_cast<uint32_t>(rn_) |
1356 B8 |
1357 i << 9 |
1358 imm5 << 3;
1359 buffer->Store<int16_t>(location_, encoding);
1360 } else {
1361 offset -= 4; // Account for PC offset.
1362 int16_t encoding;
1363 // 16 bit.
1364 if (cond_ == AL) {
1365 encoding = B15 | B14 | B13 |
1366 ((offset >> 1) & 0x7ff);
1367 } else {
1368 encoding = B15 | B14 | B12 |
1369 cond_ << 8 | ((offset >> 1) & 0xff);
1370 }
1371 buffer->Store<int16_t>(location_, encoding);
1372 }
1373 }
1374}
1375
1376
1377uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00001378 CHECK(IsLowRegister(rn));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001379 uint32_t location = buffer_.Size();
1380
1381 // This is always unresolved as it must be a forward branch.
1382 Emit16(prev); // Previous link.
1383 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1384 location, rn);
1385}
1386
1387
1388// NOTE: this only support immediate offsets, not [rx,ry].
1389// TODO: support [rx,ry] instructions.
1390void Thumb2Assembler::EmitLoadStore(Condition cond,
1391 bool load,
1392 bool byte,
1393 bool half,
1394 bool is_signed,
1395 Register rd,
1396 const Address& ad) {
1397 CHECK_NE(rd, kNoRegister);
1398 CheckCondition(cond);
1399 bool must_be_32bit = force_32bit_;
1400 if (IsHighRegister(rd)) {
1401 must_be_32bit = true;
1402 }
1403
1404 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001405 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001406 must_be_32bit = true;
1407 }
1408
1409 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1410 must_be_32bit = true;
1411 }
1412
Dave Allison45fdb932014-06-25 12:37:10 -07001413 if (ad.IsImmediate()) {
1414 // Immediate offset
1415 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001416
Dave Allison45fdb932014-06-25 12:37:10 -07001417 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001418 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001419 must_be_32bit = true;
1420 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001421
1422 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001423 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001424 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001425 must_be_32bit = true;
1426 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001427 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001428 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001429 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001430 must_be_32bit = true;
1431 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001432 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001433 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001434 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001435 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001436 }
1437 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001438
Dave Allison45fdb932014-06-25 12:37:10 -07001439 if (must_be_32bit) {
1440 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1441 (load ? B20 : 0) |
1442 (is_signed ? B24 : 0) |
1443 static_cast<uint32_t>(rd) << 12 |
1444 ad.encodingThumb(true) |
1445 (byte ? 0 : half ? B21 : B22);
1446 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001447 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001448 // 16 bit thumb1.
1449 uint8_t opA = 0;
1450 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001451
1452 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001453 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001454 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001455 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001456 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001457 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001458 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001459 sp_relative = true;
1460 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001461 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001462 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001463 }
Dave Allison45fdb932014-06-25 12:37:10 -07001464 int16_t encoding = opA << 12 |
1465 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001466
Dave Allison45fdb932014-06-25 12:37:10 -07001467 CHECK_GE(offset, 0);
1468 if (sp_relative) {
1469 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001470 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001471 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001472 encoding |= rd << 8 | offset >> 2;
1473 } else {
1474 // No SP relative. The offset is shifted right depending on
1475 // the size of the load/store.
1476 encoding |= static_cast<uint32_t>(rd);
1477
1478 if (byte) {
1479 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001480 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001481 } else if (half) {
1482 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001483 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001484 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001485 offset >>= 1;
1486 } else {
1487 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001488 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001489 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001490 offset >>= 2;
1491 }
1492 encoding |= rn << 3 | offset << 6;
1493 }
1494
1495 Emit16(encoding);
1496 }
1497 } else {
1498 // Register shift.
1499 if (ad.GetRegister() == PC) {
1500 // PC relative literal encoding.
1501 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001502 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001503 int32_t up = B23;
1504 if (offset < 0) {
1505 offset = -offset;
1506 up = 0;
1507 }
1508 CHECK_LT(offset, (1 << 12));
1509 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1510 offset | up |
1511 static_cast<uint32_t>(rd) << 12;
1512 Emit32(encoding);
1513 } else {
1514 // 16 bit literal load.
1515 CHECK_GE(offset, 0);
1516 CHECK_LT(offset, (1 << 10));
1517 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1518 Emit16(encoding);
1519 }
1520 } else {
1521 if (ad.GetShiftCount() != 0) {
1522 // If there is a shift count this must be 32 bit.
1523 must_be_32bit = true;
1524 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1525 must_be_32bit = true;
1526 }
1527
1528 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001529 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001530 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001531 if (half) {
1532 encoding |= B21;
1533 } else if (!byte) {
1534 encoding |= B22;
1535 }
Dave Allison45fdb932014-06-25 12:37:10 -07001536 Emit32(encoding);
1537 } else {
1538 // 16 bit register offset.
1539 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1540 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001541 if (byte) {
1542 encoding |= B10;
1543 } else if (half) {
1544 encoding |= B9;
1545 }
Dave Allison45fdb932014-06-25 12:37:10 -07001546 Emit16(encoding);
1547 }
1548 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001549 }
1550}
1551
1552
1553void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001554 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001555 bool load,
1556 Register base,
1557 RegList regs) {
1558 CHECK_NE(base, kNoRegister);
1559 CheckCondition(cond);
1560 bool must_be_32bit = force_32bit_;
1561
Vladimir Markoe8469c12014-11-26 18:09:30 +00001562 if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
1563 (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
1564 // Use 16-bit PUSH/POP.
1565 int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
1566 ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
1567 Emit16(encoding);
1568 return;
1569 }
1570
Dave Allison65fcc2c2014-04-28 13:45:27 -07001571 if ((regs & 0xff00) != 0) {
1572 must_be_32bit = true;
1573 }
1574
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001575 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001576 // 16 bit always uses writeback.
1577 if (!w_bit) {
1578 must_be_32bit = true;
1579 }
1580
1581 if (must_be_32bit) {
1582 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001583 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001584 case IA:
1585 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001586 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001587 break;
1588 case DB:
1589 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001590 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001591 break;
1592 case DA:
1593 case IB:
1594 case DA_W:
1595 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001596 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001597 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001598 }
1599 if (load) {
1600 // Cannot have SP in the list.
1601 CHECK_EQ((regs & (1 << SP)), 0);
1602 } else {
1603 // Cannot have PC or SP in the list.
1604 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1605 }
1606 int32_t encoding = B31 | B30 | B29 | B27 |
1607 (op << 23) |
1608 (load ? B20 : 0) |
1609 base << 16 |
1610 regs |
1611 (w_bit << 21);
1612 Emit32(encoding);
1613 } else {
1614 int16_t encoding = B15 | B14 |
1615 (load ? B11 : 0) |
1616 base << 8 |
1617 regs;
1618 Emit16(encoding);
1619 }
1620}
1621
1622
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00001623void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x, bool is_near) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001624 uint32_t pc = buffer_.Size();
1625 Branch::Type branch_type;
1626 if (cond == AL) {
1627 if (link) {
1628 if (x) {
1629 branch_type = Branch::kUnconditionalLinkX; // BLX.
1630 } else {
1631 branch_type = Branch::kUnconditionalLink; // BX.
1632 }
1633 } else {
1634 branch_type = Branch::kUnconditional; // B.
1635 }
1636 } else {
1637 branch_type = Branch::kConditional; // B<cond>.
1638 }
1639
1640 if (label->IsBound()) {
1641 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1642
1643 // The branch is to a bound label which means that it's a backwards branch. We know the
1644 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1645 // branch the size may change if it so happens that other branches change size that change
1646 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1647 if (size == Branch::k16Bit) {
1648 Emit16(0); // Space for a 16 bit branch.
1649 } else {
1650 Emit32(0); // Space for a 32 bit branch.
1651 }
1652 } else {
1653 // Branch is to an unbound label. Emit space for it.
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00001654 uint16_t branch_id = AddBranch(branch_type, pc, cond, is_near); // Unresolved branch.
1655 if (force_32bit_ || (!CanRelocateBranches() && !is_near)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001656 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1657 Emit16(0); // another 16 bits.
1658 } else {
1659 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1660 }
1661 label->LinkTo(branch_id); // Link to the branch ID.
1662 }
1663}
1664
1665
1666void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1667 CHECK_NE(rd, kNoRegister);
1668 CHECK_NE(rm, kNoRegister);
1669 CheckCondition(cond);
1670 CHECK_NE(rd, PC);
1671 CHECK_NE(rm, PC);
1672 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1673 B25 | B23 | B21 | B20 |
1674 static_cast<uint32_t>(rm) << 16 |
1675 0xf << 12 |
1676 static_cast<uint32_t>(rd) << 8 |
1677 B7 |
1678 static_cast<uint32_t>(rm);
1679 Emit32(encoding);
1680}
1681
1682
1683void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1684 CheckCondition(cond);
1685 bool must_be_32bit = force_32bit_;
1686 if (IsHighRegister(rd)|| imm16 >= 256u) {
1687 must_be_32bit = true;
1688 }
1689
1690 if (must_be_32bit) {
1691 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001692 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1693 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1694 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001695 uint32_t imm8 = imm16 & 0xff;
1696 int32_t encoding = B31 | B30 | B29 | B28 |
1697 B25 | B22 |
1698 static_cast<uint32_t>(rd) << 8 |
1699 i << 26 |
1700 imm4 << 16 |
1701 imm3 << 12 |
1702 imm8;
1703 Emit32(encoding);
1704 } else {
1705 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1706 imm16;
1707 Emit16(encoding);
1708 }
1709}
1710
1711
1712void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1713 CheckCondition(cond);
1714 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001715 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1716 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1717 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001718 uint32_t imm8 = imm16 & 0xff;
1719 int32_t encoding = B31 | B30 | B29 | B28 |
1720 B25 | B23 | B22 |
1721 static_cast<uint32_t>(rd) << 8 |
1722 i << 26 |
1723 imm4 << 16 |
1724 imm3 << 12 |
1725 imm8;
1726 Emit32(encoding);
1727}
1728
1729
1730void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1731 CHECK_NE(rn, kNoRegister);
1732 CHECK_NE(rt, kNoRegister);
1733 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001734 CHECK_LT(imm, (1u << 10));
1735
1736 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1737 static_cast<uint32_t>(rn) << 16 |
1738 static_cast<uint32_t>(rt) << 12 |
1739 0xf << 8 |
1740 imm >> 2;
1741 Emit32(encoding);
1742}
1743
1744
1745void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1746 ldrex(rt, rn, 0, cond);
1747}
1748
1749
1750void Thumb2Assembler::strex(Register rd,
1751 Register rt,
1752 Register rn,
1753 uint16_t imm,
1754 Condition cond) {
1755 CHECK_NE(rn, kNoRegister);
1756 CHECK_NE(rd, kNoRegister);
1757 CHECK_NE(rt, kNoRegister);
1758 CheckCondition(cond);
1759 CHECK_LT(imm, (1u << 10));
1760
1761 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1762 static_cast<uint32_t>(rn) << 16 |
1763 static_cast<uint32_t>(rt) << 12 |
1764 static_cast<uint32_t>(rd) << 8 |
1765 imm >> 2;
1766 Emit32(encoding);
1767}
1768
1769
Calin Juravle52c48962014-12-16 17:02:57 +00001770void Thumb2Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
1771 CHECK_NE(rn, kNoRegister);
1772 CHECK_NE(rt, kNoRegister);
1773 CHECK_NE(rt2, kNoRegister);
1774 CHECK_NE(rt, rt2);
1775 CheckCondition(cond);
1776
1777 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 | B20 |
1778 static_cast<uint32_t>(rn) << 16 |
1779 static_cast<uint32_t>(rt) << 12 |
1780 static_cast<uint32_t>(rt2) << 8 |
1781 B6 | B5 | B4 | B3 | B2 | B1 | B0;
1782 Emit32(encoding);
1783}
1784
1785
Dave Allison65fcc2c2014-04-28 13:45:27 -07001786void Thumb2Assembler::strex(Register rd,
1787 Register rt,
1788 Register rn,
1789 Condition cond) {
1790 strex(rd, rt, rn, 0, cond);
1791}
1792
1793
Calin Juravle52c48962014-12-16 17:02:57 +00001794void Thumb2Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
1795 CHECK_NE(rd, kNoRegister);
1796 CHECK_NE(rn, kNoRegister);
1797 CHECK_NE(rt, kNoRegister);
1798 CHECK_NE(rt2, kNoRegister);
1799 CHECK_NE(rt, rt2);
1800 CHECK_NE(rd, rt);
1801 CHECK_NE(rd, rt2);
1802 CheckCondition(cond);
1803
1804 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 |
1805 static_cast<uint32_t>(rn) << 16 |
1806 static_cast<uint32_t>(rt) << 12 |
1807 static_cast<uint32_t>(rt2) << 8 |
1808 B6 | B5 | B4 |
1809 static_cast<uint32_t>(rd);
1810 Emit32(encoding);
1811}
1812
1813
Dave Allison65fcc2c2014-04-28 13:45:27 -07001814void Thumb2Assembler::clrex(Condition cond) {
1815 CheckCondition(cond);
1816 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1817 B21 | B20 |
1818 0xf << 16 |
1819 B15 |
1820 0xf << 8 |
1821 B5 |
1822 0xf;
1823 Emit32(encoding);
1824}
1825
1826
1827void Thumb2Assembler::nop(Condition cond) {
1828 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001829 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001830 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001831 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001832}
1833
1834
1835void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1836 CHECK_NE(sn, kNoSRegister);
1837 CHECK_NE(rt, kNoRegister);
1838 CHECK_NE(rt, SP);
1839 CHECK_NE(rt, PC);
1840 CheckCondition(cond);
1841 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1842 B27 | B26 | B25 |
1843 ((static_cast<int32_t>(sn) >> 1)*B16) |
1844 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1845 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1846 Emit32(encoding);
1847}
1848
1849
1850void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1851 CHECK_NE(sn, kNoSRegister);
1852 CHECK_NE(rt, kNoRegister);
1853 CHECK_NE(rt, SP);
1854 CHECK_NE(rt, PC);
1855 CheckCondition(cond);
1856 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1857 B27 | B26 | B25 | B20 |
1858 ((static_cast<int32_t>(sn) >> 1)*B16) |
1859 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1860 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1861 Emit32(encoding);
1862}
1863
1864
1865void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1866 Condition cond) {
1867 CHECK_NE(sm, kNoSRegister);
1868 CHECK_NE(sm, S31);
1869 CHECK_NE(rt, kNoRegister);
1870 CHECK_NE(rt, SP);
1871 CHECK_NE(rt, PC);
1872 CHECK_NE(rt2, kNoRegister);
1873 CHECK_NE(rt2, SP);
1874 CHECK_NE(rt2, PC);
1875 CheckCondition(cond);
1876 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1877 B27 | B26 | B22 |
1878 (static_cast<int32_t>(rt2)*B16) |
1879 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1880 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1881 (static_cast<int32_t>(sm) >> 1);
1882 Emit32(encoding);
1883}
1884
1885
1886void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1887 Condition cond) {
1888 CHECK_NE(sm, kNoSRegister);
1889 CHECK_NE(sm, S31);
1890 CHECK_NE(rt, kNoRegister);
1891 CHECK_NE(rt, SP);
1892 CHECK_NE(rt, PC);
1893 CHECK_NE(rt2, kNoRegister);
1894 CHECK_NE(rt2, SP);
1895 CHECK_NE(rt2, PC);
1896 CHECK_NE(rt, rt2);
1897 CheckCondition(cond);
1898 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1899 B27 | B26 | B22 | B20 |
1900 (static_cast<int32_t>(rt2)*B16) |
1901 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1902 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1903 (static_cast<int32_t>(sm) >> 1);
1904 Emit32(encoding);
1905}
1906
1907
1908void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1909 Condition cond) {
1910 CHECK_NE(dm, kNoDRegister);
1911 CHECK_NE(rt, kNoRegister);
1912 CHECK_NE(rt, SP);
1913 CHECK_NE(rt, PC);
1914 CHECK_NE(rt2, kNoRegister);
1915 CHECK_NE(rt2, SP);
1916 CHECK_NE(rt2, PC);
1917 CheckCondition(cond);
1918 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1919 B27 | B26 | B22 |
1920 (static_cast<int32_t>(rt2)*B16) |
1921 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1922 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1923 (static_cast<int32_t>(dm) & 0xf);
1924 Emit32(encoding);
1925}
1926
1927
1928void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1929 Condition cond) {
1930 CHECK_NE(dm, kNoDRegister);
1931 CHECK_NE(rt, kNoRegister);
1932 CHECK_NE(rt, SP);
1933 CHECK_NE(rt, PC);
1934 CHECK_NE(rt2, kNoRegister);
1935 CHECK_NE(rt2, SP);
1936 CHECK_NE(rt2, PC);
1937 CHECK_NE(rt, rt2);
1938 CheckCondition(cond);
1939 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1940 B27 | B26 | B22 | B20 |
1941 (static_cast<int32_t>(rt2)*B16) |
1942 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1943 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1944 (static_cast<int32_t>(dm) & 0xf);
1945 Emit32(encoding);
1946}
1947
1948
1949void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1950 const Address& addr = static_cast<const Address&>(ad);
1951 CHECK_NE(sd, kNoSRegister);
1952 CheckCondition(cond);
1953 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1954 B27 | B26 | B24 | B20 |
1955 ((static_cast<int32_t>(sd) & 1)*B22) |
1956 ((static_cast<int32_t>(sd) >> 1)*B12) |
1957 B11 | B9 | addr.vencoding();
1958 Emit32(encoding);
1959}
1960
1961
1962void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1963 const Address& addr = static_cast<const Address&>(ad);
1964 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1965 CHECK_NE(sd, kNoSRegister);
1966 CheckCondition(cond);
1967 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1968 B27 | B26 | B24 |
1969 ((static_cast<int32_t>(sd) & 1)*B22) |
1970 ((static_cast<int32_t>(sd) >> 1)*B12) |
1971 B11 | B9 | addr.vencoding();
1972 Emit32(encoding);
1973}
1974
1975
1976void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1977 const Address& addr = static_cast<const Address&>(ad);
1978 CHECK_NE(dd, kNoDRegister);
1979 CheckCondition(cond);
1980 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1981 B27 | B26 | B24 | B20 |
1982 ((static_cast<int32_t>(dd) >> 4)*B22) |
1983 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1984 B11 | B9 | B8 | addr.vencoding();
1985 Emit32(encoding);
1986}
1987
1988
1989void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1990 const Address& addr = static_cast<const Address&>(ad);
1991 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1992 CHECK_NE(dd, kNoDRegister);
1993 CheckCondition(cond);
1994 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1995 B27 | B26 | B24 |
1996 ((static_cast<int32_t>(dd) >> 4)*B22) |
1997 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1998 B11 | B9 | B8 | addr.vencoding();
1999 Emit32(encoding);
2000}
2001
2002
2003void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
2004 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
2005}
2006
2007
2008void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
2009 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
2010}
2011
2012
2013void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
2014 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
2015}
2016
2017
2018void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
2019 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
2020}
2021
2022
2023void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
2024 CheckCondition(cond);
2025
2026 uint32_t D;
2027 uint32_t Vd;
2028 if (dbl) {
2029 // Encoded as D:Vd.
2030 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07002031 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002032 } else {
2033 // Encoded as Vd:D.
2034 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07002035 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002036 }
2037 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
2038 B11 | B9 |
2039 (dbl ? B8 : 0) |
2040 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07002041 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07002042 nregs << (dbl ? 1 : 0) |
2043 D << 22 |
2044 Vd << 12;
2045 Emit32(encoding);
2046}
2047
2048
2049void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
2050 SRegister sd, SRegister sn, SRegister sm) {
2051 CHECK_NE(sd, kNoSRegister);
2052 CHECK_NE(sn, kNoSRegister);
2053 CHECK_NE(sm, kNoSRegister);
2054 CheckCondition(cond);
2055 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2056 B27 | B26 | B25 | B11 | B9 | opcode |
2057 ((static_cast<int32_t>(sd) & 1)*B22) |
2058 ((static_cast<int32_t>(sn) >> 1)*B16) |
2059 ((static_cast<int32_t>(sd) >> 1)*B12) |
2060 ((static_cast<int32_t>(sn) & 1)*B7) |
2061 ((static_cast<int32_t>(sm) & 1)*B5) |
2062 (static_cast<int32_t>(sm) >> 1);
2063 Emit32(encoding);
2064}
2065
2066
2067void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
2068 DRegister dd, DRegister dn, DRegister dm) {
2069 CHECK_NE(dd, kNoDRegister);
2070 CHECK_NE(dn, kNoDRegister);
2071 CHECK_NE(dm, kNoDRegister);
2072 CheckCondition(cond);
2073 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2074 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
2075 ((static_cast<int32_t>(dd) >> 4)*B22) |
2076 ((static_cast<int32_t>(dn) & 0xf)*B16) |
2077 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2078 ((static_cast<int32_t>(dn) >> 4)*B7) |
2079 ((static_cast<int32_t>(dm) >> 4)*B5) |
2080 (static_cast<int32_t>(dm) & 0xf);
2081 Emit32(encoding);
2082}
2083
2084
2085void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
2086 SRegister sd, DRegister dm) {
2087 CHECK_NE(sd, kNoSRegister);
2088 CHECK_NE(dm, kNoDRegister);
2089 CheckCondition(cond);
2090 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2091 B27 | B26 | B25 | B11 | B9 | opcode |
2092 ((static_cast<int32_t>(sd) & 1)*B22) |
2093 ((static_cast<int32_t>(sd) >> 1)*B12) |
2094 ((static_cast<int32_t>(dm) >> 4)*B5) |
2095 (static_cast<int32_t>(dm) & 0xf);
2096 Emit32(encoding);
2097}
2098
2099
2100void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
2101 DRegister dd, SRegister sm) {
2102 CHECK_NE(dd, kNoDRegister);
2103 CHECK_NE(sm, kNoSRegister);
2104 CheckCondition(cond);
2105 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2106 B27 | B26 | B25 | B11 | B9 | opcode |
2107 ((static_cast<int32_t>(dd) >> 4)*B22) |
2108 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2109 ((static_cast<int32_t>(sm) & 1)*B5) |
2110 (static_cast<int32_t>(sm) >> 1);
2111 Emit32(encoding);
2112}
2113
2114
2115void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00002116 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002117 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00002118 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2119 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
2120 (static_cast<int32_t>(PC)*B12) |
2121 B11 | B9 | B4;
2122 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002123}
2124
2125
2126void Thumb2Assembler::svc(uint32_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002127 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002128 int16_t encoding = B15 | B14 | B12 |
2129 B11 | B10 | B9 | B8 |
2130 imm8;
2131 Emit16(encoding);
2132}
2133
2134
2135void Thumb2Assembler::bkpt(uint16_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002136 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002137 int16_t encoding = B15 | B13 | B12 |
2138 B11 | B10 | B9 |
2139 imm8;
2140 Emit16(encoding);
2141}
2142
2143// Convert the given IT state to a mask bit given bit 0 of the first
2144// condition and a shift position.
2145static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2146 switch (s) {
2147 case kItOmitted: return 1 << shift;
2148 case kItThen: return firstcond0 << shift;
2149 case kItElse: return !firstcond0 << shift;
2150 }
2151 return 0;
2152}
2153
2154
2155// Set the IT condition in the given position for the given state. This is used
2156// to check that conditional instructions match the preceding IT statement.
2157void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2158 switch (s) {
2159 case kItOmitted: it_conditions_[index] = AL; break;
2160 case kItThen: it_conditions_[index] = cond; break;
2161 case kItElse:
2162 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2163 break;
2164 }
2165}
2166
2167
2168void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2169 CheckCondition(AL); // Not allowed in IT block.
2170 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2171
2172 // All conditions to AL.
2173 for (uint8_t i = 0; i < 4; ++i) {
2174 it_conditions_[i] = AL;
2175 }
2176
2177 SetItCondition(kItThen, firstcond, 0);
2178 uint8_t mask = ToItMask(i1, firstcond0, 3);
2179 SetItCondition(i1, firstcond, 1);
2180
2181 if (i1 != kItOmitted) {
2182 mask |= ToItMask(i2, firstcond0, 2);
2183 SetItCondition(i2, firstcond, 2);
2184 if (i2 != kItOmitted) {
2185 mask |= ToItMask(i3, firstcond0, 1);
2186 SetItCondition(i3, firstcond, 3);
2187 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002188 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002189 }
2190 }
2191 }
2192
2193 // Start at first condition.
2194 it_cond_index_ = 0;
2195 next_condition_ = it_conditions_[0];
2196 uint16_t encoding = B15 | B13 | B12 |
2197 B11 | B10 | B9 | B8 |
2198 firstcond << 4 |
2199 mask;
2200 Emit16(encoding);
2201}
2202
2203
2204void Thumb2Assembler::cbz(Register rn, Label* label) {
2205 CheckCondition(AL);
2206 if (label->IsBound()) {
2207 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002208 UNREACHABLE();
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00002209 } else if (IsHighRegister(rn)) {
2210 LOG(FATAL) << "cbz can only be used with low registers";
2211 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002212 } else {
2213 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2214 label->LinkTo(branchid);
2215 }
2216}
2217
2218
2219void Thumb2Assembler::cbnz(Register rn, Label* label) {
2220 CheckCondition(AL);
2221 if (label->IsBound()) {
2222 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002223 UNREACHABLE();
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00002224 } else if (IsHighRegister(rn)) {
2225 LOG(FATAL) << "cbnz can only be used with low registers";
2226 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002227 } else {
2228 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2229 label->LinkTo(branchid);
2230 }
2231}
2232
2233
2234void Thumb2Assembler::blx(Register rm, Condition cond) {
2235 CHECK_NE(rm, kNoRegister);
2236 CheckCondition(cond);
2237 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2238 Emit16(encoding);
2239}
2240
2241
2242void Thumb2Assembler::bx(Register rm, Condition cond) {
2243 CHECK_NE(rm, kNoRegister);
2244 CheckCondition(cond);
2245 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2246 Emit16(encoding);
2247}
2248
2249
2250void Thumb2Assembler::Push(Register rd, Condition cond) {
2251 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2252}
2253
2254
2255void Thumb2Assembler::Pop(Register rd, Condition cond) {
2256 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2257}
2258
2259
2260void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2261 stm(DB_W, SP, regs, cond);
2262}
2263
2264
2265void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2266 ldm(IA_W, SP, regs, cond);
2267}
2268
2269
2270void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2271 if (cond != AL || rd != rm) {
2272 mov(rd, ShifterOperand(rm), cond);
2273 }
2274}
2275
2276
2277// A branch has changed size. Make a hole for it.
2278void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2279 // Move the contents of the buffer using: Move(newposition, oldposition)
2280 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2281 buffer_.Move(location + delta, location);
2282}
2283
2284
2285void Thumb2Assembler::Bind(Label* label) {
2286 CHECK(!label->IsBound());
2287 uint32_t bound_pc = buffer_.Size();
2288 std::vector<Branch*> changed_branches;
2289
2290 while (label->IsLinked()) {
2291 uint16_t position = label->Position(); // Branch id for linked branch.
2292 Branch* branch = GetBranch(position); // Get the branch at this id.
2293 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2294 uint32_t branch_location = branch->GetLocation();
2295 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2296 if (changed) {
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +01002297 DCHECK(CanRelocateBranches());
Dave Allison65fcc2c2014-04-28 13:45:27 -07002298 MakeHoleForBranch(branch->GetLocation(), 2);
2299 if (branch->IsCompareAndBranch()) {
2300 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2301 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2302 // cmp rn, #0
2303 // b<eq|ne> target
2304 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2305 Condition cond = n ? NE : EQ;
2306 branch->Move(2); // Move the branch forward by 2 bytes.
2307 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2308 branch->ResetSize(Branch::k16Bit);
2309
2310 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002311 buffer_.Store<int16_t>(branch_location,
2312 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002313
2314 // Since have moved made a hole in the code we need to reload the
2315 // current pc.
2316 bound_pc = buffer_.Size();
2317
2318 // Now resolve the newly added branch.
2319 changed = branch->Resolve(bound_pc);
2320 if (changed) {
2321 MakeHoleForBranch(branch->GetLocation(), 2);
2322 changed_branches.push_back(branch);
2323 }
2324 } else {
2325 changed_branches.push_back(branch);
2326 }
2327 }
2328 label->position_ = next; // Move to next.
2329 }
2330 label->BindTo(bound_pc);
2331
2332 // Now relocate any changed branches. Do this until there are no more changes.
2333 std::vector<Branch*> branches_to_process = changed_branches;
2334 while (branches_to_process.size() != 0) {
2335 changed_branches.clear();
2336 for (auto& changed_branch : branches_to_process) {
2337 for (auto& branch : branches_) {
2338 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2339 if (changed) {
2340 changed_branches.push_back(branch);
2341 }
2342 }
2343 branches_to_process = changed_branches;
2344 }
2345 }
2346}
2347
2348
2349void Thumb2Assembler::EmitBranches() {
2350 for (auto& branch : branches_) {
2351 branch->Emit(&buffer_);
2352 }
2353}
2354
2355
2356void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002357 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002358 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002359 CheckCondition(cond);
2360 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002361}
2362
2363
2364void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002365 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002366 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002367 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002368 CheckCondition(cond);
2369 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002370}
2371
2372
2373void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002374 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002375 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002376 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002377 CheckCondition(cond);
2378 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002379}
2380
2381
2382void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002383 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002384 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002385 CheckCondition(cond);
2386 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002387}
2388
2389
Dave Allison45fdb932014-06-25 12:37:10 -07002390void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2391 CheckCondition(cond);
2392 EmitShift(rd, rm, RRX, rm, setcc);
2393}
2394
2395
2396void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2397 bool setcc, Condition cond) {
2398 CheckCondition(cond);
2399 EmitShift(rd, rm, LSL, rn, setcc);
2400}
2401
2402
2403void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2404 bool setcc, Condition cond) {
2405 CheckCondition(cond);
2406 EmitShift(rd, rm, LSR, rn, setcc);
2407}
2408
2409
2410void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2411 bool setcc, Condition cond) {
2412 CheckCondition(cond);
2413 EmitShift(rd, rm, ASR, rn, setcc);
2414}
2415
2416
2417void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2418 bool setcc, Condition cond) {
2419 CheckCondition(cond);
2420 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002421}
2422
2423
2424int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2425 // The offset is off by 4 due to the way the ARM CPUs read PC.
2426 offset -= 4;
2427 offset >>= 1;
2428
2429 uint32_t value = 0;
2430 // There are two different encodings depending on the value of bit 12. In one case
2431 // intermediate values are calculated using the sign bit.
2432 if ((inst & B12) == B12) {
2433 // 25 bits of offset.
2434 uint32_t signbit = (offset >> 31) & 0x1;
2435 uint32_t i1 = (offset >> 22) & 0x1;
2436 uint32_t i2 = (offset >> 21) & 0x1;
2437 uint32_t imm10 = (offset >> 11) & 0x03ff;
2438 uint32_t imm11 = offset & 0x07ff;
2439 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2440 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2441 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2442 imm11;
2443 // Remove the offset from the current encoding.
2444 inst &= ~(0x3ff << 16 | 0x7ff);
2445 } else {
2446 uint32_t signbit = (offset >> 31) & 0x1;
2447 uint32_t imm6 = (offset >> 11) & 0x03f;
2448 uint32_t imm11 = offset & 0x07ff;
2449 uint32_t j1 = (offset >> 19) & 1;
2450 uint32_t j2 = (offset >> 17) & 1;
2451 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2452 imm11;
2453 // Remove the offset from the current encoding.
2454 inst &= ~(0x3f << 16 | 0x7ff);
2455 }
2456 // Mask out offset bits in current instruction.
2457 inst &= ~(B26 | B13 | B11);
2458 inst |= value;
2459 return inst;
2460}
2461
2462
2463int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2464 int32_t imm32;
2465 if ((instr & B12) == B12) {
2466 uint32_t S = (instr >> 26) & 1;
2467 uint32_t J2 = (instr >> 11) & 1;
2468 uint32_t J1 = (instr >> 13) & 1;
2469 uint32_t imm10 = (instr >> 16) & 0x3FF;
2470 uint32_t imm11 = instr & 0x7FF;
2471
2472 uint32_t I1 = ~(J1 ^ S) & 1;
2473 uint32_t I2 = ~(J2 ^ S) & 1;
2474 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2475 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2476 } else {
2477 uint32_t S = (instr >> 26) & 1;
2478 uint32_t J2 = (instr >> 11) & 1;
2479 uint32_t J1 = (instr >> 13) & 1;
2480 uint32_t imm6 = (instr >> 16) & 0x3F;
2481 uint32_t imm11 = instr & 0x7FF;
2482
2483 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2484 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2485 }
2486 imm32 += 4;
2487 return imm32;
2488}
2489
2490
2491void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2492 AddConstant(rd, rd, value, cond);
2493}
2494
2495
2496void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2497 Condition cond) {
2498 if (value == 0) {
2499 if (rd != rn) {
2500 mov(rd, ShifterOperand(rn), cond);
2501 }
2502 return;
2503 }
2504 // We prefer to select the shorter code sequence rather than selecting add for
2505 // positive values and sub for negatives ones, which would slightly improve
2506 // the readability of generated code for some constants.
2507 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002508 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002509 add(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002510 } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002511 sub(rd, rn, shifter_op, cond);
2512 } else {
2513 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002514 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002515 mvn(IP, shifter_op, cond);
2516 add(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002517 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002518 mvn(IP, shifter_op, cond);
2519 sub(rd, rn, ShifterOperand(IP), cond);
2520 } else {
2521 movw(IP, Low16Bits(value), cond);
2522 uint16_t value_high = High16Bits(value);
2523 if (value_high != 0) {
2524 movt(IP, value_high, cond);
2525 }
2526 add(rd, rn, ShifterOperand(IP), cond);
2527 }
2528 }
2529}
2530
2531
2532void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2533 Condition cond) {
2534 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002535 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002536 adds(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002537 } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002538 subs(rd, rn, shifter_op, cond);
2539 } else {
2540 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002541 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002542 mvn(IP, shifter_op, cond);
2543 adds(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002544 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002545 mvn(IP, shifter_op, cond);
2546 subs(rd, rn, ShifterOperand(IP), cond);
2547 } else {
2548 movw(IP, Low16Bits(value), cond);
2549 uint16_t value_high = High16Bits(value);
2550 if (value_high != 0) {
2551 movt(IP, value_high, cond);
2552 }
2553 adds(rd, rn, ShifterOperand(IP), cond);
2554 }
2555 }
2556}
2557
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002558
Dave Allison65fcc2c2014-04-28 13:45:27 -07002559void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2560 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002561 if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002562 mov(rd, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002563 } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002564 mvn(rd, shifter_op, cond);
2565 } else {
2566 movw(rd, Low16Bits(value), cond);
2567 uint16_t value_high = High16Bits(value);
2568 if (value_high != 0) {
2569 movt(rd, value_high, cond);
2570 }
2571 }
2572}
2573
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002574
Dave Allison65fcc2c2014-04-28 13:45:27 -07002575// Implementation note: this method must emit at most one instruction when
2576// Address::CanHoldLoadOffsetThumb.
2577void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2578 Register reg,
2579 Register base,
2580 int32_t offset,
2581 Condition cond) {
2582 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002583 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002584 LoadImmediate(IP, offset, cond);
2585 add(IP, IP, ShifterOperand(base), cond);
2586 base = IP;
2587 offset = 0;
2588 }
2589 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2590 switch (type) {
2591 case kLoadSignedByte:
2592 ldrsb(reg, Address(base, offset), cond);
2593 break;
2594 case kLoadUnsignedByte:
2595 ldrb(reg, Address(base, offset), cond);
2596 break;
2597 case kLoadSignedHalfword:
2598 ldrsh(reg, Address(base, offset), cond);
2599 break;
2600 case kLoadUnsignedHalfword:
2601 ldrh(reg, Address(base, offset), cond);
2602 break;
2603 case kLoadWord:
2604 ldr(reg, Address(base, offset), cond);
2605 break;
2606 case kLoadWordPair:
2607 ldrd(reg, Address(base, offset), cond);
2608 break;
2609 default:
2610 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002611 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002612 }
2613}
2614
2615
2616// Implementation note: this method must emit at most one instruction when
2617// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2618void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2619 Register base,
2620 int32_t offset,
2621 Condition cond) {
2622 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2623 CHECK_NE(base, IP);
2624 LoadImmediate(IP, offset, cond);
2625 add(IP, IP, ShifterOperand(base), cond);
2626 base = IP;
2627 offset = 0;
2628 }
2629 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2630 vldrs(reg, Address(base, offset), cond);
2631}
2632
2633
2634// Implementation note: this method must emit at most one instruction when
2635// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2636void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2637 Register base,
2638 int32_t offset,
2639 Condition cond) {
2640 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2641 CHECK_NE(base, IP);
2642 LoadImmediate(IP, offset, cond);
2643 add(IP, IP, ShifterOperand(base), cond);
2644 base = IP;
2645 offset = 0;
2646 }
2647 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2648 vldrd(reg, Address(base, offset), cond);
2649}
2650
2651
2652// Implementation note: this method must emit at most one instruction when
2653// Address::CanHoldStoreOffsetThumb.
2654void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2655 Register reg,
2656 Register base,
2657 int32_t offset,
2658 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002659 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002660 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002661 CHECK_NE(base, IP);
Roland Levillain4af147e2015-04-07 13:54:49 +01002662 if (reg != IP &&
2663 (type != kStoreWordPair || reg + 1 != IP)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002664 tmp_reg = IP;
2665 } else {
Roland Levillain4af147e2015-04-07 13:54:49 +01002666 // Be careful not to use IP twice (for `reg` (or `reg` + 1 in
2667 // the case of a word-pair store)) and to build the Address
2668 // object used by the store instruction(s) below). Instead,
2669 // save R5 on the stack (or R6 if R5 is not available), use it
2670 // as secondary temporary register, and restore it after the
2671 // store instruction has been emitted.
Roland Levillain775ef492014-11-04 17:43:11 +00002672 tmp_reg = base != R5 ? R5 : R6;
2673 Push(tmp_reg);
2674 if (base == SP) {
2675 offset += kRegisterSize;
2676 }
2677 }
2678 LoadImmediate(tmp_reg, offset, cond);
2679 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2680 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002681 offset = 0;
2682 }
2683 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2684 switch (type) {
2685 case kStoreByte:
2686 strb(reg, Address(base, offset), cond);
2687 break;
2688 case kStoreHalfword:
2689 strh(reg, Address(base, offset), cond);
2690 break;
2691 case kStoreWord:
2692 str(reg, Address(base, offset), cond);
2693 break;
2694 case kStoreWordPair:
2695 strd(reg, Address(base, offset), cond);
2696 break;
2697 default:
2698 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002699 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002700 }
Roland Levillain775ef492014-11-04 17:43:11 +00002701 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2702 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2703 Pop(tmp_reg);
2704 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002705}
2706
2707
2708// Implementation note: this method must emit at most one instruction when
2709// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2710void Thumb2Assembler::StoreSToOffset(SRegister reg,
2711 Register base,
2712 int32_t offset,
2713 Condition cond) {
2714 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2715 CHECK_NE(base, IP);
2716 LoadImmediate(IP, offset, cond);
2717 add(IP, IP, ShifterOperand(base), cond);
2718 base = IP;
2719 offset = 0;
2720 }
2721 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2722 vstrs(reg, Address(base, offset), cond);
2723}
2724
2725
2726// Implementation note: this method must emit at most one instruction when
2727// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2728void Thumb2Assembler::StoreDToOffset(DRegister reg,
2729 Register base,
2730 int32_t offset,
2731 Condition cond) {
2732 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2733 CHECK_NE(base, IP);
2734 LoadImmediate(IP, offset, cond);
2735 add(IP, IP, ShifterOperand(base), cond);
2736 base = IP;
2737 offset = 0;
2738 }
2739 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2740 vstrd(reg, Address(base, offset), cond);
2741}
2742
2743
2744void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2745 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002746 dmb(SY);
2747}
2748
2749
2750void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002751 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2752 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002753}
2754
2755
2756void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00002757 if (CanRelocateBranches() && IsLowRegister(r)) {
2758 cbz(r, label);
2759 } else {
2760 cmp(r, ShifterOperand(0));
2761 b(label, EQ);
2762 }
2763}
2764
2765
2766void Thumb2Assembler::CompareAndBranchIfZero(Register r, NearLabel* label) {
2767 if (IsLowRegister(r)) {
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +01002768 cbz(r, label);
2769 } else {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002770 cmp(r, ShifterOperand(0));
2771 b(label, EQ);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002772 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002773}
2774
2775
2776void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +00002777 if (CanRelocateBranches() && IsLowRegister(r)) {
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +01002778 cbnz(r, label);
2779 } else {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002780 cmp(r, ShifterOperand(0));
2781 b(label, NE);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002782 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002783}
2784} // namespace arm
2785} // namespace art