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 <type_traits>
21 #include <vector>
22 
23 #include "base/arena_allocator.h"
24 #include "base/arena_containers.h"
25 #include "base/bit_utils.h"
26 #include "base/logging.h"
27 #include "base/stl_util.h"
28 #include "base/value_object.h"
29 #include "constants_arm.h"
30 #include "utils/arm/managed_register_arm.h"
31 #include "utils/assembler.h"
32 #include "offsets.h"
33 
34 namespace art {
35 namespace arm {
36 
37 class Arm32Assembler;
38 class Thumb2Assembler;
39 
40 // Assembler literal is a value embedded in code, retrieved using a PC-relative load.
41 class Literal {
42  public:
43   static constexpr size_t kMaxSize = 8;
44 
Literal(uint32_t size,const uint8_t * data)45   Literal(uint32_t size, const uint8_t* data)
46       : label_(), size_(size) {
47     DCHECK_LE(size, Literal::kMaxSize);
48     memcpy(data_, data, size);
49   }
50 
51   template <typename T>
GetValue()52   T GetValue() const {
53     DCHECK_EQ(size_, sizeof(T));
54     T value;
55     memcpy(&value, data_, sizeof(T));
56     return value;
57   }
58 
GetSize()59   uint32_t GetSize() const {
60     return size_;
61   }
62 
GetData()63   const uint8_t* GetData() const {
64     return data_;
65   }
66 
GetLabel()67   Label* GetLabel() {
68     return &label_;
69   }
70 
GetLabel()71   const Label* GetLabel() const {
72     return &label_;
73   }
74 
75  private:
76   Label label_;
77   const uint32_t size_;
78   uint8_t data_[kMaxSize];
79 
80   DISALLOW_COPY_AND_ASSIGN(Literal);
81 };
82 
83 // Jump table: table of labels emitted after the literals. Similar to literals.
84 class JumpTable {
85  public:
JumpTable(std::vector<Label * > && labels)86   explicit JumpTable(std::vector<Label*>&& labels)
87       : label_(), anchor_label_(), labels_(std::move(labels)) {
88   }
89 
GetSize()90   uint32_t GetSize() const {
91     return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t);
92   }
93 
GetData()94   const std::vector<Label*>& GetData() const {
95     return labels_;
96   }
97 
GetLabel()98   Label* GetLabel() {
99     return &label_;
100   }
101 
GetLabel()102   const Label* GetLabel() const {
103     return &label_;
104   }
105 
GetAnchorLabel()106   Label* GetAnchorLabel() {
107     return &anchor_label_;
108   }
109 
GetAnchorLabel()110   const Label* GetAnchorLabel() const {
111     return &anchor_label_;
112   }
113 
114  private:
115   Label label_;
116   Label anchor_label_;
117   std::vector<Label*> labels_;
118 
119   DISALLOW_COPY_AND_ASSIGN(JumpTable);
120 };
121 
122 class ShifterOperand {
123  public:
ShifterOperand()124   ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
125       is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
126   }
127 
128   explicit ShifterOperand(uint32_t immed);
129 
130   // Data-processing operands - Register
ShifterOperand(Register rm)131   explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister),
132       is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) {
133   }
134 
ShifterOperand(uint32_t rotate,uint32_t immed8)135   ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister),
136       rs_(kNoRegister),
137       is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) {
138   }
139 
type_(kRegister)140   ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm),
141       rs_(kNoRegister),
142       is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) {
143   }
144 
145   // Data-processing operands - Logical shift/rotate by register
ShifterOperand(Register rm,Shift shift,Register rs)146   ShifterOperand(Register rm, Shift shift, Register rs)  : type_(kRegister), rm_(rm),
147       rs_(rs),
148       is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) {
149   }
150 
is_valid()151   bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); }
152 
type()153   uint32_t type() const {
154     CHECK(is_valid());
155     return type_;
156   }
157 
158   uint32_t encodingArm() const;
159   uint32_t encodingThumb() const;
160 
IsEmpty()161   bool IsEmpty() const {
162     return type_ == kUnknown;
163   }
164 
IsImmediate()165   bool IsImmediate() const {
166     return type_ == kImmediate;
167   }
168 
IsRegister()169   bool IsRegister() const {
170     return type_ == kRegister;
171   }
172 
IsShift()173   bool IsShift() const {
174     return is_shift_;
175   }
176 
GetImmediate()177   uint32_t GetImmediate() const {
178     return immed_;
179   }
180 
GetShift()181   Shift GetShift() const {
182     return shift_;
183   }
184 
GetRegister()185   Register GetRegister() const {
186     return rm_;
187   }
188 
GetSecondRegister()189   Register GetSecondRegister() const {
190     return rs_;
191   }
192 
193   enum Type {
194     kUnknown = -1,
195     kRegister,
196     kImmediate
197   };
198 
199  private:
200   Type type_;
201   Register rm_;
202   Register rs_;
203   bool is_rotate_;
204   bool is_shift_;
205   Shift shift_;
206   uint32_t rotate_;
207   uint32_t immed_;
208 
209   friend class Arm32Assembler;
210   friend class Thumb2Assembler;
211 
212 #ifdef SOURCE_ASSEMBLER_SUPPORT
213   friend class BinaryAssembler;
214 #endif
215 };
216 
217 
218 enum LoadOperandType {
219   kLoadSignedByte,
220   kLoadUnsignedByte,
221   kLoadSignedHalfword,
222   kLoadUnsignedHalfword,
223   kLoadWord,
224   kLoadWordPair,
225   kLoadSWord,
226   kLoadDWord
227 };
228 
229 
230 enum StoreOperandType {
231   kStoreByte,
232   kStoreHalfword,
233   kStoreWord,
234   kStoreWordPair,
235   kStoreSWord,
236   kStoreDWord
237 };
238 
239 
240 // Load/store multiple addressing mode.
241 enum BlockAddressMode {
242   // bit encoding P U W
243   DA           = (0|0|0) << 21,  // decrement after
244   IA           = (0|4|0) << 21,  // increment after
245   DB           = (8|0|0) << 21,  // decrement before
246   IB           = (8|4|0) << 21,  // increment before
247   DA_W         = (0|0|1) << 21,  // decrement after with writeback to base
248   IA_W         = (0|4|1) << 21,  // increment after with writeback to base
249   DB_W         = (8|0|1) << 21,  // decrement before with writeback to base
250   IB_W         = (8|4|1) << 21   // increment before with writeback to base
251 };
252 inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) {
253   os << static_cast<int>(rhs);
254   return os;
255 }
256 
257 class Address : public ValueObject {
258  public:
259   // Memory operand addressing mode (in ARM encoding form.  For others we need
260   // to adjust)
261   enum Mode {
262     // bit encoding P U W
263     Offset       = (8|4|0) << 21,  // offset (w/o writeback to base)
264     PreIndex     = (8|4|1) << 21,  // pre-indexed addressing with writeback
265     PostIndex    = (0|4|0) << 21,  // post-indexed addressing with writeback
266     NegOffset    = (8|0|0) << 21,  // negative offset (w/o writeback to base)
267     NegPreIndex  = (8|0|1) << 21,  // negative pre-indexed with writeback
268     NegPostIndex = (0|0|0) << 21   // negative post-indexed with writeback
269   };
270 
rn_(rn)271   Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
272       offset_(offset),
273       am_(am), is_immed_offset_(true), shift_(LSL) {
274   }
275 
rn_(rn)276   Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
277       am_(am), is_immed_offset_(false), shift_(LSL) {
278     CHECK_NE(rm, PC);
279   }
280 
281   Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
rn_(rn)282                        rn_(rn), rm_(rm), offset_(count),
283                        am_(am), is_immed_offset_(false), shift_(shift) {
284     CHECK_NE(rm, PC);
285   }
286 
287   // LDR(literal) - pc relative load.
Address(int32_t offset)288   explicit Address(int32_t offset) :
289                rn_(PC), rm_(R0), offset_(offset),
290                am_(Offset), is_immed_offset_(false), shift_(LSL) {
291   }
292 
293   static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
294   static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset);
295 
296   static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset);
297   static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
298 
299   uint32_t encodingArm() const;
300   uint32_t encodingThumb(bool is_32bit) const;
301 
302   uint32_t encoding3() const;
303   uint32_t vencoding() const;
304 
305   uint32_t encodingThumbLdrdStrd() const;
306 
GetRegister()307   Register GetRegister() const {
308     return rn_;
309   }
310 
GetRegisterOffset()311   Register GetRegisterOffset() const {
312     return rm_;
313   }
314 
GetOffset()315   int32_t GetOffset() const {
316     return offset_;
317   }
318 
GetMode()319   Mode GetMode() const {
320     return am_;
321   }
322 
IsImmediate()323   bool IsImmediate() const {
324     return is_immed_offset_;
325   }
326 
GetShift()327   Shift GetShift() const {
328     return shift_;
329   }
330 
GetShiftCount()331   int32_t GetShiftCount() const {
332     CHECK(!is_immed_offset_);
333     return offset_;
334   }
335 
336  private:
337   const Register rn_;
338   const Register rm_;
339   const int32_t offset_;      // Used as shift amount for register offset.
340   const Mode am_;
341   const bool is_immed_offset_;
342   const Shift shift_;
343 };
344 inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) {
345   os << static_cast<int>(rhs);
346   return os;
347 }
348 
349 // Instruction encoding bits.
350 enum {
351   H   = 1 << 5,   // halfword (or byte)
352   L   = 1 << 20,  // load (or store)
353   S   = 1 << 20,  // set condition code (or leave unchanged)
354   W   = 1 << 21,  // writeback base register (or leave unchanged)
355   A   = 1 << 21,  // accumulate in multiply instruction (or not)
356   B   = 1 << 22,  // unsigned byte (or word)
357   N   = 1 << 22,  // long (or short)
358   U   = 1 << 23,  // positive (or negative) offset/index
359   P   = 1 << 24,  // offset/pre-indexed addressing (or post-indexed addressing)
360   I   = 1 << 25,  // immediate shifter operand (or not)
361 
362   B0 = 1,
363   B1 = 1 << 1,
364   B2 = 1 << 2,
365   B3 = 1 << 3,
366   B4 = 1 << 4,
367   B5 = 1 << 5,
368   B6 = 1 << 6,
369   B7 = 1 << 7,
370   B8 = 1 << 8,
371   B9 = 1 << 9,
372   B10 = 1 << 10,
373   B11 = 1 << 11,
374   B12 = 1 << 12,
375   B13 = 1 << 13,
376   B14 = 1 << 14,
377   B15 = 1 << 15,
378   B16 = 1 << 16,
379   B17 = 1 << 17,
380   B18 = 1 << 18,
381   B19 = 1 << 19,
382   B20 = 1 << 20,
383   B21 = 1 << 21,
384   B22 = 1 << 22,
385   B23 = 1 << 23,
386   B24 = 1 << 24,
387   B25 = 1 << 25,
388   B26 = 1 << 26,
389   B27 = 1 << 27,
390   B28 = 1 << 28,
391   B29 = 1 << 29,
392   B30 = 1 << 30,
393   B31 = 1 << 31,
394 
395   // Instruction bit masks.
396   RdMask = 15 << 12,  // in str instruction
397   CondMask = 15 << 28,
398   CoprocessorMask = 15 << 8,
399   OpCodeMask = 15 << 21,  // in data-processing instructions
400   Imm24Mask = (1 << 24) - 1,
401   Off12Mask = (1 << 12) - 1,
402 
403   // ldrex/strex register field encodings.
404   kLdExRnShift = 16,
405   kLdExRtShift = 12,
406   kStrExRnShift = 16,
407   kStrExRdShift = 12,
408   kStrExRtShift = 0,
409 };
410 
411 // IfThen state for IT instructions.
412 enum ItState {
413   kItOmitted,
414   kItThen,
415   kItT = kItThen,
416   kItElse,
417   kItE = kItElse
418 };
419 
420 // Set condition codes request.
421 enum SetCc {
422   kCcDontCare,  // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
423   kCcSet,
424   kCcKeep,
425 };
426 
427 constexpr uint32_t kNoItCondition = 3;
428 constexpr uint32_t kInvalidModifiedImmediate = -1;
429 
430 extern const char* kRegisterNames[];
431 extern const char* kConditionNames[];
432 
433 // This is an abstract ARM assembler.  Subclasses provide assemblers for the individual
434 // instruction sets (ARM32, Thumb2, etc.)
435 //
436 class ArmAssembler : public Assembler {
437  public:
~ArmAssembler()438   virtual ~ArmAssembler() {}
439 
440   // Is this assembler for the thumb instruction set?
441   virtual bool IsThumb() const = 0;
442 
443   // Data-processing instructions.
444   virtual void and_(Register rd, Register rn, const ShifterOperand& so,
445                     Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
446 
447   virtual void ands(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
448     and_(rd, rn, so, cond, kCcSet);
449   }
450 
451   virtual void eor(Register rd, Register rn, const ShifterOperand& so,
452                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
453 
454   virtual void eors(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
455     eor(rd, rn, so, cond, kCcSet);
456   }
457 
458   virtual void sub(Register rd, Register rn, const ShifterOperand& so,
459                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
460 
461   virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
462     sub(rd, rn, so, cond, kCcSet);
463   }
464 
465   virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
466                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
467 
468   virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
469     rsb(rd, rn, so, cond, kCcSet);
470   }
471 
472   virtual void add(Register rd, Register rn, const ShifterOperand& so,
473                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
474 
475   virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
476     add(rd, rn, so, cond, kCcSet);
477   }
478 
479   virtual void adc(Register rd, Register rn, const ShifterOperand& so,
480                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
481 
482   virtual void adcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
483     adc(rd, rn, so, cond, kCcSet);
484   }
485 
486   virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
487                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
488 
489   virtual void sbcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
490     sbc(rd, rn, so, cond, kCcSet);
491   }
492 
493   virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
494                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
495 
496   virtual void rscs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
497     rsc(rd, rn, so, cond, kCcSet);
498   }
499 
500   virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
501 
502   virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
503 
504   virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
505 
506   // Note: CMN updates flags based on addition of its operands. Do not confuse
507   // the "N" suffix with bitwise inversion performed by MVN.
508   virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0;
509 
510   virtual void orr(Register rd, Register rn, const ShifterOperand& so,
511                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
512 
513   virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
514     orr(rd, rn, so, cond, kCcSet);
515   }
516 
517   virtual void orn(Register rd, Register rn, const ShifterOperand& so,
518                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
519 
520   virtual void orns(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
521     orn(rd, rn, so, cond, kCcSet);
522   }
523 
524   virtual void mov(Register rd, const ShifterOperand& so,
525                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
526 
527   virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) {
528     mov(rd, so, cond, kCcSet);
529   }
530 
531   virtual void bic(Register rd, Register rn, const ShifterOperand& so,
532                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
533 
534   virtual void bics(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
535     bic(rd, rn, so, cond, kCcSet);
536   }
537 
538   virtual void mvn(Register rd, const ShifterOperand& so,
539                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
540 
541   virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) {
542     mvn(rd, so, cond, kCcSet);
543   }
544 
545   // Miscellaneous data-processing instructions.
546   virtual void clz(Register rd, Register rm, Condition cond = AL) = 0;
547   virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0;
548   virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0;
549   virtual void rbit(Register rd, Register rm, Condition cond = AL) = 0;
550   virtual void rev(Register rd, Register rm, Condition cond = AL) = 0;
551   virtual void rev16(Register rd, Register rm, Condition cond = AL) = 0;
552   virtual void revsh(Register rd, Register rm, Condition cond = AL) = 0;
553 
554   // Multiply instructions.
555   virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
556   virtual void mla(Register rd, Register rn, Register rm, Register ra,
557                    Condition cond = AL) = 0;
558   virtual void mls(Register rd, Register rn, Register rm, Register ra,
559                    Condition cond = AL) = 0;
560   virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
561                      Condition cond = AL) = 0;
562   virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
563                      Condition cond = AL) = 0;
564 
565   virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
566   virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0;
567 
568   // Bit field extract instructions.
569   virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
570                     Condition cond = AL) = 0;
571   virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width,
572                     Condition cond = AL) = 0;
573 
574   // Load/store instructions.
575   virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0;
576   virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0;
577 
578   virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0;
579   virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0;
580 
581   virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0;
582   virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0;
583 
584   virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0;
585   virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0;
586 
587   virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0;
588   virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0;
589 
590   virtual void ldm(BlockAddressMode am, Register base,
591                    RegList regs, Condition cond = AL) = 0;
592   virtual void stm(BlockAddressMode am, Register base,
593                    RegList regs, Condition cond = AL) = 0;
594 
595   virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0;
596   virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0;
597   virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
598   virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0;
599 
600   // Miscellaneous instructions.
601   virtual void clrex(Condition cond = AL) = 0;
602   virtual void nop(Condition cond = AL) = 0;
603 
604   // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
605   virtual void bkpt(uint16_t imm16) = 0;
606   virtual void svc(uint32_t imm24) = 0;
607 
608   virtual void it(Condition firstcond ATTRIBUTE_UNUSED,
609                   ItState i1 ATTRIBUTE_UNUSED = kItOmitted,
610                   ItState i2 ATTRIBUTE_UNUSED = kItOmitted,
611                   ItState i3 ATTRIBUTE_UNUSED = kItOmitted) {
612     // Ignored if not supported.
613   }
614 
615   virtual void cbz(Register rn, Label* target) = 0;
616   virtual void cbnz(Register rn, Label* target) = 0;
617 
618   // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
619   virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0;
620   virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0;
621   virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0;
622   virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0;
623   virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0;
624   virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0;
625   virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
626   virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
627 
628   // Returns false if the immediate cannot be encoded.
629   virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0;
630   virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0;
631 
632   virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
633   virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0;
634   virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
635   virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0;
636 
637   virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
638   virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
639   virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
640   virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
641   virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
642   virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
643   virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
644   virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
645   virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
646   virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
647   virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0;
648   virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0;
649 
650   virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0;
651   virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
652   virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0;
653   virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
654   virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0;
655   virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
656 
657   virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0;
658   virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0;
659   virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0;
660   virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0;
661   virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0;
662   virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0;
663   virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0;
664   virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0;
665   virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0;
666   virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0;
667 
668   virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0;
669   virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0;
670   virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0;
671   virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0;
672   virtual void vmstat(Condition cond = AL) = 0;  // VMRS APSR_nzcv, FPSCR
673 
674   virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0;
675   virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
676   virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
677   virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
678 
679   // Branch instructions.
680   virtual void b(Label* label, Condition cond = AL) = 0;
681   virtual void bl(Label* label, Condition cond = AL) = 0;
682   virtual void blx(Register rm, Condition cond = AL) = 0;
683   virtual void bx(Register rm, Condition cond = AL) = 0;
684 
685   // Memory barriers.
686   virtual void dmb(DmbOptions flavor) = 0;
687 
688   void Pad(uint32_t bytes);
689 
690   // Adjust label position.
AdjustLabelPosition(Label * label)691   void AdjustLabelPosition(Label* label) {
692     DCHECK(label->IsBound());
693     uint32_t old_position = static_cast<uint32_t>(label->Position());
694     uint32_t new_position = GetAdjustedPosition(old_position);
695     label->Reinitialize();
696     DCHECK_GE(static_cast<int>(new_position), 0);
697     label->BindTo(static_cast<int>(new_position));
698   }
699 
700   // Get the final position of a label after local fixup based on the old position
701   // recorded before FinalizeCode().
702   virtual uint32_t GetAdjustedPosition(uint32_t old_position) = 0;
703 
704   // Macros.
705   // Most of these are pure virtual as they need to be implemented per instruction set.
706 
707   // Create a new literal with a given value.
708   // NOTE: Force the template parameter to be explicitly specified.
709   template <typename T>
NewLiteral(typename Identity<T>::type value)710   Literal* NewLiteral(typename Identity<T>::type value) {
711     static_assert(std::is_integral<T>::value, "T must be an integral type.");
712     return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
713   }
714 
715   // Create a new literal with the given data.
716   virtual Literal* NewLiteral(size_t size, const uint8_t* data) = 0;
717 
718   // Load literal.
719   virtual void LoadLiteral(Register rt, Literal* literal) = 0;
720   virtual void LoadLiteral(Register rt, Register rt2, Literal* literal) = 0;
721   virtual void LoadLiteral(SRegister sd, Literal* literal) = 0;
722   virtual void LoadLiteral(DRegister dd, Literal* literal) = 0;
723 
724   // Add signed constant value to rd. May clobber IP.
725   virtual void AddConstant(Register rd, Register rn, int32_t value,
726                            Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
727   void AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond = AL) {
728     AddConstant(rd, rn, value, cond, kCcSet);
729   }
730   void AddConstant(Register rd, int32_t value, Condition cond = AL, SetCc set_cc = kCcDontCare) {
731     AddConstant(rd, rd, value, cond, set_cc);
732   }
733 
734   virtual void CmpConstant(Register rn, int32_t value, Condition cond = AL) = 0;
735 
736   // Load and Store. May clobber IP.
737   virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0;
738   void LoadSImmediate(SRegister sd, float value, Condition cond = AL) {
739     if (!vmovs(sd, value, cond)) {
740       int32_t int_value = bit_cast<int32_t, float>(value);
741       if (int_value == bit_cast<int32_t, float>(0.0f)) {
742         // 0.0 is quite common, so we special case it by loading
743         // 2.0 in `sd` and then substracting it.
744         bool success = vmovs(sd, 2.0, cond);
745         CHECK(success);
746         vsubs(sd, sd, sd, cond);
747       } else {
748         LoadImmediate(IP, int_value, cond);
749         vmovsr(sd, IP, cond);
750       }
751     }
752   }
753 
754   void LoadDImmediate(DRegister sd, double value, Condition cond = AL) {
755     if (!vmovd(sd, value, cond)) {
756       uint64_t int_value = bit_cast<uint64_t, double>(value);
757       if (int_value == bit_cast<uint64_t, double>(0.0)) {
758         // 0.0 is quite common, so we special case it by loading
759         // 2.0 in `sd` and then substracting it.
760         bool success = vmovd(sd, 2.0, cond);
761         CHECK(success);
762         vsubd(sd, sd, sd, cond);
763       } else {
764         if (sd < 16) {
765           SRegister low = static_cast<SRegister>(sd << 1);
766           SRegister high = static_cast<SRegister>(low + 1);
767           LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond);
768           if (High32Bits(int_value) == Low32Bits(int_value)) {
769             vmovs(high, low);
770           } else {
771             LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond);
772           }
773         } else {
774           LOG(FATAL) << "Unimplemented loading of double into a D register "
775                      << "that cannot be split into two S registers";
776         }
777       }
778     }
779   }
780 
781   virtual void MarkExceptionHandler(Label* label) = 0;
782   virtual void LoadFromOffset(LoadOperandType type,
783                               Register reg,
784                               Register base,
785                               int32_t offset,
786                               Condition cond = AL) = 0;
787   virtual void StoreToOffset(StoreOperandType type,
788                              Register reg,
789                              Register base,
790                              int32_t offset,
791                              Condition cond = AL) = 0;
792   virtual void LoadSFromOffset(SRegister reg,
793                                Register base,
794                                int32_t offset,
795                                Condition cond = AL) = 0;
796   virtual void StoreSToOffset(SRegister reg,
797                               Register base,
798                               int32_t offset,
799                               Condition cond = AL) = 0;
800   virtual void LoadDFromOffset(DRegister reg,
801                                Register base,
802                                int32_t offset,
803                                Condition cond = AL) = 0;
804   virtual void StoreDToOffset(DRegister reg,
805                               Register base,
806                               int32_t offset,
807                               Condition cond = AL) = 0;
808 
809   virtual void Push(Register rd, Condition cond = AL) = 0;
810   virtual void Pop(Register rd, Condition cond = AL) = 0;
811 
812   virtual void PushList(RegList regs, Condition cond = AL) = 0;
813   virtual void PopList(RegList regs, Condition cond = AL) = 0;
814 
815   virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
816 
817   // Convenience shift instructions. Use mov instruction with shifter operand
818   // for variants setting the status flags or using a register shift count.
819   virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
820                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
821 
822   void Lsls(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
823     Lsl(rd, rm, shift_imm, cond, kCcSet);
824   }
825 
826   virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
827                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
828 
829   void Lsrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
830     Lsr(rd, rm, shift_imm, cond, kCcSet);
831   }
832 
833   virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
834                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
835 
836   void Asrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
837     Asr(rd, rm, shift_imm, cond, kCcSet);
838   }
839 
840   virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
841                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
842 
843   void Rors(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) {
844     Ror(rd, rm, shift_imm, cond, kCcSet);
845   }
846 
847   virtual void Rrx(Register rd, Register rm,
848                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
849 
850   void Rrxs(Register rd, Register rm, Condition cond = AL) {
851     Rrx(rd, rm, cond, kCcSet);
852   }
853 
854   virtual void Lsl(Register rd, Register rm, Register rn,
855                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
856 
857   void Lsls(Register rd, Register rm, Register rn, Condition cond = AL) {
858     Lsl(rd, rm, rn, cond, kCcSet);
859   }
860 
861   virtual void Lsr(Register rd, Register rm, Register rn,
862                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
863 
864   void Lsrs(Register rd, Register rm, Register rn, Condition cond = AL) {
865     Lsr(rd, rm, rn, cond, kCcSet);
866   }
867 
868   virtual void Asr(Register rd, Register rm, Register rn,
869                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
870 
871   void Asrs(Register rd, Register rm, Register rn, Condition cond = AL) {
872     Asr(rd, rm, rn, cond, kCcSet);
873   }
874 
875   virtual void Ror(Register rd, Register rm, Register rn,
876                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
877 
878   void Rors(Register rd, Register rm, Register rn, Condition cond = AL) {
879     Ror(rd, rm, rn, cond, kCcSet);
880   }
881 
882   // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes,
883   // `shifter_op` contains the operand.
884   virtual bool ShifterOperandCanHold(Register rd,
885                                      Register rn,
886                                      Opcode opcode,
887                                      uint32_t immediate,
888                                      SetCc set_cc,
889                                      ShifterOperand* shifter_op) = 0;
ShifterOperandCanHold(Register rd,Register rn,Opcode opcode,uint32_t immediate,ShifterOperand * shifter_op)890   bool ShifterOperandCanHold(Register rd,
891                              Register rn,
892                              Opcode opcode,
893                              uint32_t immediate,
894                              ShifterOperand* shifter_op) {
895     return ShifterOperandCanHold(rd, rn, opcode, immediate, kCcDontCare, shifter_op);
896   }
897 
898   virtual bool ShifterOperandCanAlwaysHold(uint32_t immediate) = 0;
899 
900   static bool IsInstructionForExceptionHandling(uintptr_t pc);
901 
902   virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
903   virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
904 
905   //
906   // Overridden common assembler high-level functionality
907   //
908 
909   // Emit code that will create an activation on the stack
910   void BuildFrame(size_t frame_size, ManagedRegister method_reg,
911                   const std::vector<ManagedRegister>& callee_save_regs,
912                   const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
913 
914   // Emit code that will remove an activation from the stack
915   void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
916     OVERRIDE;
917 
918   void IncreaseFrameSize(size_t adjust) OVERRIDE;
919   void DecreaseFrameSize(size_t adjust) OVERRIDE;
920 
921   // Store routines
922   void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
923   void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
924   void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
925 
926   void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
927 
928   void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
929       OVERRIDE;
930 
931   void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
932                                   ManagedRegister scratch) OVERRIDE;
933 
934   void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
935 
936   void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
937                      ManagedRegister scratch) OVERRIDE;
938 
939   // Load routines
940   void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
941 
942   void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
943 
944   void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
945 
946   void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
947                bool unpoison_reference) OVERRIDE;
948 
949   void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
950 
951   void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
952 
953   // Copying routines
954   void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
955 
956   void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
957                               ManagedRegister scratch) OVERRIDE;
958 
959   void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
960       OVERRIDE;
961 
962   void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
963 
964   void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
965 
966   void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch,
967             size_t size) OVERRIDE;
968 
969   void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch,
970             size_t size) OVERRIDE;
971 
972   void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch,
973             size_t size) OVERRIDE;
974 
975   void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
976             ManagedRegister scratch, size_t size) OVERRIDE;
977 
978   void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
979             ManagedRegister scratch, size_t size) OVERRIDE;
980 
981   // Sign extension
982   void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
983 
984   // Zero extension
985   void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
986 
987   // Exploit fast access in managed code to Thread::Current()
988   void GetCurrentThread(ManagedRegister tr) OVERRIDE;
989   void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE;
990 
991   // Set up out_reg to hold a Object** into the handle scope, or to be null if the
992   // value is null and null_allowed. in_reg holds a possibly stale reference
993   // that can be used to avoid loading the handle scope entry to see if the value is
994   // null.
995   void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
996                               ManagedRegister in_reg, bool null_allowed) OVERRIDE;
997 
998   // Set up out_off to hold a Object** into the handle scope, or to be null if the
999   // value is null and null_allowed.
1000   void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
1001                               ManagedRegister scratch, bool null_allowed) OVERRIDE;
1002 
1003   // src holds a handle scope entry (Object**) load this into dst
1004   void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
1005 
1006   // Heap::VerifyObject on src. In some cases (such as a reference to this) we
1007   // know that src may not be null.
1008   void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
1009   void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
1010 
1011   // Call to address held at [base+offset]
1012   void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
1013   void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
1014   void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
1015 
1016   // Generate code to check if Thread::Current()->exception_ is non-null
1017   // and branch to a ExceptionSlowPath if it is.
1018   void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
1019 
1020   static uint32_t ModifiedImmediate(uint32_t value);
1021 
IsLowRegister(Register r)1022   static bool IsLowRegister(Register r) {
1023     return r < R8;
1024   }
1025 
IsHighRegister(Register r)1026   static bool IsHighRegister(Register r) {
1027      return r >= R8;
1028   }
1029 
1030   //
1031   // Heap poisoning.
1032   //
1033 
1034   // Poison a heap reference contained in `reg`.
PoisonHeapReference(Register reg)1035   void PoisonHeapReference(Register reg) {
1036     // reg = -reg.
1037     rsb(reg, reg, ShifterOperand(0));
1038   }
1039   // Unpoison a heap reference contained in `reg`.
UnpoisonHeapReference(Register reg)1040   void UnpoisonHeapReference(Register reg) {
1041     // reg = -reg.
1042     rsb(reg, reg, ShifterOperand(0));
1043   }
1044   // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
MaybeUnpoisonHeapReference(Register reg)1045   void MaybeUnpoisonHeapReference(Register reg) {
1046     if (kPoisonHeapReferences) {
1047       UnpoisonHeapReference(reg);
1048     }
1049   }
1050 
Jump(Label * label)1051   void Jump(Label* label) OVERRIDE {
1052     b(label);
1053   }
1054 
1055   // Jump table support. This is split into three functions:
1056   //
1057   // * CreateJumpTable creates the internal metadata to track the jump targets, and emits code to
1058   // load the base address of the jump table.
1059   //
1060   // * EmitJumpTableDispatch emits the code to actually jump, assuming that the right table value
1061   // has been loaded into a register already.
1062   //
1063   // * FinalizeTables emits the jump table into the literal pool. This can only be called after the
1064   // labels for the jump targets have been finalized.
1065 
1066   // Create a jump table for the given labels that will be emitted when finalizing. Create a load
1067   // sequence (or placeholder) that stores the base address into the given register. When the table
1068   // is emitted, offsets will be relative to the location EmitJumpTableDispatch was called on (the
1069   // anchor).
1070   virtual JumpTable* CreateJumpTable(std::vector<Label*>&& labels, Register base_reg) = 0;
1071 
1072   // Emit the jump-table jump, assuming that the right value was loaded into displacement_reg.
1073   virtual void EmitJumpTableDispatch(JumpTable* jump_table, Register displacement_reg) = 0;
1074 
1075   // Bind a Label that needs to be updated by the assembler in FinalizeCode() if its position
1076   // changes due to branch/literal fixup.
BindTrackedLabel(Label * label)1077   void BindTrackedLabel(Label* label) {
1078     Bind(label);
1079     tracked_labels_.push_back(label);
1080   }
1081 
1082  protected:
ArmAssembler(ArenaAllocator * arena)1083   explicit ArmAssembler(ArenaAllocator* arena)
1084       : Assembler(arena), tracked_labels_(arena->Adapter(kArenaAllocAssembler)) {}
1085 
1086   // Returns whether or not the given register is used for passing parameters.
RegisterCompare(const Register * reg1,const Register * reg2)1087   static int RegisterCompare(const Register* reg1, const Register* reg2) {
1088     return *reg1 - *reg2;
1089   }
1090 
1091   void FinalizeTrackedLabels();
1092 
1093   // Tracked labels. Use a vector, as we need to sort before adjusting.
1094   ArenaVector<Label*> tracked_labels_;
1095 };
1096 
1097 // Slowpath entered when Thread::Current()->_exception is non-null
1098 class ArmExceptionSlowPath FINAL : public SlowPath {
1099  public:
ArmExceptionSlowPath(ArmManagedRegister scratch,size_t stack_adjust)1100   ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust)
1101       : scratch_(scratch), stack_adjust_(stack_adjust) {
1102   }
1103   void Emit(Assembler *sp_asm) OVERRIDE;
1104  private:
1105   const ArmManagedRegister scratch_;
1106   const size_t stack_adjust_;
1107 };
1108 
1109 }  // namespace arm
1110 }  // namespace art
1111 
1112 #endif  // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
1113