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  F(dpcs1, 0b101, 0b000, 0b01)
1087#undef F
1088
1089  enum SystemRegister { // o0<1> op1<3> CRn<4> CRm<4> op2<3>
1090    SysReg_NZCV = 0b101101000010000,
1091    SysReg_FPCR = 0b101101000100000,
1092  };
1093
1094  void mrs(Register rt, SystemRegister systemReg) {
1095    assert ((systemReg >> 15) == 0, "systemReg is out of range");
1096    emit_int32(0b110101010011 << 20 | systemReg << 5 | rt->encoding_with_zr());
1097  }
1098
1099  void msr(SystemRegister systemReg, Register rt) {
1100    assert ((systemReg >> 15) == 0, "systemReg is out of range");
1101    emit_int32(0b110101010001 << 20 | systemReg << 5 | rt->encoding_with_zr());
1102  }
1103
1104  // Floating-point instructions
1105
1106#define F(mnemonic, M, S, type, opcode2) \
1107  void mnemonic(FloatRegister rn, FloatRegister rm) {                         \
1108    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |     \
1109        rm->encoding() << 16 | 0b1000 << 10 | rn->encoding() << 5 | opcode2); \
1110  }
1111
1112  F(fcmp_s,   0, 0, 0b00, 0b00000)
1113  F(fcmpe_s,  0, 0, 0b00, 0b01000)
1114  F(fcmp_d,   0, 0, 0b01, 0b00000)
1115  F(fcmpe_d,  0, 0, 0b01, 0b10000)
1116#undef F
1117
1118#define F(mnemonic, M, S, type, opcode2) \
1119  void mnemonic(FloatRegister rn) {                                           \
1120    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |     \
1121        0b1000 << 10 | rn->encoding() << 5 | opcode2);                        \
1122  }
1123
1124  F(fcmp0_s,   0, 0, 0b00, 0b01000)
1125  F(fcmpe0_s,  0, 0, 0b00, 0b11000)
1126  F(fcmp0_d,   0, 0, 0b01, 0b01000)
1127  F(fcmpe0_d,  0, 0, 0b01, 0b11000)
1128#undef F
1129
1130#define F(mnemonic, M, S, type, op) \
1131  void mnemonic(FloatRegister rn, FloatRegister rm, int nzcv, AsmCondition cond) { \
1132    assert ((nzcv >> 4) == 0, "illegal nzcv");                                                  \
1133    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                       \
1134        rm->encoding() << 16 | cond << 12 | 0b01 << 10 | rn->encoding() << 5 | op << 4 | nzcv); \
1135  }
1136
1137  F(fccmp_s,   0, 0, 0b00, 0)
1138  F(fccmpe_s,  0, 0, 0b00, 1)
1139  F(fccmp_d,   0, 0, 0b01, 0)
1140  F(fccmpe_d,  0, 0, 0b01, 1)
1141#undef F
1142
1143#define F(mnemonic, M, S, type) \
1144  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, AsmCondition cond) { \
1145    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                       \
1146        rm->encoding() << 16 | cond << 12 | 0b11 << 10 | rn->encoding() << 5 | rd->encoding()); \
1147  }
1148
1149  F(fcsel_s,   0, 0, 0b00)
1150  F(fcsel_d,   0, 0, 0b01)
1151#undef F
1152
1153#define F(mnemonic, M, S, type, opcode) \
1154  void mnemonic(FloatRegister rd, FloatRegister rn) { \
1155    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |      \
1156        opcode << 15 | 0b10000 << 10 | rn->encoding() << 5 | rd->encoding());  \
1157  }
1158
1159  F(fmov_s,   0, 0, 0b00, 0b000000)
1160  F(fabs_s,   0, 0, 0b00, 0b000001)
1161  F(fneg_s,   0, 0, 0b00, 0b000010)
1162  F(fsqrt_s,  0, 0, 0b00, 0b000011)
1163  F(fcvt_ds,  0, 0, 0b00, 0b000101)
1164  F(fcvt_hs,  0, 0, 0b00, 0b000111)
1165  F(frintn_s, 0, 0, 0b00, 0b001000)
1166  F(frintp_s, 0, 0, 0b00, 0b001001)
1167  F(frintm_s, 0, 0, 0b00, 0b001010)
1168  F(frintz_s, 0, 0, 0b00, 0b001011)
1169  F(frinta_s, 0, 0, 0b00, 0b001100)
1170  F(frintx_s, 0, 0, 0b00, 0b001110)
1171  F(frinti_s, 0, 0, 0b00, 0b001111)
1172
1173  F(fmov_d,   0, 0, 0b01, 0b000000)
1174  F(fabs_d,   0, 0, 0b01, 0b000001)
1175  F(fneg_d,   0, 0, 0b01, 0b000010)
1176  F(fsqrt_d,  0, 0, 0b01, 0b000011)
1177  F(fcvt_sd,  0, 0, 0b01, 0b000100)
1178  F(fcvt_hd,  0, 0, 0b01, 0b000111)
1179  F(frintn_d, 0, 0, 0b01, 0b001000)
1180  F(frintp_d, 0, 0, 0b01, 0b001001)
1181  F(frintm_d, 0, 0, 0b01, 0b001010)
1182  F(frintz_d, 0, 0, 0b01, 0b001011)
1183  F(frinta_d, 0, 0, 0b01, 0b001100)
1184  F(frintx_d, 0, 0, 0b01, 0b001110)
1185  F(frinti_d, 0, 0, 0b01, 0b001111)
1186
1187  F(fcvt_sh,  0, 0, 0b11, 0b000100)
1188  F(fcvt_dh,  0, 0, 0b11, 0b000101)
1189#undef F
1190
1191#define F(mnemonic, M, S, type, opcode) \
1192  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm) { \
1193    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |                          \
1194        rm->encoding() << 16 | opcode << 12 | 0b10 << 10 | rn->encoding() << 5 | rd->encoding());  \
1195  }
1196
1197  F(fmul_s,   0, 0, 0b00, 0b0000)
1198  F(fdiv_s,   0, 0, 0b00, 0b0001)
1199  F(fadd_s,   0, 0, 0b00, 0b0010)
1200  F(fsub_s,   0, 0, 0b00, 0b0011)
1201  F(fmax_s,   0, 0, 0b00, 0b0100)
1202  F(fmin_s,   0, 0, 0b00, 0b0101)
1203  F(fmaxnm_s, 0, 0, 0b00, 0b0110)
1204  F(fminnm_s, 0, 0, 0b00, 0b0111)
1205  F(fnmul_s,  0, 0, 0b00, 0b1000)
1206
1207  F(fmul_d,   0, 0, 0b01, 0b0000)
1208  F(fdiv_d,   0, 0, 0b01, 0b0001)
1209  F(fadd_d,   0, 0, 0b01, 0b0010)
1210  F(fsub_d,   0, 0, 0b01, 0b0011)
1211  F(fmax_d,   0, 0, 0b01, 0b0100)
1212  F(fmin_d,   0, 0, 0b01, 0b0101)
1213  F(fmaxnm_d, 0, 0, 0b01, 0b0110)
1214  F(fminnm_d, 0, 0, 0b01, 0b0111)
1215  F(fnmul_d,  0, 0, 0b01, 0b1000)
1216#undef F
1217
1218#define F(mnemonic, M, S, type, o1, o0) \
1219  void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, FloatRegister ra) { \
1220    emit_int32(M << 31 | S << 29 | 0b11111 << 24 | type << 22 | o1 << 21 | rm->encoding() << 16 |  \
1221         o0 << 15 | ra->encoding() << 10 | rn->encoding() << 5 | rd->encoding());                  \
1222  }
1223
1224  F(fmadd_s,  0, 0, 0b00, 0, 0)
1225  F(fmsub_s,  0, 0, 0b00, 0, 1)
1226  F(fnmadd_s, 0, 0, 0b00, 1, 0)
1227  F(fnmsub_s, 0, 0, 0b00, 1, 1)
1228
1229  F(fmadd_d,  0, 0, 0b01, 0, 0)
1230  F(fmsub_d,  0, 0, 0b01, 0, 1)
1231  F(fnmadd_d, 0, 0, 0b01, 1, 0)
1232  F(fnmsub_d, 0, 0, 0b01, 1, 1)
1233#undef F
1234
1235#define F(mnemonic, M, S, type) \
1236  void mnemonic(FloatRegister rd, int imm8) { \
1237    assert ((imm8 >> 8) == 0, "immediate is out of range");                \
1238    emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |  \
1239         imm8 << 13 | 0b100 << 10 | rd->encoding());                       \
1240  }
1241
1242  F(fmov_s, 0, 0, 0b00)
1243  F(fmov_d, 0, 0, 0b01)
1244#undef F
1245
1246#define F(mnemonic, sf, S, type, rmode, opcode) \
1247  void mnemonic(Register rd, FloatRegister rn) {                                     \
1248    emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |           \
1249         rmode << 19 | opcode << 16 | rn->encoding() << 5 | rd->encoding_with_zr()); \
1250  }
1251
1252  F(fcvtns_ws, 0, 0, 0b00, 0b00, 0b000)
1253  F(fcvtnu_ws, 0, 0, 0b00, 0b00, 0b001)
1254  F(fcvtas_ws, 0, 0, 0b00, 0b00, 0b100)
1255  F(fcvtau_ws, 0, 0, 0b00, 0b00, 0b101)
1256  F(fmov_ws,   0, 0, 0b00, 0b00, 0b110)
1257  F(fcvtps_ws, 0, 0, 0b00, 0b01, 0b000)
1258  F(fcvtpu_ws, 0, 0, 0b00, 0b01, 0b001)
1259  F(fcvtms_ws, 0, 0, 0b00, 0b10, 0b000)
1260  F(fcvtmu_ws, 0, 0, 0b00, 0b10, 0b001)
1261  F(fcvtzs_ws, 0, 0, 0b00, 0b11, 0b000)
1262  F(fcvtzu_ws, 0, 0, 0b00, 0b11, 0b001)
1263
1264  F(fcvtns_wd, 0, 0, 0b01, 0b00, 0b000)
1265  F(fcvtnu_wd, 0, 0, 0b01, 0b00, 0b001)
1266  F(fcvtas_wd, 0, 0, 0b01, 0b00, 0b100)
1267  F(fcvtau_wd, 0, 0, 0b01, 0b00, 0b101)
1268  F(fcvtps_wd, 0, 0, 0b01, 0b01, 0b000)
1269  F(fcvtpu_wd, 0, 0, 0b01, 0b01, 0b001)
1270  F(fcvtms_wd, 0, 0, 0b01, 0b10, 0b000)
1271  F(fcvtmu_wd, 0, 0, 0b01, 0b10, 0b001)
1272  F(fcvtzs_wd, 0, 0, 0b01, 0b11, 0b000)
1273  F(fcvtzu_wd, 0, 0, 0b01, 0b11, 0b001)
1274
1275  F(fcvtns_xs, 1, 0, 0b00, 0b00, 0b000)
1276  F(fcvtnu_xs, 1, 0, 0b00, 0b00, 0b001)
1277  F(fcvtas_xs, 1, 0, 0b00, 0b00, 0b100)
1278  F(fcvtau_xs, 1, 0, 0b00, 0b00, 0b101)
1279  F(fcvtps_xs, 1, 0, 0b00, 0b01, 0b000)
1280  F(fcvtpu_xs, 1, 0, 0b00, 0b01, 0b001)
1281  F(fcvtms_xs, 1, 0, 0b00, 0b10, 0b000)
1282  F(fcvtmu_xs, 1, 0, 0b00, 0b10, 0b001)
1283  F(fcvtzs_xs, 1, 0, 0b00, 0b11, 0b000)
1284  F(fcvtzu_xs, 1, 0, 0b00, 0b11, 0b001)
1285
1286  F(fcvtns_xd, 1, 0, 0b01, 0b00, 0b000)
1287  F(fcvtnu_xd, 1, 0, 0b01, 0b00, 0b001)
1288  F(fcvtas_xd, 1, 0, 0b01, 0b00, 0b100)
1289  F(fcvtau_xd, 1, 0, 0b01, 0b00, 0b101)
1290  F(fmov_xd,   1, 0, 0b01, 0b00, 0b110)
1291  F(fcvtps_xd, 1, 0, 0b01, 0b01, 0b000)
1292  F(fcvtpu_xd, 1, 0, 0b01, 0b01, 0b001)
1293  F(fcvtms_xd, 1, 0, 0b01, 0b10, 0b000)
1294  F(fcvtmu_xd, 1, 0, 0b01, 0b10, 0b001)
1295  F(fcvtzs_xd, 1, 0, 0b01, 0b11, 0b000)
1296  F(fcvtzu_xd, 1, 0, 0b01, 0b11, 0b001)
1297
1298  F(fmov_xq,   1, 0, 0b10, 0b01, 0b110)
1299#undef F
1300
1301#define F(mnemonic, sf, S, type, rmode, opcode) \
1302  void mnemonic(FloatRegister rd, Register rn) {                                     \
1303    emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 |           \
1304         rmode << 19 | opcode << 16 | rn->encoding_with_zr() << 5 | rd->encoding()); \
1305  }
1306
1307  F(scvtf_sw,  0, 0, 0b00, 0b00, 0b010)
1308  F(ucvtf_sw,  0, 0, 0b00, 0b00, 0b011)
1309  F(fmov_sw,   0, 0, 0b00, 0b00, 0b111)
1310  F(scvtf_dw,  0, 0, 0b01, 0b00, 0b010)
1311  F(ucvtf_dw,  0, 0, 0b01, 0b00, 0b011)
1312
1313  F(scvtf_sx,  1, 0, 0b00, 0b00, 0b010)
1314  F(ucvtf_sx,  1, 0, 0b00, 0b00, 0b011)
1315  F(scvtf_dx,  1, 0, 0b01, 0b00, 0b010)
1316  F(ucvtf_dx,  1, 0, 0b01, 0b00, 0b011)
1317  F(fmov_dx,   1, 0, 0b01, 0b00, 0b111)
1318
1319  F(fmov_qx,   1, 0, 0b10, 0b01, 0b111)
1320#undef F
1321
1322#define F(mnemonic, opcode) \
1323  void mnemonic(FloatRegister Vd, FloatRegister Vn) {                                     \
1324    emit_int32( opcode << 10 | Vn->encoding() << 5 | Vd->encoding());             \
1325  }
1326
1327  F(aese, 0b0100111000101000010010);
1328  F(aesd, 0b0100111000101000010110);
1329  F(aesmc, 0b0100111000101000011010);
1330  F(aesimc, 0b0100111000101000011110);
1331#undef F
1332
1333#ifdef COMPILER2
1334  typedef VFP::double_num double_num;
1335  typedef VFP::float_num  float_num;
1336#endif
1337
1338  void vcnt(FloatRegister Dd, FloatRegister Dn, int quad = 0, int size = 0) {
1339    // emitted at VM startup to detect whether the instruction is available
1340    assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction");
1341    assert(size == 0, "illegal size value");
1342    emit_int32(0x0e205800 | quad << 30 | size << 22 | Dn->encoding() << 5 | Dd->encoding());
1343  }
1344
1345#ifdef COMPILER2
1346  void addv(FloatRegister Dd, FloatRegister Dm, int quad, int size) {
1347    // emitted at VM startup to detect whether the instruction is available
1348    assert(VM_Version::has_simd(), "simd instruction");
1349    assert((quad & ~1) == 0, "illegal value");
1350    assert(size >= 0 && size < 3, "illegal value");
1351    assert(((size << 1) | quad) != 4, "illegal values (size 2, quad 0)");
1352    emit_int32(0x0e31b800 | quad << 30 | size << 22 | Dm->encoding() << 5 | Dd->encoding());
1353  }
1354
1355  enum VElem_Size {
1356    VELEM_SIZE_8  = 0x00,
1357    VELEM_SIZE_16 = 0x01,
1358    VELEM_SIZE_32 = 0x02,
1359    VELEM_SIZE_64 = 0x03
1360  };
1361
1362  enum VLD_Type {
1363    VLD1_TYPE_1_REG  = 0b0111,
1364    VLD1_TYPE_2_REGS = 0b1010,
1365    VLD1_TYPE_3_REGS = 0b0110,
1366    VLD1_TYPE_4_REGS = 0b0010
1367  };
1368
1369  enum VFloat_Arith_Size {
1370    VFA_SIZE_F32 = 0b0,
1371    VFA_SIZE_F64 = 0b1
1372  };
1373
1374#define F(mnemonic, U, S, P) \
1375  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
1376                int size, int quad) {                                    \
1377    assert(VM_Version::has_simd(), "simd instruction");                  \
1378    assert(!(size == VFA_SIZE_F64 && !quad), "reserved");                \
1379    assert((size & 1) == size, "overflow");                              \
1380    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 |                    \
1381               S << 23 | size << 22 | 1 << 21 | P << 11 | 1 << 10 |      \
1382               fm->encoding() << 16 |                                    \
1383               fn->encoding() <<  5 |                                    \
1384               fd->encoding());                                          \
1385  }
1386
1387  F(vaddF, 0, 0, 0b11010)  // Vd = Vn + Vm (float)
1388  F(vsubF, 0, 1, 0b11010)  // Vd = Vn - Vm (float)
1389  F(vmulF, 1, 0, 0b11011)  // Vd = Vn - Vm (float)
1390  F(vdivF, 1, 0, 0b11111)  // Vd = Vn / Vm (float)
1391#undef F
1392
1393#define F(mnemonic, U) \
1394  void mnemonic(FloatRegister fd, FloatRegister fm, FloatRegister fn,    \
1395                int size, int quad) {                                    \
1396    assert(VM_Version::has_simd(), "simd instruction");                  \
1397    assert(!(size == VELEM_SIZE_64 && !quad), "reserved");               \
1398    assert((size & 0b11) == size, "overflow");                           \
1399    int R = 0; /* rounding */                                            \
1400    int S = 0; /* saturating */                                          \
1401    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 |       \
1402               1 << 21 | R << 12 | S << 11 | 0b10001 << 10 |             \
1403               fm->encoding() << 16 |                                    \
1404               fn->encoding() <<  5 |                                    \
1405               fd->encoding());                                          \
1406  }
1407
1408  F(vshlSI, 0)  // Vd = ashift(Vn,Vm) (int)
1409  F(vshlUI, 1)  // Vd = lshift(Vn,Vm) (int)
1410#undef F
1411
1412#define F(mnemonic, U, P, M) \
1413  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
1414                int size, int quad) {                                    \
1415    assert(VM_Version::has_simd(), "simd instruction");                  \
1416    assert(!(size == VELEM_SIZE_64 && !quad), "reserved");               \
1417    assert(!(size == VELEM_SIZE_64 && M), "reserved");                   \
1418    assert((size & 0b11) == size, "overflow");                           \
1419    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 |       \
1420               1 << 21 | P << 11 | 1 << 10 |                             \
1421               fm->encoding() << 16 |                                    \
1422               fn->encoding() <<  5 |                                    \
1423               fd->encoding());                                          \
1424  }
1425
1426  F(vmulI, 0, 0b10011,  true)  // Vd = Vn * Vm (int)
1427  F(vaddI, 0, 0b10000, false)  // Vd = Vn + Vm (int)
1428  F(vsubI, 1, 0b10000, false)  // Vd = Vn - Vm (int)
1429#undef F
1430
1431#define F(mnemonic, U, O) \
1432  void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm,    \
1433                int quad) {                                              \
1434    assert(VM_Version::has_simd(), "simd instruction");                  \
1435    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | O << 22 |          \
1436               1 << 21 | 0b00011 << 11 | 1 << 10 |                       \
1437               fm->encoding() << 16 |                                    \
1438               fn->encoding() <<  5 |                                    \
1439               fd->encoding());                                          \
1440  }
1441
1442  F(vandI, 0, 0b00)  // Vd = Vn & Vm (int)
1443  F(vorI,  0, 0b10)  // Vd = Vn | Vm (int)
1444  F(vxorI, 1, 0b00)  // Vd = Vn ^ Vm (int)
1445#undef F
1446
1447  void vnegI(FloatRegister fd, FloatRegister fn, int size, int quad) {
1448    int U = 1;
1449    assert(VM_Version::has_simd(), "simd instruction");
1450    assert(quad || size != VELEM_SIZE_64, "reserved");
1451    emit_int32(quad << 30 | U << 29 | 0b01110 << 24 |
1452              size << 22 | 0b100000101110 << 10 |
1453              fn->encoding() << 5 |
1454              fd->encoding() << 0);
1455  }
1456
1457  void vshli(FloatRegister fd, FloatRegister fn, int esize, int imm, int quad) {
1458    assert(VM_Version::has_simd(), "simd instruction");
1459
1460    if (imm >= esize) {
1461      // maximum shift gives all zeroes, direction doesn't matter,
1462      // but only available for shift right
1463      vshri(fd, fn, esize, esize, true /* unsigned */, quad);
1464      return;
1465    }
1466    assert(imm >= 0 && imm < esize, "out of range");
1467
1468    int imm7 = esize + imm;
1469    int immh = imm7 >> 3;
1470    assert(immh != 0, "encoding constraint");
1471    assert((uint)immh < 16, "sanity");
1472    assert(((immh >> 2) | quad) != 0b10, "reserved");
1473    emit_int32(quad << 30 | 0b011110 << 23 | imm7 << 16 |
1474               0b010101 << 10 | fn->encoding() << 5 | fd->encoding() << 0);
1475  }
1476
1477  void vshri(FloatRegister fd, FloatRegister fn, int esize, int imm,
1478             bool U /* unsigned */, int quad) {
1479    assert(VM_Version::has_simd(), "simd instruction");
1480    assert(imm > 0, "out of range");
1481    if (imm >= esize) {
1482      // maximum shift (all zeroes)
1483      imm = esize;
1484    }
1485    int imm7 = 2 * esize - imm ;
1486    int immh = imm7 >> 3;
1487    assert(immh != 0, "encoding constraint");
1488    assert((uint)immh < 16, "sanity");
1489    assert(((immh >> 2) | quad) != 0b10, "reserved");
1490    emit_int32(quad << 30 | U << 29 | 0b011110 << 23 | imm7 << 16 |
1491               0b000001 << 10 | fn->encoding() << 5 | fd->encoding() << 0);
1492  }
1493  void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
1494    vshri(fd, fm, size, imm, true /* unsigned */, quad);
1495  }
1496  void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
1497    vshri(fd, fm, size, imm, false /* signed */, quad);
1498  }
1499
1500  void vld1(FloatRegister Vt, Address addr, VElem_Size size, int bits) {
1501    assert(VM_Version::has_simd(), "simd instruction");
1502    assert(bits == 128, "unsupported");
1503    assert(addr.disp() == 0 || addr.disp() == 16, "must be");
1504    int type = 0b11; // 2D
1505    int quad = 1;
1506    int L = 1;
1507    int opcode = VLD1_TYPE_1_REG;
1508    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1509               Vt->encoding() << 0 | addr.encoding_simd());
1510  }
1511
1512  void vst1(FloatRegister Vt, Address addr, VElem_Size size, int bits) {
1513    assert(VM_Version::has_simd(), "simd instruction");
1514    assert(bits == 128, "unsupported");
1515    assert(addr.disp() == 0 || addr.disp() == 16, "must be");
1516    int type = 0b11; // 2D
1517    int quad = 1;
1518    int L = 0;
1519    int opcode = VLD1_TYPE_1_REG;
1520    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1521               Vt->encoding() << 0 | addr.encoding_simd());
1522  }
1523
1524  void vld1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) {
1525    assert(VM_Version::has_simd(), "simd instruction");
1526    assert(bits == 128, "unsupported");
1527    assert(Vt->successor() == Vt2, "Registers must be ordered");
1528    assert(addr.disp() == 0 || addr.disp() == 32, "must be");
1529    int type = 0b11; // 2D
1530    int quad = 1;
1531    int L = 1;
1532    int opcode = VLD1_TYPE_2_REGS;
1533    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1534               Vt->encoding() << 0 | addr.encoding_simd());
1535  }
1536
1537  void vst1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) {
1538    assert(VM_Version::has_simd(), "simd instruction");
1539    assert(Vt->successor() == Vt2, "Registers must be ordered");
1540    assert(bits == 128, "unsupported");
1541    assert(addr.disp() == 0 || addr.disp() == 32, "must be");
1542    int type = 0b11; // 2D
1543    int quad = 1;
1544    int L = 0;
1545    int opcode = VLD1_TYPE_2_REGS;
1546    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1547               Vt->encoding() << 0 | addr.encoding_simd());
1548  }
1549
1550  void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1551            Address addr, VElem_Size size, int bits) {
1552    assert(VM_Version::has_simd(), "simd instruction");
1553    assert(bits == 128, "unsupported");
1554    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3,
1555          "Registers must be ordered");
1556    assert(addr.disp() == 0 || addr.disp() == 48, "must be");
1557    int type = 0b11; // 2D
1558    int quad = 1;
1559    int L = 1;
1560    int opcode = VLD1_TYPE_3_REGS;
1561    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1562               Vt->encoding() << 0 | addr.encoding_simd());
1563  }
1564
1565  void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1566            Address addr, VElem_Size size, int bits) {
1567    assert(VM_Version::has_simd(), "simd instruction");
1568    assert(bits == 128, "unsupported");
1569    assert(Vt->successor() == Vt2 &&  Vt2->successor() == Vt3,
1570           "Registers must be ordered");
1571    assert(addr.disp() == 0 || addr.disp() == 48, "must be");
1572    int type = 0b11; // 2D
1573    int quad = 1;
1574    int L = 0;
1575    int opcode = VLD1_TYPE_3_REGS;
1576    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1577               Vt->encoding() << 0 | addr.encoding_simd());
1578  }
1579
1580  void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1581            FloatRegister Vt4, Address addr, VElem_Size size, int bits) {
1582    assert(VM_Version::has_simd(), "simd instruction");
1583    assert(bits == 128, "unsupported");
1584    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 &&
1585           Vt3->successor() == Vt4, "Registers must be ordered");
1586    assert(addr.disp() == 0 || addr.disp() == 64, "must be");
1587    int type = 0b11; // 2D
1588    int quad = 1;
1589    int L = 1;
1590    int opcode = VLD1_TYPE_4_REGS;
1591    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1592               Vt->encoding() << 0 | addr.encoding_simd());
1593  }
1594
1595  void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3,
1596            FloatRegister Vt4,  Address addr, VElem_Size size, int bits) {
1597    assert(VM_Version::has_simd(), "simd instruction");
1598    assert(bits == 128, "unsupported");
1599    assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 &&
1600           Vt3->successor() == Vt4, "Registers must be ordered");
1601    assert(addr.disp() == 0 || addr.disp() == 64, "must be");
1602    int type = 0b11; // 2D
1603    int quad = 1;
1604    int L = 0;
1605    int opcode = VLD1_TYPE_4_REGS;
1606    emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 |
1607               Vt->encoding() << 0 | addr.encoding_simd());
1608  }
1609
1610  void rev32(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) {
1611    assert(VM_Version::has_simd(), "simd instruction");
1612    assert(size == VELEM_SIZE_8 || size == VELEM_SIZE_16, "must be");
1613    emit_int32(quad << 30 | 0b101110 << 24 | size << 22 |
1614               0b100000000010 << 10 | Vn->encoding() << 5 | Vd->encoding());
1615  }
1616
1617  void eor(FloatRegister Vd, FloatRegister Vn,  FloatRegister Vm, VElem_Size size, int quad) {
1618    assert(VM_Version::has_simd(), "simd instruction");
1619    assert(size == VELEM_SIZE_8, "must be");
1620    emit_int32(quad << 30 | 0b101110001 << 21 | Vm->encoding() << 16 |
1621               0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding());
1622  }
1623
1624  void orr(FloatRegister Vd, FloatRegister Vn,  FloatRegister Vm, VElem_Size size, int quad) {
1625    assert(VM_Version::has_simd(), "simd instruction");
1626    assert(size == VELEM_SIZE_8, "must be");
1627    emit_int32(quad << 30 | 0b001110101 << 21 | Vm->encoding() << 16 |
1628               0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding());
1629  }
1630
1631  void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) {
1632    assert(VM_Version::has_simd(), "simd instruction");
1633    assert(imm8 >= 0 && imm8 < 256, "out of range");
1634    int op;
1635    int cmode;
1636    switch (size) {
1637    case VELEM_SIZE_8:
1638      op = 0;
1639      cmode = 0b1110;
1640      break;
1641    case VELEM_SIZE_16:
1642      op = 0;
1643      cmode = 0b1000;
1644      break;
1645    case VELEM_SIZE_32:
1646      op = 0;
1647      cmode = 0b0000;
1648      break;
1649    default:
1650      cmode = 0;
1651      ShouldNotReachHere();
1652    }
1653    int abc = imm8 >> 5;
1654    int defgh = imm8 & 0b11111;
1655    emit_int32(quad << 30 | op << 29 | 0b1111 << 24 |
1656               abc << 16 | cmode << 12 | 0b01 << 10 |
1657               defgh << 5 | Dd->encoding() << 0);
1658  }
1659
1660  void vdupI(FloatRegister Dd, Register Rn, VElem_Size size, int quad) {
1661    assert(VM_Version::has_simd(), "simd instruction");
1662    assert(size <= 3, "unallocated encoding");
1663    assert(size != 3 || quad == 1, "reserved");
1664    int imm5 = 1 << size;
1665#ifdef ASSERT
1666    switch (size) {
1667    case VELEM_SIZE_8:
1668      assert(imm5 == 0b00001, "sanity");
1669      break;
1670    case VELEM_SIZE_16:
1671      assert(imm5 == 0b00010, "sanity");
1672      break;
1673    case VELEM_SIZE_32:
1674      assert(imm5 == 0b00100, "sanity");
1675      break;
1676    case VELEM_SIZE_64:
1677      assert(imm5 == 0b01000, "sanity");
1678      break;
1679    default:
1680      ShouldNotReachHere();
1681    }
1682#endif
1683    emit_int32(quad << 30 | 0b111 << 25 | 0b11 << 10 |
1684               imm5 << 16 | Rn->encoding() << 5 |
1685               Dd->encoding() << 0);
1686  }
1687
1688  void vdup(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) {
1689    assert(VM_Version::has_simd(), "simd instruction");
1690    int index = 0;
1691    int bytes = 1 << size;
1692    int range = 16 / bytes;
1693    assert(index < range, "overflow");
1694
1695    assert(size != VELEM_SIZE_64 || quad, "reserved");
1696    assert(8 << VELEM_SIZE_8  ==  8, "sanity");
1697    assert(8 << VELEM_SIZE_16 == 16, "sanity");
1698    assert(8 << VELEM_SIZE_32 == 32, "sanity");
1699    assert(8 << VELEM_SIZE_64 == 64, "sanity");
1700
1701    int imm5 = (index << (size + 1)) | bytes;
1702
1703    emit_int32(quad << 30 | 0b001110000 << 21 | imm5 << 16 | 0b000001 << 10 |
1704               Vn->encoding() << 5 | Vd->encoding() << 0);
1705  }
1706
1707  void vdupF(FloatRegister Vd, FloatRegister Vn, int quad) {
1708    vdup(Vd, Vn, VELEM_SIZE_32, quad);
1709  }
1710
1711  void vdupD(FloatRegister Vd, FloatRegister Vn, int quad) {
1712    vdup(Vd, Vn, VELEM_SIZE_64, quad);
1713  }
1714#endif
1715};
1716
1717
1718#endif // CPU_ARM_VM_ASSEMBLER_ARM_64_HPP
1719