blob: ab83f95084435164c7779707cd34300dcf69f399 [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
Vladimir Marko80afd022015-05-19 18:08:00 +010019#include "base/bit_utils.h"
Dave Allison65fcc2c2014-04-28 13:45:27 -070020#include "base/logging.h"
21#include "entrypoints/quick/quick_entrypoints.h"
22#include "offsets.h"
23#include "thread.h"
Dave Allison65fcc2c2014-04-28 13:45:27 -070024
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
Nicolas Geoffray1f277e32015-05-21 12:26:31 +00001616void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001617 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) {
1641 Emit16(0); // Space for a 16 bit branch.
1642 } else {
1643 Emit32(0); // Space for a 32 bit branch.
1644 }
1645 } else {
1646 // Branch is to an unbound label. Emit space for it.
Nicolas Geoffray1f277e32015-05-21 12:26:31 +00001647 uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
1648 if (!CanRelocateBranches() || force_32bit_) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07001649 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1650 Emit16(0); // another 16 bits.
1651 } else {
1652 Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
1653 }
1654 label->LinkTo(branch_id); // Link to the branch ID.
1655 }
1656}
1657
1658
1659void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) {
1660 CHECK_NE(rd, kNoRegister);
1661 CHECK_NE(rm, kNoRegister);
1662 CheckCondition(cond);
1663 CHECK_NE(rd, PC);
1664 CHECK_NE(rm, PC);
1665 int32_t encoding = B31 | B30 | B29 | B28 | B27 |
1666 B25 | B23 | B21 | B20 |
1667 static_cast<uint32_t>(rm) << 16 |
1668 0xf << 12 |
1669 static_cast<uint32_t>(rd) << 8 |
1670 B7 |
1671 static_cast<uint32_t>(rm);
1672 Emit32(encoding);
1673}
1674
1675
1676void Thumb2Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
1677 CheckCondition(cond);
1678 bool must_be_32bit = force_32bit_;
1679 if (IsHighRegister(rd)|| imm16 >= 256u) {
1680 must_be_32bit = true;
1681 }
1682
1683 if (must_be_32bit) {
1684 // Use encoding T3.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001685 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1686 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1687 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001688 uint32_t imm8 = imm16 & 0xff;
1689 int32_t encoding = B31 | B30 | B29 | B28 |
1690 B25 | B22 |
1691 static_cast<uint32_t>(rd) << 8 |
1692 i << 26 |
1693 imm4 << 16 |
1694 imm3 << 12 |
1695 imm8;
1696 Emit32(encoding);
1697 } else {
1698 int16_t encoding = B13 | static_cast<uint16_t>(rd) << 8 |
1699 imm16;
1700 Emit16(encoding);
1701 }
1702}
1703
1704
1705void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
1706 CheckCondition(cond);
1707 // Always 32 bits.
Andreas Gampec8ccf682014-09-29 20:07:43 -07001708 uint32_t imm4 = (imm16 >> 12) & 15U /* 0b1111 */;
1709 uint32_t i = (imm16 >> 11) & 1U /* 0b1 */;
1710 uint32_t imm3 = (imm16 >> 8) & 7U /* 0b111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07001711 uint32_t imm8 = imm16 & 0xff;
1712 int32_t encoding = B31 | B30 | B29 | B28 |
1713 B25 | B23 | B22 |
1714 static_cast<uint32_t>(rd) << 8 |
1715 i << 26 |
1716 imm4 << 16 |
1717 imm3 << 12 |
1718 imm8;
1719 Emit32(encoding);
1720}
1721
1722
1723void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) {
1724 CHECK_NE(rn, kNoRegister);
1725 CHECK_NE(rt, kNoRegister);
1726 CheckCondition(cond);
Dave Allison65fcc2c2014-04-28 13:45:27 -07001727 CHECK_LT(imm, (1u << 10));
1728
1729 int32_t encoding = B31 | B30 | B29 | B27 | B22 | B20 |
1730 static_cast<uint32_t>(rn) << 16 |
1731 static_cast<uint32_t>(rt) << 12 |
1732 0xf << 8 |
1733 imm >> 2;
1734 Emit32(encoding);
1735}
1736
1737
1738void Thumb2Assembler::ldrex(Register rt, Register rn, Condition cond) {
1739 ldrex(rt, rn, 0, cond);
1740}
1741
1742
1743void Thumb2Assembler::strex(Register rd,
1744 Register rt,
1745 Register rn,
1746 uint16_t imm,
1747 Condition cond) {
1748 CHECK_NE(rn, kNoRegister);
1749 CHECK_NE(rd, kNoRegister);
1750 CHECK_NE(rt, kNoRegister);
1751 CheckCondition(cond);
1752 CHECK_LT(imm, (1u << 10));
1753
1754 int32_t encoding = B31 | B30 | B29 | B27 | B22 |
1755 static_cast<uint32_t>(rn) << 16 |
1756 static_cast<uint32_t>(rt) << 12 |
1757 static_cast<uint32_t>(rd) << 8 |
1758 imm >> 2;
1759 Emit32(encoding);
1760}
1761
1762
Calin Juravle52c48962014-12-16 17:02:57 +00001763void Thumb2Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
1764 CHECK_NE(rn, kNoRegister);
1765 CHECK_NE(rt, kNoRegister);
1766 CHECK_NE(rt2, kNoRegister);
1767 CHECK_NE(rt, rt2);
1768 CheckCondition(cond);
1769
1770 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 | B20 |
1771 static_cast<uint32_t>(rn) << 16 |
1772 static_cast<uint32_t>(rt) << 12 |
1773 static_cast<uint32_t>(rt2) << 8 |
1774 B6 | B5 | B4 | B3 | B2 | B1 | B0;
1775 Emit32(encoding);
1776}
1777
1778
Dave Allison65fcc2c2014-04-28 13:45:27 -07001779void Thumb2Assembler::strex(Register rd,
1780 Register rt,
1781 Register rn,
1782 Condition cond) {
1783 strex(rd, rt, rn, 0, cond);
1784}
1785
1786
Calin Juravle52c48962014-12-16 17:02:57 +00001787void Thumb2Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
1788 CHECK_NE(rd, kNoRegister);
1789 CHECK_NE(rn, kNoRegister);
1790 CHECK_NE(rt, kNoRegister);
1791 CHECK_NE(rt2, kNoRegister);
1792 CHECK_NE(rt, rt2);
1793 CHECK_NE(rd, rt);
1794 CHECK_NE(rd, rt2);
1795 CheckCondition(cond);
1796
1797 int32_t encoding = B31 | B30 | B29 | B27 | B23 | B22 |
1798 static_cast<uint32_t>(rn) << 16 |
1799 static_cast<uint32_t>(rt) << 12 |
1800 static_cast<uint32_t>(rt2) << 8 |
1801 B6 | B5 | B4 |
1802 static_cast<uint32_t>(rd);
1803 Emit32(encoding);
1804}
1805
1806
Dave Allison65fcc2c2014-04-28 13:45:27 -07001807void Thumb2Assembler::clrex(Condition cond) {
1808 CheckCondition(cond);
1809 int32_t encoding = B31 | B30 | B29 | B27 | B28 | B25 | B24 | B23 |
1810 B21 | B20 |
1811 0xf << 16 |
1812 B15 |
1813 0xf << 8 |
1814 B5 |
1815 0xf;
1816 Emit32(encoding);
1817}
1818
1819
1820void Thumb2Assembler::nop(Condition cond) {
1821 CheckCondition(cond);
Andreas Gampec8ccf682014-09-29 20:07:43 -07001822 uint16_t encoding = B15 | B13 | B12 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07001823 B11 | B10 | B9 | B8;
Andreas Gampec8ccf682014-09-29 20:07:43 -07001824 Emit16(static_cast<int16_t>(encoding));
Dave Allison65fcc2c2014-04-28 13:45:27 -07001825}
1826
1827
1828void Thumb2Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
1829 CHECK_NE(sn, kNoSRegister);
1830 CHECK_NE(rt, kNoRegister);
1831 CHECK_NE(rt, SP);
1832 CHECK_NE(rt, PC);
1833 CheckCondition(cond);
1834 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1835 B27 | B26 | B25 |
1836 ((static_cast<int32_t>(sn) >> 1)*B16) |
1837 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1838 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1839 Emit32(encoding);
1840}
1841
1842
1843void Thumb2Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
1844 CHECK_NE(sn, kNoSRegister);
1845 CHECK_NE(rt, kNoRegister);
1846 CHECK_NE(rt, SP);
1847 CHECK_NE(rt, PC);
1848 CheckCondition(cond);
1849 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1850 B27 | B26 | B25 | B20 |
1851 ((static_cast<int32_t>(sn) >> 1)*B16) |
1852 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1853 ((static_cast<int32_t>(sn) & 1)*B7) | B4;
1854 Emit32(encoding);
1855}
1856
1857
1858void Thumb2Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
1859 Condition cond) {
1860 CHECK_NE(sm, kNoSRegister);
1861 CHECK_NE(sm, S31);
1862 CHECK_NE(rt, kNoRegister);
1863 CHECK_NE(rt, SP);
1864 CHECK_NE(rt, PC);
1865 CHECK_NE(rt2, kNoRegister);
1866 CHECK_NE(rt2, SP);
1867 CHECK_NE(rt2, PC);
1868 CheckCondition(cond);
1869 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1870 B27 | B26 | B22 |
1871 (static_cast<int32_t>(rt2)*B16) |
1872 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1873 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1874 (static_cast<int32_t>(sm) >> 1);
1875 Emit32(encoding);
1876}
1877
1878
1879void Thumb2Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
1880 Condition cond) {
1881 CHECK_NE(sm, kNoSRegister);
1882 CHECK_NE(sm, S31);
1883 CHECK_NE(rt, kNoRegister);
1884 CHECK_NE(rt, SP);
1885 CHECK_NE(rt, PC);
1886 CHECK_NE(rt2, kNoRegister);
1887 CHECK_NE(rt2, SP);
1888 CHECK_NE(rt2, PC);
1889 CHECK_NE(rt, rt2);
1890 CheckCondition(cond);
1891 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1892 B27 | B26 | B22 | B20 |
1893 (static_cast<int32_t>(rt2)*B16) |
1894 (static_cast<int32_t>(rt)*B12) | B11 | B9 |
1895 ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
1896 (static_cast<int32_t>(sm) >> 1);
1897 Emit32(encoding);
1898}
1899
1900
1901void Thumb2Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
1902 Condition cond) {
1903 CHECK_NE(dm, kNoDRegister);
1904 CHECK_NE(rt, kNoRegister);
1905 CHECK_NE(rt, SP);
1906 CHECK_NE(rt, PC);
1907 CHECK_NE(rt2, kNoRegister);
1908 CHECK_NE(rt2, SP);
1909 CHECK_NE(rt2, PC);
1910 CheckCondition(cond);
1911 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1912 B27 | B26 | B22 |
1913 (static_cast<int32_t>(rt2)*B16) |
1914 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1915 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1916 (static_cast<int32_t>(dm) & 0xf);
1917 Emit32(encoding);
1918}
1919
1920
1921void Thumb2Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
1922 Condition cond) {
1923 CHECK_NE(dm, kNoDRegister);
1924 CHECK_NE(rt, kNoRegister);
1925 CHECK_NE(rt, SP);
1926 CHECK_NE(rt, PC);
1927 CHECK_NE(rt2, kNoRegister);
1928 CHECK_NE(rt2, SP);
1929 CHECK_NE(rt2, PC);
1930 CHECK_NE(rt, rt2);
1931 CheckCondition(cond);
1932 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1933 B27 | B26 | B22 | B20 |
1934 (static_cast<int32_t>(rt2)*B16) |
1935 (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
1936 ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
1937 (static_cast<int32_t>(dm) & 0xf);
1938 Emit32(encoding);
1939}
1940
1941
1942void Thumb2Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
1943 const Address& addr = static_cast<const Address&>(ad);
1944 CHECK_NE(sd, kNoSRegister);
1945 CheckCondition(cond);
1946 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1947 B27 | B26 | B24 | B20 |
1948 ((static_cast<int32_t>(sd) & 1)*B22) |
1949 ((static_cast<int32_t>(sd) >> 1)*B12) |
1950 B11 | B9 | addr.vencoding();
1951 Emit32(encoding);
1952}
1953
1954
1955void Thumb2Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
1956 const Address& addr = static_cast<const Address&>(ad);
1957 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1958 CHECK_NE(sd, kNoSRegister);
1959 CheckCondition(cond);
1960 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1961 B27 | B26 | B24 |
1962 ((static_cast<int32_t>(sd) & 1)*B22) |
1963 ((static_cast<int32_t>(sd) >> 1)*B12) |
1964 B11 | B9 | addr.vencoding();
1965 Emit32(encoding);
1966}
1967
1968
1969void Thumb2Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
1970 const Address& addr = static_cast<const Address&>(ad);
1971 CHECK_NE(dd, kNoDRegister);
1972 CheckCondition(cond);
1973 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1974 B27 | B26 | B24 | B20 |
1975 ((static_cast<int32_t>(dd) >> 4)*B22) |
1976 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1977 B11 | B9 | B8 | addr.vencoding();
1978 Emit32(encoding);
1979}
1980
1981
1982void Thumb2Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
1983 const Address& addr = static_cast<const Address&>(ad);
1984 CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
1985 CHECK_NE(dd, kNoDRegister);
1986 CheckCondition(cond);
1987 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1988 B27 | B26 | B24 |
1989 ((static_cast<int32_t>(dd) >> 4)*B22) |
1990 ((static_cast<int32_t>(dd) & 0xf)*B12) |
1991 B11 | B9 | B8 | addr.vencoding();
1992 Emit32(encoding);
1993}
1994
1995
1996void Thumb2Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
1997 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
1998}
1999
2000
2001void Thumb2Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
2002 EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
2003}
2004
2005
2006void Thumb2Assembler::vpops(SRegister reg, int nregs, Condition cond) {
2007 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
2008}
2009
2010
2011void Thumb2Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
2012 EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
2013}
2014
2015
2016void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
2017 CheckCondition(cond);
2018
2019 uint32_t D;
2020 uint32_t Vd;
2021 if (dbl) {
2022 // Encoded as D:Vd.
2023 D = (reg >> 4) & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07002024 Vd = reg & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002025 } else {
2026 // Encoded as Vd:D.
2027 D = reg & 1;
Andreas Gampec8ccf682014-09-29 20:07:43 -07002028 Vd = (reg >> 1) & 15U /* 0b1111 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002029 }
2030 int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
2031 B11 | B9 |
2032 (dbl ? B8 : 0) |
2033 (push ? B24 : (B23 | B20)) |
Andreas Gampec8ccf682014-09-29 20:07:43 -07002034 14U /* 0b1110 */ << 28 |
Dave Allison65fcc2c2014-04-28 13:45:27 -07002035 nregs << (dbl ? 1 : 0) |
2036 D << 22 |
2037 Vd << 12;
2038 Emit32(encoding);
2039}
2040
2041
2042void Thumb2Assembler::EmitVFPsss(Condition cond, int32_t opcode,
2043 SRegister sd, SRegister sn, SRegister sm) {
2044 CHECK_NE(sd, kNoSRegister);
2045 CHECK_NE(sn, kNoSRegister);
2046 CHECK_NE(sm, kNoSRegister);
2047 CheckCondition(cond);
2048 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2049 B27 | B26 | B25 | B11 | B9 | opcode |
2050 ((static_cast<int32_t>(sd) & 1)*B22) |
2051 ((static_cast<int32_t>(sn) >> 1)*B16) |
2052 ((static_cast<int32_t>(sd) >> 1)*B12) |
2053 ((static_cast<int32_t>(sn) & 1)*B7) |
2054 ((static_cast<int32_t>(sm) & 1)*B5) |
2055 (static_cast<int32_t>(sm) >> 1);
2056 Emit32(encoding);
2057}
2058
2059
2060void Thumb2Assembler::EmitVFPddd(Condition cond, int32_t opcode,
2061 DRegister dd, DRegister dn, DRegister dm) {
2062 CHECK_NE(dd, kNoDRegister);
2063 CHECK_NE(dn, kNoDRegister);
2064 CHECK_NE(dm, kNoDRegister);
2065 CheckCondition(cond);
2066 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2067 B27 | B26 | B25 | B11 | B9 | B8 | opcode |
2068 ((static_cast<int32_t>(dd) >> 4)*B22) |
2069 ((static_cast<int32_t>(dn) & 0xf)*B16) |
2070 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2071 ((static_cast<int32_t>(dn) >> 4)*B7) |
2072 ((static_cast<int32_t>(dm) >> 4)*B5) |
2073 (static_cast<int32_t>(dm) & 0xf);
2074 Emit32(encoding);
2075}
2076
2077
2078void Thumb2Assembler::EmitVFPsd(Condition cond, int32_t opcode,
2079 SRegister sd, DRegister dm) {
2080 CHECK_NE(sd, kNoSRegister);
2081 CHECK_NE(dm, kNoDRegister);
2082 CheckCondition(cond);
2083 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2084 B27 | B26 | B25 | B11 | B9 | opcode |
2085 ((static_cast<int32_t>(sd) & 1)*B22) |
2086 ((static_cast<int32_t>(sd) >> 1)*B12) |
2087 ((static_cast<int32_t>(dm) >> 4)*B5) |
2088 (static_cast<int32_t>(dm) & 0xf);
2089 Emit32(encoding);
2090}
2091
2092
2093void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode,
2094 DRegister dd, SRegister sm) {
2095 CHECK_NE(dd, kNoDRegister);
2096 CHECK_NE(sm, kNoSRegister);
2097 CheckCondition(cond);
2098 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2099 B27 | B26 | B25 | B11 | B9 | opcode |
2100 ((static_cast<int32_t>(dd) >> 4)*B22) |
2101 ((static_cast<int32_t>(dd) & 0xf)*B12) |
2102 ((static_cast<int32_t>(sm) & 1)*B5) |
2103 (static_cast<int32_t>(sm) >> 1);
2104 Emit32(encoding);
2105}
2106
2107
2108void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR.
Calin Juravleddb7df22014-11-25 20:56:51 +00002109 CHECK_NE(cond, kNoCondition);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002110 CheckCondition(cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00002111 int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
2112 B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
2113 (static_cast<int32_t>(PC)*B12) |
2114 B11 | B9 | B4;
2115 Emit32(encoding);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002116}
2117
2118
2119void Thumb2Assembler::svc(uint32_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002120 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002121 int16_t encoding = B15 | B14 | B12 |
2122 B11 | B10 | B9 | B8 |
2123 imm8;
2124 Emit16(encoding);
2125}
2126
2127
2128void Thumb2Assembler::bkpt(uint16_t imm8) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -08002129 CHECK(IsUint<8>(imm8)) << imm8;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002130 int16_t encoding = B15 | B13 | B12 |
2131 B11 | B10 | B9 |
2132 imm8;
2133 Emit16(encoding);
2134}
2135
2136// Convert the given IT state to a mask bit given bit 0 of the first
2137// condition and a shift position.
2138static uint8_t ToItMask(ItState s, uint8_t firstcond0, uint8_t shift) {
2139 switch (s) {
2140 case kItOmitted: return 1 << shift;
2141 case kItThen: return firstcond0 << shift;
2142 case kItElse: return !firstcond0 << shift;
2143 }
2144 return 0;
2145}
2146
2147
2148// Set the IT condition in the given position for the given state. This is used
2149// to check that conditional instructions match the preceding IT statement.
2150void Thumb2Assembler::SetItCondition(ItState s, Condition cond, uint8_t index) {
2151 switch (s) {
2152 case kItOmitted: it_conditions_[index] = AL; break;
2153 case kItThen: it_conditions_[index] = cond; break;
2154 case kItElse:
2155 it_conditions_[index] = static_cast<Condition>(static_cast<uint8_t>(cond) ^ 1);
2156 break;
2157 }
2158}
2159
2160
2161void Thumb2Assembler::it(Condition firstcond, ItState i1, ItState i2, ItState i3) {
2162 CheckCondition(AL); // Not allowed in IT block.
2163 uint8_t firstcond0 = static_cast<uint8_t>(firstcond) & 1;
2164
2165 // All conditions to AL.
2166 for (uint8_t i = 0; i < 4; ++i) {
2167 it_conditions_[i] = AL;
2168 }
2169
2170 SetItCondition(kItThen, firstcond, 0);
2171 uint8_t mask = ToItMask(i1, firstcond0, 3);
2172 SetItCondition(i1, firstcond, 1);
2173
2174 if (i1 != kItOmitted) {
2175 mask |= ToItMask(i2, firstcond0, 2);
2176 SetItCondition(i2, firstcond, 2);
2177 if (i2 != kItOmitted) {
2178 mask |= ToItMask(i3, firstcond0, 1);
2179 SetItCondition(i3, firstcond, 3);
2180 if (i3 != kItOmitted) {
Andreas Gampec8ccf682014-09-29 20:07:43 -07002181 mask |= 1U /* 0b0001 */;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002182 }
2183 }
2184 }
2185
2186 // Start at first condition.
2187 it_cond_index_ = 0;
2188 next_condition_ = it_conditions_[0];
2189 uint16_t encoding = B15 | B13 | B12 |
2190 B11 | B10 | B9 | B8 |
2191 firstcond << 4 |
2192 mask;
2193 Emit16(encoding);
2194}
2195
2196
2197void Thumb2Assembler::cbz(Register rn, Label* label) {
2198 CheckCondition(AL);
2199 if (label->IsBound()) {
2200 LOG(FATAL) << "cbz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002201 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002202 } else {
2203 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
2204 label->LinkTo(branchid);
2205 }
2206}
2207
2208
2209void Thumb2Assembler::cbnz(Register rn, Label* label) {
2210 CheckCondition(AL);
2211 if (label->IsBound()) {
2212 LOG(FATAL) << "cbnz can only be used to branch forwards";
Vladimir Markoe8469c12014-11-26 18:09:30 +00002213 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002214 } else {
2215 uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
2216 label->LinkTo(branchid);
2217 }
2218}
2219
2220
2221void Thumb2Assembler::blx(Register rm, Condition cond) {
2222 CHECK_NE(rm, kNoRegister);
2223 CheckCondition(cond);
2224 int16_t encoding = B14 | B10 | B9 | B8 | B7 | static_cast<int16_t>(rm) << 3;
2225 Emit16(encoding);
2226}
2227
2228
2229void Thumb2Assembler::bx(Register rm, Condition cond) {
2230 CHECK_NE(rm, kNoRegister);
2231 CheckCondition(cond);
2232 int16_t encoding = B14 | B10 | B9 | B8 | static_cast<int16_t>(rm) << 3;
2233 Emit16(encoding);
2234}
2235
2236
2237void Thumb2Assembler::Push(Register rd, Condition cond) {
2238 str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
2239}
2240
2241
2242void Thumb2Assembler::Pop(Register rd, Condition cond) {
2243 ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
2244}
2245
2246
2247void Thumb2Assembler::PushList(RegList regs, Condition cond) {
2248 stm(DB_W, SP, regs, cond);
2249}
2250
2251
2252void Thumb2Assembler::PopList(RegList regs, Condition cond) {
2253 ldm(IA_W, SP, regs, cond);
2254}
2255
2256
2257void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
2258 if (cond != AL || rd != rm) {
2259 mov(rd, ShifterOperand(rm), cond);
2260 }
2261}
2262
2263
2264// A branch has changed size. Make a hole for it.
2265void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
2266 // Move the contents of the buffer using: Move(newposition, oldposition)
2267 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2268 buffer_.Move(location + delta, location);
2269}
2270
2271
2272void Thumb2Assembler::Bind(Label* label) {
2273 CHECK(!label->IsBound());
2274 uint32_t bound_pc = buffer_.Size();
2275 std::vector<Branch*> changed_branches;
2276
2277 while (label->IsLinked()) {
2278 uint16_t position = label->Position(); // Branch id for linked branch.
2279 Branch* branch = GetBranch(position); // Get the branch at this id.
2280 bool changed = branch->Resolve(bound_pc); // Branch can be resolved now.
2281 uint32_t branch_location = branch->GetLocation();
2282 uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
2283 if (changed) {
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +01002284 DCHECK(CanRelocateBranches());
Dave Allison65fcc2c2014-04-28 13:45:27 -07002285 MakeHoleForBranch(branch->GetLocation(), 2);
2286 if (branch->IsCompareAndBranch()) {
2287 // A cbz/cbnz instruction has changed size. There is no valid encoding for
2288 // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
2289 // cmp rn, #0
2290 // b<eq|ne> target
2291 bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
2292 Condition cond = n ? NE : EQ;
2293 branch->Move(2); // Move the branch forward by 2 bytes.
2294 branch->ResetTypeAndCondition(Branch::kConditional, cond);
2295 branch->ResetSize(Branch::k16Bit);
2296
2297 // Now add a compare instruction in the place the branch was.
Andreas Gampe277ccbd2014-11-03 21:36:10 -08002298 buffer_.Store<int16_t>(branch_location,
2299 B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002300
2301 // Since have moved made a hole in the code we need to reload the
2302 // current pc.
2303 bound_pc = buffer_.Size();
2304
2305 // Now resolve the newly added branch.
2306 changed = branch->Resolve(bound_pc);
2307 if (changed) {
2308 MakeHoleForBranch(branch->GetLocation(), 2);
2309 changed_branches.push_back(branch);
2310 }
2311 } else {
2312 changed_branches.push_back(branch);
2313 }
2314 }
2315 label->position_ = next; // Move to next.
2316 }
2317 label->BindTo(bound_pc);
2318
2319 // Now relocate any changed branches. Do this until there are no more changes.
2320 std::vector<Branch*> branches_to_process = changed_branches;
2321 while (branches_to_process.size() != 0) {
2322 changed_branches.clear();
2323 for (auto& changed_branch : branches_to_process) {
2324 for (auto& branch : branches_) {
2325 bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
2326 if (changed) {
2327 changed_branches.push_back(branch);
2328 }
2329 }
2330 branches_to_process = changed_branches;
2331 }
2332 }
2333}
2334
2335
2336void Thumb2Assembler::EmitBranches() {
2337 for (auto& branch : branches_) {
2338 branch->Emit(&buffer_);
2339 }
2340}
2341
2342
2343void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002344 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002345 CHECK_LE(shift_imm, 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002346 CheckCondition(cond);
2347 EmitShift(rd, rm, LSL, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002348}
2349
2350
2351void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002352 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002353 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002354 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002355 CheckCondition(cond);
2356 EmitShift(rd, rm, LSR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002357}
2358
2359
2360void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002361 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002362 CHECK(1u <= shift_imm && shift_imm <= 32u);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002363 if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
Dave Allison45fdb932014-06-25 12:37:10 -07002364 CheckCondition(cond);
2365 EmitShift(rd, rm, ASR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002366}
2367
2368
2369void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Dave Allison45fdb932014-06-25 12:37:10 -07002370 bool setcc, Condition cond) {
Calin Juravle9aec02f2014-11-18 23:06:35 +00002371 CHECK(1u <= shift_imm && shift_imm <= 31u);
Dave Allison45fdb932014-06-25 12:37:10 -07002372 CheckCondition(cond);
2373 EmitShift(rd, rm, ROR, shift_imm, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002374}
2375
2376
Dave Allison45fdb932014-06-25 12:37:10 -07002377void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) {
2378 CheckCondition(cond);
2379 EmitShift(rd, rm, RRX, rm, setcc);
2380}
2381
2382
2383void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn,
2384 bool setcc, Condition cond) {
2385 CheckCondition(cond);
2386 EmitShift(rd, rm, LSL, rn, setcc);
2387}
2388
2389
2390void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn,
2391 bool setcc, Condition cond) {
2392 CheckCondition(cond);
2393 EmitShift(rd, rm, LSR, rn, setcc);
2394}
2395
2396
2397void Thumb2Assembler::Asr(Register rd, Register rm, Register rn,
2398 bool setcc, Condition cond) {
2399 CheckCondition(cond);
2400 EmitShift(rd, rm, ASR, rn, setcc);
2401}
2402
2403
2404void Thumb2Assembler::Ror(Register rd, Register rm, Register rn,
2405 bool setcc, Condition cond) {
2406 CheckCondition(cond);
2407 EmitShift(rd, rm, ROR, rn, setcc);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002408}
2409
2410
2411int32_t Thumb2Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2412 // The offset is off by 4 due to the way the ARM CPUs read PC.
2413 offset -= 4;
2414 offset >>= 1;
2415
2416 uint32_t value = 0;
2417 // There are two different encodings depending on the value of bit 12. In one case
2418 // intermediate values are calculated using the sign bit.
2419 if ((inst & B12) == B12) {
2420 // 25 bits of offset.
2421 uint32_t signbit = (offset >> 31) & 0x1;
2422 uint32_t i1 = (offset >> 22) & 0x1;
2423 uint32_t i2 = (offset >> 21) & 0x1;
2424 uint32_t imm10 = (offset >> 11) & 0x03ff;
2425 uint32_t imm11 = offset & 0x07ff;
2426 uint32_t j1 = (i1 ^ signbit) ? 0 : 1;
2427 uint32_t j2 = (i2 ^ signbit) ? 0 : 1;
2428 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) |
2429 imm11;
2430 // Remove the offset from the current encoding.
2431 inst &= ~(0x3ff << 16 | 0x7ff);
2432 } else {
2433 uint32_t signbit = (offset >> 31) & 0x1;
2434 uint32_t imm6 = (offset >> 11) & 0x03f;
2435 uint32_t imm11 = offset & 0x07ff;
2436 uint32_t j1 = (offset >> 19) & 1;
2437 uint32_t j2 = (offset >> 17) & 1;
2438 value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm6 << 16) |
2439 imm11;
2440 // Remove the offset from the current encoding.
2441 inst &= ~(0x3f << 16 | 0x7ff);
2442 }
2443 // Mask out offset bits in current instruction.
2444 inst &= ~(B26 | B13 | B11);
2445 inst |= value;
2446 return inst;
2447}
2448
2449
2450int Thumb2Assembler::DecodeBranchOffset(int32_t instr) {
2451 int32_t imm32;
2452 if ((instr & B12) == B12) {
2453 uint32_t S = (instr >> 26) & 1;
2454 uint32_t J2 = (instr >> 11) & 1;
2455 uint32_t J1 = (instr >> 13) & 1;
2456 uint32_t imm10 = (instr >> 16) & 0x3FF;
2457 uint32_t imm11 = instr & 0x7FF;
2458
2459 uint32_t I1 = ~(J1 ^ S) & 1;
2460 uint32_t I2 = ~(J2 ^ S) & 1;
2461 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
2462 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate.
2463 } else {
2464 uint32_t S = (instr >> 26) & 1;
2465 uint32_t J2 = (instr >> 11) & 1;
2466 uint32_t J1 = (instr >> 13) & 1;
2467 uint32_t imm6 = (instr >> 16) & 0x3F;
2468 uint32_t imm11 = instr & 0x7FF;
2469
2470 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
2471 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate.
2472 }
2473 imm32 += 4;
2474 return imm32;
2475}
2476
2477
2478void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
2479 AddConstant(rd, rd, value, cond);
2480}
2481
2482
2483void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value,
2484 Condition cond) {
2485 if (value == 0) {
2486 if (rd != rn) {
2487 mov(rd, ShifterOperand(rn), cond);
2488 }
2489 return;
2490 }
2491 // We prefer to select the shorter code sequence rather than selecting add for
2492 // positive values and sub for negatives ones, which would slightly improve
2493 // the readability of generated code for some constants.
2494 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002495 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002496 add(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002497 } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002498 sub(rd, rn, shifter_op, cond);
2499 } else {
2500 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002501 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002502 mvn(IP, shifter_op, cond);
2503 add(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002504 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002505 mvn(IP, shifter_op, cond);
2506 sub(rd, rn, ShifterOperand(IP), cond);
2507 } else {
2508 movw(IP, Low16Bits(value), cond);
2509 uint16_t value_high = High16Bits(value);
2510 if (value_high != 0) {
2511 movt(IP, value_high, cond);
2512 }
2513 add(rd, rn, ShifterOperand(IP), cond);
2514 }
2515 }
2516}
2517
2518
2519void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value,
2520 Condition cond) {
2521 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002522 if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002523 adds(rd, rn, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002524 } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002525 subs(rd, rn, shifter_op, cond);
2526 } else {
2527 CHECK(rn != IP);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002528 if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002529 mvn(IP, shifter_op, cond);
2530 adds(rd, rn, ShifterOperand(IP), cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002531 } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002532 mvn(IP, shifter_op, cond);
2533 subs(rd, rn, ShifterOperand(IP), cond);
2534 } else {
2535 movw(IP, Low16Bits(value), cond);
2536 uint16_t value_high = High16Bits(value);
2537 if (value_high != 0) {
2538 movt(IP, value_high, cond);
2539 }
2540 adds(rd, rn, ShifterOperand(IP), cond);
2541 }
2542 }
2543}
2544
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002545
Dave Allison65fcc2c2014-04-28 13:45:27 -07002546void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2547 ShifterOperand shifter_op;
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002548 if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002549 mov(rd, shifter_op, cond);
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002550 } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -07002551 mvn(rd, shifter_op, cond);
2552 } else {
2553 movw(rd, Low16Bits(value), cond);
2554 uint16_t value_high = High16Bits(value);
2555 if (value_high != 0) {
2556 movt(rd, value_high, cond);
2557 }
2558 }
2559}
2560
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +00002561
Dave Allison65fcc2c2014-04-28 13:45:27 -07002562// Implementation note: this method must emit at most one instruction when
2563// Address::CanHoldLoadOffsetThumb.
2564void Thumb2Assembler::LoadFromOffset(LoadOperandType type,
2565 Register reg,
2566 Register base,
2567 int32_t offset,
2568 Condition cond) {
2569 if (!Address::CanHoldLoadOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002570 CHECK_NE(base, IP);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002571 LoadImmediate(IP, offset, cond);
2572 add(IP, IP, ShifterOperand(base), cond);
2573 base = IP;
2574 offset = 0;
2575 }
2576 CHECK(Address::CanHoldLoadOffsetThumb(type, offset));
2577 switch (type) {
2578 case kLoadSignedByte:
2579 ldrsb(reg, Address(base, offset), cond);
2580 break;
2581 case kLoadUnsignedByte:
2582 ldrb(reg, Address(base, offset), cond);
2583 break;
2584 case kLoadSignedHalfword:
2585 ldrsh(reg, Address(base, offset), cond);
2586 break;
2587 case kLoadUnsignedHalfword:
2588 ldrh(reg, Address(base, offset), cond);
2589 break;
2590 case kLoadWord:
2591 ldr(reg, Address(base, offset), cond);
2592 break;
2593 case kLoadWordPair:
2594 ldrd(reg, Address(base, offset), cond);
2595 break;
2596 default:
2597 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002598 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002599 }
2600}
2601
2602
2603// Implementation note: this method must emit at most one instruction when
2604// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2605void Thumb2Assembler::LoadSFromOffset(SRegister reg,
2606 Register base,
2607 int32_t offset,
2608 Condition cond) {
2609 if (!Address::CanHoldLoadOffsetThumb(kLoadSWord, offset)) {
2610 CHECK_NE(base, IP);
2611 LoadImmediate(IP, offset, cond);
2612 add(IP, IP, ShifterOperand(base), cond);
2613 base = IP;
2614 offset = 0;
2615 }
2616 CHECK(Address::CanHoldLoadOffsetThumb(kLoadSWord, offset));
2617 vldrs(reg, Address(base, offset), cond);
2618}
2619
2620
2621// Implementation note: this method must emit at most one instruction when
2622// Address::CanHoldLoadOffsetThumb, as expected by JIT::GuardedLoadFromOffset.
2623void Thumb2Assembler::LoadDFromOffset(DRegister reg,
2624 Register base,
2625 int32_t offset,
2626 Condition cond) {
2627 if (!Address::CanHoldLoadOffsetThumb(kLoadDWord, offset)) {
2628 CHECK_NE(base, IP);
2629 LoadImmediate(IP, offset, cond);
2630 add(IP, IP, ShifterOperand(base), cond);
2631 base = IP;
2632 offset = 0;
2633 }
2634 CHECK(Address::CanHoldLoadOffsetThumb(kLoadDWord, offset));
2635 vldrd(reg, Address(base, offset), cond);
2636}
2637
2638
2639// Implementation note: this method must emit at most one instruction when
2640// Address::CanHoldStoreOffsetThumb.
2641void Thumb2Assembler::StoreToOffset(StoreOperandType type,
2642 Register reg,
2643 Register base,
2644 int32_t offset,
2645 Condition cond) {
Roland Levillain775ef492014-11-04 17:43:11 +00002646 Register tmp_reg = kNoRegister;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002647 if (!Address::CanHoldStoreOffsetThumb(type, offset)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002648 CHECK_NE(base, IP);
Roland Levillain4af147e2015-04-07 13:54:49 +01002649 if (reg != IP &&
2650 (type != kStoreWordPair || reg + 1 != IP)) {
Roland Levillain775ef492014-11-04 17:43:11 +00002651 tmp_reg = IP;
2652 } else {
Roland Levillain4af147e2015-04-07 13:54:49 +01002653 // Be careful not to use IP twice (for `reg` (or `reg` + 1 in
2654 // the case of a word-pair store)) and to build the Address
2655 // object used by the store instruction(s) below). Instead,
2656 // save R5 on the stack (or R6 if R5 is not available), use it
2657 // as secondary temporary register, and restore it after the
2658 // store instruction has been emitted.
Roland Levillain775ef492014-11-04 17:43:11 +00002659 tmp_reg = base != R5 ? R5 : R6;
2660 Push(tmp_reg);
2661 if (base == SP) {
2662 offset += kRegisterSize;
2663 }
2664 }
2665 LoadImmediate(tmp_reg, offset, cond);
2666 add(tmp_reg, tmp_reg, ShifterOperand(base), cond);
2667 base = tmp_reg;
Dave Allison65fcc2c2014-04-28 13:45:27 -07002668 offset = 0;
2669 }
2670 CHECK(Address::CanHoldStoreOffsetThumb(type, offset));
2671 switch (type) {
2672 case kStoreByte:
2673 strb(reg, Address(base, offset), cond);
2674 break;
2675 case kStoreHalfword:
2676 strh(reg, Address(base, offset), cond);
2677 break;
2678 case kStoreWord:
2679 str(reg, Address(base, offset), cond);
2680 break;
2681 case kStoreWordPair:
2682 strd(reg, Address(base, offset), cond);
2683 break;
2684 default:
2685 LOG(FATAL) << "UNREACHABLE";
Ian Rogers2c4257b2014-10-24 14:20:06 -07002686 UNREACHABLE();
Dave Allison65fcc2c2014-04-28 13:45:27 -07002687 }
Roland Levillain775ef492014-11-04 17:43:11 +00002688 if (tmp_reg != kNoRegister && tmp_reg != IP) {
2689 DCHECK(tmp_reg == R5 || tmp_reg == R6);
2690 Pop(tmp_reg);
2691 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002692}
2693
2694
2695// Implementation note: this method must emit at most one instruction when
2696// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreToOffset.
2697void Thumb2Assembler::StoreSToOffset(SRegister reg,
2698 Register base,
2699 int32_t offset,
2700 Condition cond) {
2701 if (!Address::CanHoldStoreOffsetThumb(kStoreSWord, offset)) {
2702 CHECK_NE(base, IP);
2703 LoadImmediate(IP, offset, cond);
2704 add(IP, IP, ShifterOperand(base), cond);
2705 base = IP;
2706 offset = 0;
2707 }
2708 CHECK(Address::CanHoldStoreOffsetThumb(kStoreSWord, offset));
2709 vstrs(reg, Address(base, offset), cond);
2710}
2711
2712
2713// Implementation note: this method must emit at most one instruction when
2714// Address::CanHoldStoreOffsetThumb, as expected by JIT::GuardedStoreSToOffset.
2715void Thumb2Assembler::StoreDToOffset(DRegister reg,
2716 Register base,
2717 int32_t offset,
2718 Condition cond) {
2719 if (!Address::CanHoldStoreOffsetThumb(kStoreDWord, offset)) {
2720 CHECK_NE(base, IP);
2721 LoadImmediate(IP, offset, cond);
2722 add(IP, IP, ShifterOperand(base), cond);
2723 base = IP;
2724 offset = 0;
2725 }
2726 CHECK(Address::CanHoldStoreOffsetThumb(kStoreDWord, offset));
2727 vstrd(reg, Address(base, offset), cond);
2728}
2729
2730
2731void Thumb2Assembler::MemoryBarrier(ManagedRegister mscratch) {
2732 CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002733 dmb(SY);
2734}
2735
2736
2737void Thumb2Assembler::dmb(DmbOptions flavor) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002738 int32_t encoding = 0xf3bf8f50; // dmb in T1 encoding.
2739 Emit32(encoding | flavor);
Dave Allison65fcc2c2014-04-28 13:45:27 -07002740}
2741
2742
2743void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +01002744 if (CanRelocateBranches()) {
2745 cbz(r, label);
2746 } else {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002747 cmp(r, ShifterOperand(0));
2748 b(label, EQ);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002749 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002750}
2751
2752
2753void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +01002754 if (CanRelocateBranches()) {
2755 cbnz(r, label);
2756 } else {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002757 cmp(r, ShifterOperand(0));
2758 b(label, NE);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002759 }
Dave Allison65fcc2c2014-04-28 13:45:27 -07002760}
2761} // namespace arm
2762} // namespace art