blob: e7cf26eee2621130865f62291917a3a2f9fd8853 [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
674void Thumb2Assembler::b(Label* label, Condition cond) {
675 EmitBranch(cond, label, false, false);
676}
677
678
679void Thumb2Assembler::bl(Label* label, Condition cond) {
680 CheckCondition(cond);
681 EmitBranch(cond, label, true, false);
682}
683
684
685void Thumb2Assembler::blx(Label* label) {
686 EmitBranch(AL, label, true, true);
687}
688
689
690void Thumb2Assembler::MarkExceptionHandler(Label* label) {
691 EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0));
692 Label l;
693 b(&l);
694 EmitBranch(AL, label, false, false);
695 Bind(&l);
696}
697
698
699void Thumb2Assembler::Emit32(int32_t value) {
700 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
701 buffer_.Emit<int16_t>(value >> 16);
702 buffer_.Emit<int16_t>(value & 0xffff);
703}
704
705
706void Thumb2Assembler::Emit16(int16_t value) {
707 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
708 buffer_.Emit<int16_t>(value);
709}
710
711
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700712bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700713 Opcode opcode,
Andreas Gampeca714582015-04-03 19:41:34 -0700714 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700715 Register rn,
716 Register rd,
717 const ShifterOperand& so) {
718 if (force_32bit_) {
719 return true;
720 }
721
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000722 // Check special case for SP relative ADD and SUB immediate.
723 if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) {
724 // If the immediate is in range, use 16 bit.
725 if (rd == SP) {
726 if (so.GetImmediate() < (1 << 9)) { // 9 bit immediate.
727 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700728 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000729 } else if (!IsHighRegister(rd) && opcode == ADD) {
730 if (so.GetImmediate() < (1 << 10)) { // 10 bit immediate.
731 return false;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700732 }
733 }
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000734 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700735
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000736 bool can_contain_high_register = (opcode == MOV)
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800737 || ((opcode == ADD) && (rn == rd) && !set_cc);
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000738
739 if (IsHighRegister(rd) || IsHighRegister(rn)) {
740 if (!can_contain_high_register) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700741 return true;
742 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100743
Vladimir Marko5bc561c2014-12-16 17:41:59 +0000744 // There are high register instructions available for this opcode.
745 // However, there is no actual shift available, neither for ADD nor for MOV (ASR/LSR/LSL/ROR).
746 if (so.IsShift() && (so.GetShift() == RRX || so.GetImmediate() != 0u)) {
747 return true;
748 }
749
750 // The ADD and MOV instructions that work with high registers don't have 16-bit
751 // immediate variants.
752 if (so.IsImmediate()) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100753 return true;
754 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700755 }
756
757 if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
758 return true;
759 }
760
Dave Allison65fcc2c2014-04-28 13:45:27 -0700761 bool rn_is_valid = true;
762
763 // Check for single operand instructions and ADD/SUB.
764 switch (opcode) {
765 case CMP:
766 case MOV:
767 case TST:
768 case MVN:
769 rn_is_valid = false; // There is no Rn for these instructions.
770 break;
771 case TEQ:
772 return true;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700773 case ADD:
774 case SUB:
775 break;
776 default:
777 if (so.IsRegister() && rd != rn) {
778 return true;
779 }
780 }
781
782 if (so.IsImmediate()) {
783 if (rn_is_valid && rn != rd) {
784 // The only thumb1 instruction with a register and an immediate are ADD and SUB. The
785 // immediate must be 3 bits.
786 if (opcode != ADD && opcode != SUB) {
787 return true;
788 } else {
789 // Check that the immediate is 3 bits for ADD and SUB.
790 if (so.GetImmediate() >= 8) {
791 return true;
792 }
793 }
794 } else {
795 // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits.
796 if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) {
797 return true;
798 } else {
799 if (so.GetImmediate() > 255) {
800 return true;
801 }
802 }
803 }
804 }
805
Zheng Xuc6667102015-05-15 16:08:45 +0800806 // Check for register shift operand.
807 if (so.IsRegister() && so.IsShift()) {
808 if (opcode != MOV) {
809 return true;
810 }
811 // Check for MOV with an ROR.
812 if (so.GetShift() == ROR) {
813 if (so.GetImmediate() != 0) {
814 return true;
815 }
816 }
817 }
818
Dave Allison65fcc2c2014-04-28 13:45:27 -0700819 // The instruction can be encoded in 16 bits.
820 return false;
821}
822
823
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700824void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700825 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700826 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700827 Register rn,
828 Register rd,
829 const ShifterOperand& so) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700830 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700831 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700832 case AND: thumb_opcode = 0U /* 0b0000 */; break;
833 case EOR: thumb_opcode = 4U /* 0b0100 */; break;
834 case SUB: thumb_opcode = 13U /* 0b1101 */; break;
835 case RSB: thumb_opcode = 14U /* 0b1110 */; break;
836 case ADD: thumb_opcode = 8U /* 0b1000 */; break;
Andreas Gampe35c68e32014-09-30 08:39:37 -0700837 case ADC: thumb_opcode = 10U /* 0b1010 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700838 case SBC: thumb_opcode = 11U /* 0b1011 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700839 case RSC: break;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700840 case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break;
841 case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break;
842 case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break;
843 case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break;
844 case ORR: thumb_opcode = 2U /* 0b0010 */; break;
845 case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break;
846 case BIC: thumb_opcode = 1U /* 0b0001 */; break;
847 case MVN: thumb_opcode = 3U /* 0b0011 */; rn = PC; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700848 default:
849 break;
850 }
851
Andreas Gampec8ccf682014-09-29 20:07:43 -0700852 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700853 LOG(FATAL) << "Invalid thumb2 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +0000854 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700855 }
856
857 int32_t encoding = 0;
858 if (so.IsImmediate()) {
859 // Check special cases.
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100860 if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000861 if (!set_cc) {
862 if (opcode == SUB) {
863 thumb_opcode = 5U;
864 } else if (opcode == ADD) {
865 thumb_opcode = 0U;
866 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700867 }
868 uint32_t imm = so.GetImmediate();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700869
870 uint32_t i = (imm >> 11) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -0700871 uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700872 uint32_t imm8 = imm & 0xff;
873
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000874 encoding = B31 | B30 | B29 | B28 |
875 (set_cc ? B20 : B25) |
876 thumb_opcode << 21 |
877 rn << 16 |
878 rd << 8 |
879 i << 26 |
880 imm3 << 12 |
881 imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700882 } else {
883 // Modified immediate.
Dave Allison45fdb932014-06-25 12:37:10 -0700884 uint32_t imm = ModifiedImmediate(so.encodingThumb());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700885 if (imm == kInvalidModifiedImmediate) {
886 LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate";
Vladimir Markoe8469c12014-11-26 18:09:30 +0000887 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700888 }
889 encoding = B31 | B30 | B29 | B28 |
890 thumb_opcode << 21 |
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000891 (set_cc ? B20 : 0) |
Dave Allison65fcc2c2014-04-28 13:45:27 -0700892 rn << 16 |
893 rd << 8 |
894 imm;
895 }
896 } else if (so.IsRegister()) {
Guillaume "Vermeille" Sanchezdc62c482015-03-11 14:30:31 +0000897 // Register (possibly shifted)
898 encoding = B31 | B30 | B29 | B27 | B25 |
899 thumb_opcode << 21 |
900 (set_cc ? B20 : 0) |
901 rn << 16 |
902 rd << 8 |
903 so.encodingThumb();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700904 }
905 Emit32(encoding);
906}
907
908
909void Thumb2Assembler::Emit16BitDataProcessing(Condition cond,
910 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700911 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700912 Register rn,
913 Register rd,
914 const ShifterOperand& so) {
915 if (opcode == ADD || opcode == SUB) {
916 Emit16BitAddSub(cond, opcode, set_cc, rn, rd, so);
917 return;
918 }
Andreas Gampec8ccf682014-09-29 20:07:43 -0700919 uint8_t thumb_opcode = 255U /* 0b11111111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700920 // Thumb1.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700921 uint8_t dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700922 uint8_t opcode_shift = 6;
923 uint8_t rd_shift = 0;
924 uint8_t rn_shift = 3;
925 uint8_t immediate_shift = 0;
926 bool use_immediate = false;
927 uint8_t immediate = 0;
928
929 if (opcode == MOV && so.IsRegister() && so.IsShift()) {
930 // Convert shifted mov operand2 into 16 bit opcodes.
931 dp_opcode = 0;
932 opcode_shift = 11;
933
934 use_immediate = true;
935 immediate = so.GetImmediate();
936 immediate_shift = 6;
937
938 rn = so.GetRegister();
939
940 switch (so.GetShift()) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700941 case LSL: thumb_opcode = 0U /* 0b00 */; break;
942 case LSR: thumb_opcode = 1U /* 0b01 */; break;
943 case ASR: thumb_opcode = 2U /* 0b10 */; break;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700944 case ROR:
945 // ROR doesn't allow immediates.
Andreas Gampec8ccf682014-09-29 20:07:43 -0700946 thumb_opcode = 7U /* 0b111 */;
947 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700948 opcode_shift = 6;
949 use_immediate = false;
950 break;
951 case RRX: break;
952 default:
953 break;
954 }
955 } else {
956 if (so.IsImmediate()) {
957 use_immediate = true;
958 immediate = so.GetImmediate();
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800959 } else {
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000960 CHECK(!(so.IsRegister() && so.IsShift() && so.GetSecondRegister() != kNoRegister))
961 << "No register-shifted register instruction available in thumb";
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800962 // Adjust rn and rd: only two registers will be emitted.
963 switch (opcode) {
964 case AND:
965 case ORR:
966 case EOR:
967 case RSB:
968 case ADC:
969 case SBC:
970 case BIC: {
971 if (rn == rd) {
972 rn = so.GetRegister();
973 } else {
974 CHECK_EQ(rd, so.GetRegister());
975 }
976 break;
977 }
978 case CMP:
979 case CMN: {
980 CHECK_EQ(rd, 0);
981 rd = rn;
982 rn = so.GetRegister();
983 break;
984 }
Andreas Gampe7b7e5242015-02-02 19:17:11 -0800985 case TST:
986 case TEQ:
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800987 case MVN: {
988 CHECK_EQ(rn, 0);
989 rn = so.GetRegister();
990 break;
991 }
992 default:
993 break;
994 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700995 }
996
997 switch (opcode) {
Andreas Gampec8ccf682014-09-29 20:07:43 -0700998 case AND: thumb_opcode = 0U /* 0b0000 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -0800999 case ORR: thumb_opcode = 12U /* 0b1100 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001000 case EOR: thumb_opcode = 1U /* 0b0001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001001 case RSB: thumb_opcode = 9U /* 0b1001 */; break;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001002 case ADC: thumb_opcode = 5U /* 0b0101 */; break;
1003 case SBC: thumb_opcode = 6U /* 0b0110 */; break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001004 case BIC: thumb_opcode = 14U /* 0b1110 */; break;
1005 case TST: thumb_opcode = 8U /* 0b1000 */; CHECK(!use_immediate); break;
1006 case MVN: thumb_opcode = 15U /* 0b1111 */; CHECK(!use_immediate); break;
1007 case CMP: {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001008 if (use_immediate) {
1009 // T2 encoding.
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001010 dp_opcode = 0;
1011 opcode_shift = 11;
1012 thumb_opcode = 5U /* 0b101 */;
1013 rd_shift = 8;
1014 rn_shift = 8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001015 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001016 thumb_opcode = 10U /* 0b1010 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001017 }
1018
1019 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001020 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001021 case CMN: {
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001022 CHECK(!use_immediate);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001023 thumb_opcode = 11U /* 0b1011 */;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001024 break;
1025 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001026 case MOV:
1027 dp_opcode = 0;
1028 if (use_immediate) {
1029 // T2 encoding.
1030 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001031 thumb_opcode = 4U /* 0b100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001032 rd_shift = 8;
1033 rn_shift = 8;
1034 } else {
1035 rn = so.GetRegister();
1036 if (IsHighRegister(rn) || IsHighRegister(rd)) {
1037 // Special mov for high registers.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001038 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001039 opcode_shift = 7;
1040 // Put the top bit of rd into the bottom bit of the opcode.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001041 thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3;
1042 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001043 } else {
1044 thumb_opcode = 0;
1045 }
1046 }
1047 break;
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001048
1049 case TEQ:
1050 case RSC:
Dave Allison65fcc2c2014-04-28 13:45:27 -07001051 default:
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001052 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001053 break;
1054 }
1055 }
1056
Andreas Gampec8ccf682014-09-29 20:07:43 -07001057 if (thumb_opcode == 255U /* 0b11111111 */) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001058 LOG(FATAL) << "Invalid thumb1 opcode " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001059 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001060 }
1061
1062 int16_t encoding = dp_opcode << 14 |
1063 (thumb_opcode << opcode_shift) |
1064 rd << rd_shift |
1065 rn << rn_shift |
1066 (use_immediate ? (immediate << immediate_shift) : 0);
1067
1068 Emit16(encoding);
1069}
1070
1071
1072// ADD and SUB are complex enough to warrant their own emitter.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001073void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001074 Opcode opcode,
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001075 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001076 Register rn,
1077 Register rd,
1078 const ShifterOperand& so) {
1079 uint8_t dp_opcode = 0;
1080 uint8_t opcode_shift = 6;
1081 uint8_t rd_shift = 0;
1082 uint8_t rn_shift = 3;
1083 uint8_t immediate_shift = 0;
1084 bool use_immediate = false;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001085 uint32_t immediate = 0; // Should be at most 9 bits but keep the full immediate for CHECKs.
Dave Allison65fcc2c2014-04-28 13:45:27 -07001086 uint8_t thumb_opcode;;
1087
1088 if (so.IsImmediate()) {
1089 use_immediate = true;
1090 immediate = so.GetImmediate();
1091 }
1092
1093 switch (opcode) {
1094 case ADD:
1095 if (so.IsRegister()) {
1096 Register rm = so.GetRegister();
Andreas Gampe513ea0c2015-02-02 13:17:52 -08001097 if (rn == rd && !set_cc) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001098 // Can use T2 encoding (allows 4 bit registers)
Andreas Gampec8ccf682014-09-29 20:07:43 -07001099 dp_opcode = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001100 opcode_shift = 10;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001101 thumb_opcode = 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001102 // Make Rn also contain the top bit of rd.
1103 rn = static_cast<Register>(static_cast<uint32_t>(rm) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07001104 (static_cast<uint32_t>(rd) & 8U /* 0b1000 */) << 1);
1105 rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001106 } else {
1107 // T1.
1108 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001109 thumb_opcode = 12U /* 0b01100 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001110 immediate = static_cast<uint32_t>(so.GetRegister());
1111 use_immediate = true;
1112 immediate_shift = 6;
1113 }
1114 } else {
1115 // Immediate.
1116 if (rd == SP && rn == SP) {
1117 // ADD sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001118 dp_opcode = 2U /* 0b10 */;
1119 thumb_opcode = 3U /* 0b11 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001120 opcode_shift = 12;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001121 CHECK_LT(immediate, (1u << 9));
1122 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001123
1124 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1125 rn = R0;
1126 rd = R0;
1127 rd_shift = 0;
1128 rn_shift = 0;
1129 immediate >>= 2;
1130 } else if (rd != SP && rn == SP) {
1131 // ADD rd, SP, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001132 dp_opcode = 2U /* 0b10 */;
1133 thumb_opcode = 5U /* 0b101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001134 opcode_shift = 11;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001135 CHECK_LT(immediate, (1u << 10));
1136 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001137
1138 // Remove rn from instruction.
1139 rn = R0;
1140 rn_shift = 0;
1141 rd_shift = 8;
1142 immediate >>= 2;
1143 } else if (rn != rd) {
1144 // Must use T1.
1145 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001146 thumb_opcode = 14U /* 0b01110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001147 immediate_shift = 6;
1148 } else {
1149 // T2 encoding.
1150 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001151 thumb_opcode = 6U /* 0b110 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001152 rd_shift = 8;
1153 rn_shift = 8;
1154 }
1155 }
1156 break;
1157
1158 case SUB:
1159 if (so.IsRegister()) {
1160 // T1.
1161 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001162 thumb_opcode = 13U /* 0b01101 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001163 immediate = static_cast<uint32_t>(so.GetRegister());
1164 use_immediate = true;
1165 immediate_shift = 6;
1166 } else {
1167 if (rd == SP && rn == SP) {
1168 // SUB sp, sp, #imm
Andreas Gampec8ccf682014-09-29 20:07:43 -07001169 dp_opcode = 2U /* 0b10 */;
1170 thumb_opcode = 0x61 /* 0b1100001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001171 opcode_shift = 7;
Vladimir Markoac0341e2014-12-18 19:56:49 +00001172 CHECK_LT(immediate, (1u << 9));
1173 CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001174
1175 // Remove rd and rn from instruction by orring it with immed and clearing bits.
1176 rn = R0;
1177 rd = R0;
1178 rd_shift = 0;
1179 rn_shift = 0;
1180 immediate >>= 2;
1181 } else if (rn != rd) {
1182 // Must use T1.
1183 opcode_shift = 9;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001184 thumb_opcode = 15U /* 0b01111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001185 immediate_shift = 6;
1186 } else {
1187 // T2 encoding.
1188 opcode_shift = 11;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001189 thumb_opcode = 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001190 rd_shift = 8;
1191 rn_shift = 8;
1192 }
1193 }
1194 break;
1195 default:
1196 LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001197 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001198 }
1199
1200 int16_t encoding = dp_opcode << 14 |
1201 (thumb_opcode << opcode_shift) |
1202 rd << rd_shift |
1203 rn << rn_shift |
1204 (use_immediate ? (immediate << immediate_shift) : 0);
1205
1206 Emit16(encoding);
1207}
1208
1209
1210void Thumb2Assembler::EmitDataProcessing(Condition cond,
1211 Opcode opcode,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001212 bool set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001213 Register rn,
1214 Register rd,
1215 const ShifterOperand& so) {
1216 CHECK_NE(rd, kNoRegister);
1217 CheckCondition(cond);
1218
1219 if (Is32BitDataProcessing(cond, opcode, set_cc, rn, rd, so)) {
1220 Emit32BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1221 } else {
1222 Emit16BitDataProcessing(cond, opcode, set_cc, rn, rd, so);
1223 }
1224}
1225
Dave Allison45fdb932014-06-25 12:37:10 -07001226void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) {
1227 CHECK_LT(amount, (1 << 5));
1228 if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) {
1229 uint16_t opcode = 0;
1230 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001231 case LSL: opcode = 0U /* 0b00 */; break;
1232 case LSR: opcode = 1U /* 0b01 */; break;
1233 case ASR: opcode = 2U /* 0b10 */; break;
1234 case ROR: opcode = 3U /* 0b11 */; break;
1235 case RRX: opcode = 3U /* 0b11 */; amount = 0; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001236 default:
1237 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001238 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001239 }
1240 // 32 bit.
1241 int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 |
1242 0xf << 16 | (setcc ? B20 : 0);
1243 uint32_t imm3 = amount >> 2;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001244 uint32_t imm2 = amount & 3U /* 0b11 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001245 encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) |
1246 static_cast<int16_t>(rd) << 8 | opcode << 4;
1247 Emit32(encoding);
1248 } else {
1249 // 16 bit shift
1250 uint16_t opcode = 0;
1251 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001252 case LSL: opcode = 0U /* 0b00 */; break;
1253 case LSR: opcode = 1U /* 0b01 */; break;
1254 case ASR: opcode = 2U /* 0b10 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001255 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001256 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1257 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001258 }
1259 int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 |
1260 static_cast<int16_t>(rd);
1261 Emit16(encoding);
1262 }
1263}
1264
1265void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) {
1266 CHECK_NE(shift, RRX);
1267 bool must_be_32bit = false;
1268 if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) {
1269 must_be_32bit = true;
1270 }
1271
1272 if (must_be_32bit) {
1273 uint16_t opcode = 0;
1274 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001275 case LSL: opcode = 0U /* 0b00 */; break;
1276 case LSR: opcode = 1U /* 0b01 */; break;
1277 case ASR: opcode = 2U /* 0b10 */; break;
1278 case ROR: opcode = 3U /* 0b11 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001279 default:
1280 LOG(FATAL) << "Unsupported thumb2 shift opcode";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001281 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001282 }
1283 // 32 bit.
1284 int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 |
1285 0xf << 12 | (setcc ? B20 : 0);
1286 encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) |
1287 static_cast<int16_t>(rd) << 8 | opcode << 21;
1288 Emit32(encoding);
1289 } else {
1290 uint16_t opcode = 0;
1291 switch (shift) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001292 case LSL: opcode = 2U /* 0b0010 */; break;
1293 case LSR: opcode = 3U /* 0b0011 */; break;
1294 case ASR: opcode = 4U /* 0b0100 */; break;
Dave Allison45fdb932014-06-25 12:37:10 -07001295 default:
Vladimir Markoe8469c12014-11-26 18:09:30 +00001296 LOG(FATAL) << "Unsupported thumb2 shift opcode";
1297 UNREACHABLE();
Dave Allison45fdb932014-06-25 12:37:10 -07001298 }
1299 int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 |
1300 static_cast<int16_t>(rd);
1301 Emit16(encoding);
1302 }
1303}
1304
1305
Dave Allison65fcc2c2014-04-28 13:45:27 -07001306
1307void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
1308 bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
1309 bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
1310 int32_t offset = target_ - location_;
1311
1312 if (size_ == k32Bit) {
1313 int32_t encoding = B31 | B30 | B29 | B28 | B15;
1314 if (link) {
1315 // BL or BLX immediate.
1316 encoding |= B14;
1317 if (!x) {
1318 encoding |= B12;
1319 } else {
1320 // Bottom bit of offset must be 0.
1321 CHECK_EQ((offset & 1), 0);
1322 }
1323 } else {
1324 if (x) {
1325 LOG(FATAL) << "Invalid use of BX";
Vladimir Markoe8469c12014-11-26 18:09:30 +00001326 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001327 } else {
1328 if (cond_ == AL) {
1329 // Can use the T4 encoding allowing a 24 bit offset.
1330 if (!x) {
1331 encoding |= B12;
1332 }
1333 } else {
1334 // Must be T3 encoding with a 20 bit offset.
1335 encoding |= cond_ << 22;
1336 }
1337 }
1338 }
1339 encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
1340 buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
1341 buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
1342 } else {
1343 if (IsCompareAndBranch()) {
1344 offset -= 4;
1345 uint16_t i = (offset >> 6) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001346 uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001347 int16_t encoding = B15 | B13 | B12 |
1348 (type_ == kCompareAndBranchNonZero ? B11 : 0) |
1349 static_cast<uint32_t>(rn_) |
1350 B8 |
1351 i << 9 |
1352 imm5 << 3;
1353 buffer->Store<int16_t>(location_, encoding);
1354 } else {
1355 offset -= 4; // Account for PC offset.
1356 int16_t encoding;
1357 // 16 bit.
1358 if (cond_ == AL) {
1359 encoding = B15 | B14 | B13 |
1360 ((offset >> 1) & 0x7ff);
1361 } else {
1362 encoding = B15 | B14 | B12 |
1363 cond_ << 8 | ((offset >> 1) & 0xff);
1364 }
1365 buffer->Store<int16_t>(location_, encoding);
1366 }
1367 }
1368}
1369
1370
1371uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
1372 uint32_t location = buffer_.Size();
1373
1374 // This is always unresolved as it must be a forward branch.
1375 Emit16(prev); // Previous link.
1376 return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
1377 location, rn);
1378}
1379
1380
1381// NOTE: this only support immediate offsets, not [rx,ry].
1382// TODO: support [rx,ry] instructions.
1383void Thumb2Assembler::EmitLoadStore(Condition cond,
1384 bool load,
1385 bool byte,
1386 bool half,
1387 bool is_signed,
1388 Register rd,
1389 const Address& ad) {
1390 CHECK_NE(rd, kNoRegister);
1391 CheckCondition(cond);
1392 bool must_be_32bit = force_32bit_;
1393 if (IsHighRegister(rd)) {
1394 must_be_32bit = true;
1395 }
1396
1397 Register rn = ad.GetRegister();
Dave Allison45fdb932014-06-25 12:37:10 -07001398 if (IsHighRegister(rn) && rn != SP && rn != PC) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001399 must_be_32bit = true;
1400 }
1401
1402 if (is_signed || ad.GetOffset() < 0 || ad.GetMode() != Address::Offset) {
1403 must_be_32bit = true;
1404 }
1405
Dave Allison45fdb932014-06-25 12:37:10 -07001406 if (ad.IsImmediate()) {
1407 // Immediate offset
1408 int32_t offset = ad.GetOffset();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001409
Dave Allison45fdb932014-06-25 12:37:10 -07001410 // The 16 bit SP relative instruction can only have a 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001411 if (rn == SP && offset >= (1 << 10)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001412 must_be_32bit = true;
1413 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001414
1415 if (byte) {
Dave Allison45fdb932014-06-25 12:37:10 -07001416 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001417 if (offset >= (1 << 5)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001418 must_be_32bit = true;
1419 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001420 } else if (half) {
Dave Allison45fdb932014-06-25 12:37:10 -07001421 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001422 if (offset >= (1 << 6)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001423 must_be_32bit = true;
1424 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001425 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001426 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001427 if (offset >= (1 << 7)) {
Dave Allison45fdb932014-06-25 12:37:10 -07001428 must_be_32bit = true;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001429 }
1430 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001431
Dave Allison45fdb932014-06-25 12:37:10 -07001432 if (must_be_32bit) {
1433 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1434 (load ? B20 : 0) |
1435 (is_signed ? B24 : 0) |
1436 static_cast<uint32_t>(rd) << 12 |
1437 ad.encodingThumb(true) |
1438 (byte ? 0 : half ? B21 : B22);
1439 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001440 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001441 // 16 bit thumb1.
1442 uint8_t opA = 0;
1443 bool sp_relative = false;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001444
1445 if (byte) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001446 opA = 7U /* 0b0111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001447 } else if (half) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001448 opA = 8U /* 0b1000 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001449 } else {
Dave Allison45fdb932014-06-25 12:37:10 -07001450 if (rn == SP) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001451 opA = 9U /* 0b1001 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001452 sp_relative = true;
1453 } else {
Andreas Gampec8ccf682014-09-29 20:07:43 -07001454 opA = 6U /* 0b0110 */;
Dave Allison45fdb932014-06-25 12:37:10 -07001455 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001456 }
Dave Allison45fdb932014-06-25 12:37:10 -07001457 int16_t encoding = opA << 12 |
1458 (load ? B11 : 0);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001459
Dave Allison45fdb932014-06-25 12:37:10 -07001460 CHECK_GE(offset, 0);
1461 if (sp_relative) {
1462 // SP relative, 10 bit offset.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001463 CHECK_LT(offset, (1 << 10));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001464 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001465 encoding |= rd << 8 | offset >> 2;
1466 } else {
1467 // No SP relative. The offset is shifted right depending on
1468 // the size of the load/store.
1469 encoding |= static_cast<uint32_t>(rd);
1470
1471 if (byte) {
1472 // 5 bit offset, no shift.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001473 CHECK_LT(offset, (1 << 5));
Dave Allison45fdb932014-06-25 12:37:10 -07001474 } else if (half) {
1475 // 6 bit offset, shifted by 1.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001476 CHECK_LT(offset, (1 << 6));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001477 CHECK_EQ((offset & 1 /* 0b1 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001478 offset >>= 1;
1479 } else {
1480 // 7 bit offset, shifted by 2.
Dave Allison0bb9ade2014-06-26 17:57:36 -07001481 CHECK_LT(offset, (1 << 7));
Andreas Gampec8ccf682014-09-29 20:07:43 -07001482 CHECK_EQ((offset & 3 /* 0b11 */), 0);
Dave Allison45fdb932014-06-25 12:37:10 -07001483 offset >>= 2;
1484 }
1485 encoding |= rn << 3 | offset << 6;
1486 }
1487
1488 Emit16(encoding);
1489 }
1490 } else {
1491 // Register shift.
1492 if (ad.GetRegister() == PC) {
1493 // PC relative literal encoding.
1494 int32_t offset = ad.GetOffset();
Dave Allison0bb9ade2014-06-26 17:57:36 -07001495 if (must_be_32bit || offset < 0 || offset >= (1 << 10) || !load) {
Dave Allison45fdb932014-06-25 12:37:10 -07001496 int32_t up = B23;
1497 if (offset < 0) {
1498 offset = -offset;
1499 up = 0;
1500 }
1501 CHECK_LT(offset, (1 << 12));
1502 int32_t encoding = 0x1f << 27 | 0xf << 16 | B22 | (load ? B20 : 0) |
1503 offset | up |
1504 static_cast<uint32_t>(rd) << 12;
1505 Emit32(encoding);
1506 } else {
1507 // 16 bit literal load.
1508 CHECK_GE(offset, 0);
1509 CHECK_LT(offset, (1 << 10));
1510 int32_t encoding = B14 | (load ? B11 : 0) | static_cast<uint32_t>(rd) << 8 | offset >> 2;
1511 Emit16(encoding);
1512 }
1513 } else {
1514 if (ad.GetShiftCount() != 0) {
1515 // If there is a shift count this must be 32 bit.
1516 must_be_32bit = true;
1517 } else if (IsHighRegister(ad.GetRegisterOffset())) {
1518 must_be_32bit = true;
1519 }
1520
1521 if (must_be_32bit) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001522 int32_t encoding = 0x1f << 27 | (load ? B20 : 0) | static_cast<uint32_t>(rd) << 12 |
Dave Allison45fdb932014-06-25 12:37:10 -07001523 ad.encodingThumb(true);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001524 if (half) {
1525 encoding |= B21;
1526 } else if (!byte) {
1527 encoding |= B22;
1528 }
Dave Allison45fdb932014-06-25 12:37:10 -07001529 Emit32(encoding);
1530 } else {
1531 // 16 bit register offset.
1532 int32_t encoding = B14 | B12 | (load ? B11 : 0) | static_cast<uint32_t>(rd) |
1533 ad.encodingThumb(false);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001534 if (byte) {
1535 encoding |= B10;
1536 } else if (half) {
1537 encoding |= B9;
1538 }
Dave Allison45fdb932014-06-25 12:37:10 -07001539 Emit16(encoding);
1540 }
1541 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07001542 }
1543}
1544
1545
1546void Thumb2Assembler::EmitMultiMemOp(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001547 BlockAddressMode bam,
Dave Allison65fcc2c2014-04-28 13:45:27 -07001548 bool load,
1549 Register base,
1550 RegList regs) {
1551 CHECK_NE(base, kNoRegister);
1552 CheckCondition(cond);
1553 bool must_be_32bit = force_32bit_;
1554
Vladimir Markoe8469c12014-11-26 18:09:30 +00001555 if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) &&
1556 (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) {
1557 // Use 16-bit PUSH/POP.
1558 int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 |
1559 ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff);
1560 Emit16(encoding);
1561 return;
1562 }
1563
Dave Allison65fcc2c2014-04-28 13:45:27 -07001564 if ((regs & 0xff00) != 0) {
1565 must_be_32bit = true;
1566 }
1567
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001568 bool w_bit = bam == IA_W || bam == DB_W || bam == DA_W || bam == IB_W;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001569 // 16 bit always uses writeback.
1570 if (!w_bit) {
1571 must_be_32bit = true;
1572 }
1573
1574 if (must_be_32bit) {
1575 uint32_t op = 0;
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001576 switch (bam) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001577 case IA:
1578 case IA_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001579 op = 1U /* 0b01 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001580 break;
1581 case DB:
1582 case DB_W:
Andreas Gampec8ccf682014-09-29 20:07:43 -07001583 op = 2U /* 0b10 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001584 break;
1585 case DA:
1586 case IB:
1587 case DA_W:
1588 case IB_W:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001589 LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam;
Vladimir Markoe8469c12014-11-26 18:09:30 +00001590 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07001591 }
1592 if (load) {
1593 // Cannot have SP in the list.
1594 CHECK_EQ((regs & (1 << SP)), 0);
1595 } else {
1596 // Cannot have PC or SP in the list.
1597 CHECK_EQ((regs & (1 << PC | 1 << SP)), 0);
1598 }
1599 int32_t encoding = B31 | B30 | B29 | B27 |
1600 (op << 23) |
1601 (load ? B20 : 0) |
1602 base << 16 |
1603 regs |
1604 (w_bit << 21);
1605 Emit32(encoding);
1606 } else {
1607 int16_t encoding = B15 | B14 |
1608 (load ? B11 : 0) |
1609 base << 8 |
1610 regs;
1611 Emit16(encoding);
1612 }
1613}
1614
1615
1616void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
1617 uint32_t pc = buffer_.Size();
1618 Branch::Type branch_type;
1619 if (cond == AL) {
1620 if (link) {
1621 if (x) {
1622 branch_type = Branch::kUnconditionalLinkX; // BLX.
1623 } else {
1624 branch_type = Branch::kUnconditionalLink; // BX.
1625 }
1626 } else {
1627 branch_type = Branch::kUnconditional; // B.
1628 }
1629 } else {
1630 branch_type = Branch::kConditional; // B<cond>.
1631 }
1632
1633 if (label->IsBound()) {
1634 Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond); // Resolved branch.
1635
1636 // The branch is to a bound label which means that it's a backwards branch. We know the
1637 // current size of it so we can emit the appropriate space. Note that if it's a 16 bit
1638 // branch the size may change if it so happens that other branches change size that change
1639 // the distance to the target and that distance puts this branch over the limit for 16 bits.
1640 if (size == Branch::k16Bit) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001641 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001642 Emit16(0); // Space for a 16 bit branch.
1643 } else {
1644 Emit32(0); // Space for a 32 bit branch.
1645 }
1646 } else {
1647 // Branch is to an unbound label. Emit space for it.
1648 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001649 if (force_32bit_branches_ || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001650 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1651 Emit16(0); // another 16 bits.
1652 } else {
1653 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1654 }
1655 label->LinkTo(branch_id); // Link to the branch ID.
1656 }
1657}
1658
1659
1660void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1661 CHECK_NE(rd, kNoRegister);
1662 CHECK_NE(rm, kNoRegister);
1663 CheckCondition(cond);
1664 CHECK_NE(rd, PC);
1665 CHECK_NE(rm, PC);
1666 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1667 B25 | B23 | B21 | B20 |
1668 static_cast<uint32_t>(rm) << 16 |
1669 0xf << 12 |
1670 static_cast<uint32_t>(rd) << 8 |
1671 B7 |
1672 static_cast<uint32_t>(rm);
1673 Emit32(encoding);
1674}
1675
1676
1677void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1678 CheckCondition(cond);
1679 bool must_be_32bit = force_32bit_;
1680 if (IsHighRegister(rd)|| imm16 >= 256u) {
1681 must_be_32bit = true;
1682 }
1683
1684 if (must_be_32bit) {
1685 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001686 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1687 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1688 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001689 uint32_t imm8 = imm16 & 0xff;
1690 int32_t encoding = B31 | B30 | B29 | B28 |
1691 B25 | B22 |
1692 static_cast<uint32_t>(rd) << 8 |
1693 i << 26 |
1694 imm4 << 16 |
1695 imm3 << 12 |
1696 imm8;
1697 Emit32(encoding);
1698 } else {
1699 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1700 imm16;
1701 Emit16(encoding);
1702 }
1703}
1704
1705
1706void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1707 CheckCondition(cond);
1708 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001709 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1710 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1711 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001712 uint32_t imm8 = imm16 & 0xff;
1713 int32_t encoding = B31 | B30 | B29 | B28 |
1714 B25 | B23 | B22 |
1715 static_cast<uint32_t>(rd) << 8 |
1716 i << 26 |
1717 imm4 << 16 |
1718 imm3 << 12 |
1719 imm8;
1720 Emit32(encoding);
1721}
1722
1723
1724void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1725 CHECK_NE(rn, kNoRegister);
1726 CHECK_NE(rt, kNoRegister);
1727 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001728 CHECK_LT(imm, (1u << 10));
1729
1730 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1731 static_cast<uint32_t>(rn) << 16 |
1732 static_cast<uint32_t>(rt) << 12 |
1733 0xf << 8 |
1734 imm >> 2;
1735 Emit32(encoding);
1736}
1737
1738
1739void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1740 ldrex(rt, rn, 0, cond);
1741}
1742
1743
1744void Thumb2Assembler::strex(Register rd,
1745 Register rt,
1746 Register rn,
1747 uint16_t imm,
1748 Condition cond) {
1749 CHECK_NE(rn, kNoRegister);
1750 CHECK_NE(rd, kNoRegister);
1751 CHECK_NE(rt, kNoRegister);
1752 CheckCondition(cond);
1753 CHECK_LT(imm, (1u << 10));
1754
1755 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1756 static_cast<uint32_t>(rn) << 16 |
1757 static_cast<uint32_t>(rt) << 12 |
1758 static_cast<uint32_t>(rd) << 8 |
1759 imm >> 2;
1760 Emit32(encoding);
1761}
1762
1763
Calin Juravle52c48962014-12-16 17:02:57 +00001764void Thumb2Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
1765 CHECK_NE(rn, kNoRegister);
1766 CHECK_NE(rt, kNoRegister);
1767 CHECK_NE(rt2, kNoRegister);
1768 CHECK_NE(rt, rt2);
1769 CheckCondition(cond);
1770
1771 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 | B20 |
1772 static_cast<uint32_t>(rn) << 16 |
1773 static_cast<uint32_t>(rt) << 12 |
1774 static_cast<uint32_t>(rt2) << 8 |
1775 B6 | B5 | B4 | B3 | B2 | B1 | B0;
1776 Emit32(encoding);
1777}
1778
1779
Dave Allison65fcc2c2014-04-28 13:45:27 -07001780void Thumb2Assembler::strex(Register rd,
1781 Register rt,
1782 Register rn,
1783 Condition cond) {
1784 strex(rd, rt, rn, 0, cond);
1785}
1786
1787
Calin Juravle52c48962014-12-16 17:02:57 +00001788void Thumb2Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
1789 CHECK_NE(rd, kNoRegister);
1790 CHECK_NE(rn, kNoRegister);
1791 CHECK_NE(rt, kNoRegister);
1792 CHECK_NE(rt2, kNoRegister);
1793 CHECK_NE(rt, rt2);
1794 CHECK_NE(rd, rt);
1795 CHECK_NE(rd, rt2);
1796 CheckCondition(cond);
1797
1798 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 |
1799 static_cast<uint32_t>(rn) << 16 |
1800 static_cast<uint32_t>(rt) << 12 |
1801 static_cast<uint32_t>(rt2) << 8 |
1802 B6 | B5 | B4 |
1803 static_cast<uint32_t>(rd);
1804 Emit32(encoding);
1805}
1806
1807
Dave Allison65fcc2c2014-04-28 13:45:27 -07001808void Thumb2Assembler::clrex(Condition cond) {
1809 CheckCondition(cond);
1810 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1811 B21 | B20 |
1812 0xf << 16 |
1813 B15 |
1814 0xf << 8 |
1815 B5 |
1816 0xf;
1817 Emit32(encoding);
1818}
1819
1820
1821void Thumb2Assembler::nop(Condition cond) {
1822 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001823 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001824 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001825 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001826}
1827
1828
1829void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1830 CHECK_NE(sn, kNoSRegister);
1831 CHECK_NE(rt, kNoRegister);
1832 CHECK_NE(rt, SP);
1833 CHECK_NE(rt, PC);
1834 CheckCondition(cond);
1835 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1836 B27 | B26 | B25 |
1837 ((static_cast<int32_t>(sn) >> 1)*B16) |
1838 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1839 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1840 Emit32(encoding);
1841}
1842
1843
1844void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1845 CHECK_NE(sn, kNoSRegister);
1846 CHECK_NE(rt, kNoRegister);
1847 CHECK_NE(rt, SP);
1848 CHECK_NE(rt, PC);
1849 CheckCondition(cond);
1850 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1851 B27 | B26 | B25 | B20 |
1852 ((static_cast<int32_t>(sn) >> 1)*B16) |
1853 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1854 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1855 Emit32(encoding);
1856}
1857
1858
1859void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1860 Condition cond) {
1861 CHECK_NE(sm, kNoSRegister);
1862 CHECK_NE(sm, S31);
1863 CHECK_NE(rt, kNoRegister);
1864 CHECK_NE(rt, SP);
1865 CHECK_NE(rt, PC);
1866 CHECK_NE(rt2, kNoRegister);
1867 CHECK_NE(rt2, SP);
1868 CHECK_NE(rt2, PC);
1869 CheckCondition(cond);
1870 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1871 B27 | B26 | B22 |
1872 (static_cast<int32_t>(rt2)*B16) |
1873 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1874 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1875 (static_cast<int32_t>(sm) >> 1);
1876 Emit32(encoding);
1877}
1878
1879
1880void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1881 Condition cond) {
1882 CHECK_NE(sm, kNoSRegister);
1883 CHECK_NE(sm, S31);
1884 CHECK_NE(rt, kNoRegister);
1885 CHECK_NE(rt, SP);
1886 CHECK_NE(rt, PC);
1887 CHECK_NE(rt2, kNoRegister);
1888 CHECK_NE(rt2, SP);
1889 CHECK_NE(rt2, PC);
1890 CHECK_NE(rt, rt2);
1891 CheckCondition(cond);
1892 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1893 B27 | B26 | B22 | B20 |
1894 (static_cast<int32_t>(rt2)*B16) |
1895 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1896 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1897 (static_cast<int32_t>(sm) >> 1);
1898 Emit32(encoding);
1899}
1900
1901
1902void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1903 Condition cond) {
1904 CHECK_NE(dm, kNoDRegister);
1905 CHECK_NE(rt, kNoRegister);
1906 CHECK_NE(rt, SP);
1907 CHECK_NE(rt, PC);
1908 CHECK_NE(rt2, kNoRegister);
1909 CHECK_NE(rt2, SP);
1910 CHECK_NE(rt2, PC);
1911 CheckCondition(cond);
1912 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1913 B27 | B26 | B22 |
1914 (static_cast<int32_t>(rt2)*B16) |
1915 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1916 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1917 (static_cast<int32_t>(dm) & 0xf);
1918 Emit32(encoding);
1919}
1920
1921
1922void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1923 Condition cond) {
1924 CHECK_NE(dm, kNoDRegister);
1925 CHECK_NE(rt, kNoRegister);
1926 CHECK_NE(rt, SP);
1927 CHECK_NE(rt, PC);
1928 CHECK_NE(rt2, kNoRegister);
1929 CHECK_NE(rt2, SP);
1930 CHECK_NE(rt2, PC);
1931 CHECK_NE(rt, rt2);
1932 CheckCondition(cond);
1933 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1934 B27 | B26 | B22 | B20 |
1935 (static_cast<int32_t>(rt2)*B16) |
1936 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1937 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1938 (static_cast<int32_t>(dm) & 0xf);
1939 Emit32(encoding);
1940}
1941
1942
1943void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1944 const Address& addr = static_cast<const Address&>(ad);
1945 CHECK_NE(sd, kNoSRegister);
1946 CheckCondition(cond);
1947 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1948 B27 | B26 | B24 | B20 |
1949 ((static_cast<int32_t>(sd) & 1)*B22) |
1950 ((static_cast<int32_t>(sd) >> 1)*B12) |
1951 B11 | B9 | addr.vencoding();
1952 Emit32(encoding);
1953}
1954
1955
1956void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1957 const Address& addr = static_cast<const Address&>(ad);
1958 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1959 CHECK_NE(sd, kNoSRegister);
1960 CheckCondition(cond);
1961 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1962 B27 | B26 | B24 |
1963 ((static_cast<int32_t>(sd) & 1)*B22) |
1964 ((static_cast<int32_t>(sd) >> 1)*B12) |
1965 B11 | B9 | addr.vencoding();
1966 Emit32(encoding);
1967}
1968
1969
1970void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1971 const Address& addr = static_cast<const Address&>(ad);
1972 CHECK_NE(dd, kNoDRegister);
1973 CheckCondition(cond);
1974 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1975 B27 | B26 | B24 | B20 |
1976 ((static_cast<int32_t>(dd) >> 4)*B22) |
1977 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1978 B11 | B9 | B8 | addr.vencoding();
1979 Emit32(encoding);
1980}
1981
1982
1983void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1984 const Address& addr = static_cast<const Address&>(ad);
1985 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1986 CHECK_NE(dd, kNoDRegister);
1987 CheckCondition(cond);
1988 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1989 B27 | B26 | B24 |
1990 ((static_cast<int32_t>(dd) >> 4)*B22) |
1991 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1992 B11 | B9 | B8 | addr.vencoding();
1993 Emit32(encoding);
1994}
1995
1996
1997void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1998 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1999}
2000
2001
2002void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
2003 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
2004}
2005
2006
2007void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
2008 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
2009}
2010
2011
2012void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
2013 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
2014}
2015
2016
2017void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
2018 CheckCondition(cond);
2019
2020 uint32_t D;
2021 uint32_t Vd;
2022 if (dbl) {
2023 // Encoded as D:Vd.
2024 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07002025 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002026 } else {
2027 // Encoded as Vd:D.
2028 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07002029 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002030 }
2031 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
2032 B11 | B9 |
2033 (dbl ? B8 : 0) |
2034 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07002035 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07002036 nregs << (dbl ? 1 : 0) |
2037 D << 22 |
2038 Vd << 12;
2039 Emit32(encoding);
2040}
2041
2042
2043void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
2044 SRegister sd, SRegister sn, SRegister sm) {
2045 CHECK_NE(sd, kNoSRegister);
2046 CHECK_NE(sn, kNoSRegister);
2047 CHECK_NE(sm, kNoSRegister);
2048 CheckCondition(cond);
2049 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2050 B27 | B26 | B25 | B11 | B9 | opcode |
2051 ((static_cast<int32_t>(sd) & 1)*B22) |
2052 ((static_cast<int32_t>(sn) >> 1)*B16) |
2053 ((static_cast<int32_t>(sd) >> 1)*B12) |
2054 ((static_cast<int32_t>(sn) & 1)*B7) |
2055 ((static_cast<int32_t>(sm) & 1)*B5) |
2056 (static_cast<int32_t>(sm) >> 1);
2057 Emit32(encoding);
2058}
2059
2060
2061void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
2062 DRegister dd, DRegister dn, DRegister dm) {
2063 CHECK_NE(dd, kNoDRegister);
2064 CHECK_NE(dn, kNoDRegister);
2065 CHECK_NE(dm, kNoDRegister);
2066 CheckCondition(cond);
2067 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2068 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
2069 ((static_cast<int32_t>(dd) >> 4)*B22) |
2070 ((static_cast<int32_t>(dn) & 0xf)*B16) |
2071 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2072 ((static_cast<int32_t>(dn) >> 4)*B7) |
2073 ((static_cast<int32_t>(dm) >> 4)*B5) |
2074 (static_cast<int32_t>(dm) & 0xf);
2075 Emit32(encoding);
2076}
2077
2078
2079void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
2080 SRegister sd, DRegister dm) {
2081 CHECK_NE(sd, kNoSRegister);
2082 CHECK_NE(dm, kNoDRegister);
2083 CheckCondition(cond);
2084 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2085 B27 | B26 | B25 | B11 | B9 | opcode |
2086 ((static_cast<int32_t>(sd) & 1)*B22) |
2087 ((static_cast<int32_t>(sd) >> 1)*B12) |
2088 ((static_cast<int32_t>(dm) >> 4)*B5) |
2089 (static_cast<int32_t>(dm) & 0xf);
2090 Emit32(encoding);
2091}
2092
2093
2094void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
2095 DRegister dd, SRegister sm) {
2096 CHECK_NE(dd, kNoDRegister);
2097 CHECK_NE(sm, kNoSRegister);
2098 CheckCondition(cond);
2099 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2100 B27 | B26 | B25 | B11 | B9 | opcode |
2101 ((static_cast<int32_t>(dd) >> 4)*B22) |
2102 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2103 ((static_cast<int32_t>(sm) & 1)*B5) |
2104 (static_cast<int32_t>(sm) >> 1);
2105 Emit32(encoding);
2106}
2107
2108
2109void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00002110 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002111 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00002112 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2113 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
2114 (static_cast<int32_t>(PC)*B12) |
2115 B11 | B9 | B4;
2116 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002117}
2118
2119
2120void Thumb2Assembler::svc(uint32_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002121 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002122 int16_t encoding = B15 | B14 | B12 |
2123 B11 | B10 | B9 | B8 |
2124 imm8;
2125 Emit16(encoding);
2126}
2127
2128
2129void Thumb2Assembler::bkpt(uint16_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002130 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002131 int16_t encoding = B15 | B13 | B12 |
2132 B11 | B10 | B9 |
2133 imm8;
2134 Emit16(encoding);
2135}
2136
2137// Convert the given IT state to a mask bit given bit 0 of the first
2138// condition and a shift position.
2139static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2140 switch (s) {
2141 case kItOmitted: return 1 << shift;
2142 case kItThen: return firstcond0 << shift;
2143 case kItElse: return !firstcond0 << shift;
2144 }
2145 return 0;
2146}
2147
2148
2149// Set the IT condition in the given position for the given state. This is used
2150// to check that conditional instructions match the preceding IT statement.
2151void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2152 switch (s) {
2153 case kItOmitted: it_conditions_[index] = AL; break;
2154 case kItThen: it_conditions_[index] = cond; break;
2155 case kItElse:
2156 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2157 break;
2158 }
2159}
2160
2161
2162void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2163 CheckCondition(AL); // Not allowed in IT block.
2164 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2165
2166 // All conditions to AL.
2167 for (uint8_t i = 0; i < 4; ++i) {
2168 it_conditions_[i] = AL;
2169 }
2170
2171 SetItCondition(kItThen, firstcond, 0);
2172 uint8_t mask = ToItMask(i1, firstcond0, 3);
2173 SetItCondition(i1, firstcond, 1);
2174
2175 if (i1 != kItOmitted) {
2176 mask |= ToItMask(i2, firstcond0, 2);
2177 SetItCondition(i2, firstcond, 2);
2178 if (i2 != kItOmitted) {
2179 mask |= ToItMask(i3, firstcond0, 1);
2180 SetItCondition(i3, firstcond, 3);
2181 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002182 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002183 }
2184 }
2185 }
2186
2187 // Start at first condition.
2188 it_cond_index_ = 0;
2189 next_condition_ = it_conditions_[0];
2190 uint16_t encoding = B15 | B13 | B12 |
2191 B11 | B10 | B9 | B8 |
2192 firstcond << 4 |
2193 mask;
2194 Emit16(encoding);
2195}
2196
2197
2198void Thumb2Assembler::cbz(Register rn, Label* label) {
2199 CheckCondition(AL);
2200 if (label->IsBound()) {
2201 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002202 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002203 } else {
2204 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2205 label->LinkTo(branchid);
2206 }
2207}
2208
2209
2210void Thumb2Assembler::cbnz(Register rn, Label* label) {
2211 CheckCondition(AL);
2212 if (label->IsBound()) {
2213 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002214 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002215 } else {
2216 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2217 label->LinkTo(branchid);
2218 }
2219}
2220
2221
2222void Thumb2Assembler::blx(Register rm, Condition cond) {
2223 CHECK_NE(rm, kNoRegister);
2224 CheckCondition(cond);
2225 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2226 Emit16(encoding);
2227}
2228
2229
2230void Thumb2Assembler::bx(Register rm, Condition cond) {
2231 CHECK_NE(rm, kNoRegister);
2232 CheckCondition(cond);
2233 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2234 Emit16(encoding);
2235}
2236
2237
2238void Thumb2Assembler::Push(Register rd, Condition cond) {
2239 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2240}
2241
2242
2243void Thumb2Assembler::Pop(Register rd, Condition cond) {
2244 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2245}
2246
2247
2248void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2249 stm(DB_W, SP, regs, cond);
2250}
2251
2252
2253void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2254 ldm(IA_W, SP, regs, cond);
2255}
2256
2257
2258void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2259 if (cond != AL || rd != rm) {
2260 mov(rd, ShifterOperand(rm), cond);
2261 }
2262}
2263
2264
2265// A branch has changed size. Make a hole for it.
2266void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2267 // Move the contents of the buffer using: Move(newposition, oldposition)
2268 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2269 buffer_.Move(location + delta, location);
2270}
2271
2272
2273void Thumb2Assembler::Bind(Label* label) {
2274 CHECK(!label->IsBound());
2275 uint32_t bound_pc = buffer_.Size();
2276 std::vector<Branch*> changed_branches;
2277
2278 while (label->IsLinked()) {
2279 uint16_t position = label->Position(); // Branch id for linked branch.
2280 Branch* branch = GetBranch(position); // Get the branch at this id.
2281 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2282 uint32_t branch_location = branch->GetLocation();
2283 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2284 if (changed) {
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002285 DCHECK(!force_32bit_branches_);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002286 MakeHoleForBranch(branch->GetLocation(), 2);
2287 if (branch->IsCompareAndBranch()) {
2288 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2289 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2290 // cmp rn, #0
2291 // b<eq|ne> target
2292 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2293 Condition cond = n ? NE : EQ;
2294 branch->Move(2); // Move the branch forward by 2 bytes.
2295 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2296 branch->ResetSize(Branch::k16Bit);
2297
2298 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002299 buffer_.Store<int16_t>(branch_location,
2300 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002301
2302 // Since have moved made a hole in the code we need to reload the
2303 // current pc.
2304 bound_pc = buffer_.Size();
2305
2306 // Now resolve the newly added branch.
2307 changed = branch->Resolve(bound_pc);
2308 if (changed) {
2309 MakeHoleForBranch(branch->GetLocation(), 2);
2310 changed_branches.push_back(branch);
2311 }
2312 } else {
2313 changed_branches.push_back(branch);
2314 }
2315 }
2316 label->position_ = next; // Move to next.
2317 }
2318 label->BindTo(bound_pc);
2319
2320 // Now relocate any changed branches. Do this until there are no more changes.
2321 std::vector<Branch*> branches_to_process = changed_branches;
2322 while (branches_to_process.size() != 0) {
2323 changed_branches.clear();
2324 for (auto& changed_branch : branches_to_process) {
2325 for (auto& branch : branches_) {
2326 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2327 if (changed) {
2328 changed_branches.push_back(branch);
2329 }
2330 }
2331 branches_to_process = changed_branches;
2332 }
2333 }
2334}
2335
2336
2337void Thumb2Assembler::EmitBranches() {
2338 for (auto& branch : branches_) {
2339 branch->Emit(&buffer_);
2340 }
2341}
2342
2343
2344void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002345 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002346 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002347 CheckCondition(cond);
2348 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002349}
2350
2351
2352void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002353 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002354 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002355 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002356 CheckCondition(cond);
2357 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002358}
2359
2360
2361void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002362 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002363 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002364 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002365 CheckCondition(cond);
2366 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002367}
2368
2369
2370void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002371 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002372 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002373 CheckCondition(cond);
2374 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002375}
2376
2377
Dave Allison45fdb932014-06-25 12:37:10 -07002378void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2379 CheckCondition(cond);
2380 EmitShift(rd, rm, RRX, rm, setcc);
2381}
2382
2383
2384void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2385 bool setcc, Condition cond) {
2386 CheckCondition(cond);
2387 EmitShift(rd, rm, LSL, rn, setcc);
2388}
2389
2390
2391void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2392 bool setcc, Condition cond) {
2393 CheckCondition(cond);
2394 EmitShift(rd, rm, LSR, rn, setcc);
2395}
2396
2397
2398void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2399 bool setcc, Condition cond) {
2400 CheckCondition(cond);
2401 EmitShift(rd, rm, ASR, rn, setcc);
2402}
2403
2404
2405void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2406 bool setcc, Condition cond) {
2407 CheckCondition(cond);
2408 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002409}
2410
2411
2412int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2413 // The offset is off by 4 due to the way the ARM CPUs read PC.
2414 offset -= 4;
2415 offset >>= 1;
2416
2417 uint32_t value = 0;
2418 // There are two different encodings depending on the value of bit 12. In one case
2419 // intermediate values are calculated using the sign bit.
2420 if ((inst & B12) == B12) {
2421 // 25 bits of offset.
2422 uint32_t signbit = (offset >> 31) & 0x1;
2423 uint32_t i1 = (offset >> 22) & 0x1;
2424 uint32_t i2 = (offset >> 21) & 0x1;
2425 uint32_t imm10 = (offset >> 11) & 0x03ff;
2426 uint32_t imm11 = offset & 0x07ff;
2427 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2428 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2429 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2430 imm11;
2431 // Remove the offset from the current encoding.
2432 inst &= ~(0x3ff << 16 | 0x7ff);
2433 } else {
2434 uint32_t signbit = (offset >> 31) & 0x1;
2435 uint32_t imm6 = (offset >> 11) & 0x03f;
2436 uint32_t imm11 = offset & 0x07ff;
2437 uint32_t j1 = (offset >> 19) & 1;
2438 uint32_t j2 = (offset >> 17) & 1;
2439 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2440 imm11;
2441 // Remove the offset from the current encoding.
2442 inst &= ~(0x3f << 16 | 0x7ff);
2443 }
2444 // Mask out offset bits in current instruction.
2445 inst &= ~(B26 | B13 | B11);
2446 inst |= value;
2447 return inst;
2448}
2449
2450
2451int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2452 int32_t imm32;
2453 if ((instr & B12) == B12) {
2454 uint32_t S = (instr >> 26) & 1;
2455 uint32_t J2 = (instr >> 11) & 1;
2456 uint32_t J1 = (instr >> 13) & 1;
2457 uint32_t imm10 = (instr >> 16) & 0x3FF;
2458 uint32_t imm11 = instr & 0x7FF;
2459
2460 uint32_t I1 = ~(J1 ^ S) & 1;
2461 uint32_t I2 = ~(J2 ^ S) & 1;
2462 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2463 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2464 } else {
2465 uint32_t S = (instr >> 26) & 1;
2466 uint32_t J2 = (instr >> 11) & 1;
2467 uint32_t J1 = (instr >> 13) & 1;
2468 uint32_t imm6 = (instr >> 16) & 0x3F;
2469 uint32_t imm11 = instr & 0x7FF;
2470
2471 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2472 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2473 }
2474 imm32 += 4;
2475 return imm32;
2476}
2477
2478
2479void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2480 AddConstant(rd, rd, value, cond);
2481}
2482
2483
2484void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2485 Condition cond) {
2486 if (value == 0) {
2487 if (rd != rn) {
2488 mov(rd, ShifterOperand(rn), cond);
2489 }
2490 return;
2491 }
2492 // We prefer to select the shorter code sequence rather than selecting add for
2493 // positive values and sub for negatives ones, which would slightly improve
2494 // the readability of generated code for some constants.
2495 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002496 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002497 add(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002498 } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002499 sub(rd, rn, shifter_op, cond);
2500 } else {
2501 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002502 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002503 mvn(IP, shifter_op, cond);
2504 add(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002505 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002506 mvn(IP, shifter_op, cond);
2507 sub(rd, rn, ShifterOperand(IP), cond);
2508 } else {
2509 movw(IP, Low16Bits(value), cond);
2510 uint16_t value_high = High16Bits(value);
2511 if (value_high != 0) {
2512 movt(IP, value_high, cond);
2513 }
2514 add(rd, rn, ShifterOperand(IP), cond);
2515 }
2516 }
2517}
2518
2519
2520void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2521 Condition cond) {
2522 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002523 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002524 adds(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002525 } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002526 subs(rd, rn, shifter_op, cond);
2527 } else {
2528 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002529 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002530 mvn(IP, shifter_op, cond);
2531 adds(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002532 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002533 mvn(IP, shifter_op, cond);
2534 subs(rd, rn, ShifterOperand(IP), cond);
2535 } else {
2536 movw(IP, Low16Bits(value), cond);
2537 uint16_t value_high = High16Bits(value);
2538 if (value_high != 0) {
2539 movt(IP, value_high, cond);
2540 }
2541 adds(rd, rn, ShifterOperand(IP), cond);
2542 }
2543 }
2544}
2545
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002546
Dave Allison65fcc2c2014-04-28 13:45:27 -07002547void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2548 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002549 if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002550 mov(rd, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002551 } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002552 mvn(rd, shifter_op, cond);
2553 } else {
2554 movw(rd, Low16Bits(value), cond);
2555 uint16_t value_high = High16Bits(value);
2556 if (value_high != 0) {
2557 movt(rd, value_high, cond);
2558 }
2559 }
2560}
2561
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002562
Dave Allison65fcc2c2014-04-28 13:45:27 -07002563// Implementation note: this method must emit at most one instruction when
2564// Address::CanHoldLoadOffsetThumb.
2565void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2566 Register reg,
2567 Register base,
2568 int32_t offset,
2569 Condition cond) {
2570 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002571 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002572 LoadImmediate(IP, offset, cond);
2573 add(IP, IP, ShifterOperand(base), cond);
2574 base = IP;
2575 offset = 0;
2576 }
2577 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2578 switch (type) {
2579 case kLoadSignedByte:
2580 ldrsb(reg, Address(base, offset), cond);
2581 break;
2582 case kLoadUnsignedByte:
2583 ldrb(reg, Address(base, offset), cond);
2584 break;
2585 case kLoadSignedHalfword:
2586 ldrsh(reg, Address(base, offset), cond);
2587 break;
2588 case kLoadUnsignedHalfword:
2589 ldrh(reg, Address(base, offset), cond);
2590 break;
2591 case kLoadWord:
2592 ldr(reg, Address(base, offset), cond);
2593 break;
2594 case kLoadWordPair:
2595 ldrd(reg, Address(base, offset), cond);
2596 break;
2597 default:
2598 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002599 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002600 }
2601}
2602
2603
2604// Implementation note: this method must emit at most one instruction when
2605// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2606void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2607 Register base,
2608 int32_t offset,
2609 Condition cond) {
2610 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2611 CHECK_NE(base, IP);
2612 LoadImmediate(IP, offset, cond);
2613 add(IP, IP, ShifterOperand(base), cond);
2614 base = IP;
2615 offset = 0;
2616 }
2617 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2618 vldrs(reg, Address(base, offset), cond);
2619}
2620
2621
2622// Implementation note: this method must emit at most one instruction when
2623// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2624void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2625 Register base,
2626 int32_t offset,
2627 Condition cond) {
2628 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2629 CHECK_NE(base, IP);
2630 LoadImmediate(IP, offset, cond);
2631 add(IP, IP, ShifterOperand(base), cond);
2632 base = IP;
2633 offset = 0;
2634 }
2635 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2636 vldrd(reg, Address(base, offset), cond);
2637}
2638
2639
2640// Implementation note: this method must emit at most one instruction when
2641// Address::CanHoldStoreOffsetThumb.
2642void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2643 Register reg,
2644 Register base,
2645 int32_t offset,
2646 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002647 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002648 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002649 CHECK_NE(base, IP);
Roland Levillain4af147e2015-04-07 13:54:49 +01002650 if (reg != IP &&
2651 (type != kStoreWordPair || reg + 1 != IP)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002652 tmp_reg = IP;
2653 } else {
Roland Levillain4af147e2015-04-07 13:54:49 +01002654 // Be careful not to use IP twice (for `reg` (or `reg` + 1 in
2655 // the case of a word-pair store)) and to build the Address
2656 // object used by the store instruction(s) below). Instead,
2657 // save R5 on the stack (or R6 if R5 is not available), use it
2658 // as secondary temporary register, and restore it after the
2659 // store instruction has been emitted.
Roland Levillain775ef492014-11-04 17:43:11 +00002660 tmp_reg = base != R5 ? R5 : R6;
2661 Push(tmp_reg);
2662 if (base == SP) {
2663 offset += kRegisterSize;
2664 }
2665 }
2666 LoadImmediate(tmp_reg, offset, cond);
2667 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2668 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002669 offset = 0;
2670 }
2671 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2672 switch (type) {
2673 case kStoreByte:
2674 strb(reg, Address(base, offset), cond);
2675 break;
2676 case kStoreHalfword:
2677 strh(reg, Address(base, offset), cond);
2678 break;
2679 case kStoreWord:
2680 str(reg, Address(base, offset), cond);
2681 break;
2682 case kStoreWordPair:
2683 strd(reg, Address(base, offset), cond);
2684 break;
2685 default:
2686 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002687 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002688 }
Roland Levillain775ef492014-11-04 17:43:11 +00002689 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2690 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2691 Pop(tmp_reg);
2692 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002693}
2694
2695
2696// Implementation note: this method must emit at most one instruction when
2697// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2698void Thumb2Assembler::StoreSToOffset(SRegister reg,
2699 Register base,
2700 int32_t offset,
2701 Condition cond) {
2702 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2703 CHECK_NE(base, IP);
2704 LoadImmediate(IP, offset, cond);
2705 add(IP, IP, ShifterOperand(base), cond);
2706 base = IP;
2707 offset = 0;
2708 }
2709 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2710 vstrs(reg, Address(base, offset), cond);
2711}
2712
2713
2714// Implementation note: this method must emit at most one instruction when
2715// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2716void Thumb2Assembler::StoreDToOffset(DRegister reg,
2717 Register base,
2718 int32_t offset,
2719 Condition cond) {
2720 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2721 CHECK_NE(base, IP);
2722 LoadImmediate(IP, offset, cond);
2723 add(IP, IP, ShifterOperand(base), cond);
2724 base = IP;
2725 offset = 0;
2726 }
2727 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2728 vstrd(reg, Address(base, offset), cond);
2729}
2730
2731
2732void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2733 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002734 dmb(SY);
2735}
2736
2737
2738void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002739 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2740 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002741}
2742
2743
2744void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002745 if (force_32bit_branches_) {
2746 cmp(r, ShifterOperand(0));
2747 b(label, EQ);
2748 } else {
2749 cbz(r, label);
2750 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002751}
2752
2753
2754void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002755 if (force_32bit_branches_) {
2756 cmp(r, ShifterOperand(0));
2757 b(label, NE);
2758 } else {
2759 cbnz(r, label);
2760 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002761}
2762} // namespace arm
2763} // namespace art