assembler_arm_64.hpp revision 12422:98fe046473c9
1/*
2 * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
26#define CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
27
28enum AsmShift12 {
29  lsl0, lsl12
30};
31
32enum AsmPrefetchOp {
33    pldl1keep = 0b00000,
34    pldl1strm,
35    pldl2keep,
36    pldl2strm,
37    pldl3keep,
38    pldl3strm,
39
40    plil1keep = 0b01000,
41    plil1strm,
42    plil2keep,
43    plil2strm,
44    plil3keep,
45    plil3strm,
46
47    pstl1keep = 0b10000,
48    pstl1strm,
49    pstl2keep,
50    pstl2strm,
51    pstl3keep,
52    pstl3strm,
53};
54
55// Shifted register operand for data processing instructions.
56class AsmOperand VALUE_OBJ_CLASS_SPEC {
57 private:
58  Register _reg;
59  AsmShift _shift;
60  int _shift_imm;
61
62 public:
63  AsmOperand(Register reg) {
64    assert(reg != SP, "SP is not allowed in shifted register operand");
65    _reg = reg;
66    _shift = lsl;
67    _shift_imm = 0;
68  }
69
70  AsmOperand(Register reg, AsmShift shift, int shift_imm) {
71    assert(reg != SP, "SP is not allowed in shifted register operand");
72    assert(shift_imm >= 0, "shift amount should be non-negative");
73    _reg = reg;
74    _shift = shift;
75    _shift_imm = shift_imm;
76  }
77
78  Register reg() const {
79    return _reg;
80  }
81
82  AsmShift shift() const {
83    return _shift;
84  }
85
86  int shift_imm() const {
87    return _shift_imm;
88  }
89};
90
91
92class Assembler : public AbstractAssembler  {
93
94 public:
95
96  static const int LogInstructionSize = 2;
97  static const int InstructionSize    = 1 << LogInstructionSize;
98
99  Assembler(CodeBuffer* code) : AbstractAssembler(code) {}
100
101  static inline AsmCondition inverse(AsmCondition cond) {
102    assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed");
103    return (AsmCondition)((int)cond ^ 1);
104  }
105
106  // Returns value of nzcv flags conforming to the given condition.
107  static inline int flags_for_condition(AsmCondition cond) {
108    switch(cond) {            // NZCV
109      case mi: case lt: return 0b1000;
110      case eq: case le: return 0b0100;
111      case hs: case hi: return 0b0010;
112      case vs:          return 0b0001;
113      default:          return 0b0000;
114    }
115  }
116
117  // Immediate, encoded into logical instructions.
118  class LogicalImmediate {
119   private:
120    bool _encoded;
121    bool _is32bit;
122    int _immN;
123    int _immr;
124    int _imms;
125
126    static inline bool has_equal_subpatterns(uintx imm, int size);
127    static inline int least_pattern_size(uintx imm);
128    static inline int population_count(uintx x);
129    static inline uintx set_least_zeroes(uintx x);
130
131#ifdef ASSERT
132    uintx decode();
133#endif
134
135    void construct(uintx imm, bool is32);
136
137   public:
138    LogicalImmediate(uintx imm, bool is32 = false) { construct(imm, is32); }
139
140    // Returns true if given immediate can be used in AArch64 logical instruction.
141    bool is_encoded() const { return _encoded; }
142
143    bool is32bit() const { return _is32bit; }
144    int immN() const { assert(_encoded, "should be"); return _immN; }
145    int immr() const { assert(_encoded, "should be"); return _immr; }
146    int imms() const { assert(_encoded, "should be"); return _imms; }
147  };
148
149  // Immediate, encoded into arithmetic add/sub instructions.
150  class ArithmeticImmediate {
151   private:
152    bool _encoded;
153    int _imm;
154    AsmShift12 _shift;
155
156   public:
157    ArithmeticImmediate(intx x) {
158      if (is_unsigned_imm_in_range(x, 12, 0)) {
159        _encoded = true;
160        _imm = x;
161        _shift = lsl0;
162      } else if (is_unsigned_imm_in_range(x, 12, 12)) {
163        _encoded = true;
164        _imm = x >> 12;
165        _shift = lsl12;
166      } else {
167        _encoded = false;
168      }
169    }
170
171    ArithmeticImmediate(intx x, AsmShift12 sh) {
172      if (is_unsigned_imm_in_range(x, 12, 0)) {
173        _encoded = true;
174        _imm = x;
175        _shift = sh;
176      } else {
177        _encoded = false;
178      }
179    }
180
181    // Returns true if this immediate can be used in AArch64 arithmetic (add/sub/cmp/cmn) instructions.
182    bool is_encoded() const  { return _encoded; }
183
184    int imm() const          { assert(_encoded, "should be"); return _imm; }
185    AsmShift12 shift() const { assert(_encoded, "should be"); return _shift; }
186  };
187
188  static inline bool is_imm_in_range(intx value, int bits, int align_bits) {
189    intx sign_bits = (value >> (bits + align_bits - 1));
190    return ((value & right_n_bits(align_bits)) == 0) && ((sign_bits == 0) || (sign_bits == -1));
191  }
192
193  static inline int encode_imm(intx value, int bits, int align_bits, int low_bit_in_encoding) {
194    assert (is_imm_in_range(value, bits, align_bits), "immediate value is out of range");
195    return ((value >> align_bits) & right_n_bits(bits)) << low_bit_in_encoding;
196  }
197
198  static inline bool is_unsigned_imm_in_range(intx value, int bits, int align_bits) {
199    return (value >= 0) && ((value & right_n_bits(align_bits)) == 0) && ((value >> (align_bits + bits)) == 0);
200  }
201
202  static inline int encode_unsigned_imm(intx value, int bits, int align_bits, int low_bit_in_encoding) {
203    assert (is_unsigned_imm_in_range(value, bits, align_bits), "immediate value is out of range");
204    return (value >> align_bits) << low_bit_in_encoding;
205  }
206
207  static inline bool is_offset_in_range(intx offset, int bits) {
208    assert (bits == 14 || bits == 19 || bits == 26, "wrong bits number");
209    return is_imm_in_range(offset, bits, 2);
210  }
211
212  static inline int encode_offset(intx offset, int bits, int low_bit_in_encoding) {
213    return encode_imm(offset, bits, 2, low_bit_in_encoding);
214  }
215
216  // Returns true if given value can be used as immediate in arithmetic (add/sub/cmp/cmn) instructions.
217  static inline bool is_arith_imm_in_range(intx value) {
218    return ArithmeticImmediate(value).is_encoded();
219  }
220
221
222  // Load/store instructions
223
224#define F(mnemonic, opc) \
225  void mnemonic(Register rd, address literal_addr) {                                                       \
226    intx offset = literal_addr - pc();                                                                     \
227    assert (opc != 0b01 || offset == 0 || ((uintx)literal_addr & 7) == 0, "ldr target should be aligned"); \
228    assert (is_offset_in_range(offset, 19), "offset is out of range");                                     \
229    emit_int32(opc << 30 | 0b011 << 27 | encode_offset(offset, 19, 5) | rd->encoding_with_zr());           \
230  }
231
232  F(ldr_w, 0b00)
233  F(ldr,   0b01)
234  F(ldrsw, 0b10)
235#undef F
236
237#define F(mnemonic, opc) \
238  void mnemonic(FloatRegister rt, address literal_addr) {                                                  \
239    intx offset = literal_addr - pc();                                                                     \
240    assert (offset == 0 || ((uintx)literal_addr & right_n_bits(2 + opc)) == 0, "ldr target should be aligned"); \
241    assert (is_offset_in_range(offset, 19), "offset is out of range");                                     \
242    emit_int32(opc << 30 | 0b011100 << 24 | encode_offset(offset, 19, 5) | rt->encoding());                \
243  }
244
245  F(ldr_s, 0b00)
246  F(ldr_d, 0b01)
247  F(ldr_q, 0b10)
248#undef F
249
250#define F(mnemonic, size, o2, L, o1, o0) \
251  void mnemonic(Register rt, Register rn) {                                                                \
252    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | 0b11111 << 16 |               \
253        o0 << 15 | 0b11111 << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());                  \
254  }
255
256  F(ldxrb,   0b00, 0, 1, 0, 0)
257  F(ldaxrb,  0b00, 0, 1, 0, 1)
258  F(ldarb,   0b00, 1, 1, 0, 1)
259  F(ldxrh,   0b01, 0, 1, 0, 0)
260  F(ldaxrh,  0b01, 0, 1, 0, 1)
261  F(ldarh,   0b01, 1, 1, 0, 1)
262  F(ldxr_w,  0b10, 0, 1, 0, 0)
263  F(ldaxr_w, 0b10, 0, 1, 0, 1)
264  F(ldar_w,  0b10, 1, 1, 0, 1)
265  F(ldxr,    0b11, 0, 1, 0, 0)
266  F(ldaxr,   0b11, 0, 1, 0, 1)
267  F(ldar,    0b11, 1, 1, 0, 1)
268
269  F(stlrb,   0b00, 1, 0, 0, 1)
270  F(stlrh,   0b01, 1, 0, 0, 1)
271  F(stlr_w,  0b10, 1, 0, 0, 1)
272  F(stlr,    0b11, 1, 0, 0, 1)
273#undef F
274
275#define F(mnemonic, size, o2, L, o1, o0) \
276  void mnemonic(Register rs, Register rt, Register rn) {                                                     \
277    assert (rs != rt, "should be different");                                                                \
278    assert (rs != rn, "should be different");                                                                \
279    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | rs->encoding_with_zr() << 16 |  \
280        o0 << 15 | 0b11111 << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());                    \
281  }
282
283  F(stxrb,   0b00, 0, 0, 0, 0)
284  F(stlxrb,  0b00, 0, 0, 0, 1)
285  F(stxrh,   0b01, 0, 0, 0, 0)
286  F(stlxrh,  0b01, 0, 0, 0, 1)
287  F(stxr_w,  0b10, 0, 0, 0, 0)
288  F(stlxr_w, 0b10, 0, 0, 0, 1)
289  F(stxr,    0b11, 0, 0, 0, 0)
290  F(stlxr,   0b11, 0, 0, 0, 1)
291#undef F
292
293#define F(mnemonic, size, o2, L, o1, o0) \
294  void mnemonic(Register rt, Register rt2, Register rn) {                                                  \
295    assert (rt != rt2, "should be different");                                                             \
296    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | 0b11111 << 16 |               \
297        o0 << 15 | rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());  \
298  }
299
300  F(ldxp_w,  0b10, 0, 1, 1, 0)
301  F(ldaxp_w, 0b10, 0, 1, 1, 1)
302  F(ldxp,    0b11, 0, 1, 1, 0)
303  F(ldaxp,   0b11, 0, 1, 1, 1)
304#undef F
305
306#define F(mnemonic, size, o2, L, o1, o0) \
307  void mnemonic(Register rs, Register rt, Register rt2, Register rn) {                                       \
308    assert (rs != rt, "should be different");                                                                \
309    assert (rs != rt2, "should be different");                                                               \
310    assert (rs != rn, "should be different");                                                                \
311    emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | rs->encoding_with_zr() << 16 |  \
312        o0 << 15 | rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());    \
313  }
314
315  F(stxp_w,  0b10, 0, 0, 1, 0)
316  F(stlxp_w, 0b10, 0, 0, 1, 1)
317  F(stxp,    0b11, 0, 0, 1, 0)
318  F(stlxp,   0b11, 0, 0, 1, 1)
319#undef F
320
321#define F(mnemonic, opc, V, L) \
322  void mnemonic(Register rt, Register rt2, Register rn, int offset = 0) {                                  \
323    assert (!L || rt != rt2, "should be different");                                                       \
324    int align_bits = 2 + (opc >> 1);                                                                       \
325    assert (is_imm_in_range(offset, 7, align_bits), "offset is out of range");                             \
326    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | L << 22 | encode_imm(offset, 7, align_bits, 15) |       \
327        rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr());             \
328  }
329
330  F(stnp_w,  0b00, 0, 0)
331  F(ldnp_w,  0b00, 0, 1)
332  F(stnp,    0b10, 0, 0)
333  F(ldnp,    0b10, 0, 1)
334#undef F
335
336#define F(mnemonic, opc, V, L) \
337  void mnemonic(FloatRegister rt, FloatRegister rt2, Register rn, int offset = 0) {                        \
338    assert (!L || (rt != rt2), "should be different");                                                     \
339    int align_bits = 2 + opc;                                                                              \
340    assert (is_imm_in_range(offset, 7, align_bits), "offset is out of range");                             \
341    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | L << 22 | encode_imm(offset, 7, align_bits, 15) |       \
342        rt2->encoding() << 10 | rn->encoding_with_sp() << 5 | rt->encoding());                             \
343  }
344
345  F(stnp_s,  0b00, 1, 0)
346  F(stnp_d,  0b01, 1, 0)
347  F(stnp_q,  0b10, 1, 0)
348  F(ldnp_s,  0b00, 1, 1)
349  F(ldnp_d,  0b01, 1, 1)
350  F(ldnp_q,  0b10, 1, 1)
351#undef F
352
353#define F(mnemonic, size, V, opc) \
354  void mnemonic(Register rt, Address addr) { \
355    assert((addr.mode() == basic_offset) || (rt != addr.base()), "should be different");                    \
356    if (addr.index() == noreg) {                                                                            \
357      if ((addr.mode() == basic_offset) && is_unsigned_imm_in_range(addr.disp(), 12, size)) {               \
358        emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 |                            \
359           encode_unsigned_imm(addr.disp(), 12, size, 10) |                                                 \
360           addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());                                  \
361      } else {                                                                                              \
362        assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range");                               \
363        emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) |     \
364           addr.mode() << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());              \
365      }                                                                                                     \
366    } else {                                                                                                \
367      assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode");                      \
368      assert ((addr.shift_imm() == 0) || (addr.shift_imm() == size), "invalid shift amount");               \
369      emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 |                                 \
370         addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 |     \
371         0b10 << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());                       \
372    }                                                                                                       \
373  }
374
375  F(strb,    0b00, 0, 0b00)
376  F(ldrb,    0b00, 0, 0b01)
377  F(ldrsb,   0b00, 0, 0b10)
378  F(ldrsb_w, 0b00, 0, 0b11)
379
380  F(strh,    0b01, 0, 0b00)
381  F(ldrh,    0b01, 0, 0b01)
382  F(ldrsh,   0b01, 0, 0b10)
383  F(ldrsh_w, 0b01, 0, 0b11)
384
385  F(str_w,   0b10, 0, 0b00)
386  F(ldr_w,   0b10, 0, 0b01)
387  F(ldrsw,   0b10, 0, 0b10)
388
389  F(str,     0b11, 0, 0b00)
390  F(ldr,     0b11, 0, 0b01)
391#undef F
392
393#define F(mnemonic, size, V, opc) \
394  void mnemonic(AsmPrefetchOp prfop, Address addr) { \
395    assert (addr.mode() == basic_offset, #mnemonic " supports only basic_offset address mode");             \
396    if (addr.index() == noreg) {                                                                            \
397      if (is_unsigned_imm_in_range(addr.disp(), 12, size)) {                                                \
398        emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 |                            \
399           encode_unsigned_imm(addr.disp(), 12, size, 10) |                                                 \
400           addr.base()->encoding_with_sp() << 5 | prfop);                                                   \
401      } else {                                                                                              \
402        assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range");                               \
403        emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) |     \
404           addr.base()->encoding_with_sp() << 5 | prfop);                                                   \
405      }                                                                                                     \
406    } else {                                                                                                \
407      assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode");                      \
408      assert ((addr.shift_imm() == 0) || (addr.shift_imm() == size), "invalid shift amount");               \
409      emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 |                                 \
410         addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 |     \
411         0b10 << 10 | addr.base()->encoding_with_sp() << 5 | prfop);                                        \
412    }                                                                                                       \
413  }
414
415  F(prfm, 0b11, 0, 0b10)
416#undef F
417
418#define F(mnemonic, size, V, opc) \
419  void mnemonic(FloatRegister rt, Address addr) { \
420    int align_bits = (((opc & 0b10) >> 1) << 2) | size;                                                     \
421    if (addr.index() == noreg) {                                                                            \
422      if ((addr.mode() == basic_offset) && is_unsigned_imm_in_range(addr.disp(), 12, align_bits)) {         \
423        emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 |                            \
424           encode_unsigned_imm(addr.disp(), 12, align_bits, 10) |                                           \
425           addr.base()->encoding_with_sp() << 5 | rt->encoding());                                          \
426      } else {                                                                                              \
427        assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range");                               \
428        emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) |     \
429           addr.mode() << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding());                      \
430      }                                                                                                     \
431    } else {                                                                                                \
432      assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode");                      \
433      assert ((addr.shift_imm() == 0) || (addr.shift_imm() == align_bits), "invalid shift amount");         \
434      emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 |                                 \
435         addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 |     \
436         0b10 << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding());                               \
437    }                                                                                                       \
438  }
439
440  F(str_b, 0b00, 1, 0b00)
441  F(ldr_b, 0b00, 1, 0b01)
442  F(str_h, 0b01, 1, 0b00)
443  F(ldr_h, 0b01, 1, 0b01)
444  F(str_s, 0b10, 1, 0b00)
445  F(ldr_s, 0b10, 1, 0b01)
446  F(str_d, 0b11, 1, 0b00)
447  F(ldr_d, 0b11, 1, 0b01)
448  F(str_q, 0b00, 1, 0b10)
449  F(ldr_q, 0b00, 1, 0b11)
450#undef F
451
452#define F(mnemonic, opc, V, L) \
453  void mnemonic(Register rt, Register rt2, Address addr) {                                                         \
454    assert((addr.mode() == basic_offset) || ((rt != addr.base()) && (rt2 != addr.base())), "should be different"); \
455    assert(!L || (rt != rt2), "should be different");                                                              \
456    assert(addr.index() == noreg, "[reg + reg] address mode is not available for load/store pair");                \
457    int align_bits = 2 + (opc >> 1);                                                                               \
458    int mode_encoding = (addr.mode() == basic_offset) ? 0b10 : addr.mode();                                        \
459    assert(is_imm_in_range(addr.disp(), 7, align_bits), "offset is out of range");                                 \
460    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | mode_encoding << 23 | L << 22 |                                 \
461       encode_imm(addr.disp(), 7, align_bits, 15) | rt2->encoding_with_zr() << 10 |                                \
462       addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr());                                             \
463  }
464
465  F(stp_w, 0b00, 0, 0)
466  F(ldp_w, 0b00, 0, 1)
467  F(ldpsw, 0b01, 0, 1)
468  F(stp,   0b10, 0, 0)
469  F(ldp,   0b10, 0, 1)
470#undef F
471
472#define F(mnemonic, opc, V, L) \
473  void mnemonic(FloatRegister rt, FloatRegister rt2, Address addr) {                                                         \
474    assert(!L || (rt != rt2), "should be different");                                                              \
475    assert(addr.index() == noreg, "[reg + reg] address mode is not available for load/store pair");                \
476    int align_bits = 2 + opc;                                                                                      \
477    int mode_encoding = (addr.mode() == basic_offset) ? 0b10 : addr.mode();                                        \
478    assert(is_imm_in_range(addr.disp(), 7, align_bits), "offset is out of range");                                 \
479    emit_int32(opc << 30 | 0b101 << 27 | V << 26 | mode_encoding << 23 | L << 22 |                                 \
480       encode_imm(addr.disp(), 7, align_bits, 15) | rt2->encoding() << 10 |                                        \
481       addr.base()->encoding_with_sp() << 5 | rt->encoding());                                                     \
482  }
483
484  F(stp_s, 0b00, 1, 0)
485  F(ldp_s, 0b00, 1, 1)
486  F(stp_d, 0b01, 1, 0)
487  F(ldp_d, 0b01, 1, 1)
488  F(stp_q, 0b10, 1, 0)
489  F(ldp_q, 0b10, 1, 1)
490#undef F
491
492  // Data processing instructions
493
494#define F(mnemonic, sf, opc) \
495  void mnemonic(Register rd, Register rn, const LogicalImmediate& imm) {                      \
496    assert (imm.is_encoded(), "illegal immediate for logical instruction");                   \
497    assert (imm.is32bit() == (sf == 0), "immediate size does not match instruction size");    \
498    emit_int32(sf << 31 | opc << 29 | 0b100100 << 23 | imm.immN() << 22 | imm.immr() << 16 |  \
499        imm.imms() << 10 | rn->encoding_with_zr() << 5 |                                      \
500        ((opc == 0b11) ? rd->encoding_with_zr() : rd->encoding_with_sp()));                   \
501  }                                                                                           \
502  void mnemonic(Register rd, Register rn, uintx imm) {                                        \
503    LogicalImmediate limm(imm, (sf == 0));                                                    \
504    mnemonic(rd, rn, limm);                                                                   \
505  }                                                                                           \
506  void mnemonic(Register rd, Register rn, unsigned int imm) {                                 \
507    mnemonic(rd, rn, (uintx)imm);                                                             \
508  }
509
510  F(andr_w, 0, 0b00)
511  F(orr_w,  0, 0b01)
512  F(eor_w,  0, 0b10)
513  F(ands_w, 0, 0b11)
514
515  F(andr, 1, 0b00)
516  F(orr,  1, 0b01)
517  F(eor,  1, 0b10)
518  F(ands, 1, 0b11)
519#undef F
520
521  void tst(Register rn, unsigned int imm) {
522    ands(ZR, rn, imm);
523  }
524
525  void tst_w(Register rn, unsigned int imm) {
526    ands_w(ZR, rn, imm);
527  }
528
529#define F(mnemonic, sf, opc, N) \
530  void mnemonic(Register rd, Register rn, AsmOperand operand) { \
531    assert (operand.shift_imm() >> (5 + sf) == 0, "shift amount is too large");          \
532    emit_int32(sf << 31 | opc << 29 | 0b01010 << 24 | operand.shift() << 22 | N << 21 |  \
533        operand.reg()->encoding_with_zr() << 16 | operand.shift_imm() << 10 |            \
534        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                           \
535  }
536
537  F(andr_w, 0, 0b00, 0)
538  F(bic_w,  0, 0b00, 1)
539  F(orr_w,  0, 0b01, 0)
540  F(orn_w,  0, 0b01, 1)
541  F(eor_w,  0, 0b10, 0)
542  F(eon_w,  0, 0b10, 1)
543  F(ands_w, 0, 0b11, 0)
544  F(bics_w, 0, 0b11, 1)
545
546  F(andr, 1, 0b00, 0)
547  F(bic,  1, 0b00, 1)
548  F(orr,  1, 0b01, 0)
549  F(orn,  1, 0b01, 1)
550  F(eor,  1, 0b10, 0)
551  F(eon,  1, 0b10, 1)
552  F(ands, 1, 0b11, 0)
553  F(bics, 1, 0b11, 1)
554#undef F
555
556  void tst(Register rn, AsmOperand operand) {
557    ands(ZR, rn, operand);
558  }
559
560  void tst_w(Register rn, AsmOperand operand) {
561    ands_w(ZR, rn, operand);
562  }
563
564  void mvn(Register rd, AsmOperand operand) {
565    orn(rd, ZR, operand);
566  }
567
568  void mvn_w(Register rd, AsmOperand operand) {
569    orn_w(rd, ZR, operand);
570  }
571
572#define F(mnemonic, sf, op, S) \
573  void mnemonic(Register rd, Register rn, const ArithmeticImmediate& imm) {                       \
574    assert(imm.is_encoded(), "immediate is out of range");                                        \
575    emit_int32(sf << 31 | op << 30 | S << 29 | 0b10001 << 24 | imm.shift() << 22 |                \
576        imm.imm() << 10 | rn->encoding_with_sp() << 5 |                                           \
577        (S == 1 ? rd->encoding_with_zr() : rd->encoding_with_sp()));                              \
578  }                                                                                               \
579  void mnemonic(Register rd, Register rn, int imm) {                                              \
580    mnemonic(rd, rn, ArithmeticImmediate(imm));                                                   \
581  }                                                                                               \
582  void mnemonic(Register rd, Register rn, int imm, AsmShift12 shift) {                            \
583    mnemonic(rd, rn, ArithmeticImmediate(imm, shift));                                            \
584  }                                                                                               \
585  void mnemonic(Register rd, Register rn, Register rm, AsmExtendOp extend, int shift_imm = 0) {   \
586    assert ((0 <= shift_imm) && (shift_imm <= 4), "shift amount is out of range");                \
587    emit_int32(sf << 31 | op << 30 | S << 29 | 0b01011001 << 21 | rm->encoding_with_zr() << 16 |  \
588        extend << 13 | shift_imm << 10 | rn->encoding_with_sp() << 5 |                            \
589        (S == 1 ? rd->encoding_with_zr() : rd->encoding_with_sp()));                              \
590  }                                                                                               \
591  void mnemonic(Register rd, Register rn, AsmOperand operand) {                                   \
592    assert (operand.shift() != ror, "illegal shift type");                                        \
593    assert (operand.shift_imm() >> (5 + sf) == 0, "shift amount is too large");                   \
594    emit_int32(sf << 31 | op << 30 | S << 29 | 0b01011 << 24 | operand.shift() << 22 |            \
595        operand.reg()->encoding_with_zr() << 16 | operand.shift_imm() << 10 |                     \
596        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                                    \
597  }
598
599  F(add_w,  0, 0, 0)
600  F(adds_w, 0, 0, 1)
601  F(sub_w,  0, 1, 0)
602  F(subs_w, 0, 1, 1)
603
604  F(add,    1, 0, 0)
605  F(adds,   1, 0, 1)
606  F(sub,    1, 1, 0)
607  F(subs,   1, 1, 1)
608#undef F
609
610  void mov(Register rd, Register rm) {
611    if ((rd == SP) || (rm == SP)) {
612      add(rd, rm, 0);
613    } else {
614      orr(rd, ZR, rm);
615    }
616  }
617
618  void mov_w(Register rd, Register rm) {
619    if ((rd == SP) || (rm == SP)) {
620      add_w(rd, rm, 0);
621    } else {
622      orr_w(rd, ZR, rm);
623    }
624  }
625
626  void cmp(Register rn, int imm) {
627    subs(ZR, rn, imm);
628  }
629
630  void cmp_w(Register rn, int imm) {
631    subs_w(ZR, rn, imm);
632  }
633
634  void cmp(Register rn, Register rm) {
635    assert (rm != SP, "SP should not be used as the 2nd operand of cmp");
636    if (rn == SP) {
637      subs(ZR, rn, rm, ex_uxtx);
638    } else {
639      subs(ZR, rn, rm);
640    }
641  }
642
643  void cmp_w(Register rn, Register rm) {
644    assert ((rn != SP) && (rm != SP), "SP should not be used in 32-bit cmp");
645    subs_w(ZR, rn, rm);
646  }
647
648  void cmp(Register rn, AsmOperand operand) {
649    assert (rn != SP, "SP is not allowed in cmp with shifted register (AsmOperand)");
650    subs(ZR, rn, operand);
651  }
652
653  void cmn(Register rn, int imm) {
654    adds(ZR, rn, imm);
655  }
656
657  void cmn_w(Register rn, int imm) {
658    adds_w(ZR, rn, imm);
659  }
660
661  void cmn(Register rn, Register rm) {
662    assert (rm != SP, "SP should not be used as the 2nd operand of cmp");
663    if (rn == SP) {
664      adds(ZR, rn, rm, ex_uxtx);
665    } else {
666      adds(ZR, rn, rm);
667    }
668  }
669
670  void cmn_w(Register rn, Register rm) {
671    assert ((rn != SP) && (rm != SP), "SP should not be used in 32-bit cmp");
672    adds_w(ZR, rn, rm);
673  }
674
675  void neg(Register rd, Register rm) {
676    sub(rd, ZR, rm);
677  }
678
679  void neg_w(Register rd, Register rm) {
680    sub_w(rd, ZR, rm);
681  }
682
683#define F(mnemonic, sf, op, S) \
684  void mnemonic(Register rd, Register rn, Register rm) { \
685    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010000 << 21 | rm->encoding_with_zr() << 16 |   \
686        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                                     \
687  }
688
689  F(adc_w,  0, 0, 0)
690  F(adcs_w, 0, 0, 1)
691  F(sbc_w,  0, 1, 0)
692  F(sbcs_w, 0, 1, 1)
693
694  F(adc,    1, 0, 0)
695  F(adcs,   1, 0, 1)
696  F(sbc,    1, 1, 0)
697  F(sbcs,   1, 1, 1)
698#undef F
699
700#define F(mnemonic, sf, N) \
701  void mnemonic(Register rd, Register rn, Register rm, int lsb) { \
702    assert ((lsb >> (5 + sf)) == 0, "illegal least significant bit position");        \
703    emit_int32(sf << 31 | 0b100111 << 23 | N << 22 | rm->encoding_with_zr() << 16 |   \
704        lsb << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());            \
705  }
706
707  F(extr_w,  0, 0)
708  F(extr,    1, 1)
709#undef F
710
711#define F(mnemonic, sf, opc) \
712  void mnemonic(Register rd, int imm, int shift) { \
713    assert ((imm >> 16) == 0, "immediate is out of range");                       \
714    assert (((shift & 0xf) == 0) && ((shift >> (5 + sf)) == 0), "invalid shift"); \
715    emit_int32(sf << 31 | opc << 29 | 0b100101 << 23 | (shift >> 4) << 21 |       \
716        imm << 5 | rd->encoding_with_zr());                                       \
717  }
718
719  F(movn_w,  0, 0b00)
720  F(movz_w,  0, 0b10)
721  F(movk_w,  0, 0b11)
722  F(movn,    1, 0b00)
723  F(movz,    1, 0b10)
724  F(movk,    1, 0b11)
725#undef F
726
727  void mov(Register rd, int imm) {
728    assert ((imm >> 16) == 0, "immediate is out of range");
729    movz(rd, imm, 0);
730  }
731
732  void mov_w(Register rd, int imm) {
733    assert ((imm >> 16) == 0, "immediate is out of range");
734    movz_w(rd, imm, 0);
735  }
736
737#define F(mnemonic, sf, op, S) \
738  void mnemonic(Register rn, int imm, int nzcv, AsmCondition cond) { \
739    assert ((imm >> 5) == 0, "immediate is out of range");                      \
740    assert ((nzcv >> 4) == 0, "illegal nzcv");                                  \
741    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010010 << 21 | imm << 16 |   \
742         cond << 12 | 1 << 11 | rn->encoding_with_zr() << 5 | nzcv);            \
743  }
744
745  F(ccmn_w, 0, 0, 1)
746  F(ccmp_w, 0, 1, 1)
747  F(ccmn,   1, 0, 1)
748  F(ccmp,   1, 1, 1)
749#undef F
750
751#define F(mnemonic, sf, op, S) \
752  void mnemonic(Register rn, Register rm, int nzcv, AsmCondition cond) { \
753    assert ((nzcv >> 4) == 0, "illegal nzcv");                                                    \
754    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010010 << 21 | rm->encoding_with_zr() << 16 |  \
755        cond << 12 | rn->encoding_with_zr() << 5 | nzcv);                                         \
756  }
757
758  F(ccmn_w, 0, 0, 1)
759  F(ccmp_w, 0, 1, 1)
760  F(ccmn,   1, 0, 1)
761  F(ccmp,   1, 1, 1)
762#undef F
763
764#define F(mnemonic, sf, op, S, op2) \
765  void mnemonic(Register rd, Register rn, Register rm, AsmCondition cond) { \
766    emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010100 << 21 | rm->encoding_with_zr() << 16 |  \
767        cond << 12 | op2 << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());           \
768  }
769
770  F(csel_w,  0, 0, 0, 0b00)
771  F(csinc_w, 0, 0, 0, 0b01)
772  F(csinv_w, 0, 1, 0, 0b00)
773  F(csneg_w, 0, 1, 0, 0b01)
774
775  F(csel,    1, 0, 0, 0b00)
776  F(csinc,   1, 0, 0, 0b01)
777  F(csinv,   1, 1, 0, 0b00)
778  F(csneg,   1, 1, 0, 0b01)
779#undef F
780
781  void cset(Register rd, AsmCondition cond) {
782    csinc(rd, ZR, ZR, inverse(cond));
783  }
784
785  void cset_w(Register rd, AsmCondition cond) {
786    csinc_w(rd, ZR, ZR, inverse(cond));
787  }
788
789  void csetm(Register rd, AsmCondition cond) {
790    csinv(rd, ZR, ZR, inverse(cond));
791  }
792
793  void csetm_w(Register rd, AsmCondition cond) {
794    csinv_w(rd, ZR, ZR, inverse(cond));
795  }
796
797  void cinc(Register rd, Register rn, AsmCondition cond) {
798    csinc(rd, rn, rn, inverse(cond));
799  }
800
801  void cinc_w(Register rd, Register rn, AsmCondition cond) {
802    csinc_w(rd, rn, rn, inverse(cond));
803  }
804
805  void cinv(Register rd, Register rn, AsmCondition cond) {
806    csinv(rd, rn, rn, inverse(cond));
807  }
808
809  void cinv_w(Register rd, Register rn, AsmCondition cond) {
810    csinv_w(rd, rn, rn, inverse(cond));
811  }
812
813#define F(mnemonic, sf, S, opcode) \
814  void mnemonic(Register rd, Register rn) { \
815    emit_int32(sf << 31 | 1 << 30 | S << 29 | 0b11010110 << 21 | opcode << 10 |  \
816        rn->encoding_with_zr() << 5 | rd->encoding_with_zr());                   \
817  }
818
819  F(rbit_w,  0, 0, 0b000000)
820  F(rev16_w, 0, 0, 0b000001)
821  F(rev_w,   0, 0, 0b000010)
822  F(clz_w,   0, 0, 0b000100)
823  F(cls_w,   0, 0, 0b000101)
824
825  F(rbit,    1, 0, 0b000000)
826  F(rev16,   1, 0, 0b000001)
827  F(rev32,   1, 0, 0b000010)
828  F(rev,     1, 0, 0b000011)
829  F(clz,     1, 0, 0b000100)
830  F(cls,     1, 0, 0b000101)
831#undef F
832
833#define F(mnemonic, sf, S, opcode) \
834  void mnemonic(Register rd, Register rn, Register rm) { \
835    emit_int32(sf << 31 | S << 29 | 0b11010110 << 21 | rm->encoding_with_zr() << 16 |  \
836        opcode << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());          \
837  }
838
839  F(udiv_w,  0, 0, 0b000010)
840  F(sdiv_w,  0, 0, 0b000011)
841  F(lslv_w,  0, 0, 0b001000)
842  F(lsrv_w,  0, 0, 0b001001)
843  F(asrv_w,  0, 0, 0b001010)
844  F(rorv_w,  0, 0, 0b001011)
845
846  F(udiv,    1, 0, 0b000010)
847  F(sdiv,    1, 0, 0b000011)
848  F(lslv,    1, 0, 0b001000)
849  F(lsrv,    1, 0, 0b001001)
850  F(asrv,    1, 0, 0b001010)
851  F(rorv,    1, 0, 0b001011)
852#undef F
853
854#define F(mnemonic, sf, op31, o0) \
855  void mnemonic(Register rd, Register rn, Register rm, Register ra) { \
856    emit_int32(sf << 31 | 0b11011 << 24 | op31 << 21 | rm->encoding_with_zr() << 16 |                     \
857        o0 << 15 | ra->encoding_with_zr() << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());  \
858  }
859
860  F(madd_w,  0, 0b000, 0)
861  F(msub_w,  0, 0b000, 1)
862  F(madd,    1, 0b000, 0)
863  F(msub,    1, 0b000, 1)
864
865  F(smaddl,  1, 0b001, 0)
866  F(smsubl,  1, 0b001, 1)
867  F(umaddl,  1, 0b101, 0)
868  F(umsubl,  1, 0b101, 1)
869#undef F
870
871  void mul(Register rd, Register rn, Register rm) {
872      madd(rd, rn, rm, ZR);
873  }
874
875  void mul_w(Register rd, Register rn, Register rm) {
876      madd_w(rd, rn, rm, ZR);
877  }
878
879#define F(mnemonic, sf, op31, o0) \
880  void mnemonic(Register rd, Register rn, Register rm) { \
881    emit_int32(sf << 31 | 0b11011 << 24 | op31 << 21 | rm->encoding_with_zr() << 16 |      \
882        o0 << 15 | 0b11111 << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());  \
883  }
884
885  F(smulh,   1, 0b010, 0)
886  F(umulh,   1, 0b110, 0)
887#undef F
888
889#define F(mnemonic, op) \
890  void mnemonic(Register rd, address addr) { \
891    intx offset;                                                        \
892    if (op == 0) {                                                      \
893      offset = addr - pc();                                             \
894    } else {                                                            \
895      offset = (((intx)addr) - (((intx)pc()) & ~0xfff)) >> 12;          \
896    }                                                                   \
897    assert (is_imm_in_range(offset, 21, 0), "offset is out of range");  \
898    emit_int32(op << 31 | (offset & 3) << 29 | 0b10000 << 24 |          \
899        encode_imm(offset >> 2, 19, 0, 5) | rd->encoding_with_zr());    \
900  }                                                                     \
901
902  F(adr,   0)
903  F(adrp,  1)
904#undef F
905
906  void adr(Register rd, Label& L) {
907    adr(rd, target(L));
908  }
909
910#define F(mnemonic, sf, opc, N)                                                \
911  void mnemonic(Register rd, Register rn, int immr, int imms) {                \
912    assert ((immr >> (5 + sf)) == 0, "immr is out of range");                  \
913    assert ((imms >> (5 + sf)) == 0, "imms is out of range");                  \
914    emit_int32(sf << 31 | opc << 29 | 0b100110 << 23 | N << 22 | immr << 16 |  \
915        imms << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr());    \
916  }
917
918  F(sbfm_w, 0, 0b00, 0)
919  F(bfm_w,  0, 0b01, 0)
920  F(ubfm_w, 0, 0b10, 0)
921
922  F(sbfm, 1, 0b00, 1)
923  F(bfm,  1, 0b01, 1)
924  F(ubfm, 1, 0b10, 1)
925#undef F
926
927#define F(alias, mnemonic, sf, immr, imms) \
928  void alias(Register rd, Register rn, int lsb, int width) {                        \
929    assert ((lsb >> (5 + sf)) == 0, "lsb is out of range");                         \
930    assert ((1 <= width) && (width <= (32 << sf) - lsb), "width is out of range");  \
931    mnemonic(rd, rn, immr, imms);                                                   \
932  }
933
934  F(bfi_w,   bfm_w,  0, (-lsb) & 0x1f, width - 1)
935  F(bfi,     bfm,    1, (-lsb) & 0x3f, width - 1)
936  F(bfxil_w, bfm_w,  0, lsb,           lsb + width - 1)
937  F(bfxil,   bfm,    1, lsb,           lsb + width - 1)
938  F(sbfiz_w, sbfm_w, 0, (-lsb) & 0x1f, width - 1)
939  F(sbfiz,   sbfm,   1, (-lsb) & 0x3f, width - 1)
940  F(sbfx_w,  sbfm_w, 0, lsb,           lsb + width - 1)
941  F(sbfx,    sbfm,   1, lsb,           lsb + width - 1)
942  F(ubfiz_w, ubfm_w, 0, (-lsb) & 0x1f, width - 1)
943  F(ubfiz,   ubfm,   1, (-lsb) & 0x3f, width - 1)
944  F(ubfx_w,  ubfm_w, 0, lsb,           lsb + width - 1)
945  F(ubfx,    ubfm,   1, lsb,           lsb + width - 1)
946#undef F
947
948#define F(alias, mnemonic, sf, immr, imms) \
949  void alias(Register rd, Register rn, int shift) {              \
950    assert ((shift >> (5 + sf)) == 0, "shift is out of range");  \
951    mnemonic(rd, rn, immr, imms);                                \
952  }
953
954  F(_asr_w, sbfm_w, 0, shift, 31)
955  F(_asr,   sbfm,   1, shift, 63)
956  F(_lsl_w, ubfm_w, 0, (-shift) & 0x1f, 31 - shift)
957  F(_lsl,   ubfm,   1, (-shift) & 0x3f, 63 - shift)
958  F(_lsr_w, ubfm_w, 0, shift, 31)
959  F(_lsr,   ubfm,   1, shift, 63)
960#undef F
961
962#define F(alias, mnemonic, immr, imms) \
963  void alias(Register rd, Register rn) {   \
964    mnemonic(rd, rn, immr, imms);          \
965  }
966
967  F(sxtb_w, sbfm_w, 0, 7)
968  F(sxtb,   sbfm,   0, 7)
969  F(sxth_w, sbfm_w, 0, 15)
970  F(sxth,   sbfm,   0, 15)
971  F(sxtw,   sbfm,   0, 31)
972  F(uxtb_w, ubfm_w, 0, 7)
973  F(uxtb,   ubfm,   0, 7)
974  F(uxth_w, ubfm_w, 0, 15)
975  F(uxth,   ubfm,   0, 15)
976#undef F
977
978  // Branch instructions
979
980#define F(mnemonic, op) \
981  void mnemonic(Register rn) {                                                             \
982    emit_int32(0b1101011 << 25 | op << 21 | 0b11111 << 16 | rn->encoding_with_zr() << 5);  \
983  }
984
985  F(br,  0b00)
986  F(blr, 0b01)
987  F(ret, 0b10)
988#undef F
989
990  void ret() {
991    ret(LR);
992  }
993
994#define F(mnemonic, op) \
995  void mnemonic(address target) {                                         \
996    intx offset = target - pc();                                          \
997    assert (is_offset_in_range(offset, 26), "offset is out of range");    \
998    emit_int32(op << 31 | 0b00101 << 26 | encode_offset(offset, 26, 0));  \
999  }
1000
1001  F(b,  0)
1002  F(bl, 1)
1003#undef F
1004
1005  void b(address target, AsmCondition cond) {
1006    if (cond == al) {
1007      b(target);
1008    } else {
1009      intx offset = target - pc();
1010      assert (is_offset_in_range(offset, 19), "offset is out of range");
1011      emit_int32(0b0101010 << 25 | encode_offset(offset, 19, 5) | cond);
1012    }
1013  }
1014
1015
1016#define F(mnemonic, sf, op)                                             \
1017  void mnemonic(Register rt, address target) {                          \
1018    intx offset = target - pc();                                        \
1019    assert (is_offset_in_range(offset, 19), "offset is out of range");  \
1020    emit_int32(sf << 31 | 0b011010 << 25 | op << 24 | encode_offset(offset, 19, 5) | rt->encoding_with_zr()); \
1021  }                                                                     \
1022
1023  F(cbz_w,  0, 0)
1024  F(cbnz_w, 0, 1)
1025  F(cbz,    1, 0)
1026  F(cbnz,   1, 1)
1027#undef F
1028
1029#define F(mnemonic, op)                                                 \
1030  void mnemonic(Register rt, int bit, address target) {                 \
1031    intx offset = target - pc();                                        \
1032    assert (is_offset_in_range(offset, 14), "offset is out of range");  \
1033    assert (0 <= bit && bit < 64, "bit number is out of range");        \
1034    emit_int32((bit >> 5) << 31 | 0b011011 << 25 | op << 24 | (bit & 0x1f) << 19 | \
1035        encode_offset(offset, 14, 5) | rt->encoding_with_zr());         \
1036  }                                                                     \
1037
1038  F(tbz,  0)
1039  F(tbnz, 1)
1040#undef F
1041
1042  // System instructions
1043
1044  enum DMB_Opt {
1045    DMB_ld  = 0b1101,
1046    DMB_st  = 0b1110,
1047    DMB_all = 0b1111
1048  };
1049
1050#define F(mnemonic, L, op0, op1, CRn, op2, Rt) \
1051  void mnemonic(DMB_Opt option) {                                       \
1052    emit_int32(0b1101010100 << 22 | L << 21 | op0 << 19 | op1 << 16 |   \
1053        CRn << 12 | option << 8 | op2 << 5 | Rt);                       \
1054  }
1055
1056  F(dsb,  0, 0b00, 0b011, 0b0011, 0b100, 0b11111)
1057  F(dmb,  0, 0b00, 0b011, 0b0011, 0b101, 0b11111)
1058#undef F
1059
1060#define F(mnemonic, L, op0, op1, CRn, Rt) \
1061  void mnemonic(int imm) {                                              \
1062    assert ((imm >> 7) == 0, "immediate is out of range");              \
1063    emit_int32(0b1101010100 << 22 | L << 21 | op0 << 19 | op1 << 16 |   \
1064        CRn << 12 | imm << 5 | Rt);                                     \
1065  }
1066
1067  F(hint, 0, 0b00, 0b011, 0b0010, 0b11111)
1068#undef F
1069
1070  void nop() {
1071    hint(0);
1072  }
1073
1074  void yield() {
1075    hint(1);
1076  }
1077
1078#define F(mnemonic, opc, op2, LL) \
1079  void mnemonic(int imm = 0) {                                           \
1080    assert ((imm >> 16) == 0, "immediate is out of range");              \
1081    emit_int32(0b11010100 << 24 | opc << 21 | imm << 5 | op2 << 2 | LL); \
1082  }
1083
1084  F(brk, 0b001, 0b000, 0b00)
1085  F(hlt, 0b010, 0b000, 0b00)
1086#undef F
1087
1088  enum SystemRegister { // o0<1> op1<3> CRn<4> CRm<4> op2<3>
1089    SysReg_NZCV = 0b101101000010000,
1090    SysReg_FPCR = 0b101101000100000,
1091  };
1092
1093  void mrs(Register rt, SystemRegister systemReg) {
1094    assert ((systemReg >> 15) == 0, "systemReg is out of range");
1095    emit_int32(0b110101010011 << 20 | systemReg << 5 | rt->encoding_with_zr());
1096  }
1097
1098  void msr(SystemRegister systemReg, Register rt) {
1099    assert ((systemReg >> 15) == 0, "systemReg is out of range");
1100    emit_int32(0b110101010001 << 20 | systemReg << 5 | rt->encoding_with_zr());
1101  }
1102
1103  // Floating-point instructions
1104
1105#define F(mnemonic, M, S, type, opcode2) \
1106  void mnemonic(FloatRegister rn, FloatRegister rm) {                         \
1107    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |     \
1108        rm->encoding() << 16 | 0b1000 << 10 | rn->encoding() << 5 | opcode2); \
1109  }
1110
1111  F(fcmp_s,   0, 0, 0b00, 0b00000)
1112  F(fcmpe_s,  0, 0, 0b00, 0b01000)
1113  F(fcmp_d,   0, 0, 0b01, 0b00000)
1114  F(fcmpe_d,  0, 0, 0b01, 0b10000)
1115#undef F
1116
1117#define F(mnemonic, M, S, type, opcode2) \
1118  void mnemonic(FloatRegister rn) {                                           \
1119    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |     \
1120        0b1000 << 10 | rn->encoding() << 5 | opcode2);                        \
1121  }
1122
1123  F(fcmp0_s,   0, 0, 0b00, 0b01000)
1124  F(fcmpe0_s,  0, 0, 0b00, 0b11000)
1125  F(fcmp0_d,   0, 0, 0b01, 0b01000)
1126  F(fcmpe0_d,  0, 0, 0b01, 0b11000)
1127#undef F
1128
1129#define F(mnemonic, M, S, type, op) \
1130  void mnemonic(FloatRegister rn, FloatRegister rm, int nzcv, AsmCondition cond) { \
1131    assert ((nzcv >> 4) == 0, "illegal nzcv");                                                  \
1132    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                       \
1133        rm->encoding() << 16 | cond << 12 | 0b01 << 10 | rn->encoding() << 5 | op << 4 | nzcv); \
1134  }
1135
1136  F(fccmp_s,   0, 0, 0b00, 0)
1137  F(fccmpe_s,  0, 0, 0b00, 1)
1138  F(fccmp_d,   0, 0, 0b01, 0)
1139  F(fccmpe_d,  0, 0, 0b01, 1)
1140#undef F
1141
1142#define F(mnemonic, M, S, type) \
1143  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, AsmCondition cond) { \
1144    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                       \
1145        rm->encoding() << 16 | cond << 12 | 0b11 << 10 | rn->encoding() << 5 | rd->encoding()); \
1146  }
1147
1148  F(fcsel_s,   0, 0, 0b00)
1149  F(fcsel_d,   0, 0, 0b01)
1150#undef F
1151
1152#define F(mnemonic, M, S, type, opcode) \
1153  void mnemonic(FloatRegister rd, FloatRegister rn) { \
1154    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |      \
1155        opcode << 15 | 0b10000 << 10 | rn->encoding() << 5 | rd->encoding());  \
1156  }
1157
1158  F(fmov_s,   0, 0, 0b00, 0b000000)
1159  F(fabs_s,   0, 0, 0b00, 0b000001)
1160  F(fneg_s,   0, 0, 0b00, 0b000010)
1161  F(fsqrt_s,  0, 0, 0b00, 0b000011)
1162  F(fcvt_ds,  0, 0, 0b00, 0b000101)
1163  F(fcvt_hs,  0, 0, 0b00, 0b000111)
1164  F(frintn_s, 0, 0, 0b00, 0b001000)
1165  F(frintp_s, 0, 0, 0b00, 0b001001)
1166  F(frintm_s, 0, 0, 0b00, 0b001010)
1167  F(frintz_s, 0, 0, 0b00, 0b001011)
1168  F(frinta_s, 0, 0, 0b00, 0b001100)
1169  F(frintx_s, 0, 0, 0b00, 0b001110)
1170  F(frinti_s, 0, 0, 0b00, 0b001111)
1171
1172  F(fmov_d,   0, 0, 0b01, 0b000000)
1173  F(fabs_d,   0, 0, 0b01, 0b000001)
1174  F(fneg_d,   0, 0, 0b01, 0b000010)
1175  F(fsqrt_d,  0, 0, 0b01, 0b000011)
1176  F(fcvt_sd,  0, 0, 0b01, 0b000100)
1177  F(fcvt_hd,  0, 0, 0b01, 0b000111)
1178  F(frintn_d, 0, 0, 0b01, 0b001000)
1179  F(frintp_d, 0, 0, 0b01, 0b001001)
1180  F(frintm_d, 0, 0, 0b01, 0b001010)
1181  F(frintz_d, 0, 0, 0b01, 0b001011)
1182  F(frinta_d, 0, 0, 0b01, 0b001100)
1183  F(frintx_d, 0, 0, 0b01, 0b001110)
1184  F(frinti_d, 0, 0, 0b01, 0b001111)
1185
1186  F(fcvt_sh,  0, 0, 0b11, 0b000100)
1187  F(fcvt_dh,  0, 0, 0b11, 0b000101)
1188#undef F
1189
1190#define F(mnemonic, M, S, type, opcode) \
1191  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm) { \
1192    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                          \
1193        rm->encoding() << 16 | opcode << 12 | 0b10 << 10 | rn->encoding() << 5 | rd->encoding());  \
1194  }
1195
1196  F(fmul_s,   0, 0, 0b00, 0b0000)
1197  F(fdiv_s,   0, 0, 0b00, 0b0001)
1198  F(fadd_s,   0, 0, 0b00, 0b0010)
1199  F(fsub_s,   0, 0, 0b00, 0b0011)
1200  F(fmax_s,   0, 0, 0b00, 0b0100)
1201  F(fmin_s,   0, 0, 0b00, 0b0101)
1202  F(fmaxnm_s, 0, 0, 0b00, 0b0110)
1203  F(fminnm_s, 0, 0, 0b00, 0b0111)
1204  F(fnmul_s,  0, 0, 0b00, 0b1000)
1205
1206  F(fmul_d,   0, 0, 0b01, 0b0000)
1207  F(fdiv_d,   0, 0, 0b01, 0b0001)
1208  F(fadd_d,   0, 0, 0b01, 0b0010)
1209  F(fsub_d,   0, 0, 0b01, 0b0011)
1210  F(fmax_d,   0, 0, 0b01, 0b0100)
1211  F(fmin_d,   0, 0, 0b01, 0b0101)
1212  F(fmaxnm_d, 0, 0, 0b01, 0b0110)
1213  F(fminnm_d, 0, 0, 0b01, 0b0111)
1214  F(fnmul_d,  0, 0, 0b01, 0b1000)
1215#undef F
1216
1217#define F(mnemonic, M, S, type, o1, o0) \
1218  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, FloatRegister ra) { \
1219    emit_int32(M << 31 | S << 29 | 0b11111 << 24 | type << 22 | o1 << 21 | rm->encoding() << 16 |  \
1220         o0 << 15 | ra->encoding() << 10 | rn->encoding() << 5 | rd->encoding());                  \
1221  }
1222
1223  F(fmadd_s,  0, 0, 0b00, 0, 0)
1224  F(fmsub_s,  0, 0, 0b00, 0, 1)
1225  F(fnmadd_s, 0, 0, 0b00, 1, 0)
1226  F(fnmsub_s, 0, 0, 0b00, 1, 1)
1227
1228  F(fmadd_d,  0, 0, 0b01, 0, 0)
1229  F(fmsub_d,  0, 0, 0b01, 0, 1)
1230  F(fnmadd_d, 0, 0, 0b01, 1, 0)
1231  F(fnmsub_d, 0, 0, 0b01, 1, 1)
1232#undef F
1233
1234#define F(mnemonic, M, S, type) \
1235  void mnemonic(FloatRegister rd, int imm8) { \
1236    assert ((imm8 >> 8) == 0, "immediate is out of range");                \
1237    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |  \
1238         imm8 << 13 | 0b100 << 10 | rd->encoding());                       \
1239  }
1240
1241  F(fmov_s, 0, 0, 0b00)
1242  F(fmov_d, 0, 0, 0b01)
1243#undef F
1244
1245#define F(mnemonic, sf, S, type, rmode, opcode) \
1246  void mnemonic(Register rd, FloatRegister rn) {                                     \
1247    emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |           \
1248         rmode << 19 | opcode << 16 | rn->encoding() << 5 | rd->encoding_with_zr()); \
1249  }
1250
1251  F(fcvtns_ws, 0, 0, 0b00, 0b00, 0b000)
1252  F(fcvtnu_ws, 0, 0, 0b00, 0b00, 0b001)
1253  F(fcvtas_ws, 0, 0, 0b00, 0b00, 0b100)
1254  F(fcvtau_ws, 0, 0, 0b00, 0b00, 0b101)
1255  F(fmov_ws,   0, 0, 0b00, 0b00, 0b110)
1256  F(fcvtps_ws, 0, 0, 0b00, 0b01, 0b000)
1257  F(fcvtpu_ws, 0, 0, 0b00, 0b01, 0b001)
1258  F(fcvtms_ws, 0, 0, 0b00, 0b10, 0b000)
1259  F(fcvtmu_ws, 0, 0, 0b00, 0b10, 0b001)
1260  F(fcvtzs_ws, 0, 0, 0b00, 0b11, 0b000)
1261  F(fcvtzu_ws, 0, 0, 0b00, 0b11, 0b001)
1262
1263  F(fcvtns_wd, 0, 0, 0b01, 0b00, 0b000)
1264  F(fcvtnu_wd, 0, 0, 0b01, 0b00, 0b001)
1265  F(fcvtas_wd, 0, 0, 0b01, 0b00, 0b100)
1266  F(fcvtau_wd, 0, 0, 0b01, 0b00, 0b101)
1267  F(fcvtps_wd, 0, 0, 0b01, 0b01, 0b000)
1268  F(fcvtpu_wd, 0, 0, 0b01, 0b01, 0b001)
1269  F(fcvtms_wd, 0, 0, 0b01, 0b10, 0b000)
1270  F(fcvtmu_wd, 0, 0, 0b01, 0b10, 0b001)
1271  F(fcvtzs_wd, 0, 0, 0b01, 0b11, 0b000)
1272  F(fcvtzu_wd, 0, 0, 0b01, 0b11, 0b001)
1273
1274  F(fcvtns_xs, 1, 0, 0b00, 0b00, 0b000)
1275  F(fcvtnu_xs, 1, 0, 0b00, 0b00, 0b001)
1276  F(fcvtas_xs, 1, 0, 0b00, 0b00, 0b100)
1277  F(fcvtau_xs, 1, 0, 0b00, 0b00, 0b101)
1278  F(fcvtps_xs, 1, 0, 0b00, 0b01, 0b000)
1279  F(fcvtpu_xs, 1, 0, 0b00, 0b01, 0b001)
1280  F(fcvtms_xs, 1, 0, 0b00, 0b10, 0b000)
1281  F(fcvtmu_xs, 1, 0, 0b00, 0b10, 0b001)
1282  F(fcvtzs_xs, 1, 0, 0b00, 0b11, 0b000)
1283  F(fcvtzu_xs, 1, 0, 0b00, 0b11, 0b001)
1284
1285  F(fcvtns_xd, 1, 0, 0b01, 0b00, 0b000)
1286  F(fcvtnu_xd, 1, 0, 0b01, 0b00, 0b001)
1287  F(fcvtas_xd, 1, 0, 0b01, 0b00, 0b100)
1288  F(fcvtau_xd, 1, 0, 0b01, 0b00, 0b101)
1289  F(fmov_xd,   1, 0, 0b01, 0b00, 0b110)
1290  F(fcvtps_xd, 1, 0, 0b01, 0b01, 0b000)
1291  F(fcvtpu_xd, 1, 0, 0b01, 0b01, 0b001)
1292  F(fcvtms_xd, 1, 0, 0b01, 0b10, 0b000)
1293  F(fcvtmu_xd, 1, 0, 0b01, 0b10, 0b001)
1294  F(fcvtzs_xd, 1, 0, 0b01, 0b11, 0b000)
1295  F(fcvtzu_xd, 1, 0, 0b01, 0b11, 0b001)
1296
1297  F(fmov_xq,   1, 0, 0b10, 0b01, 0b110)
1298#undef F
1299
1300#define F(mnemonic, sf, S, type, rmode, opcode) \
1301  void mnemonic(FloatRegister rd, Register rn) {                                     \
1302    emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |           \
1303         rmode << 19 | opcode << 16 | rn->encoding_with_zr() << 5 | rd->encoding()); \
1304  }
1305
1306  F(scvtf_sw,  0, 0, 0b00, 0b00, 0b010)
1307  F(ucvtf_sw,  0, 0, 0b00, 0b00, 0b011)
1308  F(fmov_sw,   0, 0, 0b00, 0b00, 0b111)
1309  F(scvtf_dw,  0, 0, 0b01, 0b00, 0b010)
1310  F(ucvtf_dw,  0, 0, 0b01, 0b00, 0b011)
1311
1312  F(scvtf_sx,  1, 0, 0b00, 0b00, 0b010)
1313  F(ucvtf_sx,  1, 0, 0b00, 0b00, 0b011)
1314  F(scvtf_dx,  1, 0, 0b01, 0b00, 0b010)
1315  F(ucvtf_dx,  1, 0, 0b01, 0b00, 0b011)
1316  F(fmov_dx,   1, 0, 0b01, 0b00, 0b111)
1317
1318  F(fmov_qx,   1, 0, 0b10, 0b01, 0b111)
1319#undef F
1320
1321#define F(mnemonic, opcode) \
1322  void mnemonic(FloatRegister Vd, FloatRegister Vn) {                                     \
1323    emit_int32( opcode << 10 | Vn->encoding() << 5 | Vd->encoding());             \
1324  }
1325
1326  F(aese, 0b0100111000101000010010);
1327  F(aesd, 0b0100111000101000010110);
1328  F(aesmc, 0b0100111000101000011010);
1329  F(aesimc, 0b0100111000101000011110);
1330#undef F
1331
1332#ifdef COMPILER2
1333  typedef VFP::double_num double_num;
1334  typedef VFP::float_num  float_num;
1335#endif
1336
1337  void vcnt(FloatRegister Dd, FloatRegister Dn, int quad = 0, int size = 0) {
1338    // emitted at VM startup to detect whether the instruction is available
1339    assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction");
1340    assert(size == 0, "illegal size value");
1341    emit_int32(0x0e205800 | quad << 30 | size << 22 | Dn->encoding() << 5 | Dd->encoding());
1342  }
1343
1344#ifdef COMPILER2
1345  void addv(FloatRegister Dd, FloatRegister Dm, int quad, int size) {
1346    // emitted at VM startup to detect whether the instruction is available
1347    assert(VM_Version::has_simd(), "simd instruction");
1348    assert((quad & ~1) == 0, "illegal value");
1349    assert(size >= 0 && size < 3, "illegal value");
1350    assert(((size << 1) | quad) != 4, "illegal values (size 2, quad 0)");
1351    emit_int32(0x0e31b800 | quad << 30 | size << 22 | Dm->encoding() << 5 | Dd->encoding());
1352  }
1353
1354  enum VElem_Size {
1355    VELEM_SIZE_8  = 0x00,
1356    VELEM_SIZE_16 = 0x01,
1357    VELEM_SIZE_32 = 0x02,
1358    VELEM_SIZE_64 = 0x03
1359  };
1360
1361  enum VLD_Type {
1362    VLD1_TYPE_1_REG  = 0b0111,
1363    VLD1_TYPE_2_REGS = 0b1010,
1364    VLD1_TYPE_3_REGS = 0b0110,
1365    VLD1_TYPE_4_REGS = 0b0010
1366  };
1367
1368  enum VFloat_Arith_Size {
1369    VFA_SIZE_F32 = 0b0,
1370    VFA_SIZE_F64 = 0b1
1371  };
1372
1373#define F(mnemonic, U, S, P) \
1374  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
1375                int size, int quad) {                                    \
1376    assert(VM_Version::has_simd(), "simd instruction");                  \
1377    assert(!(size == VFA_SIZE_F64 && !quad), "reserved");                \
1378    assert((size & 1) == size, "overflow");                              \
1379    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 |                    \
1380               S << 23 | size << 22 | 1 << 21 | P << 11 | 1 << 10 |      \
1381               fm->encoding() << 16 |                                    \
1382               fn->encoding() <<  5 |                                    \
1383               fd->encoding());                                          \
1384  }
1385
1386  F(vaddF, 0, 0, 0b11010)  // Vd = Vn + Vm (float)
1387  F(vsubF, 0, 1, 0b11010)  // Vd = Vn - Vm (float)
1388  F(vmulF, 1, 0, 0b11011)  // Vd = Vn - Vm (float)
1389  F(vdivF, 1, 0, 0b11111)  // Vd = Vn / Vm (float)
1390#undef F
1391
1392#define F(mnemonic, U) \
1393  void mnemonic(FloatRegister fd, FloatRegister fm, FloatRegister fn,    \
1394                int size, int quad) {                                    \
1395    assert(VM_Version::has_simd(), "simd instruction");                  \
1396    assert(!(size == VELEM_SIZE_64 && !quad), "reserved");               \
1397    assert((size & 0b11) == size, "overflow");                           \
1398    int R = 0; /* rounding */                                            \
1399    int S = 0; /* saturating */                                          \
1400    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 |       \
1401               1 << 21 | R << 12 | S << 11 | 0b10001 << 10 |             \
1402               fm->encoding() << 16 |                                    \
1403               fn->encoding() <<  5 |                                    \
1404               fd->encoding());                                          \
1405  }
1406
1407  F(vshlSI, 0)  // Vd = ashift(Vn,Vm) (int)
1408  F(vshlUI, 1)  // Vd = lshift(Vn,Vm) (int)
1409#undef F
1410
1411#define F(mnemonic, U, P, M) \
1412  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
1413                int size, int quad) {                                    \
1414    assert(VM_Version::has_simd(), "simd instruction");                  \
1415    assert(!(size == VELEM_SIZE_64 && !quad), "reserved");               \
1416    assert(!(size == VELEM_SIZE_64 && M), "reserved");                   \
1417    assert((size & 0b11) == size, "overflow");                           \
1418    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 |       \
1419               1 << 21 | P << 11 | 1 << 10 |                             \
1420               fm->encoding() << 16 |                                    \
1421               fn->encoding() <<  5 |                                    \
1422               fd->encoding());                                          \
1423  }
1424
1425  F(vmulI, 0, 0b10011,  true)  // Vd = Vn * Vm (int)
1426  F(vaddI, 0, 0b10000, false)  // Vd = Vn + Vm (int)
1427  F(vsubI, 1, 0b10000, false)  // Vd = Vn - Vm (int)
1428#undef F
1429
1430#define F(mnemonic, U, O) \
1431  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
1432                int quad) {                                              \
1433    assert(VM_Version::has_simd(), "simd instruction");                  \
1434    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | O << 22 |          \
1435               1 << 21 | 0b00011 << 11 | 1 << 10 |                       \
1436               fm->encoding() << 16 |                                    \
1437               fn->encoding() <<  5 |                                    \
1438               fd->encoding());                                          \
1439  }
1440
1441  F(vandI, 0, 0b00)  // Vd = Vn & Vm (int)
1442  F(vorI,  0, 0b10)  // Vd = Vn | Vm (int)
1443  F(vxorI, 1, 0b00)  // Vd = Vn ^ Vm (int)
1444#undef F
1445
1446  void vnegI(FloatRegister fd, FloatRegister fn, int size, int quad) {
1447    int U = 1;
1448    assert(VM_Version::has_simd(), "simd instruction");
1449    assert(quad || size != VELEM_SIZE_64, "reserved");
1450    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 |
1451              size << 22 | 0b100000101110 << 10 |
1452              fn->encoding() << 5 |
1453              fd->encoding() << 0);
1454  }
1455
1456  void vshli(FloatRegister fd, FloatRegister fn, int esize, int imm, int quad) {
1457    assert(VM_Version::has_simd(), "simd instruction");
1458
1459    if (imm >= esize) {
1460      // maximum shift gives all zeroes, direction doesn't matter,
1461      // but only available for shift right
1462      vshri(fd, fn, esize, esize, true /* unsigned */, quad);
1463      return;
1464    }
1465    assert(imm >= 0 && imm < esize, "out of range");
1466
1467    int imm7 = esize + imm;
1468    int immh = imm7 >> 3;
1469    assert(immh != 0, "encoding constraint");
1470    assert((uint)immh < 16, "sanity");
1471    assert(((immh >> 2) | quad) != 0b10, "reserved");
1472    emit_int32(quad << 30 | 0b011110 << 23 | imm7 << 16 |
1473               0b010101 << 10 | fn->encoding() << 5 | fd->encoding() << 0);
1474  }
1475
1476  void vshri(FloatRegister fd, FloatRegister fn, int esize, int imm,
1477             bool U /* unsigned */, int quad) {
1478    assert(VM_Version::has_simd(), "simd instruction");
1479    assert(imm > 0, "out of range");
1480    if (imm >= esize) {
1481      // maximum shift (all zeroes)
1482      imm = esize;
1483    }
1484    int imm7 = 2 * esize - imm ;
1485    int immh = imm7 >> 3;
1486    assert(immh != 0, "encoding constraint");
1487    assert((uint)immh < 16, "sanity");
1488    assert(((immh >> 2) | quad) != 0b10, "reserved");
1489    emit_int32(quad << 30 | U << 29 | 0b011110 << 23 | imm7 << 16 |
1490               0b000001 << 10 | fn->encoding() << 5 | fd->encoding() << 0);
1491  }
1492  void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
1493    vshri(fd, fm, size, imm, true /* unsigned */, quad);
1494  }
1495  void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
1496    vshri(fd, fm, size, imm, false /* signed */, quad);
1497  }
1498
1499  void vld1(FloatRegister Vt, Address addr, VElem_Size size, int bits) {
1500    assert(VM_Version::has_simd(), "simd instruction");
1501    assert(bits == 128, "unsupported");
1502    assert(addr.disp() == 0 || addr.disp() == 16, "must be");
1503    int type = 0b11; // 2D
1504    int quad = 1;
1505    int L = 1;
1506    int opcode = VLD1_TYPE_1_REG;
1507    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1508               Vt->encoding() << 0 | addr.encoding_simd());
1509  }
1510
1511  void vst1(FloatRegister Vt, Address addr, VElem_Size size, int bits) {
1512    assert(VM_Version::has_simd(), "simd instruction");
1513    assert(bits == 128, "unsupported");
1514    assert(addr.disp() == 0 || addr.disp() == 16, "must be");
1515    int type = 0b11; // 2D
1516    int quad = 1;
1517    int L = 0;
1518    int opcode = VLD1_TYPE_1_REG;
1519    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1520               Vt->encoding() << 0 | addr.encoding_simd());
1521  }
1522
1523  void vld1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) {
1524    assert(VM_Version::has_simd(), "simd instruction");
1525    assert(bits == 128, "unsupported");
1526    assert(Vt->successor() == Vt2, "Registers must be ordered");
1527    assert(addr.disp() == 0 || addr.disp() == 32, "must be");
1528    int type = 0b11; // 2D
1529    int quad = 1;
1530    int L = 1;
1531    int opcode = VLD1_TYPE_2_REGS;
1532    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1533               Vt->encoding() << 0 | addr.encoding_simd());
1534  }
1535
1536  void vst1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) {
1537    assert(VM_Version::has_simd(), "simd instruction");
1538    assert(Vt->successor() == Vt2, "Registers must be ordered");
1539    assert(bits == 128, "unsupported");
1540    assert(addr.disp() == 0 || addr.disp() == 32, "must be");
1541    int type = 0b11; // 2D
1542    int quad = 1;
1543    int L = 0;
1544    int opcode = VLD1_TYPE_2_REGS;
1545    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1546               Vt->encoding() << 0 | addr.encoding_simd());
1547  }
1548
1549  void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1550            Address addr, VElem_Size size, int bits) {
1551    assert(VM_Version::has_simd(), "simd instruction");
1552    assert(bits == 128, "unsupported");
1553    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3,
1554          "Registers must be ordered");
1555    assert(addr.disp() == 0 || addr.disp() == 48, "must be");
1556    int type = 0b11; // 2D
1557    int quad = 1;
1558    int L = 1;
1559    int opcode = VLD1_TYPE_3_REGS;
1560    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1561               Vt->encoding() << 0 | addr.encoding_simd());
1562  }
1563
1564  void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1565            Address addr, VElem_Size size, int bits) {
1566    assert(VM_Version::has_simd(), "simd instruction");
1567    assert(bits == 128, "unsupported");
1568    assert(Vt->successor() == Vt2 &&  Vt2->successor() == Vt3,
1569           "Registers must be ordered");
1570    assert(addr.disp() == 0 || addr.disp() == 48, "must be");
1571    int type = 0b11; // 2D
1572    int quad = 1;
1573    int L = 0;
1574    int opcode = VLD1_TYPE_3_REGS;
1575    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1576               Vt->encoding() << 0 | addr.encoding_simd());
1577  }
1578
1579  void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1580            FloatRegister Vt4, Address addr, VElem_Size size, int bits) {
1581    assert(VM_Version::has_simd(), "simd instruction");
1582    assert(bits == 128, "unsupported");
1583    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 &&
1584           Vt3->successor() == Vt4, "Registers must be ordered");
1585    assert(addr.disp() == 0 || addr.disp() == 64, "must be");
1586    int type = 0b11; // 2D
1587    int quad = 1;
1588    int L = 1;
1589    int opcode = VLD1_TYPE_4_REGS;
1590    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1591               Vt->encoding() << 0 | addr.encoding_simd());
1592  }
1593
1594  void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1595            FloatRegister Vt4,  Address addr, VElem_Size size, int bits) {
1596    assert(VM_Version::has_simd(), "simd instruction");
1597    assert(bits == 128, "unsupported");
1598    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 &&
1599           Vt3->successor() == Vt4, "Registers must be ordered");
1600    assert(addr.disp() == 0 || addr.disp() == 64, "must be");
1601    int type = 0b11; // 2D
1602    int quad = 1;
1603    int L = 0;
1604    int opcode = VLD1_TYPE_4_REGS;
1605    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1606               Vt->encoding() << 0 | addr.encoding_simd());
1607  }
1608
1609  void rev32(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) {
1610    assert(VM_Version::has_simd(), "simd instruction");
1611    assert(size == VELEM_SIZE_8 || size == VELEM_SIZE_16, "must be");
1612    emit_int32(quad << 30 | 0b101110 << 24 | size << 22 |
1613               0b100000000010 << 10 | Vn->encoding() << 5 | Vd->encoding());
1614  }
1615
1616  void eor(FloatRegister Vd, FloatRegister Vn,  FloatRegister Vm, VElem_Size size, int quad) {
1617    assert(VM_Version::has_simd(), "simd instruction");
1618    assert(size == VELEM_SIZE_8, "must be");
1619    emit_int32(quad << 30 | 0b101110001 << 21 | Vm->encoding() << 16 |
1620               0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding());
1621  }
1622
1623  void orr(FloatRegister Vd, FloatRegister Vn,  FloatRegister Vm, VElem_Size size, int quad) {
1624    assert(VM_Version::has_simd(), "simd instruction");
1625    assert(size == VELEM_SIZE_8, "must be");
1626    emit_int32(quad << 30 | 0b001110101 << 21 | Vm->encoding() << 16 |
1627               0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding());
1628  }
1629
1630  void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) {
1631    assert(VM_Version::has_simd(), "simd instruction");
1632    assert(imm8 >= 0 && imm8 < 256, "out of range");
1633    int op;
1634    int cmode;
1635    switch (size) {
1636    case VELEM_SIZE_8:
1637      op = 0;
1638      cmode = 0b1110;
1639      break;
1640    case VELEM_SIZE_16:
1641      op = 0;
1642      cmode = 0b1000;
1643      break;
1644    case VELEM_SIZE_32:
1645      op = 0;
1646      cmode = 0b0000;
1647      break;
1648    default:
1649      cmode = 0;
1650      ShouldNotReachHere();
1651    }
1652    int abc = imm8 >> 5;
1653    int defgh = imm8 & 0b11111;
1654    emit_int32(quad << 30 | op << 29 | 0b1111 << 24 |
1655               abc << 16 | cmode << 12 | 0b01 << 10 |
1656               defgh << 5 | Dd->encoding() << 0);
1657  }
1658
1659  void vdupI(FloatRegister Dd, Register Rn, VElem_Size size, int quad) {
1660    assert(VM_Version::has_simd(), "simd instruction");
1661    assert(size <= 3, "unallocated encoding");
1662    assert(size != 3 || quad == 1, "reserved");
1663    int imm5 = 1 << size;
1664#ifdef ASSERT
1665    switch (size) {
1666    case VELEM_SIZE_8:
1667      assert(imm5 == 0b00001, "sanity");
1668      break;
1669    case VELEM_SIZE_16:
1670      assert(imm5 == 0b00010, "sanity");
1671      break;
1672    case VELEM_SIZE_32:
1673      assert(imm5 == 0b00100, "sanity");
1674      break;
1675    case VELEM_SIZE_64:
1676      assert(imm5 == 0b01000, "sanity");
1677      break;
1678    default:
1679      ShouldNotReachHere();
1680    }
1681#endif
1682    emit_int32(quad << 30 | 0b111 << 25 | 0b11 << 10 |
1683               imm5 << 16 | Rn->encoding() << 5 |
1684               Dd->encoding() << 0);
1685  }
1686
1687  void vdup(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) {
1688    assert(VM_Version::has_simd(), "simd instruction");
1689    int index = 0;
1690    int bytes = 1 << size;
1691    int range = 16 / bytes;
1692    assert(index < range, "overflow");
1693
1694    assert(size != VELEM_SIZE_64 || quad, "reserved");
1695    assert(8 << VELEM_SIZE_8  ==  8, "sanity");
1696    assert(8 << VELEM_SIZE_16 == 16, "sanity");
1697    assert(8 << VELEM_SIZE_32 == 32, "sanity");
1698    assert(8 << VELEM_SIZE_64 == 64, "sanity");
1699
1700    int imm5 = (index << (size + 1)) | bytes;
1701
1702    emit_int32(quad << 30 | 0b001110000 << 21 | imm5 << 16 | 0b000001 << 10 |
1703               Vn->encoding() << 5 | Vd->encoding() << 0);
1704  }
1705
1706  void vdupF(FloatRegister Vd, FloatRegister Vn, int quad) {
1707    vdup(Vd, Vn, VELEM_SIZE_32, quad);
1708  }
1709
1710  void vdupD(FloatRegister Vd, FloatRegister Vn, int quad) {
1711    vdup(Vd, Vn, VELEM_SIZE_64, quad);
1712  }
1713#endif
1714};
1715
1716
1717#endif // CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
1718