blob: 08d88ab5921fe937c5ac41e85c3546f225530552 [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
Carl Shapiroa2e18e12011-06-21 18:57:55 -070080class ShifterOperand {
81 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -070082 ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
83 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -070084 }
85
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010086 explicit ShifterOperand(uint32_t immed);
Carl Shapiroa2e18e12011-06-21 18:57:55 -070087
88 // Data-processing operands - Register
Dave Allison65fcc2c2014-04-28 13:45:27 -070089 explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister),
90 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -070091 }
92
Dave Allison65fcc2c2014-04-28 13:45:27 -070093 ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister),
94 rs_(kNoRegister),
95 is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) {
96 }
97
98 ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm),
99 rs_(kNoRegister),
100 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700101 }
102
103 // Data-processing operands - Logical shift/rotate by register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700104 ShifterOperand(Register rm, Shift shift, Register rs) : type_(kRegister), rm_(rm),
105 rs_(rs),
106 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700107 }
108
Dave Allison65fcc2c2014-04-28 13:45:27 -0700109 bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700110
111 uint32_t type() const {
112 CHECK(is_valid());
113 return type_;
114 }
115
Dave Allison65fcc2c2014-04-28 13:45:27 -0700116 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700117 uint32_t encodingThumb() const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700118
119 bool IsEmpty() const {
120 return type_ == kUnknown;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700121 }
122
Dave Allison65fcc2c2014-04-28 13:45:27 -0700123 bool IsImmediate() const {
124 return type_ == kImmediate;
125 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700126
Dave Allison65fcc2c2014-04-28 13:45:27 -0700127 bool IsRegister() const {
128 return type_ == kRegister;
129 }
130
131 bool IsShift() const {
132 return is_shift_;
133 }
134
135 uint32_t GetImmediate() const {
136 return immed_;
137 }
138
139 Shift GetShift() const {
140 return shift_;
141 }
142
143 Register GetRegister() const {
144 return rm_;
145 }
146
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000147 Register GetSecondRegister() const {
148 return rs_;
149 }
150
Dave Allison65fcc2c2014-04-28 13:45:27 -0700151 enum Type {
152 kUnknown = -1,
153 kRegister,
154 kImmediate
155 };
156
Dave Allison65fcc2c2014-04-28 13:45:27 -0700157 private:
158 Type type_;
159 Register rm_;
160 Register rs_;
161 bool is_rotate_;
162 bool is_shift_;
163 Shift shift_;
164 uint32_t rotate_;
165 uint32_t immed_;
166
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000167 friend class Arm32Assembler;
168 friend class Thumb2Assembler;
169
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700170#ifdef SOURCE_ASSEMBLER_SUPPORT
171 friend class BinaryAssembler;
172#endif
173};
174
175
176enum LoadOperandType {
177 kLoadSignedByte,
178 kLoadUnsignedByte,
179 kLoadSignedHalfword,
180 kLoadUnsignedHalfword,
181 kLoadWord,
182 kLoadWordPair,
183 kLoadSWord,
184 kLoadDWord
185};
186
187
188enum StoreOperandType {
189 kStoreByte,
190 kStoreHalfword,
191 kStoreWord,
192 kStoreWordPair,
193 kStoreSWord,
194 kStoreDWord
195};
196
197
198// Load/store multiple addressing mode.
199enum BlockAddressMode {
200 // bit encoding P U W
201 DA = (0|0|0) << 21, // decrement after
202 IA = (0|4|0) << 21, // increment after
203 DB = (8|0|0) << 21, // decrement before
204 IB = (8|4|0) << 21, // increment before
205 DA_W = (0|0|1) << 21, // decrement after with writeback to base
206 IA_W = (0|4|1) << 21, // increment after with writeback to base
207 DB_W = (8|0|1) << 21, // decrement before with writeback to base
208 IB_W = (8|4|1) << 21 // increment before with writeback to base
209};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700210inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) {
211 os << static_cast<int>(rhs);
212 return os;
213}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700214
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700215class Address : public ValueObject {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700216 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700217 // Memory operand addressing mode (in ARM encoding form. For others we need
218 // to adjust)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700219 enum Mode {
220 // bit encoding P U W
221 Offset = (8|4|0) << 21, // offset (w/o writeback to base)
222 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
223 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
224 NegOffset = (8|0|0) << 21, // negative offset (w/o writeback to base)
225 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
226 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
227 };
228
Dave Allison45fdb932014-06-25 12:37:10 -0700229 Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
230 offset_(offset),
231 am_(am), is_immed_offset_(true), shift_(LSL) {
232 }
233
234 Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
235 am_(am), is_immed_offset_(false), shift_(LSL) {
236 CHECK_NE(rm, PC);
237 }
238
239 Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
240 rn_(rn), rm_(rm), offset_(count),
241 am_(am), is_immed_offset_(false), shift_(shift) {
242 CHECK_NE(rm, PC);
243 }
244
245 // LDR(literal) - pc relative load.
246 explicit Address(int32_t offset) :
247 rn_(PC), rm_(R0), offset_(offset),
248 am_(Offset), is_immed_offset_(false), shift_(LSL) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700249 }
250
Dave Allison65fcc2c2014-04-28 13:45:27 -0700251 static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
252 static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset);
253
254 static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset);
255 static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
256
257 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700258 uint32_t encodingThumb(bool is_32bit) const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700259
260 uint32_t encoding3() const;
261 uint32_t vencoding() const;
262
263 uint32_t encodingThumbLdrdStrd() const;
264
265 Register GetRegister() const {
266 return rn_;
267 }
268
Dave Allison45fdb932014-06-25 12:37:10 -0700269 Register GetRegisterOffset() const {
270 return rm_;
271 }
272
Dave Allison65fcc2c2014-04-28 13:45:27 -0700273 int32_t GetOffset() const {
274 return offset_;
275 }
276
277 Mode GetMode() const {
278 return am_;
279 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700280
Dave Allison45fdb932014-06-25 12:37:10 -0700281 bool IsImmediate() const {
282 return is_immed_offset_;
283 }
284
285 Shift GetShift() const {
286 return shift_;
287 }
288
289 int32_t GetShiftCount() const {
290 CHECK(!is_immed_offset_);
291 return offset_;
292 }
293
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700294 private:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700295 const Register rn_;
296 const Register rm_;
297 const int32_t offset_; // Used as shift amount for register offset.
298 const Mode am_;
299 const bool is_immed_offset_;
300 const Shift shift_;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700301};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700302inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) {
303 os << static_cast<int>(rhs);
304 return os;
305}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700306
Dave Allison65fcc2c2014-04-28 13:45:27 -0700307// Instruction encoding bits.
308enum {
309 H = 1 << 5, // halfword (or byte)
310 L = 1 << 20, // load (or store)
311 S = 1 << 20, // set condition code (or leave unchanged)
312 W = 1 << 21, // writeback base register (or leave unchanged)
313 A = 1 << 21, // accumulate in multiply instruction (or not)
314 B = 1 << 22, // unsigned byte (or word)
315 N = 1 << 22, // long (or short)
316 U = 1 << 23, // positive (or negative) offset/index
317 P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing)
318 I = 1 << 25, // immediate shifter operand (or not)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700319
Dave Allison65fcc2c2014-04-28 13:45:27 -0700320 B0 = 1,
321 B1 = 1 << 1,
322 B2 = 1 << 2,
323 B3 = 1 << 3,
324 B4 = 1 << 4,
325 B5 = 1 << 5,
326 B6 = 1 << 6,
327 B7 = 1 << 7,
328 B8 = 1 << 8,
329 B9 = 1 << 9,
330 B10 = 1 << 10,
331 B11 = 1 << 11,
332 B12 = 1 << 12,
333 B13 = 1 << 13,
334 B14 = 1 << 14,
335 B15 = 1 << 15,
336 B16 = 1 << 16,
337 B17 = 1 << 17,
338 B18 = 1 << 18,
339 B19 = 1 << 19,
340 B20 = 1 << 20,
341 B21 = 1 << 21,
342 B22 = 1 << 22,
343 B23 = 1 << 23,
344 B24 = 1 << 24,
345 B25 = 1 << 25,
346 B26 = 1 << 26,
347 B27 = 1 << 27,
348 B28 = 1 << 28,
349 B29 = 1 << 29,
350 B30 = 1 << 30,
351 B31 = 1 << 31,
352
353 // Instruction bit masks.
354 RdMask = 15 << 12, // in str instruction
355 CondMask = 15 << 28,
356 CoprocessorMask = 15 << 8,
357 OpCodeMask = 15 << 21, // in data-processing instructions
358 Imm24Mask = (1 << 24) - 1,
359 Off12Mask = (1 << 12) - 1,
360
361 // ldrex/strex register field encodings.
362 kLdExRnShift = 16,
363 kLdExRtShift = 12,
364 kStrExRnShift = 16,
365 kStrExRdShift = 12,
366 kStrExRtShift = 0,
367};
368
369// IfThen state for IT instructions.
370enum ItState {
371 kItOmitted,
372 kItThen,
373 kItT = kItThen,
374 kItElse,
375 kItE = kItElse
376};
377
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100378// Set condition codes request.
379enum SetCc {
380 kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
381 kCcSet,
382 kCcKeep,
383};
384
Dave Allison65fcc2c2014-04-28 13:45:27 -0700385constexpr uint32_t kNoItCondition = 3;
386constexpr uint32_t kInvalidModifiedImmediate = -1;
387
388extern const char* kRegisterNames[];
389extern const char* kConditionNames[];
Dave Allison65fcc2c2014-04-28 13:45:27 -0700390
391// This is an abstract ARM assembler. Subclasses provide assemblers for the individual
392// instruction sets (ARM32, Thumb2, etc.)
393//
394class ArmAssembler : public Assembler {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700395 public:
Ian Rogers2c8f6532011-09-02 17:16:34 -0700396 virtual ~ArmAssembler() {}
buzbeec143c552011-08-20 17:38:58 -0700397
Dave Allison65fcc2c2014-04-28 13:45:27 -0700398 // Is this assembler for the thumb instruction set?
399 virtual bool IsThumb() const = 0;
400
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700401 // Data-processing instructions.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100402 virtual void and_(Register rd, Register rn, const ShifterOperand& so,
403 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700404
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100405 virtual void ands(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
406 and_(rd, rn, so, cond, kCcSet);
407 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700408
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100409 virtual void eor(Register rd, Register rn, const ShifterOperand& so,
410 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700411
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100412 virtual void eors(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
413 eor(rd, rn, so, cond, kCcSet);
414 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700415
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100416 virtual void sub(Register rd, Register rn, const ShifterOperand& so,
417 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700418
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100419 virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
420 sub(rd, rn, so, cond, kCcSet);
421 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700422
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100423 virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
424 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700425
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100426 virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
427 rsb(rd, rn, so, cond, kCcSet);
428 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700429
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100430 virtual void add(Register rd, Register rn, const ShifterOperand& so,
431 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
432
433 virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
434 add(rd, rn, so, cond, kCcSet);
435 }
436
437 virtual void adc(Register rd, Register rn, const ShifterOperand& so,
438 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
439
440 virtual void adcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
441 adc(rd, rn, so, cond, kCcSet);
442 }
443
444 virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
445 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
446
447 virtual void sbcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
448 sbc(rd, rn, so, cond, kCcSet);
449 }
450
451 virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
452 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
453
454 virtual void rscs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
455 rsc(rd, rn, so, cond, kCcSet);
456 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700457
Dave Allison65fcc2c2014-04-28 13:45:27 -0700458 virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700459
Dave Allison65fcc2c2014-04-28 13:45:27 -0700460 virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700461
Dave Allison65fcc2c2014-04-28 13:45:27 -0700462 virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700463
Dave Allison65fcc2c2014-04-28 13:45:27 -0700464 virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700465
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100466 virtual void orr(Register rd, Register rn, const ShifterOperand& so,
467 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700468
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100469 virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
470 orr(rd, rn, so, cond, kCcSet);
471 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700472
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100473 virtual void mov(Register rd, const ShifterOperand& so,
474 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700475
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100476 virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) {
477 mov(rd, so, cond, kCcSet);
478 }
479
480 virtual void bic(Register rd, Register rn, const ShifterOperand& so,
481 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
482
483 virtual void bics(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
484 bic(rd, rn, so, cond, kCcSet);
485 }
486
487 virtual void mvn(Register rd, const ShifterOperand& so,
488 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
489
490 virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) {
491 mvn(rd, so, cond, kCcSet);
492 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700493
494 // Miscellaneous data-processing instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700495 virtual void clz(Register rd, Register rm, Condition cond = AL) = 0;
496 virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0;
497 virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0;
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100498 virtual void rbit(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700499
500 // Multiply instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700501 virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
502 virtual void mla(Register rd, Register rn, Register rm, Register ra,
503 Condition cond = AL) = 0;
504 virtual void mls(Register rd, Register rn, Register rm, Register ra,
505 Condition cond = AL) = 0;
Zheng Xuc6667102015-05-15 16:08:45 +0800506 virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
507 Condition cond = AL) = 0;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700508 virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
509 Condition cond = AL) = 0;
510
511 virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
512 virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700513
Roland Levillain981e4542014-11-14 11:47:14 +0000514 // Bit field extract instructions.
Roland Levillain51d3fc42014-11-13 14:11:42 +0000515 virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
516 Condition cond = AL) = 0;
Roland Levillain981e4542014-11-14 11:47:14 +0000517 virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
518 Condition cond = AL) = 0;
Roland Levillain51d3fc42014-11-13 14:11:42 +0000519
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700520 // Load/store instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700521 virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
522 virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700523
Dave Allison65fcc2c2014-04-28 13:45:27 -0700524 virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0;
525 virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700526
Dave Allison65fcc2c2014-04-28 13:45:27 -0700527 virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0;
528 virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700529
Dave Allison65fcc2c2014-04-28 13:45:27 -0700530 virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0;
531 virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700532
Dave Allison65fcc2c2014-04-28 13:45:27 -0700533 virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0;
534 virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700535
Dave Allison65fcc2c2014-04-28 13:45:27 -0700536 virtual void ldm(BlockAddressMode am, Register base,
537 RegList regs, Condition cond = AL) = 0;
538 virtual void stm(BlockAddressMode am, Register base,
539 RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700540
Dave Allison65fcc2c2014-04-28 13:45:27 -0700541 virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
542 virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
Calin Juravle52c48962014-12-16 17:02:57 +0000543 virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
544 virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700545
546 // Miscellaneous instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700547 virtual void clrex(Condition cond = AL) = 0;
548 virtual void nop(Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700549
550 // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700551 virtual void bkpt(uint16_t imm16) = 0;
552 virtual void svc(uint32_t imm24) = 0;
553
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700554 virtual void it(Condition firstcond ATTRIBUTE_UNUSED,
555 ItState i1 ATTRIBUTE_UNUSED = kItOmitted,
556 ItState i2 ATTRIBUTE_UNUSED = kItOmitted,
557 ItState i3 ATTRIBUTE_UNUSED = kItOmitted) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700558 // Ignored if not supported.
559 }
560
561 virtual void cbz(Register rn, Label* target) = 0;
562 virtual void cbnz(Register rn, Label* target) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700563
564 // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
Dave Allison65fcc2c2014-04-28 13:45:27 -0700565 virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0;
566 virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0;
567 virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0;
568 virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0;
569 virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0;
570 virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0;
571 virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
572 virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700573
574 // Returns false if the immediate cannot be encoded.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700575 virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0;
576 virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700577
Dave Allison65fcc2c2014-04-28 13:45:27 -0700578 virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
579 virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
580 virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
581 virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700582
Dave Allison65fcc2c2014-04-28 13:45:27 -0700583 virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
584 virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
585 virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
586 virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
587 virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
588 virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
589 virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
590 virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
591 virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
592 virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
593 virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
594 virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700595
Dave Allison65fcc2c2014-04-28 13:45:27 -0700596 virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0;
597 virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
598 virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
599 virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
600 virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0;
601 virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700602
Dave Allison65fcc2c2014-04-28 13:45:27 -0700603 virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0;
604 virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0;
605 virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0;
606 virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0;
607 virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0;
608 virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0;
609 virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0;
610 virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0;
611 virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0;
612 virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700613
Dave Allison65fcc2c2014-04-28 13:45:27 -0700614 virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0;
615 virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
616 virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0;
617 virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0;
618 virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR
619
620 virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0;
621 virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
622 virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
623 virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700624
625 // Branch instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700626 virtual void b(Label* label, Condition cond = AL) = 0;
627 virtual void bl(Label* label, Condition cond = AL) = 0;
628 virtual void blx(Register rm, Condition cond = AL) = 0;
629 virtual void bx(Register rm, Condition cond = AL) = 0;
630
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100631 // Memory barriers.
632 virtual void dmb(DmbOptions flavor) = 0;
633
Dave Allison65fcc2c2014-04-28 13:45:27 -0700634 void Pad(uint32_t bytes);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700635
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000636 // Adjust label position.
637 void AdjustLabelPosition(Label* label) {
638 DCHECK(label->IsBound());
639 uint32_t old_position = static_cast<uint32_t>(label->Position());
640 uint32_t new_position = GetAdjustedPosition(old_position);
641 label->Reinitialize();
642 DCHECK_GE(static_cast<int>(new_position), 0);
643 label->BindTo(static_cast<int>(new_position));
644 }
645
646 // Get the final position of a label after local fixup based on the old position
647 // recorded before FinalizeCode().
648 virtual uint32_t GetAdjustedPosition(uint32_t old_position) = 0;
649
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700650 // Macros.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700651 // Most of these are pure virtual as they need to be implemented per instruction set.
652
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000653 // Create a new literal with a given value.
654 // NOTE: Force the template parameter to be explicitly specified. In the absence of
655 // std::omit_from_type_deduction<T> or std::identity<T>, use std::decay<T>.
656 template <typename T>
657 Literal* NewLiteral(typename std::decay<T>::type value) {
658 static_assert(std::is_integral<T>::value, "T must be an integral type.");
659 return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
660 }
661
662 // Create a new literal with the given data.
663 virtual Literal* NewLiteral(size_t size, const uint8_t* data) = 0;
664
665 // Load literal.
666 virtual void LoadLiteral(Register rt, Literal* literal) = 0;
667 virtual void LoadLiteral(Register rt, Register rt2, Literal* literal) = 0;
668 virtual void LoadLiteral(SRegister sd, Literal* literal) = 0;
669 virtual void LoadLiteral(DRegister dd, Literal* literal) = 0;
670
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700671 // Add signed constant value to rd. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700672 virtual void AddConstant(Register rd, Register rn, int32_t value,
Vladimir Marko449b1092015-09-08 12:16:45 +0100673 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
674 void AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond = AL) {
675 AddConstant(rd, rn, value, cond, kCcSet);
676 }
677 void AddConstant(Register rd, int32_t value, Condition cond = AL, SetCc set_cc = kCcDontCare) {
678 AddConstant(rd, rd, value, cond, set_cc);
679 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700680
681 // Load and Store. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700682 virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000683 void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {
684 if (!vmovs(sd, value, cond)) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000685 int32_t int_value = bit_cast<int32_t, float>(value);
686 if (int_value == bit_cast<int32_t, float>(0.0f)) {
687 // 0.0 is quite common, so we special case it by loading
688 // 2.0 in `sd` and then substracting it.
689 bool success = vmovs(sd, 2.0, cond);
690 CHECK(success);
691 vsubs(sd, sd, sd, cond);
692 } else {
693 LoadImmediate(IP, int_value, cond);
694 vmovsr(sd, IP, cond);
695 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000696 }
697 }
698
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000699 void LoadDImmediate(DRegister sd, double value, Condition cond = AL) {
700 if (!vmovd(sd, value, cond)) {
701 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000702 if (int_value == bit_cast<uint64_t, double>(0.0)) {
703 // 0.0 is quite common, so we special case it by loading
704 // 2.0 in `sd` and then substracting it.
705 bool success = vmovd(sd, 2.0, cond);
706 CHECK(success);
707 vsubd(sd, sd, sd, cond);
708 } else {
709 if (sd < 16) {
710 SRegister low = static_cast<SRegister>(sd << 1);
711 SRegister high = static_cast<SRegister>(low + 1);
712 LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond);
713 if (High32Bits(int_value) == Low32Bits(int_value)) {
714 vmovs(high, low);
715 } else {
716 LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond);
717 }
718 } else {
719 LOG(FATAL) << "Unimplemented loading of double into a D register "
720 << "that cannot be split into two S registers";
721 }
722 }
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000723 }
724 }
725
Dave Allison65fcc2c2014-04-28 13:45:27 -0700726 virtual void MarkExceptionHandler(Label* label) = 0;
727 virtual void LoadFromOffset(LoadOperandType type,
728 Register reg,
729 Register base,
730 int32_t offset,
731 Condition cond = AL) = 0;
732 virtual void StoreToOffset(StoreOperandType type,
733 Register reg,
734 Register base,
735 int32_t offset,
736 Condition cond = AL) = 0;
737 virtual void LoadSFromOffset(SRegister reg,
738 Register base,
739 int32_t offset,
740 Condition cond = AL) = 0;
741 virtual void StoreSToOffset(SRegister reg,
742 Register base,
743 int32_t offset,
744 Condition cond = AL) = 0;
745 virtual void LoadDFromOffset(DRegister reg,
746 Register base,
747 int32_t offset,
748 Condition cond = AL) = 0;
749 virtual void StoreDToOffset(DRegister reg,
750 Register base,
751 int32_t offset,
752 Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700753
Dave Allison65fcc2c2014-04-28 13:45:27 -0700754 virtual void Push(Register rd, Condition cond = AL) = 0;
755 virtual void Pop(Register rd, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700756
Dave Allison65fcc2c2014-04-28 13:45:27 -0700757 virtual void PushList(RegList regs, Condition cond = AL) = 0;
758 virtual void PopList(RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700759
Dave Allison65fcc2c2014-04-28 13:45:27 -0700760 virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700761
762 // Convenience shift instructions. Use mov instruction with shifter operand
763 // for variants setting the status flags or using a register shift count.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100764 virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
765 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Dave Allison45fdb932014-06-25 12:37:10 -0700766
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100767 void Lsls(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
768 Lsl(rd, rm, shift_imm, cond, kCcSet);
769 }
770
771 virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
772 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
773
774 void Lsrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
775 Lsr(rd, rm, shift_imm, cond, kCcSet);
776 }
777
778 virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
779 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
780
781 void Asrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
782 Asr(rd, rm, shift_imm, cond, kCcSet);
783 }
784
785 virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
786 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
787
788 void Rors(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
789 Ror(rd, rm, shift_imm, cond, kCcSet);
790 }
791
792 virtual void Rrx(Register rd, Register rm,
793 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
794
795 void Rrxs(Register rd, Register rm, Condition cond = AL) {
796 Rrx(rd, rm, cond, kCcSet);
797 }
798
799 virtual void Lsl(Register rd, Register rm, Register rn,
800 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
801
802 void Lsls(Register rd, Register rm, Register rn, Condition cond = AL) {
803 Lsl(rd, rm, rn, cond, kCcSet);
804 }
805
806 virtual void Lsr(Register rd, Register rm, Register rn,
807 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
808
809 void Lsrs(Register rd, Register rm, Register rn, Condition cond = AL) {
810 Lsr(rd, rm, rn, cond, kCcSet);
811 }
812
813 virtual void Asr(Register rd, Register rm, Register rn,
814 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
815
816 void Asrs(Register rd, Register rm, Register rn, Condition cond = AL) {
817 Asr(rd, rm, rn, cond, kCcSet);
818 }
819
820 virtual void Ror(Register rd, Register rm, Register rn,
821 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
822
823 void Rors(Register rd, Register rm, Register rn, Condition cond = AL) {
824 Ror(rd, rm, rn, cond, kCcSet);
825 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700826
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000827 // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes,
828 // `shifter_op` contains the operand.
829 virtual bool ShifterOperandCanHold(Register rd,
830 Register rn,
831 Opcode opcode,
832 uint32_t immediate,
833 ShifterOperand* shifter_op) = 0;
834
Nicolas Geoffray0ccb3832015-10-14 11:44:23 +0100835 virtual bool ShifterOperandCanAlwaysHold(uint32_t immediate) = 0;
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +0100836
Ian Rogers13735952014-10-08 12:43:28 -0700837 static bool IsInstructionForExceptionHandling(uintptr_t pc);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700838
Dave Allison65fcc2c2014-04-28 13:45:27 -0700839 virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
840 virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700841
Ian Rogers2c8f6532011-09-02 17:16:34 -0700842 //
843 // Overridden common assembler high-level functionality
844 //
Ian Rogers45a76cb2011-07-21 22:00:15 -0700845
Ian Rogers2c8f6532011-09-02 17:16:34 -0700846 // Emit code that will create an activation on the stack
Ian Rogersdd7624d2014-03-14 17:43:00 -0700847 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
848 const std::vector<ManagedRegister>& callee_save_regs,
849 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -0700850
Ian Rogers2c8f6532011-09-02 17:16:34 -0700851 // Emit code that will remove an activation from the stack
Ian Rogersdd7624d2014-03-14 17:43:00 -0700852 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
Dave Allison65fcc2c2014-04-28 13:45:27 -0700853 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700854
Ian Rogersdd7624d2014-03-14 17:43:00 -0700855 void IncreaseFrameSize(size_t adjust) OVERRIDE;
856 void DecreaseFrameSize(size_t adjust) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700857
858 // Store routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700859 void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
860 void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
861 void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700862
Ian Rogersdd7624d2014-03-14 17:43:00 -0700863 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700864
Ian Rogersdd7624d2014-03-14 17:43:00 -0700865 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
866 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700867
Ian Rogersdd7624d2014-03-14 17:43:00 -0700868 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
869 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700870
Ian Rogersdd7624d2014-03-14 17:43:00 -0700871 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700872
Ian Rogersdd7624d2014-03-14 17:43:00 -0700873 void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
874 ManagedRegister scratch) OVERRIDE;
Ian Rogersbdb03912011-09-14 00:55:44 -0700875
Ian Rogers2c8f6532011-09-02 17:16:34 -0700876 // Load routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700877 void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700878
Ian Rogersdd7624d2014-03-14 17:43:00 -0700879 void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700880
Mathieu Chartiere401d142015-04-22 13:56:20 -0700881 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700882
Mathieu Chartiere401d142015-04-22 13:56:20 -0700883 void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100884 bool unpoison_reference) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700885
Ian Rogersdd7624d2014-03-14 17:43:00 -0700886 void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700887
Ian Rogersdd7624d2014-03-14 17:43:00 -0700888 void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700889
890 // Copying routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700891 void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700892
Ian Rogersdd7624d2014-03-14 17:43:00 -0700893 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
894 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700895
Ian Rogersdd7624d2014-03-14 17:43:00 -0700896 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
897 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700898
Ian Rogersdd7624d2014-03-14 17:43:00 -0700899 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700900
Ian Rogersdd7624d2014-03-14 17:43:00 -0700901 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700902
Ian Rogersdd7624d2014-03-14 17:43:00 -0700903 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch,
904 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700905
Ian Rogersdd7624d2014-03-14 17:43:00 -0700906 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch,
907 size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700908
Ian Rogersdd7624d2014-03-14 17:43:00 -0700909 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch,
910 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700911
Ian Rogersdd7624d2014-03-14 17:43:00 -0700912 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
913 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700914
Ian Rogersdd7624d2014-03-14 17:43:00 -0700915 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
916 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700917
jeffhao58136ca2012-05-24 13:40:11 -0700918 // Sign extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700919 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao58136ca2012-05-24 13:40:11 -0700920
jeffhaocee4d0c2012-06-15 14:42:01 -0700921 // Zero extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700922 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhaocee4d0c2012-06-15 14:42:01 -0700923
Ian Rogers2c8f6532011-09-02 17:16:34 -0700924 // Exploit fast access in managed code to Thread::Current()
Ian Rogersdd7624d2014-03-14 17:43:00 -0700925 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
926 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700927
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700928 // 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 -0700929 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700930 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700931 // null.
932 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
933 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700934
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700935 // 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 -0700936 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700937 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
938 ManagedRegister scratch, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700939
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700940 // src holds a handle scope entry (Object**) load this into dst
941 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700942
943 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
944 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700945 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
946 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700947
948 // Call to address held at [base+offset]
Ian Rogersdd7624d2014-03-14 17:43:00 -0700949 void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
950 void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
951 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700952
Ian Rogers2c8f6532011-09-02 17:16:34 -0700953 // Generate code to check if Thread::Current()->exception_ is non-null
954 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700955 void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -0700956
Dave Allison65fcc2c2014-04-28 13:45:27 -0700957 static uint32_t ModifiedImmediate(uint32_t value);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700958
Dave Allison45fdb932014-06-25 12:37:10 -0700959 static bool IsLowRegister(Register r) {
960 return r < R8;
961 }
962
963 static bool IsHighRegister(Register r) {
964 return r >= R8;
965 }
966
Roland Levillain4d027112015-07-01 15:41:14 +0100967 //
968 // Heap poisoning.
969 //
970
971 // Poison a heap reference contained in `reg`.
972 void PoisonHeapReference(Register reg) {
973 // reg = -reg.
974 rsb(reg, reg, ShifterOperand(0));
975 }
976 // Unpoison a heap reference contained in `reg`.
977 void UnpoisonHeapReference(Register reg) {
978 // reg = -reg.
979 rsb(reg, reg, ShifterOperand(0));
980 }
981 // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
982 void MaybeUnpoisonHeapReference(Register reg) {
983 if (kPoisonHeapReferences) {
984 UnpoisonHeapReference(reg);
985 }
986 }
987
Andreas Gampe85b62f22015-09-09 13:15:38 -0700988 void Jump(Label* label) OVERRIDE {
989 b(label);
990 }
991
Dave Allison65fcc2c2014-04-28 13:45:27 -0700992 protected:
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700993 // Returns whether or not the given register is used for passing parameters.
994 static int RegisterCompare(const Register* reg1, const Register* reg2) {
995 return *reg1 - *reg2;
996 }
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -0700997};
998
Ian Rogers2c8f6532011-09-02 17:16:34 -0700999// Slowpath entered when Thread::Current()->_exception is non-null
Ian Rogersdd7624d2014-03-14 17:43:00 -07001000class ArmExceptionSlowPath FINAL : public SlowPath {
Ian Rogers2c8f6532011-09-02 17:16:34 -07001001 public:
Roland Levillain3887c462015-08-12 18:15:42 +01001002 ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust)
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001003 : scratch_(scratch), stack_adjust_(stack_adjust) {
1004 }
Ian Rogersdd7624d2014-03-14 17:43:00 -07001005 void Emit(Assembler *sp_asm) OVERRIDE;
Ian Rogers67375ac2011-09-14 00:55:44 -07001006 private:
1007 const ArmManagedRegister scratch_;
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001008 const size_t stack_adjust_;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001009};
1010
Ian Rogers2c8f6532011-09-02 17:16:34 -07001011} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -07001012} // namespace art
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001013
Ian Rogers166db042013-07-26 12:05:57 -07001014#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_