blob: a8945654255bc2a7d3bd45d010f8ef45302d2cb3 [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"
Vladimir Marko88b2b802015-12-04 14:19:04 +000025#include "base/stl_util.h"
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070026#include "base/value_object.h"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070027#include "constants_arm.h"
Ian Rogers166db042013-07-26 12:05:57 -070028#include "utils/arm/managed_register_arm.h"
29#include "utils/assembler.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070030#include "offsets.h"
Carl Shapiroa2e18e12011-06-21 18:57:55 -070031
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070032namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070033namespace arm {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070034
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +000035class Arm32Assembler;
36class Thumb2Assembler;
37
Vladimir Markocf93a5c2015-06-16 11:33:24 +000038// Assembler literal is a value embedded in code, retrieved using a PC-relative load.
39class Literal {
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000040 public:
Vladimir Markocf93a5c2015-06-16 11:33:24 +000041 static constexpr size_t kMaxSize = 8;
42
43 Literal(uint32_t size, const uint8_t* data)
44 : label_(), size_(size) {
45 DCHECK_LE(size, Literal::kMaxSize);
46 memcpy(data_, data, size);
47 }
48
49 template <typename T>
50 T GetValue() const {
51 DCHECK_EQ(size_, sizeof(T));
52 T value;
53 memcpy(&value, data_, sizeof(T));
54 return value;
55 }
56
57 uint32_t GetSize() const {
58 return size_;
59 }
60
61 const uint8_t* GetData() const {
62 return data_;
63 }
64
65 Label* GetLabel() {
66 return &label_;
67 }
68
69 const Label* GetLabel() const {
70 return &label_;
71 }
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000072
73 private:
Vladimir Markocf93a5c2015-06-16 11:33:24 +000074 Label label_;
75 const uint32_t size_;
76 uint8_t data_[kMaxSize];
77
78 DISALLOW_COPY_AND_ASSIGN(Literal);
Nicolas Geoffrayd56376c2015-05-21 12:32:34 +000079};
80
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070081// Jump table: table of labels emitted after the literals. Similar to literals.
82class JumpTable {
83 public:
84 explicit JumpTable(std::vector<Label*>&& labels)
85 : label_(), anchor_label_(), labels_(std::move(labels)) {
86 }
87
88 uint32_t GetSize() const {
89 return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t);
90 }
91
92 const std::vector<Label*>& GetData() const {
93 return labels_;
94 }
95
96 Label* GetLabel() {
97 return &label_;
98 }
99
100 const Label* GetLabel() const {
101 return &label_;
102 }
103
104 Label* GetAnchorLabel() {
105 return &anchor_label_;
106 }
107
108 const Label* GetAnchorLabel() const {
109 return &anchor_label_;
110 }
111
112 private:
113 Label label_;
114 Label anchor_label_;
115 std::vector<Label*> labels_;
116
117 DISALLOW_COPY_AND_ASSIGN(JumpTable);
118};
119
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700120class ShifterOperand {
121 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700122 ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
123 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700124 }
125
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100126 explicit ShifterOperand(uint32_t immed);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700127
128 // Data-processing operands - Register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700129 explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister),
130 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700131 }
132
Dave Allison65fcc2c2014-04-28 13:45:27 -0700133 ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister),
134 rs_(kNoRegister),
135 is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) {
136 }
137
138 ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm),
139 rs_(kNoRegister),
140 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700141 }
142
143 // Data-processing operands - Logical shift/rotate by register
Dave Allison65fcc2c2014-04-28 13:45:27 -0700144 ShifterOperand(Register rm, Shift shift, Register rs) : type_(kRegister), rm_(rm),
145 rs_(rs),
146 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700147 }
148
Dave Allison65fcc2c2014-04-28 13:45:27 -0700149 bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700150
151 uint32_t type() const {
152 CHECK(is_valid());
153 return type_;
154 }
155
Dave Allison65fcc2c2014-04-28 13:45:27 -0700156 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700157 uint32_t encodingThumb() const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700158
159 bool IsEmpty() const {
160 return type_ == kUnknown;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700161 }
162
Dave Allison65fcc2c2014-04-28 13:45:27 -0700163 bool IsImmediate() const {
164 return type_ == kImmediate;
165 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700166
Dave Allison65fcc2c2014-04-28 13:45:27 -0700167 bool IsRegister() const {
168 return type_ == kRegister;
169 }
170
171 bool IsShift() const {
172 return is_shift_;
173 }
174
175 uint32_t GetImmediate() const {
176 return immed_;
177 }
178
179 Shift GetShift() const {
180 return shift_;
181 }
182
183 Register GetRegister() const {
184 return rm_;
185 }
186
Guillaume "Vermeille" Sanchezab4a2f52015-03-11 14:00:30 +0000187 Register GetSecondRegister() const {
188 return rs_;
189 }
190
Dave Allison65fcc2c2014-04-28 13:45:27 -0700191 enum Type {
192 kUnknown = -1,
193 kRegister,
194 kImmediate
195 };
196
Dave Allison65fcc2c2014-04-28 13:45:27 -0700197 private:
198 Type type_;
199 Register rm_;
200 Register rs_;
201 bool is_rotate_;
202 bool is_shift_;
203 Shift shift_;
204 uint32_t rotate_;
205 uint32_t immed_;
206
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000207 friend class Arm32Assembler;
208 friend class Thumb2Assembler;
209
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700210#ifdef SOURCE_ASSEMBLER_SUPPORT
211 friend class BinaryAssembler;
212#endif
213};
214
215
216enum LoadOperandType {
217 kLoadSignedByte,
218 kLoadUnsignedByte,
219 kLoadSignedHalfword,
220 kLoadUnsignedHalfword,
221 kLoadWord,
222 kLoadWordPair,
223 kLoadSWord,
224 kLoadDWord
225};
226
227
228enum StoreOperandType {
229 kStoreByte,
230 kStoreHalfword,
231 kStoreWord,
232 kStoreWordPair,
233 kStoreSWord,
234 kStoreDWord
235};
236
237
238// Load/store multiple addressing mode.
239enum BlockAddressMode {
240 // bit encoding P U W
241 DA = (0|0|0) << 21, // decrement after
242 IA = (0|4|0) << 21, // increment after
243 DB = (8|0|0) << 21, // decrement before
244 IB = (8|4|0) << 21, // increment before
245 DA_W = (0|0|1) << 21, // decrement after with writeback to base
246 IA_W = (0|4|1) << 21, // increment after with writeback to base
247 DB_W = (8|0|1) << 21, // decrement before with writeback to base
248 IB_W = (8|4|1) << 21 // increment before with writeback to base
249};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700250inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) {
251 os << static_cast<int>(rhs);
252 return os;
253}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700254
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700255class Address : public ValueObject {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700256 public:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700257 // Memory operand addressing mode (in ARM encoding form. For others we need
258 // to adjust)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700259 enum Mode {
260 // bit encoding P U W
261 Offset = (8|4|0) << 21, // offset (w/o writeback to base)
262 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
263 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
264 NegOffset = (8|0|0) << 21, // negative offset (w/o writeback to base)
265 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
266 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
267 };
268
Dave Allison45fdb932014-06-25 12:37:10 -0700269 Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
270 offset_(offset),
271 am_(am), is_immed_offset_(true), shift_(LSL) {
272 }
273
274 Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
275 am_(am), is_immed_offset_(false), shift_(LSL) {
276 CHECK_NE(rm, PC);
277 }
278
279 Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
280 rn_(rn), rm_(rm), offset_(count),
281 am_(am), is_immed_offset_(false), shift_(shift) {
282 CHECK_NE(rm, PC);
283 }
284
285 // LDR(literal) - pc relative load.
286 explicit Address(int32_t offset) :
287 rn_(PC), rm_(R0), offset_(offset),
288 am_(Offset), is_immed_offset_(false), shift_(LSL) {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700289 }
290
Dave Allison65fcc2c2014-04-28 13:45:27 -0700291 static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
292 static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset);
293
294 static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset);
295 static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
296
297 uint32_t encodingArm() const;
Dave Allison45fdb932014-06-25 12:37:10 -0700298 uint32_t encodingThumb(bool is_32bit) const;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700299
300 uint32_t encoding3() const;
301 uint32_t vencoding() const;
302
303 uint32_t encodingThumbLdrdStrd() const;
304
305 Register GetRegister() const {
306 return rn_;
307 }
308
Dave Allison45fdb932014-06-25 12:37:10 -0700309 Register GetRegisterOffset() const {
310 return rm_;
311 }
312
Dave Allison65fcc2c2014-04-28 13:45:27 -0700313 int32_t GetOffset() const {
314 return offset_;
315 }
316
317 Mode GetMode() const {
318 return am_;
319 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700320
Dave Allison45fdb932014-06-25 12:37:10 -0700321 bool IsImmediate() const {
322 return is_immed_offset_;
323 }
324
325 Shift GetShift() const {
326 return shift_;
327 }
328
329 int32_t GetShiftCount() const {
330 CHECK(!is_immed_offset_);
331 return offset_;
332 }
333
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700334 private:
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700335 const Register rn_;
336 const Register rm_;
337 const int32_t offset_; // Used as shift amount for register offset.
338 const Mode am_;
339 const bool is_immed_offset_;
340 const Shift shift_;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700341};
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700342inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) {
343 os << static_cast<int>(rhs);
344 return os;
345}
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700346
Dave Allison65fcc2c2014-04-28 13:45:27 -0700347// Instruction encoding bits.
348enum {
349 H = 1 << 5, // halfword (or byte)
350 L = 1 << 20, // load (or store)
351 S = 1 << 20, // set condition code (or leave unchanged)
352 W = 1 << 21, // writeback base register (or leave unchanged)
353 A = 1 << 21, // accumulate in multiply instruction (or not)
354 B = 1 << 22, // unsigned byte (or word)
355 N = 1 << 22, // long (or short)
356 U = 1 << 23, // positive (or negative) offset/index
357 P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing)
358 I = 1 << 25, // immediate shifter operand (or not)
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700359
Dave Allison65fcc2c2014-04-28 13:45:27 -0700360 B0 = 1,
361 B1 = 1 << 1,
362 B2 = 1 << 2,
363 B3 = 1 << 3,
364 B4 = 1 << 4,
365 B5 = 1 << 5,
366 B6 = 1 << 6,
367 B7 = 1 << 7,
368 B8 = 1 << 8,
369 B9 = 1 << 9,
370 B10 = 1 << 10,
371 B11 = 1 << 11,
372 B12 = 1 << 12,
373 B13 = 1 << 13,
374 B14 = 1 << 14,
375 B15 = 1 << 15,
376 B16 = 1 << 16,
377 B17 = 1 << 17,
378 B18 = 1 << 18,
379 B19 = 1 << 19,
380 B20 = 1 << 20,
381 B21 = 1 << 21,
382 B22 = 1 << 22,
383 B23 = 1 << 23,
384 B24 = 1 << 24,
385 B25 = 1 << 25,
386 B26 = 1 << 26,
387 B27 = 1 << 27,
388 B28 = 1 << 28,
389 B29 = 1 << 29,
390 B30 = 1 << 30,
391 B31 = 1 << 31,
392
393 // Instruction bit masks.
394 RdMask = 15 << 12, // in str instruction
395 CondMask = 15 << 28,
396 CoprocessorMask = 15 << 8,
397 OpCodeMask = 15 << 21, // in data-processing instructions
398 Imm24Mask = (1 << 24) - 1,
399 Off12Mask = (1 << 12) - 1,
400
401 // ldrex/strex register field encodings.
402 kLdExRnShift = 16,
403 kLdExRtShift = 12,
404 kStrExRnShift = 16,
405 kStrExRdShift = 12,
406 kStrExRtShift = 0,
407};
408
409// IfThen state for IT instructions.
410enum ItState {
411 kItOmitted,
412 kItThen,
413 kItT = kItThen,
414 kItElse,
415 kItE = kItElse
416};
417
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100418// Set condition codes request.
419enum SetCc {
420 kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
421 kCcSet,
422 kCcKeep,
423};
424
Dave Allison65fcc2c2014-04-28 13:45:27 -0700425constexpr uint32_t kNoItCondition = 3;
426constexpr uint32_t kInvalidModifiedImmediate = -1;
427
428extern const char* kRegisterNames[];
429extern const char* kConditionNames[];
Dave Allison65fcc2c2014-04-28 13:45:27 -0700430
431// This is an abstract ARM assembler. Subclasses provide assemblers for the individual
432// instruction sets (ARM32, Thumb2, etc.)
433//
434class ArmAssembler : public Assembler {
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700435 public:
Ian Rogers2c8f6532011-09-02 17:16:34 -0700436 virtual ~ArmAssembler() {}
buzbeec143c552011-08-20 17:38:58 -0700437
Dave Allison65fcc2c2014-04-28 13:45:27 -0700438 // Is this assembler for the thumb instruction set?
439 virtual bool IsThumb() const = 0;
440
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700441 // Data-processing instructions.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100442 virtual void and_(Register rd, Register rn, const ShifterOperand& so,
443 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700444
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100445 virtual void ands(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
446 and_(rd, rn, so, cond, kCcSet);
447 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700448
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100449 virtual void eor(Register rd, Register rn, const ShifterOperand& so,
450 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700451
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100452 virtual void eors(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
453 eor(rd, rn, so, cond, kCcSet);
454 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700455
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100456 virtual void sub(Register rd, Register rn, const ShifterOperand& so,
457 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700458
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100459 virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
460 sub(rd, rn, so, cond, kCcSet);
461 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700462
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100463 virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
464 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700465
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100466 virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
467 rsb(rd, rn, so, cond, kCcSet);
468 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700469
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100470 virtual void add(Register rd, Register rn, const ShifterOperand& so,
471 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
472
473 virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
474 add(rd, rn, so, cond, kCcSet);
475 }
476
477 virtual void adc(Register rd, Register rn, const ShifterOperand& so,
478 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
479
480 virtual void adcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
481 adc(rd, rn, so, cond, kCcSet);
482 }
483
484 virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
485 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
486
487 virtual void sbcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
488 sbc(rd, rn, so, cond, kCcSet);
489 }
490
491 virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
492 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
493
494 virtual void rscs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
495 rsc(rd, rn, so, cond, kCcSet);
496 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700497
Dave Allison65fcc2c2014-04-28 13:45:27 -0700498 virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700499
Dave Allison65fcc2c2014-04-28 13:45:27 -0700500 virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700501
Dave Allison65fcc2c2014-04-28 13:45:27 -0700502 virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700503
Vladimir Markoac6ac102015-12-17 12:14:00 +0000504 // Note: CMN updates flags based on addition of its operands. Do not confuse
505 // the "N" suffix with bitwise inversion performed by MVN.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700506 virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700507
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100508 virtual void orr(Register rd, Register rn, const ShifterOperand& so,
509 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700510
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100511 virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
512 orr(rd, rn, so, cond, kCcSet);
513 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700514
Vladimir Markod2b4ca22015-09-14 15:13:26 +0100515 virtual void orn(Register rd, Register rn, const ShifterOperand& so,
516 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
517
518 virtual void orns(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
519 orn(rd, rn, so, cond, kCcSet);
520 }
521
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100522 virtual void mov(Register rd, const ShifterOperand& so,
523 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700524
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100525 virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) {
526 mov(rd, so, cond, kCcSet);
527 }
528
529 virtual void bic(Register rd, Register rn, const ShifterOperand& so,
530 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
531
532 virtual void bics(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
533 bic(rd, rn, so, cond, kCcSet);
534 }
535
536 virtual void mvn(Register rd, const ShifterOperand& so,
537 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
538
539 virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) {
540 mvn(rd, so, cond, kCcSet);
541 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700542
543 // Miscellaneous data-processing instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700544 virtual void clz(Register rd, Register rm, Condition cond = AL) = 0;
545 virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0;
546 virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0;
Scott Wakeling9ee23f42015-07-23 10:44:35 +0100547 virtual void rbit(Register rd, Register rm, Condition cond = AL) = 0;
Artem Serovc257da72016-02-02 13:49:43 +0000548 virtual void rev(Register rd, Register rm, Condition cond = AL) = 0;
549 virtual void rev16(Register rd, Register rm, Condition cond = AL) = 0;
550 virtual void revsh(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700551
552 // Multiply instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700553 virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
554 virtual void mla(Register rd, Register rn, Register rm, Register ra,
555 Condition cond = AL) = 0;
556 virtual void mls(Register rd, Register rn, Register rm, Register ra,
557 Condition cond = AL) = 0;
Zheng Xuc6667102015-05-15 16:08:45 +0800558 virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
559 Condition cond = AL) = 0;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700560 virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
561 Condition cond = AL) = 0;
562
563 virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
564 virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700565
Roland Levillain981e4542014-11-14 11:47:14 +0000566 // Bit field extract instructions.
Roland Levillain51d3fc42014-11-13 14:11:42 +0000567 virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
568 Condition cond = AL) = 0;
Roland Levillain981e4542014-11-14 11:47:14 +0000569 virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
570 Condition cond = AL) = 0;
Roland Levillain51d3fc42014-11-13 14:11:42 +0000571
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700572 // Load/store instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700573 virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
574 virtual void str(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 ldrb(Register rd, const Address& ad, Condition cond = AL) = 0;
577 virtual void strb(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 ldrh(Register rd, const Address& ad, Condition cond = AL) = 0;
580 virtual void strh(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 ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0;
583 virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700584
Dave Allison65fcc2c2014-04-28 13:45:27 -0700585 virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0;
586 virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700587
Dave Allison65fcc2c2014-04-28 13:45:27 -0700588 virtual void ldm(BlockAddressMode am, Register base,
589 RegList regs, Condition cond = AL) = 0;
590 virtual void stm(BlockAddressMode am, Register base,
591 RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700592
Dave Allison65fcc2c2014-04-28 13:45:27 -0700593 virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
594 virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
Calin Juravle52c48962014-12-16 17:02:57 +0000595 virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
596 virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700597
598 // Miscellaneous instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700599 virtual void clrex(Condition cond = AL) = 0;
600 virtual void nop(Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700601
602 // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700603 virtual void bkpt(uint16_t imm16) = 0;
604 virtual void svc(uint32_t imm24) = 0;
605
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700606 virtual void it(Condition firstcond ATTRIBUTE_UNUSED,
607 ItState i1 ATTRIBUTE_UNUSED = kItOmitted,
608 ItState i2 ATTRIBUTE_UNUSED = kItOmitted,
609 ItState i3 ATTRIBUTE_UNUSED = kItOmitted) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700610 // Ignored if not supported.
611 }
612
613 virtual void cbz(Register rn, Label* target) = 0;
614 virtual void cbnz(Register rn, Label* target) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700615
616 // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
Dave Allison65fcc2c2014-04-28 13:45:27 -0700617 virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0;
618 virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0;
619 virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0;
620 virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0;
621 virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0;
622 virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0;
623 virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
624 virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700625
626 // Returns false if the immediate cannot be encoded.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700627 virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0;
628 virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700629
Dave Allison65fcc2c2014-04-28 13:45:27 -0700630 virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
631 virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
632 virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
633 virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700634
Dave Allison65fcc2c2014-04-28 13:45:27 -0700635 virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
636 virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
637 virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
638 virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
639 virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
640 virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
641 virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
642 virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
643 virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
644 virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
645 virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
646 virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700647
Dave Allison65fcc2c2014-04-28 13:45:27 -0700648 virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0;
649 virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
650 virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
651 virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
652 virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0;
653 virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700654
Dave Allison65fcc2c2014-04-28 13:45:27 -0700655 virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0;
656 virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0;
657 virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0;
658 virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0;
659 virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0;
660 virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0;
661 virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0;
662 virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0;
663 virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0;
664 virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700665
Dave Allison65fcc2c2014-04-28 13:45:27 -0700666 virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0;
667 virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
668 virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0;
669 virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0;
670 virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR
671
672 virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0;
673 virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
674 virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
675 virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700676
677 // Branch instructions.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700678 virtual void b(Label* label, Condition cond = AL) = 0;
679 virtual void bl(Label* label, Condition cond = AL) = 0;
680 virtual void blx(Register rm, Condition cond = AL) = 0;
681 virtual void bx(Register rm, Condition cond = AL) = 0;
682
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100683 // Memory barriers.
684 virtual void dmb(DmbOptions flavor) = 0;
685
Dave Allison65fcc2c2014-04-28 13:45:27 -0700686 void Pad(uint32_t bytes);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700687
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000688 // Adjust label position.
689 void AdjustLabelPosition(Label* label) {
690 DCHECK(label->IsBound());
691 uint32_t old_position = static_cast<uint32_t>(label->Position());
692 uint32_t new_position = GetAdjustedPosition(old_position);
693 label->Reinitialize();
694 DCHECK_GE(static_cast<int>(new_position), 0);
695 label->BindTo(static_cast<int>(new_position));
696 }
697
698 // Get the final position of a label after local fixup based on the old position
699 // recorded before FinalizeCode().
700 virtual uint32_t GetAdjustedPosition(uint32_t old_position) = 0;
701
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700702 // Macros.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700703 // Most of these are pure virtual as they need to be implemented per instruction set.
704
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000705 // Create a new literal with a given value.
Vladimir Marko88b2b802015-12-04 14:19:04 +0000706 // NOTE: Force the template parameter to be explicitly specified.
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000707 template <typename T>
Vladimir Marko88b2b802015-12-04 14:19:04 +0000708 Literal* NewLiteral(typename Identity<T>::type value) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000709 static_assert(std::is_integral<T>::value, "T must be an integral type.");
710 return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
711 }
712
713 // Create a new literal with the given data.
714 virtual Literal* NewLiteral(size_t size, const uint8_t* data) = 0;
715
716 // Load literal.
717 virtual void LoadLiteral(Register rt, Literal* literal) = 0;
718 virtual void LoadLiteral(Register rt, Register rt2, Literal* literal) = 0;
719 virtual void LoadLiteral(SRegister sd, Literal* literal) = 0;
720 virtual void LoadLiteral(DRegister dd, Literal* literal) = 0;
721
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700722 // Add signed constant value to rd. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700723 virtual void AddConstant(Register rd, Register rn, int32_t value,
Vladimir Marko449b1092015-09-08 12:16:45 +0100724 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
725 void AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond = AL) {
726 AddConstant(rd, rn, value, cond, kCcSet);
727 }
728 void AddConstant(Register rd, int32_t value, Condition cond = AL, SetCc set_cc = kCcDontCare) {
729 AddConstant(rd, rd, value, cond, set_cc);
730 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700731
Andreas Gampe7cffc3b2015-10-19 21:31:53 -0700732 virtual void CmpConstant(Register rn, int32_t value, Condition cond = AL) = 0;
733
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700734 // Load and Store. May clobber IP.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700735 virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000736 void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {
737 if (!vmovs(sd, value, cond)) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000738 int32_t int_value = bit_cast<int32_t, float>(value);
739 if (int_value == bit_cast<int32_t, float>(0.0f)) {
740 // 0.0 is quite common, so we special case it by loading
741 // 2.0 in `sd` and then substracting it.
742 bool success = vmovs(sd, 2.0, cond);
743 CHECK(success);
744 vsubs(sd, sd, sd, cond);
745 } else {
746 LoadImmediate(IP, int_value, cond);
747 vmovsr(sd, IP, cond);
748 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +0000749 }
750 }
751
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000752 void LoadDImmediate(DRegister sd, double value, Condition cond = AL) {
753 if (!vmovd(sd, value, cond)) {
754 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +0000755 if (int_value == bit_cast<uint64_t, double>(0.0)) {
756 // 0.0 is quite common, so we special case it by loading
757 // 2.0 in `sd` and then substracting it.
758 bool success = vmovd(sd, 2.0, cond);
759 CHECK(success);
760 vsubd(sd, sd, sd, cond);
761 } else {
762 if (sd < 16) {
763 SRegister low = static_cast<SRegister>(sd << 1);
764 SRegister high = static_cast<SRegister>(low + 1);
765 LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond);
766 if (High32Bits(int_value) == Low32Bits(int_value)) {
767 vmovs(high, low);
768 } else {
769 LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond);
770 }
771 } else {
772 LOG(FATAL) << "Unimplemented loading of double into a D register "
773 << "that cannot be split into two S registers";
774 }
775 }
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000776 }
777 }
778
Dave Allison65fcc2c2014-04-28 13:45:27 -0700779 virtual void MarkExceptionHandler(Label* label) = 0;
780 virtual void LoadFromOffset(LoadOperandType type,
781 Register reg,
782 Register base,
783 int32_t offset,
784 Condition cond = AL) = 0;
785 virtual void StoreToOffset(StoreOperandType type,
786 Register reg,
787 Register base,
788 int32_t offset,
789 Condition cond = AL) = 0;
790 virtual void LoadSFromOffset(SRegister reg,
791 Register base,
792 int32_t offset,
793 Condition cond = AL) = 0;
794 virtual void StoreSToOffset(SRegister reg,
795 Register base,
796 int32_t offset,
797 Condition cond = AL) = 0;
798 virtual void LoadDFromOffset(DRegister reg,
799 Register base,
800 int32_t offset,
801 Condition cond = AL) = 0;
802 virtual void StoreDToOffset(DRegister reg,
803 Register base,
804 int32_t offset,
805 Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700806
Dave Allison65fcc2c2014-04-28 13:45:27 -0700807 virtual void Push(Register rd, Condition cond = AL) = 0;
808 virtual void Pop(Register rd, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700809
Dave Allison65fcc2c2014-04-28 13:45:27 -0700810 virtual void PushList(RegList regs, Condition cond = AL) = 0;
811 virtual void PopList(RegList regs, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700812
Dave Allison65fcc2c2014-04-28 13:45:27 -0700813 virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700814
815 // Convenience shift instructions. Use mov instruction with shifter operand
816 // for variants setting the status flags or using a register shift count.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100817 virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
818 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
Dave Allison45fdb932014-06-25 12:37:10 -0700819
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100820 void Lsls(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
821 Lsl(rd, rm, shift_imm, cond, kCcSet);
822 }
823
824 virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
825 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
826
827 void Lsrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
828 Lsr(rd, rm, shift_imm, cond, kCcSet);
829 }
830
831 virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
832 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
833
834 void Asrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
835 Asr(rd, rm, shift_imm, cond, kCcSet);
836 }
837
838 virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
839 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
840
841 void Rors(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
842 Ror(rd, rm, shift_imm, cond, kCcSet);
843 }
844
845 virtual void Rrx(Register rd, Register rm,
846 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
847
848 void Rrxs(Register rd, Register rm, Condition cond = AL) {
849 Rrx(rd, rm, cond, kCcSet);
850 }
851
852 virtual void Lsl(Register rd, Register rm, Register rn,
853 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
854
855 void Lsls(Register rd, Register rm, Register rn, Condition cond = AL) {
856 Lsl(rd, rm, rn, cond, kCcSet);
857 }
858
859 virtual void Lsr(Register rd, Register rm, Register rn,
860 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
861
862 void Lsrs(Register rd, Register rm, Register rn, Condition cond = AL) {
863 Lsr(rd, rm, rn, cond, kCcSet);
864 }
865
866 virtual void Asr(Register rd, Register rm, Register rn,
867 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
868
869 void Asrs(Register rd, Register rm, Register rn, Condition cond = AL) {
870 Asr(rd, rm, rn, cond, kCcSet);
871 }
872
873 virtual void Ror(Register rd, Register rm, Register rn,
874 Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
875
876 void Rors(Register rd, Register rm, Register rn, Condition cond = AL) {
877 Ror(rd, rm, rn, cond, kCcSet);
878 }
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700879
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000880 // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes,
881 // `shifter_op` contains the operand.
882 virtual bool ShifterOperandCanHold(Register rd,
883 Register rn,
884 Opcode opcode,
885 uint32_t immediate,
Vladimir Markof5c09c32015-12-17 12:08:08 +0000886 SetCc set_cc,
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000887 ShifterOperand* shifter_op) = 0;
Vladimir Markof5c09c32015-12-17 12:08:08 +0000888 bool ShifterOperandCanHold(Register rd,
889 Register rn,
890 Opcode opcode,
891 uint32_t immediate,
892 ShifterOperand* shifter_op) {
893 return ShifterOperandCanHold(rd, rn, opcode, immediate, kCcDontCare, shifter_op);
894 }
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000895
Nicolas Geoffray0ccb3832015-10-14 11:44:23 +0100896 virtual bool ShifterOperandCanAlwaysHold(uint32_t immediate) = 0;
Nicolas Geoffray5bd05a52015-10-13 09:48:30 +0100897
Ian Rogers13735952014-10-08 12:43:28 -0700898 static bool IsInstructionForExceptionHandling(uintptr_t pc);
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700899
Dave Allison65fcc2c2014-04-28 13:45:27 -0700900 virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
901 virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
Carl Shapiroa2e18e12011-06-21 18:57:55 -0700902
Ian Rogers2c8f6532011-09-02 17:16:34 -0700903 //
904 // Overridden common assembler high-level functionality
905 //
Ian Rogers45a76cb2011-07-21 22:00:15 -0700906
Ian Rogers2c8f6532011-09-02 17:16:34 -0700907 // Emit code that will create an activation on the stack
Ian Rogersdd7624d2014-03-14 17:43:00 -0700908 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
909 const std::vector<ManagedRegister>& callee_save_regs,
910 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -0700911
Ian Rogers2c8f6532011-09-02 17:16:34 -0700912 // Emit code that will remove an activation from the stack
Ian Rogersdd7624d2014-03-14 17:43:00 -0700913 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
Dave Allison65fcc2c2014-04-28 13:45:27 -0700914 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700915
Ian Rogersdd7624d2014-03-14 17:43:00 -0700916 void IncreaseFrameSize(size_t adjust) OVERRIDE;
917 void DecreaseFrameSize(size_t adjust) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700918
919 // Store routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700920 void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
921 void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
922 void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700923
Ian Rogersdd7624d2014-03-14 17:43:00 -0700924 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700925
Ian Rogersdd7624d2014-03-14 17:43:00 -0700926 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
927 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700928
Ian Rogersdd7624d2014-03-14 17:43:00 -0700929 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
930 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700931
Ian Rogersdd7624d2014-03-14 17:43:00 -0700932 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700933
Ian Rogersdd7624d2014-03-14 17:43:00 -0700934 void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
935 ManagedRegister scratch) OVERRIDE;
Ian Rogersbdb03912011-09-14 00:55:44 -0700936
Ian Rogers2c8f6532011-09-02 17:16:34 -0700937 // Load routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700938 void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700939
Ian Rogersdd7624d2014-03-14 17:43:00 -0700940 void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700941
Mathieu Chartiere401d142015-04-22 13:56:20 -0700942 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700943
Mathieu Chartiere401d142015-04-22 13:56:20 -0700944 void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100945 bool unpoison_reference) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700946
Ian Rogersdd7624d2014-03-14 17:43:00 -0700947 void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700948
Ian Rogersdd7624d2014-03-14 17:43:00 -0700949 void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700950
951 // Copying routines
Ian Rogersdd7624d2014-03-14 17:43:00 -0700952 void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700953
Ian Rogersdd7624d2014-03-14 17:43:00 -0700954 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
955 ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700956
Ian Rogersdd7624d2014-03-14 17:43:00 -0700957 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
958 OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700959
Ian Rogersdd7624d2014-03-14 17:43:00 -0700960 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700961
Ian Rogersdd7624d2014-03-14 17:43:00 -0700962 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700963
Ian Rogersdd7624d2014-03-14 17:43:00 -0700964 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch,
965 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700966
Ian Rogersdd7624d2014-03-14 17:43:00 -0700967 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch,
968 size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700969
Ian Rogersdd7624d2014-03-14 17:43:00 -0700970 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch,
971 size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700972
Ian Rogersdd7624d2014-03-14 17:43:00 -0700973 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
974 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700975
Ian Rogersdd7624d2014-03-14 17:43:00 -0700976 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
977 ManagedRegister scratch, size_t size) OVERRIDE;
Ian Rogersdc51b792011-09-22 20:41:37 -0700978
jeffhao58136ca2012-05-24 13:40:11 -0700979 // Sign extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700980 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao58136ca2012-05-24 13:40:11 -0700981
jeffhaocee4d0c2012-06-15 14:42:01 -0700982 // Zero extension
Ian Rogersdd7624d2014-03-14 17:43:00 -0700983 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhaocee4d0c2012-06-15 14:42:01 -0700984
Ian Rogers2c8f6532011-09-02 17:16:34 -0700985 // Exploit fast access in managed code to Thread::Current()
Ian Rogersdd7624d2014-03-14 17:43:00 -0700986 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
987 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700988
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700989 // 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 -0700990 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700991 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700992 // null.
993 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
994 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700995
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700996 // 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 -0700997 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700998 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
999 ManagedRegister scratch, bool null_allowed) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001000
Mathieu Chartiereb8167a2014-05-07 15:43:14 -07001001 // src holds a handle scope entry (Object**) load this into dst
1002 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001003
1004 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
1005 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001006 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
1007 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001008
1009 // Call to address held at [base+offset]
Ian Rogersdd7624d2014-03-14 17:43:00 -07001010 void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
1011 void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
1012 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001013
Ian Rogers2c8f6532011-09-02 17:16:34 -07001014 // Generate code to check if Thread::Current()->exception_ is non-null
1015 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -07001016 void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
Ian Rogersb033c752011-07-20 12:22:35 -07001017
Dave Allison65fcc2c2014-04-28 13:45:27 -07001018 static uint32_t ModifiedImmediate(uint32_t value);
Carl Shapiroa2e18e12011-06-21 18:57:55 -07001019
Dave Allison45fdb932014-06-25 12:37:10 -07001020 static bool IsLowRegister(Register r) {
1021 return r < R8;
1022 }
1023
1024 static bool IsHighRegister(Register r) {
1025 return r >= R8;
1026 }
1027
Roland Levillain4d027112015-07-01 15:41:14 +01001028 //
1029 // Heap poisoning.
1030 //
1031
1032 // Poison a heap reference contained in `reg`.
1033 void PoisonHeapReference(Register reg) {
1034 // reg = -reg.
1035 rsb(reg, reg, ShifterOperand(0));
1036 }
1037 // Unpoison a heap reference contained in `reg`.
1038 void UnpoisonHeapReference(Register reg) {
1039 // reg = -reg.
1040 rsb(reg, reg, ShifterOperand(0));
1041 }
1042 // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
1043 void MaybeUnpoisonHeapReference(Register reg) {
1044 if (kPoisonHeapReferences) {
1045 UnpoisonHeapReference(reg);
1046 }
1047 }
1048
Andreas Gampe85b62f22015-09-09 13:15:38 -07001049 void Jump(Label* label) OVERRIDE {
1050 b(label);
1051 }
1052
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001053 // Jump table support. This is split into three functions:
1054 //
1055 // * CreateJumpTable creates the internal metadata to track the jump targets, and emits code to
1056 // load the base address of the jump table.
1057 //
1058 // * EmitJumpTableDispatch emits the code to actually jump, assuming that the right table value
1059 // has been loaded into a register already.
1060 //
1061 // * FinalizeTables emits the jump table into the literal pool. This can only be called after the
1062 // labels for the jump targets have been finalized.
1063
1064 // Create a jump table for the given labels that will be emitted when finalizing. Create a load
1065 // sequence (or placeholder) that stores the base address into the given register. When the table
1066 // is emitted, offsets will be relative to the location EmitJumpTableDispatch was called on (the
1067 // anchor).
1068 virtual JumpTable* CreateJumpTable(std::vector<Label*>&& labels, Register base_reg) = 0;
1069
1070 // Emit the jump-table jump, assuming that the right value was loaded into displacement_reg.
1071 virtual void EmitJumpTableDispatch(JumpTable* jump_table, Register displacement_reg) = 0;
1072
1073 // Bind a Label that needs to be updated by the assembler in FinalizeCode() if its position
1074 // changes due to branch/literal fixup.
1075 void BindTrackedLabel(Label* label) {
1076 Bind(label);
1077 tracked_labels_.push_back(label);
1078 }
1079
Dave Allison65fcc2c2014-04-28 13:45:27 -07001080 protected:
Carl Shapiroa2e18e12011-06-21 18:57:55 -07001081 // Returns whether or not the given register is used for passing parameters.
1082 static int RegisterCompare(const Register* reg1, const Register* reg2) {
1083 return *reg1 - *reg2;
1084 }
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07001085
1086 void FinalizeTrackedLabels();
1087
1088 // Tracked labels. Use a vector, as we need to sort before adjusting.
1089 std::vector<Label*> tracked_labels_;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001090};
1091
Ian Rogers2c8f6532011-09-02 17:16:34 -07001092// Slowpath entered when Thread::Current()->_exception is non-null
Ian Rogersdd7624d2014-03-14 17:43:00 -07001093class ArmExceptionSlowPath FINAL : public SlowPath {
Ian Rogers2c8f6532011-09-02 17:16:34 -07001094 public:
Roland Levillain3887c462015-08-12 18:15:42 +01001095 ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust)
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001096 : scratch_(scratch), stack_adjust_(stack_adjust) {
1097 }
Ian Rogersdd7624d2014-03-14 17:43:00 -07001098 void Emit(Assembler *sp_asm) OVERRIDE;
Ian Rogers67375ac2011-09-14 00:55:44 -07001099 private:
1100 const ArmManagedRegister scratch_;
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001101 const size_t stack_adjust_;
Ian Rogers2c8f6532011-09-02 17:16:34 -07001102};
1103
Ian Rogers2c8f6532011-09-02 17:16:34 -07001104} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -07001105} // namespace art
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001106
Ian Rogers166db042013-07-26 12:05:57 -07001107#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_