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