blob: a571d14a71f2de081a1875fa44c61fbcb30402f8 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 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 */
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070016
Ian Rogers166db042013-07-26 12:05:57 -070017#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
18#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070019
Vladimir Markocf93a5c2015-06-16 11:33:24 +000020#include <type_traits>
Elliott Hughes07ed66b2012-12-12 18:34:25 -080021#include <vector>
22
Vladimir Marko93205e32016-04-13 11:59:46 +010023#include "base/arena_allocator.h"
24#include "base/arena_containers.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010025#include "base/bit_utils.h"
Elliott Hughes07ed66b2012-12-12 18:34:25 -080026#include "base/logging.h"
Vladimir Marko88b2b802015-12-04 14:19:04 +000027#include "base/stl_util.h"
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070028#include "base/value_object.h"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070029#include "constants_arm.h"
Ian Rogers166db042013-07-26 12:05:57 -070030#include "utils/arm/managed_register_arm.h"
31#include "utils/assembler.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070032#include "offsets.h"
Carl Shapiroa2e18e12011-06-21 18:57:55 -070033
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070034namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070035namespace arm {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070036
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +000037class Arm32Assembler;
38class Thumb2Assembler;
39
Vladimir Markocf93a5c2015-06-16 11:33:24 +000040// Assembler literal is a value embedded in code, retrieved using a PC-relative load.
41class Literal {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000042 public:
Vladimir Markocf93a5c2015-06-16 11:33:24 +000043 static constexpr size_t kMaxSize = 8;
44
45 Literal(uint32_t size, const uint8_t* data)
46 : label_(), size_(size) {
47 DCHECK_LE(size, Literal::kMaxSize);
48 memcpy(data_, data, size);
49 }
50
51 template <typename T>
52 T GetValue() const {
53 DCHECK_EQ(size_, sizeof(T));
54 T value;
55 memcpy(&value, data_, sizeof(T));
56 return value;
57 }
58
59 uint32_t GetSize() const {
60 return size_;
61 }
62
63 const uint8_t* GetData() const {
64 return data_;
65 }
66
67 Label* GetLabel() {
68 return &label_;
69 }
70
71 const Label* GetLabel() const {
72 return &label_;
73 }
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000074
75 private:
Vladimir Markocf93a5c2015-06-16 11:33:24 +000076 Label label_;
77 const uint32_t size_;
78 uint8_t data_[kMaxSize];
79
80 DISALLOW_COPY_AND_ASSIGN(Literal);
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000081};
82
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070083// Jump table: table of labels emitted after the literals. Similar to literals.
84class JumpTable {
85 public:
86 explicit JumpTable(std::vector<Label*>&& labels)
87 : label_(), anchor_label_(), labels_(std::move(labels)) {
88 }
89
90 uint32_t GetSize() const {
91 return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t);
92 }
93
94 const std::vector<Label*>& GetData() const {
95 return labels_;
96 }
97
98 Label* GetLabel() {
99 return &label_;
100 }
101
102 const Label* GetLabel() const {
103 return &label_;
104 }
105
106 Label* GetAnchorLabel() {
107 return &anchor_label_;
108 }
109
110 const Label* GetAnchorLabel() const {
111 return &anchor_label_;
112 }
113
114 private:
115 Label label_;
116 Label anchor_label_;
117 std::vector<Label*> labels_;
118
119 DISALLOW_COPY_AND_ASSIGN(JumpTable);
120};
121
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700122class ShifterOperand {
123 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700124 ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
125 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700126 }
127
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100128 explicit ShifterOperand(uint32_t immed);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700129
130 // Data-processing operands - Register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700131 explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister),
132 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700133 }
134
Dave Allison65fcc2c2014-04-28 13:45:27 -0700135 ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister),
136 rs_(kNoRegister),
137 is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) {
138 }
139
140 ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm),
141 rs_(kNoRegister),
142 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700143 }
144
145 // Data-processing operands - Logical shift/rotate by register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700146 ShifterOperand(Register rm, Shift shift, Register rs) : type_(kRegister), rm_(rm),
147 rs_(rs),
148 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700149 }
150
Dave Allison65fcc2c2014-04-28 13:45:27 -0700151 bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700152
153 uint32_t type() const {
154 CHECK(is_valid());
155 return type_;
156 }
157
Dave Allison65fcc2c2014-04-28 13:45:27 -0700158 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700159 uint32_t encodingThumb() const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700160
161 bool IsEmpty() const {
162 return type_ == kUnknown;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700163 }
164
Dave Allison65fcc2c2014-04-28 13:45:27 -0700165 bool IsImmediate() const {
166 return type_ == kImmediate;
167 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700168
Dave Allison65fcc2c2014-04-28 13:45:27 -0700169 bool IsRegister() const {
170 return type_ == kRegister;
171 }
172
173 bool IsShift() const {
174 return is_shift_;
175 }
176
177 uint32_t GetImmediate() const {
178 return immed_;
179 }
180
181 Shift GetShift() const {
182 return shift_;
183 }
184
185 Register GetRegister() const {
186 return rm_;
187 }
188
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000189 Register GetSecondRegister() const {
190 return rs_;
191 }
192
Dave Allison65fcc2c2014-04-28 13:45:27 -0700193 enum Type {
194 kUnknown = -1,
195 kRegister,
196 kImmediate
197 };
198
Dave Allison65fcc2c2014-04-28 13:45:27 -0700199 private:
200 Type type_;
201 Register rm_;
202 Register rs_;
203 bool is_rotate_;
204 bool is_shift_;
205 Shift shift_;
206 uint32_t rotate_;
207 uint32_t immed_;
208
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000209 friend class Arm32Assembler;
210 friend class Thumb2Assembler;
211
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700212#ifdef SOURCE_ASSEMBLER_SUPPORT
213 friend class BinaryAssembler;
214#endif
215};
216
217
218enum LoadOperandType {
219 kLoadSignedByte,
220 kLoadUnsignedByte,
221 kLoadSignedHalfword,
222 kLoadUnsignedHalfword,
223 kLoadWord,
224 kLoadWordPair,
225 kLoadSWord,
226 kLoadDWord
227};
228
229
230enum StoreOperandType {
231 kStoreByte,
232 kStoreHalfword,
233 kStoreWord,
234 kStoreWordPair,
235 kStoreSWord,
236 kStoreDWord
237};
238
239
240// Load/store multiple addressing mode.
241enum BlockAddressMode {
242 // bit encoding P U W
243 DA = (0|0|0) << 21, // decrement after
244 IA = (0|4|0) << 21, // increment after
245 DB = (8|0|0) << 21, // decrement before
246 IB = (8|4|0) << 21, // increment before
247 DA_W = (0|0|1) << 21, // decrement after with writeback to base
248 IA_W = (0|4|1) << 21, // increment after with writeback to base
249 DB_W = (8|0|1) << 21, // decrement before with writeback to base
250 IB_W = (8|4|1) << 21 // increment before with writeback to base
251};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700252inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) {
253 os << static_cast<int>(rhs);
254 return os;
255}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700256
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700257class Address : public ValueObject {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700258 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700259 // Memory operand addressing mode (in ARM encoding form. For others we need
260 // to adjust)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700261 enum Mode {
262 // bit encoding P U W
263 Offset = (8|4|0) << 21, // offset (w/o writeback to base)
264 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
265 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
266 NegOffset = (8|0|0) << 21, // negative offset (w/o writeback to base)
267 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
268 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
269 };
270
Dave Allison45fdb932014-06-25 12:37:10 -0700271 Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
272 offset_(offset),
273 am_(am), is_immed_offset_(true), shift_(LSL) {
274 }
275
276 Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
277 am_(am), is_immed_offset_(false), shift_(LSL) {
278 CHECK_NE(rm, PC);
279 }
280
281 Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
282 rn_(rn), rm_(rm), offset_(count),
283 am_(am), is_immed_offset_(false), shift_(shift) {
284 CHECK_NE(rm, PC);
285 }
286
287 // LDR(literal) - pc relative load.
288 explicit Address(int32_t offset) :
289 rn_(PC), rm_(R0), offset_(offset),
290 am_(Offset), is_immed_offset_(false), shift_(LSL) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700291 }
292
Dave Allison65fcc2c2014-04-28 13:45:27 -0700293 static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
294 static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset);
295
296 static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset);
297 static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
298
299 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700300 uint32_t encodingThumb(bool is_32bit) const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700301
302 uint32_t encoding3() const;
303 uint32_t vencoding() const;
304
305 uint32_t encodingThumbLdrdStrd() const;
306
307 Register GetRegister() const {
308 return rn_;
309 }
310
Dave Allison45fdb932014-06-25 12:37:10 -0700311 Register GetRegisterOffset() const {
312 return rm_;
313 }
314
Dave Allison65fcc2c2014-04-28 13:45:27 -0700315 int32_t GetOffset() const {
316 return offset_;
317 }
318
319 Mode GetMode() const {
320 return am_;
321 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700322
Dave Allison45fdb932014-06-25 12:37:10 -0700323 bool IsImmediate() const {
324 return is_immed_offset_;
325 }
326
327 Shift GetShift() const {
328 return shift_;
329 }
330
331 int32_t GetShiftCount() const {
332 CHECK(!is_immed_offset_);
333 return offset_;
334 }
335
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700336 private:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700337 const Register rn_;
338 const Register rm_;
339 const int32_t offset_; // Used as shift amount for register offset.
340 const Mode am_;
341 const bool is_immed_offset_;
342 const Shift shift_;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700343};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700344inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) {
345 os << static_cast<int>(rhs);
346 return os;
347}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700348
Dave Allison65fcc2c2014-04-28 13:45:27 -0700349// Instruction encoding bits.
350enum {
351 H = 1 << 5, // halfword (or byte)
352 L = 1 << 20, // load (or store)
353 S = 1 << 20, // set condition code (or leave unchanged)
354 W = 1 << 21, // writeback base register (or leave unchanged)
355 A = 1 << 21, // accumulate in multiply instruction (or not)
356 B = 1 << 22, // unsigned byte (or word)
357 N = 1 << 22, // long (or short)
358 U = 1 << 23, // positive (or negative) offset/index
359 P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing)
360 I = 1 << 25, // immediate shifter operand (or not)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700361
Dave Allison65fcc2c2014-04-28 13:45:27 -0700362 B0 = 1,
363 B1 = 1 << 1,
364 B2 = 1 << 2,
365 B3 = 1 << 3,
366 B4 = 1 << 4,
367 B5 = 1 << 5,
368 B6 = 1 << 6,
369 B7 = 1 << 7,
370 B8 = 1 << 8,
371 B9 = 1 << 9,
372 B10 = 1 << 10,
373 B11 = 1 << 11,
374 B12 = 1 << 12,
375 B13 = 1 << 13,
376 B14 = 1 << 14,
377 B15 = 1 << 15,
378 B16 = 1 << 16,
379 B17 = 1 << 17,
380 B18 = 1 << 18,
381 B19 = 1 << 19,
382 B20 = 1 << 20,
383 B21 = 1 << 21,
384 B22 = 1 << 22,
385 B23 = 1 << 23,
386 B24 = 1 << 24,
387 B25 = 1 << 25,
388 B26 = 1 << 26,
389 B27 = 1 << 27,
390 B28 = 1 << 28,
391 B29 = 1 << 29,
392 B30 = 1 << 30,
393 B31 = 1 << 31,
394
395 // Instruction bit masks.
396 RdMask = 15 << 12, // in str instruction
397 CondMask = 15 << 28,
398 CoprocessorMask = 15 << 8,
399 OpCodeMask = 15 << 21, // in data-processing instructions
400 Imm24Mask = (1 << 24) - 1,
401 Off12Mask = (1 << 12) - 1,
402
403 // ldrex/strex register field encodings.
404 kLdExRnShift = 16,
405 kLdExRtShift = 12,
406 kStrExRnShift = 16,
407 kStrExRdShift = 12,
408 kStrExRtShift = 0,
409};
410
411// IfThen state for IT instructions.
412enum ItState {
413 kItOmitted,
414 kItThen,
415 kItT = kItThen,
416 kItElse,
417 kItE = kItElse
418};
419
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100420// Set condition codes request.
421enum SetCc {
422 kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
423 kCcSet,
424 kCcKeep,
425};
426
Dave Allison65fcc2c2014-04-28 13:45:27 -0700427constexpr uint32_t kNoItCondition = 3;
428constexpr uint32_t kInvalidModifiedImmediate = -1;
429
430extern const char* kRegisterNames[];
431extern const char* kConditionNames[];
Dave Allison65fcc2c2014-04-28 13:45:27 -0700432
433// This is an abstract ARM assembler. Subclasses provide assemblers for the individual
434// instruction sets (ARM32, Thumb2, etc.)
435//
436class ArmAssembler : public Assembler {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700437 public:
Ian Rogers2c8f6532011-09-02 17:16:34 -0700438 virtual ~ArmAssembler() {}
buzbeec143c552011-08-20 17:38:58 -0700439
Dave Allison65fcc2c2014-04-28 13:45:27 -0700440 // Is this assembler for the thumb instruction set?
441 virtual bool IsThumb() const = 0;
442
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700443 // Data-processing instructions.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100444 virtual void and_(Register rd, Register rn, const ShifterOperand& so,
445 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700446
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100447 virtual void ands(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
448 and_(rd, rn, so, cond, kCcSet);
449 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700450
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100451 virtual void eor(Register rd, Register rn, const ShifterOperand& so,
452 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700453
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100454 virtual void eors(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
455 eor(rd, rn, so, cond, kCcSet);
456 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700457
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100458 virtual void sub(Register rd, Register rn, const ShifterOperand& so,
459 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700460
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100461 virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
462 sub(rd, rn, so, cond, kCcSet);
463 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700464
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100465 virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
466 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700467
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100468 virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
469 rsb(rd, rn, so, cond, kCcSet);
470 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700471
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100472 virtual void add(Register rd, Register rn, const ShifterOperand& so,
473 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
474
475 virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
476 add(rd, rn, so, cond, kCcSet);
477 }
478
479 virtual void adc(Register rd, Register rn, const ShifterOperand& so,
480 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
481
482 virtual void adcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
483 adc(rd, rn, so, cond, kCcSet);
484 }
485
486 virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
487 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
488
489 virtual void sbcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
490 sbc(rd, rn, so, cond, kCcSet);
491 }
492
493 virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
494 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
495
496 virtual void rscs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
497 rsc(rd, rn, so, cond, kCcSet);
498 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700499
Dave Allison65fcc2c2014-04-28 13:45:27 -0700500 virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700501
Dave Allison65fcc2c2014-04-28 13:45:27 -0700502 virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700503
Dave Allison65fcc2c2014-04-28 13:45:27 -0700504 virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700505
Vladimir Markoac6ac102015-12-17 12:14:00 +0000506 // Note: CMN updates flags based on addition of its operands. Do not confuse
507 // the "N" suffix with bitwise inversion performed by MVN.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700508 virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700509
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100510 virtual void orr(Register rd, Register rn, const ShifterOperand& so,
511 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700512
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100513 virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
514 orr(rd, rn, so, cond, kCcSet);
515 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700516
Vladimir Markod2b4ca22015-09-14 15:13:26 +0100517 virtual void orn(Register rd, Register rn, const ShifterOperand& so,
518 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
519
520 virtual void orns(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
521 orn(rd, rn, so, cond, kCcSet);
522 }
523
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100524 virtual void mov(Register rd, const ShifterOperand& so,
525 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700526
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100527 virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) {
528 mov(rd, so, cond, kCcSet);
529 }
530
531 virtual void bic(Register rd, Register rn, const ShifterOperand& so,
532 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
533
534 virtual void bics(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
535 bic(rd, rn, so, cond, kCcSet);
536 }
537
538 virtual void mvn(Register rd, const ShifterOperand& so,
539 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
540
541 virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) {
542 mvn(rd, so, cond, kCcSet);
543 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700544
545 // Miscellaneous data-processing instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700546 virtual void clz(Register rd, Register rm, Condition cond = AL) = 0;
547 virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0;
548 virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0;
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100549 virtual void rbit(Register rd, Register rm, Condition cond = AL) = 0;
Artem Serovc257da72016-02-02 13:49:43 +0000550 virtual void rev(Register rd, Register rm, Condition cond = AL) = 0;
551 virtual void rev16(Register rd, Register rm, Condition cond = AL) = 0;
552 virtual void revsh(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700553
554 // Multiply instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700555 virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
556 virtual void mla(Register rd, Register rn, Register rm, Register ra,
557 Condition cond = AL) = 0;
558 virtual void mls(Register rd, Register rn, Register rm, Register ra,
559 Condition cond = AL) = 0;
Zheng Xuc6667102015-05-15 16:08:45 +0800560 virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
561 Condition cond = AL) = 0;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700562 virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
563 Condition cond = AL) = 0;
564
565 virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
566 virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700567
Roland Levillain981e4542014-11-14 11:47:14 +0000568 // Bit field extract instructions.
Roland Levillain51d3fc42014-11-13 14:11:42 +0000569 virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
570 Condition cond = AL) = 0;
Roland Levillain981e4542014-11-14 11:47:14 +0000571 virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
572 Condition cond = AL) = 0;
Roland Levillain51d3fc42014-11-13 14:11:42 +0000573
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700574 // Load/store instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700575 virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
576 virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700577
Dave Allison65fcc2c2014-04-28 13:45:27 -0700578 virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0;
579 virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700580
Dave Allison65fcc2c2014-04-28 13:45:27 -0700581 virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0;
582 virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700583
Dave Allison65fcc2c2014-04-28 13:45:27 -0700584 virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0;
585 virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700586
Dave Allison65fcc2c2014-04-28 13:45:27 -0700587 virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0;
588 virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700589
Dave Allison65fcc2c2014-04-28 13:45:27 -0700590 virtual void ldm(BlockAddressMode am, Register base,
591 RegList regs, Condition cond = AL) = 0;
592 virtual void stm(BlockAddressMode am, Register base,
593 RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700594
Dave Allison65fcc2c2014-04-28 13:45:27 -0700595 virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
596 virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
Calin Juravle52c48962014-12-16 17:02:57 +0000597 virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
598 virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700599
600 // Miscellaneous instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700601 virtual void clrex(Condition cond = AL) = 0;
602 virtual void nop(Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700603
604 // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700605 virtual void bkpt(uint16_t imm16) = 0;
606 virtual void svc(uint32_t imm24) = 0;
607
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700608 virtual void it(Condition firstcond ATTRIBUTE_UNUSED,
609 ItState i1 ATTRIBUTE_UNUSED = kItOmitted,
610 ItState i2 ATTRIBUTE_UNUSED = kItOmitted,
611 ItState i3 ATTRIBUTE_UNUSED = kItOmitted) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700612 // Ignored if not supported.
613 }
614
615 virtual void cbz(Register rn, Label* target) = 0;
616 virtual void cbnz(Register rn, Label* target) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700617
618 // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
Dave Allison65fcc2c2014-04-28 13:45:27 -0700619 virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0;
620 virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0;
621 virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0;
622 virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0;
623 virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0;
624 virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0;
625 virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
626 virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700627
628 // Returns false if the immediate cannot be encoded.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700629 virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0;
630 virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700631
Dave Allison65fcc2c2014-04-28 13:45:27 -0700632 virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
633 virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
634 virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
635 virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700636
Dave Allison65fcc2c2014-04-28 13:45:27 -0700637 virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
638 virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
639 virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
640 virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
641 virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
642 virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
643 virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
644 virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
645 virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
646 virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
647 virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
648 virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700649
Dave Allison65fcc2c2014-04-28 13:45:27 -0700650 virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0;
651 virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
652 virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
653 virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
654 virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0;
655 virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700656
Dave Allison65fcc2c2014-04-28 13:45:27 -0700657 virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0;
658 virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0;
659 virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0;
660 virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0;
661 virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0;
662 virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0;
663 virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0;
664 virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0;
665 virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0;
666 virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700667
Dave Allison65fcc2c2014-04-28 13:45:27 -0700668 virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0;
669 virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
670 virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0;
671 virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0;
672 virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR
673
xueliang.zhonge652c122016-06-13 14:42:27 +0100674 virtual void vcntd(DRegister dd, DRegister dm) = 0;
675 virtual void vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) = 0;
676
Dave Allison65fcc2c2014-04-28 13:45:27 -0700677 virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0;
678 virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
679 virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
680 virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700681
682 // Branch instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700683 virtual void b(Label* label, Condition cond = AL) = 0;
684 virtual void bl(Label* label, Condition cond = AL) = 0;
685 virtual void blx(Register rm, Condition cond = AL) = 0;
686 virtual void bx(Register rm, Condition cond = AL) = 0;
687
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100688 // Memory barriers.
689 virtual void dmb(DmbOptions flavor) = 0;
690
Dave Allison65fcc2c2014-04-28 13:45:27 -0700691 void Pad(uint32_t bytes);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700692
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000693 // Adjust label position.
694 void AdjustLabelPosition(Label* label) {
695 DCHECK(label->IsBound());
696 uint32_t old_position = static_cast<uint32_t>(label->Position());
697 uint32_t new_position = GetAdjustedPosition(old_position);
698 label->Reinitialize();
699 DCHECK_GE(static_cast<int>(new_position), 0);
700 label->BindTo(static_cast<int>(new_position));
701 }
702
703 // Get the final position of a label after local fixup based on the old position
704 // recorded before FinalizeCode().
705 virtual uint32_t GetAdjustedPosition(uint32_t old_position) = 0;
706
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700707 // Macros.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700708 // Most of these are pure virtual as they need to be implemented per instruction set.
709
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000710 // Create a new literal with a given value.
Vladimir Marko88b2b802015-12-04 14:19:04 +0000711 // NOTE: Force the template parameter to be explicitly specified.
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000712 template <typename T>
Vladimir Marko88b2b802015-12-04 14:19:04 +0000713 Literal* NewLiteral(typename Identity<T>::type value) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000714 static_assert(std::is_integral<T>::value, "T must be an integral type.");
715 return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
716 }
717
718 // Create a new literal with the given data.
719 virtual Literal* NewLiteral(size_t size, const uint8_t* data) = 0;
720
721 // Load literal.
722 virtual void LoadLiteral(Register rt, Literal* literal) = 0;
723 virtual void LoadLiteral(Register rt, Register rt2, Literal* literal) = 0;
724 virtual void LoadLiteral(SRegister sd, Literal* literal) = 0;
725 virtual void LoadLiteral(DRegister dd, Literal* literal) = 0;
726
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700727 // Add signed constant value to rd. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700728 virtual void AddConstant(Register rd, Register rn, int32_t value,
Vladimir Marko449b1092015-09-08 12:16:45 +0100729 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
730 void AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond = AL) {
731 AddConstant(rd, rn, value, cond, kCcSet);
732 }
733 void AddConstant(Register rd, int32_t value, Condition cond = AL, SetCc set_cc = kCcDontCare) {
734 AddConstant(rd, rd, value, cond, set_cc);
735 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700736
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700737 virtual void CmpConstant(Register rn, int32_t value, Condition cond = AL) = 0;
738
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700739 // Load and Store. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700740 virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000741 void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {
742 if (!vmovs(sd, value, cond)) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000743 int32_t int_value = bit_cast<int32_t, float>(value);
744 if (int_value == bit_cast<int32_t, float>(0.0f)) {
745 // 0.0 is quite common, so we special case it by loading
746 // 2.0 in `sd` and then substracting it.
747 bool success = vmovs(sd, 2.0, cond);
748 CHECK(success);
749 vsubs(sd, sd, sd, cond);
750 } else {
751 LoadImmediate(IP, int_value, cond);
752 vmovsr(sd, IP, cond);
753 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000754 }
755 }
756
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000757 void LoadDImmediate(DRegister sd, double value, Condition cond = AL) {
758 if (!vmovd(sd, value, cond)) {
759 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000760 if (int_value == bit_cast<uint64_t, double>(0.0)) {
761 // 0.0 is quite common, so we special case it by loading
762 // 2.0 in `sd` and then substracting it.
763 bool success = vmovd(sd, 2.0, cond);
764 CHECK(success);
765 vsubd(sd, sd, sd, cond);
766 } else {
767 if (sd < 16) {
768 SRegister low = static_cast<SRegister>(sd << 1);
769 SRegister high = static_cast<SRegister>(low + 1);
770 LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond);
771 if (High32Bits(int_value) == Low32Bits(int_value)) {
772 vmovs(high, low);
773 } else {
774 LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond);
775 }
776 } else {
777 LOG(FATAL) << "Unimplemented loading of double into a D register "
778 << "that cannot be split into two S registers";
779 }
780 }
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000781 }
782 }
783
Dave Allison65fcc2c2014-04-28 13:45:27 -0700784 virtual void MarkExceptionHandler(Label* label) = 0;
785 virtual void LoadFromOffset(LoadOperandType type,
786 Register reg,
787 Register base,
788 int32_t offset,
789 Condition cond = AL) = 0;
790 virtual void StoreToOffset(StoreOperandType type,
791 Register reg,
792 Register base,
793 int32_t offset,
794 Condition cond = AL) = 0;
795 virtual void LoadSFromOffset(SRegister reg,
796 Register base,
797 int32_t offset,
798 Condition cond = AL) = 0;
799 virtual void StoreSToOffset(SRegister reg,
800 Register base,
801 int32_t offset,
802 Condition cond = AL) = 0;
803 virtual void LoadDFromOffset(DRegister reg,
804 Register base,
805 int32_t offset,
806 Condition cond = AL) = 0;
807 virtual void StoreDToOffset(DRegister reg,
808 Register base,
809 int32_t offset,
810 Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700811
Dave Allison65fcc2c2014-04-28 13:45:27 -0700812 virtual void Push(Register rd, Condition cond = AL) = 0;
813 virtual void Pop(Register rd, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700814
Dave Allison65fcc2c2014-04-28 13:45:27 -0700815 virtual void PushList(RegList regs, Condition cond = AL) = 0;
816 virtual void PopList(RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700817
Dave Allison65fcc2c2014-04-28 13:45:27 -0700818 virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700819
820 // Convenience shift instructions. Use mov instruction with shifter operand
821 // for variants setting the status flags or using a register shift count.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100822 virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
823 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Dave Allison45fdb932014-06-25 12:37:10 -0700824
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100825 void Lsls(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
826 Lsl(rd, rm, shift_imm, cond, kCcSet);
827 }
828
829 virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
830 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
831
832 void Lsrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
833 Lsr(rd, rm, shift_imm, cond, kCcSet);
834 }
835
836 virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
837 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
838
839 void Asrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
840 Asr(rd, rm, shift_imm, cond, kCcSet);
841 }
842
843 virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
844 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
845
846 void Rors(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
847 Ror(rd, rm, shift_imm, cond, kCcSet);
848 }
849
850 virtual void Rrx(Register rd, Register rm,
851 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
852
853 void Rrxs(Register rd, Register rm, Condition cond = AL) {
854 Rrx(rd, rm, cond, kCcSet);
855 }
856
857 virtual void Lsl(Register rd, Register rm, Register rn,
858 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
859
860 void Lsls(Register rd, Register rm, Register rn, Condition cond = AL) {
861 Lsl(rd, rm, rn, cond, kCcSet);
862 }
863
864 virtual void Lsr(Register rd, Register rm, Register rn,
865 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
866
867 void Lsrs(Register rd, Register rm, Register rn, Condition cond = AL) {
868 Lsr(rd, rm, rn, cond, kCcSet);
869 }
870
871 virtual void Asr(Register rd, Register rm, Register rn,
872 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
873
874 void Asrs(Register rd, Register rm, Register rn, Condition cond = AL) {
875 Asr(rd, rm, rn, cond, kCcSet);
876 }
877
878 virtual void Ror(Register rd, Register rm, Register rn,
879 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
880
881 void Rors(Register rd, Register rm, Register rn, Condition cond = AL) {
882 Ror(rd, rm, rn, cond, kCcSet);
883 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700884
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000885 // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes,
886 // `shifter_op` contains the operand.
887 virtual bool ShifterOperandCanHold(Register rd,
888 Register rn,
889 Opcode opcode,
890 uint32_t immediate,
Vladimir Markof5c09c32015-12-17 12:08:08 +0000891 SetCc set_cc,
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000892 ShifterOperand* shifter_op) = 0;
Vladimir Markof5c09c32015-12-17 12:08:08 +0000893 bool ShifterOperandCanHold(Register rd,
894 Register rn,
895 Opcode opcode,
896 uint32_t immediate,
897 ShifterOperand* shifter_op) {
898 return ShifterOperandCanHold(rd, rn, opcode, immediate, kCcDontCare, shifter_op);
899 }
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000900
Nicolas Geoffray0ccb3832015-10-14 11:44:23 +0100901 virtual bool ShifterOperandCanAlwaysHold(uint32_t immediate) = 0;
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +0100902
Ian Rogers13735952014-10-08 12:43:28 -0700903 static bool IsInstructionForExceptionHandling(uintptr_t pc);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700904
Dave Allison65fcc2c2014-04-28 13:45:27 -0700905 virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
906 virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700907
Ian Rogers2c8f6532011-09-02 17:16:34 -0700908 //
909 // Overridden common assembler high-level functionality
910 //
Ian Rogers45a76cb2011-07-21 22:00:15 -0700911
Ian Rogers2c8f6532011-09-02 17:16:34 -0700912 // Emit code that will create an activation on the stack
Vladimir Marko32248382016-05-19 10:37:24 +0100913 void BuildFrame(size_t frame_size,
914 ManagedRegister method_reg,
915 ArrayRef<const ManagedRegister> callee_save_regs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700916 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -0700917
Ian Rogers2c8f6532011-09-02 17:16:34 -0700918 // Emit code that will remove an activation from the stack
Vladimir Marko32248382016-05-19 10:37:24 +0100919 void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs)
Dave Allison65fcc2c2014-04-28 13:45:27 -0700920 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700921
Ian Rogersdd7624d2014-03-14 17:43:00 -0700922 void IncreaseFrameSize(size_t adjust) OVERRIDE;
923 void DecreaseFrameSize(size_t adjust) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700924
925 // Store routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700926 void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
927 void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
928 void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700929
Ian Rogersdd7624d2014-03-14 17:43:00 -0700930 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700931
Ian Rogersdd7624d2014-03-14 17:43:00 -0700932 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
933 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700934
Ian Rogersdd7624d2014-03-14 17:43:00 -0700935 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
936 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700937
Ian Rogersdd7624d2014-03-14 17:43:00 -0700938 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700939
Ian Rogersdd7624d2014-03-14 17:43:00 -0700940 void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
941 ManagedRegister scratch) OVERRIDE;
Ian Rogersbdb03912011-09-14 00:55:44 -0700942
Ian Rogers2c8f6532011-09-02 17:16:34 -0700943 // Load routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700944 void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700945
Ian Rogersdd7624d2014-03-14 17:43:00 -0700946 void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700947
Mathieu Chartiere401d142015-04-22 13:56:20 -0700948 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700949
Mathieu Chartiere401d142015-04-22 13:56:20 -0700950 void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100951 bool unpoison_reference) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700952
Ian Rogersdd7624d2014-03-14 17:43:00 -0700953 void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700954
Ian Rogersdd7624d2014-03-14 17:43:00 -0700955 void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700956
957 // Copying routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700958 void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700959
Ian Rogersdd7624d2014-03-14 17:43:00 -0700960 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
961 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700962
Ian Rogersdd7624d2014-03-14 17:43:00 -0700963 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
964 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700965
Ian Rogersdd7624d2014-03-14 17:43:00 -0700966 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700967
Ian Rogersdd7624d2014-03-14 17:43:00 -0700968 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700969
Ian Rogersdd7624d2014-03-14 17:43:00 -0700970 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch,
971 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700972
Ian Rogersdd7624d2014-03-14 17:43:00 -0700973 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch,
974 size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700975
Ian Rogersdd7624d2014-03-14 17:43:00 -0700976 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch,
977 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700978
Ian Rogersdd7624d2014-03-14 17:43:00 -0700979 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
980 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700981
Ian Rogersdd7624d2014-03-14 17:43:00 -0700982 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
983 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700984
jeffhao58136ca2012-05-24 13:40:11 -0700985 // Sign extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700986 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao58136ca2012-05-24 13:40:11 -0700987
jeffhaocee4d0c2012-06-15 14:42:01 -0700988 // Zero extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700989 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhaocee4d0c2012-06-15 14:42:01 -0700990
Ian Rogers2c8f6532011-09-02 17:16:34 -0700991 // Exploit fast access in managed code to Thread::Current()
Ian Rogersdd7624d2014-03-14 17:43:00 -0700992 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
993 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700994
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700995 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
Ian Rogers2c8f6532011-09-02 17:16:34 -0700996 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700997 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700998 // null.
999 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
1000 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001001
Mathieu Chartier2cebb242015-04-21 16:50:40 -07001002 // Set up out_off to hold a Object** into the handle scope, or to be null if the
Ian Rogers2c8f6532011-09-02 17:16:34 -07001003 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -07001004 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
1005 ManagedRegister scratch, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001006
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07001007 // src holds a handle scope entry (Object**) load this into dst
1008 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001009
1010 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
1011 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001012 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
1013 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001014
1015 // Call to address held at [base+offset]
Ian Rogersdd7624d2014-03-14 17:43:00 -07001016 void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
1017 void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
1018 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001019
Ian Rogers2c8f6532011-09-02 17:16:34 -07001020 // Generate code to check if Thread::Current()->exception_ is non-null
1021 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001022 void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -07001023
Dave Allison65fcc2c2014-04-28 13:45:27 -07001024 static uint32_t ModifiedImmediate(uint32_t value);
Carl Shapiroa2e18e12011-06-21 18:57:55 -07001025
Dave Allison45fdb932014-06-25 12:37:10 -07001026 static bool IsLowRegister(Register r) {
1027 return r < R8;
1028 }
1029
1030 static bool IsHighRegister(Register r) {
1031 return r >= R8;
1032 }
1033
Roland Levillain4d027112015-07-01 15:41:14 +01001034 //
1035 // Heap poisoning.
1036 //
1037
1038 // Poison a heap reference contained in `reg`.
1039 void PoisonHeapReference(Register reg) {
1040 // reg = -reg.
1041 rsb(reg, reg, ShifterOperand(0));
1042 }
1043 // Unpoison a heap reference contained in `reg`.
1044 void UnpoisonHeapReference(Register reg) {
1045 // reg = -reg.
1046 rsb(reg, reg, ShifterOperand(0));
1047 }
1048 // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
1049 void MaybeUnpoisonHeapReference(Register reg) {
1050 if (kPoisonHeapReferences) {
1051 UnpoisonHeapReference(reg);
1052 }
1053 }
1054
Andreas Gampe85b62f22015-09-09 13:15:38 -07001055 void Jump(Label* label) OVERRIDE {
1056 b(label);
1057 }
1058
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001059 // Jump table support. This is split into three functions:
1060 //
1061 // * CreateJumpTable creates the internal metadata to track the jump targets, and emits code to
1062 // load the base address of the jump table.
1063 //
1064 // * EmitJumpTableDispatch emits the code to actually jump, assuming that the right table value
1065 // has been loaded into a register already.
1066 //
1067 // * FinalizeTables emits the jump table into the literal pool. This can only be called after the
1068 // labels for the jump targets have been finalized.
1069
1070 // Create a jump table for the given labels that will be emitted when finalizing. Create a load
1071 // sequence (or placeholder) that stores the base address into the given register. When the table
1072 // is emitted, offsets will be relative to the location EmitJumpTableDispatch was called on (the
1073 // anchor).
1074 virtual JumpTable* CreateJumpTable(std::vector<Label*>&& labels, Register base_reg) = 0;
1075
1076 // Emit the jump-table jump, assuming that the right value was loaded into displacement_reg.
1077 virtual void EmitJumpTableDispatch(JumpTable* jump_table, Register displacement_reg) = 0;
1078
1079 // Bind a Label that needs to be updated by the assembler in FinalizeCode() if its position
1080 // changes due to branch/literal fixup.
1081 void BindTrackedLabel(Label* label) {
1082 Bind(label);
1083 tracked_labels_.push_back(label);
1084 }
1085
Dave Allison65fcc2c2014-04-28 13:45:27 -07001086 protected:
Vladimir Marko93205e32016-04-13 11:59:46 +01001087 explicit ArmAssembler(ArenaAllocator* arena)
1088 : Assembler(arena), tracked_labels_(arena->Adapter(kArenaAllocAssembler)) {}
1089
Carl Shapiroa2e18e12011-06-21 18:57:55 -07001090 // Returns whether or not the given register is used for passing parameters.
1091 static int RegisterCompare(const Register* reg1, const Register* reg2) {
1092 return *reg1 - *reg2;
1093 }
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001094
1095 void FinalizeTrackedLabels();
1096
1097 // Tracked labels. Use a vector, as we need to sort before adjusting.
Vladimir Marko93205e32016-04-13 11:59:46 +01001098 ArenaVector<Label*> tracked_labels_;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001099};
1100
Ian Rogers2c8f6532011-09-02 17:16:34 -07001101// Slowpath entered when Thread::Current()->_exception is non-null
Ian Rogersdd7624d2014-03-14 17:43:00 -07001102class ArmExceptionSlowPath FINAL : public SlowPath {
Ian Rogers2c8f6532011-09-02 17:16:34 -07001103 public:
Roland Levillain3887c462015-08-12 18:15:42 +01001104 ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust)
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001105 : scratch_(scratch), stack_adjust_(stack_adjust) {
1106 }
Ian Rogersdd7624d2014-03-14 17:43:00 -07001107 void Emit(Assembler *sp_asm) OVERRIDE;
Ian Rogers67375ac2011-09-14 00:55:44 -07001108 private:
1109 const ArmManagedRegister scratch_;
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001110 const size_t stack_adjust_;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001111};
1112
Ian Rogers2c8f6532011-09-02 17:16:34 -07001113} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -07001114} // namespace art
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001115
Ian Rogers166db042013-07-26 12:05:57 -07001116#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_