assembler_arm.h revision 96f89a290eb67d7bf4b1636798fa28df14309cc7
1/*
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 */
16
17#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
18#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
19
20#include <vector>
21
22#include "base/logging.h"
23#include "constants_arm.h"
24#include "utils/arm/managed_register_arm.h"
25#include "utils/assembler.h"
26#include "offsets.h"
27#include "utils.h"
28
29namespace art {
30namespace arm {
31
32class ShifterOperand {
33 public:
34  ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
35      is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
36  }
37
38  explicit ShifterOperand(uint32_t immed);
39
40  // Data-processing operands - Register
41  explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister),
42      is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
43  }
44
45  ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister),
46      rs_(kNoRegister),
47      is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) {
48  }
49
50  ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm),
51      rs_(kNoRegister),
52      is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) {
53  }
54
55  // Data-processing operands - Logical shift/rotate by register
56  ShifterOperand(Register rm, Shift shift, Register rs)  : type_(kRegister), rm_(rm),
57      rs_(rs),
58      is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) {
59  }
60
61  bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); }
62
63  uint32_t type() const {
64    CHECK(is_valid());
65    return type_;
66  }
67
68  uint32_t encodingArm() const;
69  uint32_t encodingThumb() const;
70
71  bool IsEmpty() const {
72    return type_ == kUnknown;
73  }
74
75  bool IsImmediate() const {
76    return type_ == kImmediate;
77  }
78
79  bool IsRegister() const {
80    return type_ == kRegister;
81  }
82
83  bool IsShift() const {
84    return is_shift_;
85  }
86
87  uint32_t GetImmediate() const {
88    return immed_;
89  }
90
91  Shift GetShift() const {
92    return shift_;
93  }
94
95  Register GetRegister() const {
96    return rm_;
97  }
98
99  enum Type {
100    kUnknown = -1,
101    kRegister,
102    kImmediate
103  };
104
105  static bool CanHoldArm(uint32_t immediate, ShifterOperand* shifter_op) {
106    // Avoid the more expensive test for frequent small immediate values.
107    if (immediate < (1 << kImmed8Bits)) {
108      shifter_op->type_ = kImmediate;
109      shifter_op->is_rotate_ = true;
110      shifter_op->rotate_ = 0;
111      shifter_op->immed_ = immediate;
112      return true;
113    }
114    // Note that immediate must be unsigned for the test to work correctly.
115    for (int rot = 0; rot < 16; rot++) {
116      uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot));
117      if (imm8 < (1 << kImmed8Bits)) {
118        shifter_op->type_ = kImmediate;
119        shifter_op->is_rotate_ = true;
120        shifter_op->rotate_ = rot;
121        shifter_op->immed_ = imm8;
122        return true;
123      }
124    }
125    return false;
126  }
127
128  static bool CanHoldThumb(Register rd, Register rn, Opcode opcode,
129                           uint32_t immediate, ShifterOperand* shifter_op);
130
131
132 private:
133  Type type_;
134  Register rm_;
135  Register rs_;
136  bool is_rotate_;
137  bool is_shift_;
138  Shift shift_;
139  uint32_t rotate_;
140  uint32_t immed_;
141
142#ifdef SOURCE_ASSEMBLER_SUPPORT
143  friend class BinaryAssembler;
144#endif
145};
146
147
148enum LoadOperandType {
149  kLoadSignedByte,
150  kLoadUnsignedByte,
151  kLoadSignedHalfword,
152  kLoadUnsignedHalfword,
153  kLoadWord,
154  kLoadWordPair,
155  kLoadSWord,
156  kLoadDWord
157};
158
159
160enum StoreOperandType {
161  kStoreByte,
162  kStoreHalfword,
163  kStoreWord,
164  kStoreWordPair,
165  kStoreSWord,
166  kStoreDWord
167};
168
169
170// Load/store multiple addressing mode.
171enum BlockAddressMode {
172  // bit encoding P U W
173  DA           = (0|0|0) << 21,  // decrement after
174  IA           = (0|4|0) << 21,  // increment after
175  DB           = (8|0|0) << 21,  // decrement before
176  IB           = (8|4|0) << 21,  // increment before
177  DA_W         = (0|0|1) << 21,  // decrement after with writeback to base
178  IA_W         = (0|4|1) << 21,  // increment after with writeback to base
179  DB_W         = (8|0|1) << 21,  // decrement before with writeback to base
180  IB_W         = (8|4|1) << 21   // increment before with writeback to base
181};
182
183class Address {
184 public:
185  // Memory operand addressing mode (in ARM encoding form.  For others we need
186  // to adjust)
187  enum Mode {
188    // bit encoding P U W
189    Offset       = (8|4|0) << 21,  // offset (w/o writeback to base)
190    PreIndex     = (8|4|1) << 21,  // pre-indexed addressing with writeback
191    PostIndex    = (0|4|0) << 21,  // post-indexed addressing with writeback
192    NegOffset    = (8|0|0) << 21,  // negative offset (w/o writeback to base)
193    NegPreIndex  = (8|0|1) << 21,  // negative pre-indexed with writeback
194    NegPostIndex = (0|0|0) << 21   // negative post-indexed with writeback
195  };
196
197  Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
198      offset_(offset),
199      am_(am), is_immed_offset_(true), shift_(LSL) {
200  }
201
202  Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
203      am_(am), is_immed_offset_(false), shift_(LSL) {
204    CHECK_NE(rm, PC);
205  }
206
207  Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
208                       rn_(rn), rm_(rm), offset_(count),
209                       am_(am), is_immed_offset_(false), shift_(shift) {
210    CHECK_NE(rm, PC);
211  }
212
213  // LDR(literal) - pc relative load.
214  explicit Address(int32_t offset) :
215               rn_(PC), rm_(R0), offset_(offset),
216               am_(Offset), is_immed_offset_(false), shift_(LSL) {
217  }
218
219  static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
220  static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset);
221
222  static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset);
223  static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
224
225  uint32_t encodingArm() const;
226  uint32_t encodingThumb(bool is_32bit) const;
227
228  uint32_t encoding3() const;
229  uint32_t vencoding() const;
230
231  uint32_t encodingThumbLdrdStrd() const;
232
233  Register GetRegister() const {
234    return rn_;
235  }
236
237  Register GetRegisterOffset() const {
238    return rm_;
239  }
240
241  int32_t GetOffset() const {
242    return offset_;
243  }
244
245  Mode GetMode() const {
246    return am_;
247  }
248
249  bool IsImmediate() const {
250    return is_immed_offset_;
251  }
252
253  Shift GetShift() const {
254    return shift_;
255  }
256
257  int32_t GetShiftCount() const {
258    CHECK(!is_immed_offset_);
259    return offset_;
260  }
261
262 private:
263  Register rn_;
264  Register rm_;
265  int32_t offset_;      // Used as shift amount for register offset.
266  Mode am_;
267  bool is_immed_offset_;
268  Shift shift_;
269};
270
271// Instruction encoding bits.
272enum {
273  H   = 1 << 5,   // halfword (or byte)
274  L   = 1 << 20,  // load (or store)
275  S   = 1 << 20,  // set condition code (or leave unchanged)
276  W   = 1 << 21,  // writeback base register (or leave unchanged)
277  A   = 1 << 21,  // accumulate in multiply instruction (or not)
278  B   = 1 << 22,  // unsigned byte (or word)
279  N   = 1 << 22,  // long (or short)
280  U   = 1 << 23,  // positive (or negative) offset/index
281  P   = 1 << 24,  // offset/pre-indexed addressing (or post-indexed addressing)
282  I   = 1 << 25,  // immediate shifter operand (or not)
283
284  B0 = 1,
285  B1 = 1 << 1,
286  B2 = 1 << 2,
287  B3 = 1 << 3,
288  B4 = 1 << 4,
289  B5 = 1 << 5,
290  B6 = 1 << 6,
291  B7 = 1 << 7,
292  B8 = 1 << 8,
293  B9 = 1 << 9,
294  B10 = 1 << 10,
295  B11 = 1 << 11,
296  B12 = 1 << 12,
297  B13 = 1 << 13,
298  B14 = 1 << 14,
299  B15 = 1 << 15,
300  B16 = 1 << 16,
301  B17 = 1 << 17,
302  B18 = 1 << 18,
303  B19 = 1 << 19,
304  B20 = 1 << 20,
305  B21 = 1 << 21,
306  B22 = 1 << 22,
307  B23 = 1 << 23,
308  B24 = 1 << 24,
309  B25 = 1 << 25,
310  B26 = 1 << 26,
311  B27 = 1 << 27,
312  B28 = 1 << 28,
313  B29 = 1 << 29,
314  B30 = 1 << 30,
315  B31 = 1 << 31,
316
317  // Instruction bit masks.
318  RdMask = 15 << 12,  // in str instruction
319  CondMask = 15 << 28,
320  CoprocessorMask = 15 << 8,
321  OpCodeMask = 15 << 21,  // in data-processing instructions
322  Imm24Mask = (1 << 24) - 1,
323  Off12Mask = (1 << 12) - 1,
324
325  // ldrex/strex register field encodings.
326  kLdExRnShift = 16,
327  kLdExRtShift = 12,
328  kStrExRnShift = 16,
329  kStrExRdShift = 12,
330  kStrExRtShift = 0,
331};
332
333// IfThen state for IT instructions.
334enum ItState {
335  kItOmitted,
336  kItThen,
337  kItT = kItThen,
338  kItElse,
339  kItE = kItElse
340};
341
342constexpr uint32_t kNoItCondition = 3;
343constexpr uint32_t kInvalidModifiedImmediate = -1;
344
345extern const char* kRegisterNames[];
346extern const char* kConditionNames[];
347extern std::ostream& operator<<(std::ostream& os, const Register& rhs);
348extern std::ostream& operator<<(std::ostream& os, const SRegister& rhs);
349extern std::ostream& operator<<(std::ostream& os, const DRegister& rhs);
350extern std::ostream& operator<<(std::ostream& os, const Condition& rhs);
351
352// This is an abstract ARM assembler.  Subclasses provide assemblers for the individual
353// instruction sets (ARM32, Thumb2, etc.)
354//
355class ArmAssembler : public Assembler {
356 public:
357  virtual ~ArmAssembler() {}
358
359  // Is this assembler for the thumb instruction set?
360  virtual bool IsThumb() const = 0;
361
362  // Data-processing instructions.
363  virtual void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
364
365  virtual void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
366
367  virtual void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
368  virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
369
370  virtual void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
371  virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
372
373  virtual void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
374
375  virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
376
377  virtual void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
378
379  virtual void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
380
381  virtual void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
382
383  virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
384
385  virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
386
387  virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
388
389  virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
390
391  virtual void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
392  virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
393
394  virtual void mov(Register rd, const ShifterOperand& so, Condition cond = AL) = 0;
395  virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) = 0;
396
397  virtual void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
398
399  virtual void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) = 0;
400  virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) = 0;
401
402  // Miscellaneous data-processing instructions.
403  virtual void clz(Register rd, Register rm, Condition cond = AL) = 0;
404  virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0;
405  virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0;
406
407  // Multiply instructions.
408  virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
409  virtual void mla(Register rd, Register rn, Register rm, Register ra,
410                   Condition cond = AL) = 0;
411  virtual void mls(Register rd, Register rn, Register rm, Register ra,
412                   Condition cond = AL) = 0;
413  virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
414                     Condition cond = AL) = 0;
415
416  virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
417  virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
418
419  // Load/store instructions.
420  virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
421  virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0;
422
423  virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0;
424  virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0;
425
426  virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0;
427  virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0;
428
429  virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0;
430  virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0;
431
432  virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0;
433  virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0;
434
435  virtual void ldm(BlockAddressMode am, Register base,
436                   RegList regs, Condition cond = AL) = 0;
437  virtual void stm(BlockAddressMode am, Register base,
438                   RegList regs, Condition cond = AL) = 0;
439
440  virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
441  virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
442
443  // Miscellaneous instructions.
444  virtual void clrex(Condition cond = AL) = 0;
445  virtual void nop(Condition cond = AL) = 0;
446
447  // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
448  virtual void bkpt(uint16_t imm16) = 0;
449  virtual void svc(uint32_t imm24) = 0;
450
451  virtual void it(Condition firstcond, ItState i1 = kItOmitted,
452                  ItState i2 = kItOmitted, ItState i3 = kItOmitted) {
453    // Ignored if not supported.
454  }
455
456  virtual void cbz(Register rn, Label* target) = 0;
457  virtual void cbnz(Register rn, Label* target) = 0;
458
459  // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
460  virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0;
461  virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0;
462  virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0;
463  virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0;
464  virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0;
465  virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0;
466  virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
467  virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
468
469  // Returns false if the immediate cannot be encoded.
470  virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0;
471  virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0;
472
473  virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
474  virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
475  virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
476  virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
477
478  virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
479  virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
480  virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
481  virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
482  virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
483  virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
484  virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
485  virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
486  virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
487  virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
488  virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
489  virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
490
491  virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0;
492  virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
493  virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
494  virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
495  virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0;
496  virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
497
498  virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0;
499  virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0;
500  virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0;
501  virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0;
502  virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0;
503  virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0;
504  virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0;
505  virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0;
506  virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0;
507  virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0;
508
509  virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0;
510  virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
511  virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0;
512  virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0;
513  virtual void vmstat(Condition cond = AL) = 0;  // VMRS APSR_nzcv, FPSCR
514
515  virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0;
516  virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
517  virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
518  virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
519
520  // Branch instructions.
521  virtual void b(Label* label, Condition cond = AL) = 0;
522  virtual void bl(Label* label, Condition cond = AL) = 0;
523  virtual void blx(Register rm, Condition cond = AL) = 0;
524  virtual void bx(Register rm, Condition cond = AL) = 0;
525
526  void Pad(uint32_t bytes);
527
528  // Macros.
529  // Most of these are pure virtual as they need to be implemented per instruction set.
530
531  // Add signed constant value to rd. May clobber IP.
532  virtual void AddConstant(Register rd, int32_t value, Condition cond = AL) = 0;
533  virtual void AddConstant(Register rd, Register rn, int32_t value,
534                           Condition cond = AL) = 0;
535  virtual void AddConstantSetFlags(Register rd, Register rn, int32_t value,
536                                   Condition cond = AL) = 0;
537  virtual void AddConstantWithCarry(Register rd, Register rn, int32_t value,
538                                    Condition cond = AL) = 0;
539
540  // Load and Store. May clobber IP.
541  virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
542  virtual void LoadSImmediate(SRegister sd, float value, Condition cond = AL) = 0;
543  virtual void LoadDImmediate(DRegister dd, double value,
544                              Register scratch, Condition cond = AL) = 0;
545  virtual void MarkExceptionHandler(Label* label) = 0;
546  virtual void LoadFromOffset(LoadOperandType type,
547                              Register reg,
548                              Register base,
549                              int32_t offset,
550                              Condition cond = AL) = 0;
551  virtual void StoreToOffset(StoreOperandType type,
552                             Register reg,
553                             Register base,
554                             int32_t offset,
555                             Condition cond = AL) = 0;
556  virtual void LoadSFromOffset(SRegister reg,
557                               Register base,
558                               int32_t offset,
559                               Condition cond = AL) = 0;
560  virtual void StoreSToOffset(SRegister reg,
561                              Register base,
562                              int32_t offset,
563                              Condition cond = AL) = 0;
564  virtual void LoadDFromOffset(DRegister reg,
565                               Register base,
566                               int32_t offset,
567                               Condition cond = AL) = 0;
568  virtual void StoreDToOffset(DRegister reg,
569                              Register base,
570                              int32_t offset,
571                              Condition cond = AL) = 0;
572
573  virtual void Push(Register rd, Condition cond = AL) = 0;
574  virtual void Pop(Register rd, Condition cond = AL) = 0;
575
576  virtual void PushList(RegList regs, Condition cond = AL) = 0;
577  virtual void PopList(RegList regs, Condition cond = AL) = 0;
578
579  virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
580
581  // Convenience shift instructions. Use mov instruction with shifter operand
582  // for variants setting the status flags or using a register shift count.
583  virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
584                   Condition cond = AL) = 0;
585  virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
586                   Condition cond = AL) = 0;
587  virtual void Asr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
588                   Condition cond = AL) = 0;
589  virtual void Ror(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
590                   Condition cond = AL) = 0;
591  virtual void Rrx(Register rd, Register rm, bool setcc = false,
592                   Condition cond = AL) = 0;
593
594  virtual void Lsl(Register rd, Register rm, Register rn, bool setcc = false,
595                   Condition cond = AL) = 0;
596  virtual void Lsr(Register rd, Register rm, Register rn, bool setcc = false,
597                   Condition cond = AL) = 0;
598  virtual void Asr(Register rd, Register rm, Register rn, bool setcc = false,
599                   Condition cond = AL) = 0;
600  virtual void Ror(Register rd, Register rm, Register rn, bool setcc = false,
601                   Condition cond = AL) = 0;
602
603  static bool IsInstructionForExceptionHandling(uword pc);
604
605  virtual void Bind(Label* label) = 0;
606
607  virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
608  virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
609
610  //
611  // Overridden common assembler high-level functionality
612  //
613
614  // Emit code that will create an activation on the stack
615  void BuildFrame(size_t frame_size, ManagedRegister method_reg,
616                  const std::vector<ManagedRegister>& callee_save_regs,
617                  const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
618
619  // Emit code that will remove an activation from the stack
620  void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
621    OVERRIDE;
622
623  void IncreaseFrameSize(size_t adjust) OVERRIDE;
624  void DecreaseFrameSize(size_t adjust) OVERRIDE;
625
626  // Store routines
627  void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
628  void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
629  void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
630
631  void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
632
633  void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
634      OVERRIDE;
635
636  void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
637                                  ManagedRegister scratch) OVERRIDE;
638
639  void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
640
641  void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
642                     ManagedRegister scratch) OVERRIDE;
643
644  // Load routines
645  void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
646
647  void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
648
649  void LoadRef(ManagedRegister dest, FrameOffset  src) OVERRIDE;
650
651  void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs) OVERRIDE;
652
653  void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
654
655  void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
656
657  // Copying routines
658  void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
659
660  void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
661                              ManagedRegister scratch) OVERRIDE;
662
663  void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
664      OVERRIDE;
665
666  void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
667
668  void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
669
670  void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch,
671            size_t size) OVERRIDE;
672
673  void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch,
674            size_t size) OVERRIDE;
675
676  void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch,
677            size_t size) OVERRIDE;
678
679  void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
680            ManagedRegister scratch, size_t size) OVERRIDE;
681
682  void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
683            ManagedRegister scratch, size_t size) OVERRIDE;
684
685  // Sign extension
686  void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
687
688  // Zero extension
689  void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
690
691  // Exploit fast access in managed code to Thread::Current()
692  void GetCurrentThread(ManagedRegister tr) OVERRIDE;
693  void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
694
695  // Set up out_reg to hold a Object** into the handle scope, or to be NULL if the
696  // value is null and null_allowed. in_reg holds a possibly stale reference
697  // that can be used to avoid loading the handle scope entry to see if the value is
698  // NULL.
699  void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, ManagedRegister in_reg,
700                       bool null_allowed) OVERRIDE;
701
702  // Set up out_off to hold a Object** into the handle scope, or to be NULL if the
703  // value is null and null_allowed.
704  void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister scratch,
705                       bool null_allowed) OVERRIDE;
706
707  // src holds a handle scope entry (Object**) load this into dst
708  void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
709
710  // Heap::VerifyObject on src. In some cases (such as a reference to this) we
711  // know that src may not be null.
712  void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
713  void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
714
715  // Call to address held at [base+offset]
716  void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
717  void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
718  void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
719
720  // Generate code to check if Thread::Current()->exception_ is non-null
721  // and branch to a ExceptionSlowPath if it is.
722  void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
723
724  static uint32_t ModifiedImmediate(uint32_t value);
725
726  static bool IsLowRegister(Register r) {
727    return r < R8;
728  }
729
730  static bool IsHighRegister(Register r) {
731     return r >= R8;
732  }
733
734 protected:
735  // Returns whether or not the given register is used for passing parameters.
736  static int RegisterCompare(const Register* reg1, const Register* reg2) {
737    return *reg1 - *reg2;
738  }
739};
740
741// Slowpath entered when Thread::Current()->_exception is non-null
742class ArmExceptionSlowPath FINAL : public SlowPath {
743 public:
744  explicit ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust)
745      : scratch_(scratch), stack_adjust_(stack_adjust) {
746  }
747  void Emit(Assembler *sp_asm) OVERRIDE;
748 private:
749  const ArmManagedRegister scratch_;
750  const size_t stack_adjust_;
751};
752
753}  // namespace arm
754}  // namespace art
755
756#endif  // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
757