blob: 4a6e6d7c3fde79064ea6f0770703104206a90a89 [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 Marko80afd022015-05-19 18:08:00 +010023#include "base/bit_utils.h"
Elliott Hughes07ed66b2012-12-12 18:34:25 -080024#include "base/logging.h"
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070025#include "base/value_object.h"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070026#include "constants_arm.h"
Ian Rogers166db042013-07-26 12:05:57 -070027#include "utils/arm/managed_register_arm.h"
28#include "utils/assembler.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070029#include "offsets.h"
Carl Shapiroa2e18e12011-06-21 18:57:55 -070030
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070031namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070032namespace arm {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070033
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +000034class Arm32Assembler;
35class Thumb2Assembler;
36
Vladimir Markocf93a5c2015-06-16 11:33:24 +000037// Assembler literal is a value embedded in code, retrieved using a PC-relative load.
38class Literal {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000039 public:
Vladimir Markocf93a5c2015-06-16 11:33:24 +000040 static constexpr size_t kMaxSize = 8;
41
42 Literal(uint32_t size, const uint8_t* data)
43 : label_(), size_(size) {
44 DCHECK_LE(size, Literal::kMaxSize);
45 memcpy(data_, data, size);
46 }
47
48 template <typename T>
49 T GetValue() const {
50 DCHECK_EQ(size_, sizeof(T));
51 T value;
52 memcpy(&value, data_, sizeof(T));
53 return value;
54 }
55
56 uint32_t GetSize() const {
57 return size_;
58 }
59
60 const uint8_t* GetData() const {
61 return data_;
62 }
63
64 Label* GetLabel() {
65 return &label_;
66 }
67
68 const Label* GetLabel() const {
69 return &label_;
70 }
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000071
72 private:
Vladimir Markocf93a5c2015-06-16 11:33:24 +000073 Label label_;
74 const uint32_t size_;
75 uint8_t data_[kMaxSize];
76
77 DISALLOW_COPY_AND_ASSIGN(Literal);
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000078};
79
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070080// Jump table: table of labels emitted after the literals. Similar to literals.
81class JumpTable {
82 public:
83 explicit JumpTable(std::vector<Label*>&& labels)
84 : label_(), anchor_label_(), labels_(std::move(labels)) {
85 }
86
87 uint32_t GetSize() const {
88 return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t);
89 }
90
91 const std::vector<Label*>& GetData() const {
92 return labels_;
93 }
94
95 Label* GetLabel() {
96 return &label_;
97 }
98
99 const Label* GetLabel() const {
100 return &label_;
101 }
102
103 Label* GetAnchorLabel() {
104 return &anchor_label_;
105 }
106
107 const Label* GetAnchorLabel() const {
108 return &anchor_label_;
109 }
110
111 private:
112 Label label_;
113 Label anchor_label_;
114 std::vector<Label*> labels_;
115
116 DISALLOW_COPY_AND_ASSIGN(JumpTable);
117};
118
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700119class ShifterOperand {
120 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700121 ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
122 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700123 }
124
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100125 explicit ShifterOperand(uint32_t immed);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700126
127 // Data-processing operands - Register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700128 explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister),
129 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700130 }
131
Dave Allison65fcc2c2014-04-28 13:45:27 -0700132 ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister),
133 rs_(kNoRegister),
134 is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) {
135 }
136
137 ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm),
138 rs_(kNoRegister),
139 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700140 }
141
142 // Data-processing operands - Logical shift/rotate by register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700143 ShifterOperand(Register rm, Shift shift, Register rs) : type_(kRegister), rm_(rm),
144 rs_(rs),
145 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700146 }
147
Dave Allison65fcc2c2014-04-28 13:45:27 -0700148 bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700149
150 uint32_t type() const {
151 CHECK(is_valid());
152 return type_;
153 }
154
Dave Allison65fcc2c2014-04-28 13:45:27 -0700155 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700156 uint32_t encodingThumb() const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700157
158 bool IsEmpty() const {
159 return type_ == kUnknown;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700160 }
161
Dave Allison65fcc2c2014-04-28 13:45:27 -0700162 bool IsImmediate() const {
163 return type_ == kImmediate;
164 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700165
Dave Allison65fcc2c2014-04-28 13:45:27 -0700166 bool IsRegister() const {
167 return type_ == kRegister;
168 }
169
170 bool IsShift() const {
171 return is_shift_;
172 }
173
174 uint32_t GetImmediate() const {
175 return immed_;
176 }
177
178 Shift GetShift() const {
179 return shift_;
180 }
181
182 Register GetRegister() const {
183 return rm_;
184 }
185
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000186 Register GetSecondRegister() const {
187 return rs_;
188 }
189
Dave Allison65fcc2c2014-04-28 13:45:27 -0700190 enum Type {
191 kUnknown = -1,
192 kRegister,
193 kImmediate
194 };
195
Dave Allison65fcc2c2014-04-28 13:45:27 -0700196 private:
197 Type type_;
198 Register rm_;
199 Register rs_;
200 bool is_rotate_;
201 bool is_shift_;
202 Shift shift_;
203 uint32_t rotate_;
204 uint32_t immed_;
205
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000206 friend class Arm32Assembler;
207 friend class Thumb2Assembler;
208
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700209#ifdef SOURCE_ASSEMBLER_SUPPORT
210 friend class BinaryAssembler;
211#endif
212};
213
214
215enum LoadOperandType {
216 kLoadSignedByte,
217 kLoadUnsignedByte,
218 kLoadSignedHalfword,
219 kLoadUnsignedHalfword,
220 kLoadWord,
221 kLoadWordPair,
222 kLoadSWord,
223 kLoadDWord
224};
225
226
227enum StoreOperandType {
228 kStoreByte,
229 kStoreHalfword,
230 kStoreWord,
231 kStoreWordPair,
232 kStoreSWord,
233 kStoreDWord
234};
235
236
237// Load/store multiple addressing mode.
238enum BlockAddressMode {
239 // bit encoding P U W
240 DA = (0|0|0) << 21, // decrement after
241 IA = (0|4|0) << 21, // increment after
242 DB = (8|0|0) << 21, // decrement before
243 IB = (8|4|0) << 21, // increment before
244 DA_W = (0|0|1) << 21, // decrement after with writeback to base
245 IA_W = (0|4|1) << 21, // increment after with writeback to base
246 DB_W = (8|0|1) << 21, // decrement before with writeback to base
247 IB_W = (8|4|1) << 21 // increment before with writeback to base
248};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700249inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) {
250 os << static_cast<int>(rhs);
251 return os;
252}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700253
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700254class Address : public ValueObject {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700255 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700256 // Memory operand addressing mode (in ARM encoding form. For others we need
257 // to adjust)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700258 enum Mode {
259 // bit encoding P U W
260 Offset = (8|4|0) << 21, // offset (w/o writeback to base)
261 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
262 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
263 NegOffset = (8|0|0) << 21, // negative offset (w/o writeback to base)
264 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
265 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
266 };
267
Dave Allison45fdb932014-06-25 12:37:10 -0700268 Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
269 offset_(offset),
270 am_(am), is_immed_offset_(true), shift_(LSL) {
271 }
272
273 Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
274 am_(am), is_immed_offset_(false), shift_(LSL) {
275 CHECK_NE(rm, PC);
276 }
277
278 Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
279 rn_(rn), rm_(rm), offset_(count),
280 am_(am), is_immed_offset_(false), shift_(shift) {
281 CHECK_NE(rm, PC);
282 }
283
284 // LDR(literal) - pc relative load.
285 explicit Address(int32_t offset) :
286 rn_(PC), rm_(R0), offset_(offset),
287 am_(Offset), is_immed_offset_(false), shift_(LSL) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700288 }
289
Dave Allison65fcc2c2014-04-28 13:45:27 -0700290 static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
291 static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset);
292
293 static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset);
294 static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
295
296 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700297 uint32_t encodingThumb(bool is_32bit) const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700298
299 uint32_t encoding3() const;
300 uint32_t vencoding() const;
301
302 uint32_t encodingThumbLdrdStrd() const;
303
304 Register GetRegister() const {
305 return rn_;
306 }
307
Dave Allison45fdb932014-06-25 12:37:10 -0700308 Register GetRegisterOffset() const {
309 return rm_;
310 }
311
Dave Allison65fcc2c2014-04-28 13:45:27 -0700312 int32_t GetOffset() const {
313 return offset_;
314 }
315
316 Mode GetMode() const {
317 return am_;
318 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700319
Dave Allison45fdb932014-06-25 12:37:10 -0700320 bool IsImmediate() const {
321 return is_immed_offset_;
322 }
323
324 Shift GetShift() const {
325 return shift_;
326 }
327
328 int32_t GetShiftCount() const {
329 CHECK(!is_immed_offset_);
330 return offset_;
331 }
332
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700333 private:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700334 const Register rn_;
335 const Register rm_;
336 const int32_t offset_; // Used as shift amount for register offset.
337 const Mode am_;
338 const bool is_immed_offset_;
339 const Shift shift_;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700340};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700341inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) {
342 os << static_cast<int>(rhs);
343 return os;
344}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700345
Dave Allison65fcc2c2014-04-28 13:45:27 -0700346// Instruction encoding bits.
347enum {
348 H = 1 << 5, // halfword (or byte)
349 L = 1 << 20, // load (or store)
350 S = 1 << 20, // set condition code (or leave unchanged)
351 W = 1 << 21, // writeback base register (or leave unchanged)
352 A = 1 << 21, // accumulate in multiply instruction (or not)
353 B = 1 << 22, // unsigned byte (or word)
354 N = 1 << 22, // long (or short)
355 U = 1 << 23, // positive (or negative) offset/index
356 P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing)
357 I = 1 << 25, // immediate shifter operand (or not)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700358
Dave Allison65fcc2c2014-04-28 13:45:27 -0700359 B0 = 1,
360 B1 = 1 << 1,
361 B2 = 1 << 2,
362 B3 = 1 << 3,
363 B4 = 1 << 4,
364 B5 = 1 << 5,
365 B6 = 1 << 6,
366 B7 = 1 << 7,
367 B8 = 1 << 8,
368 B9 = 1 << 9,
369 B10 = 1 << 10,
370 B11 = 1 << 11,
371 B12 = 1 << 12,
372 B13 = 1 << 13,
373 B14 = 1 << 14,
374 B15 = 1 << 15,
375 B16 = 1 << 16,
376 B17 = 1 << 17,
377 B18 = 1 << 18,
378 B19 = 1 << 19,
379 B20 = 1 << 20,
380 B21 = 1 << 21,
381 B22 = 1 << 22,
382 B23 = 1 << 23,
383 B24 = 1 << 24,
384 B25 = 1 << 25,
385 B26 = 1 << 26,
386 B27 = 1 << 27,
387 B28 = 1 << 28,
388 B29 = 1 << 29,
389 B30 = 1 << 30,
390 B31 = 1 << 31,
391
392 // Instruction bit masks.
393 RdMask = 15 << 12, // in str instruction
394 CondMask = 15 << 28,
395 CoprocessorMask = 15 << 8,
396 OpCodeMask = 15 << 21, // in data-processing instructions
397 Imm24Mask = (1 << 24) - 1,
398 Off12Mask = (1 << 12) - 1,
399
400 // ldrex/strex register field encodings.
401 kLdExRnShift = 16,
402 kLdExRtShift = 12,
403 kStrExRnShift = 16,
404 kStrExRdShift = 12,
405 kStrExRtShift = 0,
406};
407
408// IfThen state for IT instructions.
409enum ItState {
410 kItOmitted,
411 kItThen,
412 kItT = kItThen,
413 kItElse,
414 kItE = kItElse
415};
416
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100417// Set condition codes request.
418enum SetCc {
419 kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
420 kCcSet,
421 kCcKeep,
422};
423
Dave Allison65fcc2c2014-04-28 13:45:27 -0700424constexpr uint32_t kNoItCondition = 3;
425constexpr uint32_t kInvalidModifiedImmediate = -1;
426
427extern const char* kRegisterNames[];
428extern const char* kConditionNames[];
Dave Allison65fcc2c2014-04-28 13:45:27 -0700429
430// This is an abstract ARM assembler. Subclasses provide assemblers for the individual
431// instruction sets (ARM32, Thumb2, etc.)
432//
433class ArmAssembler : public Assembler {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700434 public:
Ian Rogers2c8f6532011-09-02 17:16:34 -0700435 virtual ~ArmAssembler() {}
buzbeec143c552011-08-20 17:38:58 -0700436
Dave Allison65fcc2c2014-04-28 13:45:27 -0700437 // Is this assembler for the thumb instruction set?
438 virtual bool IsThumb() const = 0;
439
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700440 // Data-processing instructions.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100441 virtual void and_(Register rd, Register rn, const ShifterOperand& so,
442 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700443
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100444 virtual void ands(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
445 and_(rd, rn, so, cond, kCcSet);
446 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700447
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100448 virtual void eor(Register rd, Register rn, const ShifterOperand& so,
449 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700450
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100451 virtual void eors(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
452 eor(rd, rn, so, cond, kCcSet);
453 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700454
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100455 virtual void sub(Register rd, Register rn, const ShifterOperand& so,
456 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700457
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100458 virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
459 sub(rd, rn, so, cond, kCcSet);
460 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700461
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100462 virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
463 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700464
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100465 virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
466 rsb(rd, rn, so, cond, kCcSet);
467 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700468
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100469 virtual void add(Register rd, Register rn, const ShifterOperand& so,
470 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
471
472 virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
473 add(rd, rn, so, cond, kCcSet);
474 }
475
476 virtual void adc(Register rd, Register rn, const ShifterOperand& so,
477 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
478
479 virtual void adcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
480 adc(rd, rn, so, cond, kCcSet);
481 }
482
483 virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
484 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
485
486 virtual void sbcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
487 sbc(rd, rn, so, cond, kCcSet);
488 }
489
490 virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
491 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
492
493 virtual void rscs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
494 rsc(rd, rn, so, cond, kCcSet);
495 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700496
Dave Allison65fcc2c2014-04-28 13:45:27 -0700497 virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700498
Dave Allison65fcc2c2014-04-28 13:45:27 -0700499 virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700500
Dave Allison65fcc2c2014-04-28 13:45:27 -0700501 virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700502
Dave Allison65fcc2c2014-04-28 13:45:27 -0700503 virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700504
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100505 virtual void orr(Register rd, Register rn, const ShifterOperand& so,
506 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700507
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100508 virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
509 orr(rd, rn, so, cond, kCcSet);
510 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700511
Vladimir Markod2b4ca22015-09-14 15:13:26 +0100512 virtual void orn(Register rd, Register rn, const ShifterOperand& so,
513 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
514
515 virtual void orns(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
516 orn(rd, rn, so, cond, kCcSet);
517 }
518
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100519 virtual void mov(Register rd, const ShifterOperand& so,
520 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700521
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100522 virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) {
523 mov(rd, so, cond, kCcSet);
524 }
525
526 virtual void bic(Register rd, Register rn, const ShifterOperand& so,
527 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
528
529 virtual void bics(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
530 bic(rd, rn, so, cond, kCcSet);
531 }
532
533 virtual void mvn(Register rd, const ShifterOperand& so,
534 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
535
536 virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) {
537 mvn(rd, so, cond, kCcSet);
538 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700539
540 // Miscellaneous data-processing instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700541 virtual void clz(Register rd, Register rm, Condition cond = AL) = 0;
542 virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0;
543 virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0;
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100544 virtual void rbit(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700545
546 // Multiply instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700547 virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
548 virtual void mla(Register rd, Register rn, Register rm, Register ra,
549 Condition cond = AL) = 0;
550 virtual void mls(Register rd, Register rn, Register rm, Register ra,
551 Condition cond = AL) = 0;
Zheng Xuc6667102015-05-15 16:08:45 +0800552 virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
553 Condition cond = AL) = 0;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700554 virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
555 Condition cond = AL) = 0;
556
557 virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
558 virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700559
Roland Levillain981e4542014-11-14 11:47:14 +0000560 // Bit field extract instructions.
Roland Levillain51d3fc42014-11-13 14:11:42 +0000561 virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
562 Condition cond = AL) = 0;
Roland Levillain981e4542014-11-14 11:47:14 +0000563 virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
564 Condition cond = AL) = 0;
Roland Levillain51d3fc42014-11-13 14:11:42 +0000565
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700566 // Load/store instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700567 virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
568 virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700569
Dave Allison65fcc2c2014-04-28 13:45:27 -0700570 virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0;
571 virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700572
Dave Allison65fcc2c2014-04-28 13:45:27 -0700573 virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0;
574 virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700575
Dave Allison65fcc2c2014-04-28 13:45:27 -0700576 virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0;
577 virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700578
Dave Allison65fcc2c2014-04-28 13:45:27 -0700579 virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0;
580 virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700581
Dave Allison65fcc2c2014-04-28 13:45:27 -0700582 virtual void ldm(BlockAddressMode am, Register base,
583 RegList regs, Condition cond = AL) = 0;
584 virtual void stm(BlockAddressMode am, Register base,
585 RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700586
Dave Allison65fcc2c2014-04-28 13:45:27 -0700587 virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
588 virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
Calin Juravle52c48962014-12-16 17:02:57 +0000589 virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
590 virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700591
592 // Miscellaneous instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700593 virtual void clrex(Condition cond = AL) = 0;
594 virtual void nop(Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700595
596 // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700597 virtual void bkpt(uint16_t imm16) = 0;
598 virtual void svc(uint32_t imm24) = 0;
599
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700600 virtual void it(Condition firstcond ATTRIBUTE_UNUSED,
601 ItState i1 ATTRIBUTE_UNUSED = kItOmitted,
602 ItState i2 ATTRIBUTE_UNUSED = kItOmitted,
603 ItState i3 ATTRIBUTE_UNUSED = kItOmitted) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700604 // Ignored if not supported.
605 }
606
607 virtual void cbz(Register rn, Label* target) = 0;
608 virtual void cbnz(Register rn, Label* target) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700609
610 // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
Dave Allison65fcc2c2014-04-28 13:45:27 -0700611 virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0;
612 virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0;
613 virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0;
614 virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0;
615 virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0;
616 virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0;
617 virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
618 virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700619
620 // Returns false if the immediate cannot be encoded.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700621 virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0;
622 virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700623
Dave Allison65fcc2c2014-04-28 13:45:27 -0700624 virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
625 virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
626 virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
627 virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700628
Dave Allison65fcc2c2014-04-28 13:45:27 -0700629 virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
630 virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
631 virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
632 virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
633 virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
634 virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
635 virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
636 virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
637 virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
638 virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
639 virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
640 virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700641
Dave Allison65fcc2c2014-04-28 13:45:27 -0700642 virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0;
643 virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
644 virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
645 virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
646 virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0;
647 virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700648
Dave Allison65fcc2c2014-04-28 13:45:27 -0700649 virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0;
650 virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0;
651 virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0;
652 virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0;
653 virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0;
654 virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0;
655 virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0;
656 virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0;
657 virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0;
658 virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700659
Dave Allison65fcc2c2014-04-28 13:45:27 -0700660 virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0;
661 virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
662 virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0;
663 virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0;
664 virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR
665
666 virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0;
667 virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
668 virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
669 virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700670
671 // Branch instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700672 virtual void b(Label* label, Condition cond = AL) = 0;
673 virtual void bl(Label* label, Condition cond = AL) = 0;
674 virtual void blx(Register rm, Condition cond = AL) = 0;
675 virtual void bx(Register rm, Condition cond = AL) = 0;
676
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100677 // Memory barriers.
678 virtual void dmb(DmbOptions flavor) = 0;
679
Dave Allison65fcc2c2014-04-28 13:45:27 -0700680 void Pad(uint32_t bytes);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700681
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000682 // Adjust label position.
683 void AdjustLabelPosition(Label* label) {
684 DCHECK(label->IsBound());
685 uint32_t old_position = static_cast<uint32_t>(label->Position());
686 uint32_t new_position = GetAdjustedPosition(old_position);
687 label->Reinitialize();
688 DCHECK_GE(static_cast<int>(new_position), 0);
689 label->BindTo(static_cast<int>(new_position));
690 }
691
692 // Get the final position of a label after local fixup based on the old position
693 // recorded before FinalizeCode().
694 virtual uint32_t GetAdjustedPosition(uint32_t old_position) = 0;
695
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700696 // Macros.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700697 // Most of these are pure virtual as they need to be implemented per instruction set.
698
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000699 // Create a new literal with a given value.
700 // NOTE: Force the template parameter to be explicitly specified. In the absence of
701 // std::omit_from_type_deduction<T> or std::identity<T>, use std::decay<T>.
702 template <typename T>
703 Literal* NewLiteral(typename std::decay<T>::type value) {
704 static_assert(std::is_integral<T>::value, "T must be an integral type.");
705 return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
706 }
707
708 // Create a new literal with the given data.
709 virtual Literal* NewLiteral(size_t size, const uint8_t* data) = 0;
710
711 // Load literal.
712 virtual void LoadLiteral(Register rt, Literal* literal) = 0;
713 virtual void LoadLiteral(Register rt, Register rt2, Literal* literal) = 0;
714 virtual void LoadLiteral(SRegister sd, Literal* literal) = 0;
715 virtual void LoadLiteral(DRegister dd, Literal* literal) = 0;
716
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700717 // Add signed constant value to rd. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700718 virtual void AddConstant(Register rd, Register rn, int32_t value,
Vladimir Marko449b1092015-09-08 12:16:45 +0100719 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
720 void AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond = AL) {
721 AddConstant(rd, rn, value, cond, kCcSet);
722 }
723 void AddConstant(Register rd, int32_t value, Condition cond = AL, SetCc set_cc = kCcDontCare) {
724 AddConstant(rd, rd, value, cond, set_cc);
725 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700726
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700727 virtual void CmpConstant(Register rn, int32_t value, Condition cond = AL) = 0;
728
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700729 // Load and Store. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700730 virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000731 void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {
732 if (!vmovs(sd, value, cond)) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000733 int32_t int_value = bit_cast<int32_t, float>(value);
734 if (int_value == bit_cast<int32_t, float>(0.0f)) {
735 // 0.0 is quite common, so we special case it by loading
736 // 2.0 in `sd` and then substracting it.
737 bool success = vmovs(sd, 2.0, cond);
738 CHECK(success);
739 vsubs(sd, sd, sd, cond);
740 } else {
741 LoadImmediate(IP, int_value, cond);
742 vmovsr(sd, IP, cond);
743 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000744 }
745 }
746
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000747 void LoadDImmediate(DRegister sd, double value, Condition cond = AL) {
748 if (!vmovd(sd, value, cond)) {
749 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000750 if (int_value == bit_cast<uint64_t, double>(0.0)) {
751 // 0.0 is quite common, so we special case it by loading
752 // 2.0 in `sd` and then substracting it.
753 bool success = vmovd(sd, 2.0, cond);
754 CHECK(success);
755 vsubd(sd, sd, sd, cond);
756 } else {
757 if (sd < 16) {
758 SRegister low = static_cast<SRegister>(sd << 1);
759 SRegister high = static_cast<SRegister>(low + 1);
760 LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond);
761 if (High32Bits(int_value) == Low32Bits(int_value)) {
762 vmovs(high, low);
763 } else {
764 LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond);
765 }
766 } else {
767 LOG(FATAL) << "Unimplemented loading of double into a D register "
768 << "that cannot be split into two S registers";
769 }
770 }
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000771 }
772 }
773
Dave Allison65fcc2c2014-04-28 13:45:27 -0700774 virtual void MarkExceptionHandler(Label* label) = 0;
775 virtual void LoadFromOffset(LoadOperandType type,
776 Register reg,
777 Register base,
778 int32_t offset,
779 Condition cond = AL) = 0;
780 virtual void StoreToOffset(StoreOperandType type,
781 Register reg,
782 Register base,
783 int32_t offset,
784 Condition cond = AL) = 0;
785 virtual void LoadSFromOffset(SRegister reg,
786 Register base,
787 int32_t offset,
788 Condition cond = AL) = 0;
789 virtual void StoreSToOffset(SRegister reg,
790 Register base,
791 int32_t offset,
792 Condition cond = AL) = 0;
793 virtual void LoadDFromOffset(DRegister reg,
794 Register base,
795 int32_t offset,
796 Condition cond = AL) = 0;
797 virtual void StoreDToOffset(DRegister reg,
798 Register base,
799 int32_t offset,
800 Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700801
Dave Allison65fcc2c2014-04-28 13:45:27 -0700802 virtual void Push(Register rd, Condition cond = AL) = 0;
803 virtual void Pop(Register rd, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700804
Dave Allison65fcc2c2014-04-28 13:45:27 -0700805 virtual void PushList(RegList regs, Condition cond = AL) = 0;
806 virtual void PopList(RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700807
Dave Allison65fcc2c2014-04-28 13:45:27 -0700808 virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700809
810 // Convenience shift instructions. Use mov instruction with shifter operand
811 // for variants setting the status flags or using a register shift count.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100812 virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
813 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Dave Allison45fdb932014-06-25 12:37:10 -0700814
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100815 void Lsls(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
816 Lsl(rd, rm, shift_imm, cond, kCcSet);
817 }
818
819 virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
820 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
821
822 void Lsrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
823 Lsr(rd, rm, shift_imm, cond, kCcSet);
824 }
825
826 virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
827 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
828
829 void Asrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
830 Asr(rd, rm, shift_imm, cond, kCcSet);
831 }
832
833 virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
834 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
835
836 void Rors(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
837 Ror(rd, rm, shift_imm, cond, kCcSet);
838 }
839
840 virtual void Rrx(Register rd, Register rm,
841 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
842
843 void Rrxs(Register rd, Register rm, Condition cond = AL) {
844 Rrx(rd, rm, cond, kCcSet);
845 }
846
847 virtual void Lsl(Register rd, Register rm, Register rn,
848 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
849
850 void Lsls(Register rd, Register rm, Register rn, Condition cond = AL) {
851 Lsl(rd, rm, rn, cond, kCcSet);
852 }
853
854 virtual void Lsr(Register rd, Register rm, Register rn,
855 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
856
857 void Lsrs(Register rd, Register rm, Register rn, Condition cond = AL) {
858 Lsr(rd, rm, rn, cond, kCcSet);
859 }
860
861 virtual void Asr(Register rd, Register rm, Register rn,
862 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
863
864 void Asrs(Register rd, Register rm, Register rn, Condition cond = AL) {
865 Asr(rd, rm, rn, cond, kCcSet);
866 }
867
868 virtual void Ror(Register rd, Register rm, Register rn,
869 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
870
871 void Rors(Register rd, Register rm, Register rn, Condition cond = AL) {
872 Ror(rd, rm, rn, cond, kCcSet);
873 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700874
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000875 // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes,
876 // `shifter_op` contains the operand.
877 virtual bool ShifterOperandCanHold(Register rd,
878 Register rn,
879 Opcode opcode,
880 uint32_t immediate,
881 ShifterOperand* shifter_op) = 0;
882
Nicolas Geoffray0ccb3832015-10-14 11:44:23 +0100883 virtual bool ShifterOperandCanAlwaysHold(uint32_t immediate) = 0;
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +0100884
Ian Rogers13735952014-10-08 12:43:28 -0700885 static bool IsInstructionForExceptionHandling(uintptr_t pc);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700886
Dave Allison65fcc2c2014-04-28 13:45:27 -0700887 virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
888 virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700889
Ian Rogers2c8f6532011-09-02 17:16:34 -0700890 //
891 // Overridden common assembler high-level functionality
892 //
Ian Rogers45a76cb2011-07-21 22:00:15 -0700893
Ian Rogers2c8f6532011-09-02 17:16:34 -0700894 // Emit code that will create an activation on the stack
Ian Rogersdd7624d2014-03-14 17:43:00 -0700895 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
896 const std::vector<ManagedRegister>& callee_save_regs,
897 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -0700898
Ian Rogers2c8f6532011-09-02 17:16:34 -0700899 // Emit code that will remove an activation from the stack
Ian Rogersdd7624d2014-03-14 17:43:00 -0700900 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
Dave Allison65fcc2c2014-04-28 13:45:27 -0700901 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700902
Ian Rogersdd7624d2014-03-14 17:43:00 -0700903 void IncreaseFrameSize(size_t adjust) OVERRIDE;
904 void DecreaseFrameSize(size_t adjust) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700905
906 // Store routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700907 void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
908 void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
909 void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700910
Ian Rogersdd7624d2014-03-14 17:43:00 -0700911 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700912
Ian Rogersdd7624d2014-03-14 17:43:00 -0700913 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
914 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700915
Ian Rogersdd7624d2014-03-14 17:43:00 -0700916 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
917 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700918
Ian Rogersdd7624d2014-03-14 17:43:00 -0700919 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700920
Ian Rogersdd7624d2014-03-14 17:43:00 -0700921 void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
922 ManagedRegister scratch) OVERRIDE;
Ian Rogersbdb03912011-09-14 00:55:44 -0700923
Ian Rogers2c8f6532011-09-02 17:16:34 -0700924 // Load routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700925 void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700926
Ian Rogersdd7624d2014-03-14 17:43:00 -0700927 void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700928
Mathieu Chartiere401d142015-04-22 13:56:20 -0700929 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700930
Mathieu Chartiere401d142015-04-22 13:56:20 -0700931 void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100932 bool unpoison_reference) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700933
Ian Rogersdd7624d2014-03-14 17:43:00 -0700934 void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700935
Ian Rogersdd7624d2014-03-14 17:43:00 -0700936 void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700937
938 // Copying routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700939 void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700940
Ian Rogersdd7624d2014-03-14 17:43:00 -0700941 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
942 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700943
Ian Rogersdd7624d2014-03-14 17:43:00 -0700944 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
945 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700946
Ian Rogersdd7624d2014-03-14 17:43:00 -0700947 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700948
Ian Rogersdd7624d2014-03-14 17:43:00 -0700949 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700950
Ian Rogersdd7624d2014-03-14 17:43:00 -0700951 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch,
952 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700953
Ian Rogersdd7624d2014-03-14 17:43:00 -0700954 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch,
955 size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700956
Ian Rogersdd7624d2014-03-14 17:43:00 -0700957 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch,
958 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700959
Ian Rogersdd7624d2014-03-14 17:43:00 -0700960 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
961 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700962
Ian Rogersdd7624d2014-03-14 17:43:00 -0700963 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
964 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700965
jeffhao58136ca2012-05-24 13:40:11 -0700966 // Sign extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700967 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao58136ca2012-05-24 13:40:11 -0700968
jeffhaocee4d0c2012-06-15 14:42:01 -0700969 // Zero extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700970 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhaocee4d0c2012-06-15 14:42:01 -0700971
Ian Rogers2c8f6532011-09-02 17:16:34 -0700972 // Exploit fast access in managed code to Thread::Current()
Ian Rogersdd7624d2014-03-14 17:43:00 -0700973 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
974 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700975
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700976 // 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 -0700977 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700978 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700979 // null.
980 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
981 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700982
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700983 // 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 -0700984 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700985 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
986 ManagedRegister scratch, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700987
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700988 // src holds a handle scope entry (Object**) load this into dst
989 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700990
991 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
992 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700993 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
994 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700995
996 // Call to address held at [base+offset]
Ian Rogersdd7624d2014-03-14 17:43:00 -0700997 void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
998 void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
999 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001000
Ian Rogers2c8f6532011-09-02 17:16:34 -07001001 // Generate code to check if Thread::Current()->exception_ is non-null
1002 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001003 void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -07001004
Dave Allison65fcc2c2014-04-28 13:45:27 -07001005 static uint32_t ModifiedImmediate(uint32_t value);
Carl Shapiroa2e18e12011-06-21 18:57:55 -07001006
Dave Allison45fdb932014-06-25 12:37:10 -07001007 static bool IsLowRegister(Register r) {
1008 return r < R8;
1009 }
1010
1011 static bool IsHighRegister(Register r) {
1012 return r >= R8;
1013 }
1014
Roland Levillain4d027112015-07-01 15:41:14 +01001015 //
1016 // Heap poisoning.
1017 //
1018
1019 // Poison a heap reference contained in `reg`.
1020 void PoisonHeapReference(Register reg) {
1021 // reg = -reg.
1022 rsb(reg, reg, ShifterOperand(0));
1023 }
1024 // Unpoison a heap reference contained in `reg`.
1025 void UnpoisonHeapReference(Register reg) {
1026 // reg = -reg.
1027 rsb(reg, reg, ShifterOperand(0));
1028 }
1029 // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
1030 void MaybeUnpoisonHeapReference(Register reg) {
1031 if (kPoisonHeapReferences) {
1032 UnpoisonHeapReference(reg);
1033 }
1034 }
1035
Andreas Gampe85b62f22015-09-09 13:15:38 -07001036 void Jump(Label* label) OVERRIDE {
1037 b(label);
1038 }
1039
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001040 // Jump table support. This is split into three functions:
1041 //
1042 // * CreateJumpTable creates the internal metadata to track the jump targets, and emits code to
1043 // load the base address of the jump table.
1044 //
1045 // * EmitJumpTableDispatch emits the code to actually jump, assuming that the right table value
1046 // has been loaded into a register already.
1047 //
1048 // * FinalizeTables emits the jump table into the literal pool. This can only be called after the
1049 // labels for the jump targets have been finalized.
1050
1051 // Create a jump table for the given labels that will be emitted when finalizing. Create a load
1052 // sequence (or placeholder) that stores the base address into the given register. When the table
1053 // is emitted, offsets will be relative to the location EmitJumpTableDispatch was called on (the
1054 // anchor).
1055 virtual JumpTable* CreateJumpTable(std::vector<Label*>&& labels, Register base_reg) = 0;
1056
1057 // Emit the jump-table jump, assuming that the right value was loaded into displacement_reg.
1058 virtual void EmitJumpTableDispatch(JumpTable* jump_table, Register displacement_reg) = 0;
1059
1060 // Bind a Label that needs to be updated by the assembler in FinalizeCode() if its position
1061 // changes due to branch/literal fixup.
1062 void BindTrackedLabel(Label* label) {
1063 Bind(label);
1064 tracked_labels_.push_back(label);
1065 }
1066
Dave Allison65fcc2c2014-04-28 13:45:27 -07001067 protected:
Carl Shapiroa2e18e12011-06-21 18:57:55 -07001068 // Returns whether or not the given register is used for passing parameters.
1069 static int RegisterCompare(const Register* reg1, const Register* reg2) {
1070 return *reg1 - *reg2;
1071 }
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001072
1073 void FinalizeTrackedLabels();
1074
1075 // Tracked labels. Use a vector, as we need to sort before adjusting.
1076 std::vector<Label*> tracked_labels_;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001077};
1078
Ian Rogers2c8f6532011-09-02 17:16:34 -07001079// Slowpath entered when Thread::Current()->_exception is non-null
Ian Rogersdd7624d2014-03-14 17:43:00 -07001080class ArmExceptionSlowPath FINAL : public SlowPath {
Ian Rogers2c8f6532011-09-02 17:16:34 -07001081 public:
Roland Levillain3887c462015-08-12 18:15:42 +01001082 ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust)
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001083 : scratch_(scratch), stack_adjust_(stack_adjust) {
1084 }
Ian Rogersdd7624d2014-03-14 17:43:00 -07001085 void Emit(Assembler *sp_asm) OVERRIDE;
Ian Rogers67375ac2011-09-14 00:55:44 -07001086 private:
1087 const ArmManagedRegister scratch_;
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001088 const size_t stack_adjust_;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001089};
1090
Ian Rogers2c8f6532011-09-02 17:16:34 -07001091} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -07001092} // namespace art
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001093
Ian Rogers166db042013-07-26 12:05:57 -07001094#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_