1 /*
2 * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #ifndef CPU_AARCH64_ASSEMBLER_AARCH64_HPP
27 #define CPU_AARCH64_ASSEMBLER_AARCH64_HPP
28
29 #include "asm/register.hpp"
30
31 #ifdef __GNUC__
32
33 // __nop needs volatile so that compiler doesn't optimize it away
34 #define NOP() asm volatile ("nop");
35
36 #elif defined(_MSC_VER)
37
38 // Use MSVC instrinsic: https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=vs-2019#I
39 #define NOP() __nop();
40
41 #endif
42
43
44 // definitions of various symbolic names for machine registers
45
46 // First intercalls between C and Java which use 8 general registers
47 // and 8 floating registers
48
49 // we also have to copy between x86 and ARM registers but that's a
50 // secondary complication -- not all code employing C call convention
51 // executes as x86 code though -- we generate some of it
52
53 class Argument {
54 public:
55 enum {
56 n_int_register_parameters_c = 8, // r0, r1, ... r7 (c_rarg0, c_rarg1, ...)
57 n_float_register_parameters_c = 8, // v0, v1, ... v7 (c_farg0, c_farg1, ... )
58
59 n_int_register_parameters_j = 8, // r1, ... r7, r0 (rj_rarg0, j_rarg1, ...
60 n_float_register_parameters_j = 8 // v0, v1, ... v7 (j_farg0, j_farg1, ...
61 };
62 };
63
64 REGISTER_DECLARATION(Register, c_rarg0, r0);
65 REGISTER_DECLARATION(Register, c_rarg1, r1);
66 REGISTER_DECLARATION(Register, c_rarg2, r2);
67 REGISTER_DECLARATION(Register, c_rarg3, r3);
68 REGISTER_DECLARATION(Register, c_rarg4, r4);
69 REGISTER_DECLARATION(Register, c_rarg5, r5);
70 REGISTER_DECLARATION(Register, c_rarg6, r6);
71 REGISTER_DECLARATION(Register, c_rarg7, r7);
72
73 REGISTER_DECLARATION(FloatRegister, c_farg0, v0);
74 REGISTER_DECLARATION(FloatRegister, c_farg1, v1);
75 REGISTER_DECLARATION(FloatRegister, c_farg2, v2);
76 REGISTER_DECLARATION(FloatRegister, c_farg3, v3);
77 REGISTER_DECLARATION(FloatRegister, c_farg4, v4);
78 REGISTER_DECLARATION(FloatRegister, c_farg5, v5);
79 REGISTER_DECLARATION(FloatRegister, c_farg6, v6);
80 REGISTER_DECLARATION(FloatRegister, c_farg7, v7);
81
82 // Symbolically name the register arguments used by the Java calling convention.
83 // We have control over the convention for java so we can do what we please.
84 // What pleases us is to offset the java calling convention so that when
85 // we call a suitable jni method the arguments are lined up and we don't
86 // have to do much shuffling. A suitable jni method is non-static and a
87 // small number of arguments
88 //
89 // |--------------------------------------------------------------------|
90 // | c_rarg0 c_rarg1 c_rarg2 c_rarg3 c_rarg4 c_rarg5 c_rarg6 c_rarg7 |
91 // |--------------------------------------------------------------------|
92 // | r0 r1 r2 r3 r4 r5 r6 r7 |
93 // |--------------------------------------------------------------------|
94 // | j_rarg7 j_rarg0 j_rarg1 j_rarg2 j_rarg3 j_rarg4 j_rarg5 j_rarg6 |
95 // |--------------------------------------------------------------------|
96
97
98 REGISTER_DECLARATION(Register, j_rarg0, c_rarg1);
99 REGISTER_DECLARATION(Register, j_rarg1, c_rarg2);
100 REGISTER_DECLARATION(Register, j_rarg2, c_rarg3);
101 REGISTER_DECLARATION(Register, j_rarg3, c_rarg4);
102 REGISTER_DECLARATION(Register, j_rarg4, c_rarg5);
103 REGISTER_DECLARATION(Register, j_rarg5, c_rarg6);
104 REGISTER_DECLARATION(Register, j_rarg6, c_rarg7);
105 REGISTER_DECLARATION(Register, j_rarg7, c_rarg0);
106
107 // Java floating args are passed as per C
108
109 REGISTER_DECLARATION(FloatRegister, j_farg0, v0);
110 REGISTER_DECLARATION(FloatRegister, j_farg1, v1);
111 REGISTER_DECLARATION(FloatRegister, j_farg2, v2);
112 REGISTER_DECLARATION(FloatRegister, j_farg3, v3);
113 REGISTER_DECLARATION(FloatRegister, j_farg4, v4);
114 REGISTER_DECLARATION(FloatRegister, j_farg5, v5);
115 REGISTER_DECLARATION(FloatRegister, j_farg6, v6);
116 REGISTER_DECLARATION(FloatRegister, j_farg7, v7);
117
118 // registers used to hold VM data either temporarily within a method
119 // or across method calls
120
121 // volatile (caller-save) registers
122
123 // r8 is used for indirect result location return
124 // we use it and r9 as scratch registers
125 REGISTER_DECLARATION(Register, rscratch1, r8);
126 REGISTER_DECLARATION(Register, rscratch2, r9);
127
128 // current method -- must be in a call-clobbered register
129 REGISTER_DECLARATION(Register, rmethod, r12);
130
131 // non-volatile (callee-save) registers are r16-29
132 // of which the following are dedicated global state
133
134 // link register
135 REGISTER_DECLARATION(Register, lr, r30);
136 // frame pointer
137 REGISTER_DECLARATION(Register, rfp, r29);
138 // current thread
139 REGISTER_DECLARATION(Register, rthread, r28);
140 // base of heap
141 REGISTER_DECLARATION(Register, rheapbase, r27);
142 // constant pool cache
143 REGISTER_DECLARATION(Register, rcpool, r26);
144 // monitors allocated on stack
145 REGISTER_DECLARATION(Register, rmonitors, r25);
146 // locals on stack
147 REGISTER_DECLARATION(Register, rlocals, r24);
148 // bytecode pointer
149 REGISTER_DECLARATION(Register, rbcp, r22);
150 // Dispatch table base
151 REGISTER_DECLARATION(Register, rdispatch, r21);
152 // Java stack pointer
153 REGISTER_DECLARATION(Register, esp, r20);
154
155 // Preserved predicate register with all elements set TRUE.
156 REGISTER_DECLARATION(PRegister, ptrue, p7);
157
158 #define assert_cond(ARG1) assert(ARG1, #ARG1)
159
160 namespace asm_util {
161 uint32_t encode_logical_immediate(bool is32, uint64_t imm);
162 };
163
164 using namespace asm_util;
165
166
167 class Assembler;
168
169 class Instruction_aarch64 {
170 unsigned insn;
171 #ifdef ASSERT
172 unsigned bits;
173 #endif
174 Assembler *assem;
175
176 public:
177
Instruction_aarch64(class Assembler * as)178 Instruction_aarch64(class Assembler *as) {
179 #ifdef ASSERT
180 bits = 0;
181 #endif
182 insn = 0;
183 assem = as;
184 }
185
186 inline ~Instruction_aarch64();
187
get_insn()188 unsigned &get_insn() { return insn; }
189 #ifdef ASSERT
get_bits()190 unsigned &get_bits() { return bits; }
191 #endif
192
extend(unsigned val,int hi=31,int lo=0)193 static inline int32_t extend(unsigned val, int hi = 31, int lo = 0) {
194 union {
195 unsigned u;
196 int n;
197 };
198
199 u = val << (31 - hi);
200 n = n >> (31 - hi + lo);
201 return n;
202 }
203
extract(uint32_t val,int msb,int lsb)204 static inline uint32_t extract(uint32_t val, int msb, int lsb) {
205 int nbits = msb - lsb + 1;
206 assert_cond(msb >= lsb);
207 uint32_t mask = checked_cast<uint32_t>(right_n_bits(nbits));
208 uint32_t result = val >> lsb;
209 result &= mask;
210 return result;
211 }
212
sextract(uint32_t val,int msb,int lsb)213 static inline int32_t sextract(uint32_t val, int msb, int lsb) {
214 uint32_t uval = extract(val, msb, lsb);
215 return extend(uval, msb - lsb);
216 }
217
patch(address a,int msb,int lsb,uint64_t val)218 static void patch(address a, int msb, int lsb, uint64_t val) {
219 int nbits = msb - lsb + 1;
220 guarantee(val < (1ULL << nbits), "Field too big for insn");
221 assert_cond(msb >= lsb);
222 unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
223 val <<= lsb;
224 mask <<= lsb;
225 unsigned target = *(unsigned *)a;
226 target &= ~mask;
227 target |= val;
228 *(unsigned *)a = target;
229 }
230
spatch(address a,int msb,int lsb,int64_t val)231 static void spatch(address a, int msb, int lsb, int64_t val) {
232 int nbits = msb - lsb + 1;
233 int64_t chk = val >> (nbits - 1);
234 guarantee (chk == -1 || chk == 0, "Field too big for insn");
235 unsigned uval = val;
236 unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
237 uval &= mask;
238 uval <<= lsb;
239 mask <<= lsb;
240 unsigned target = *(unsigned *)a;
241 target &= ~mask;
242 target |= uval;
243 *(unsigned *)a = target;
244 }
245
f(unsigned val,int msb,int lsb)246 void f(unsigned val, int msb, int lsb) {
247 int nbits = msb - lsb + 1;
248 guarantee(val < (1ULL << nbits), "Field too big for insn");
249 assert_cond(msb >= lsb);
250 unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
251 val <<= lsb;
252 mask <<= lsb;
253 insn |= val;
254 assert_cond((bits & mask) == 0);
255 #ifdef ASSERT
256 bits |= mask;
257 #endif
258 }
259
f(unsigned val,int bit)260 void f(unsigned val, int bit) {
261 f(val, bit, bit);
262 }
263
sf(int64_t val,int msb,int lsb)264 void sf(int64_t val, int msb, int lsb) {
265 int nbits = msb - lsb + 1;
266 int64_t chk = val >> (nbits - 1);
267 guarantee (chk == -1 || chk == 0, "Field too big for insn");
268 unsigned uval = val;
269 unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
270 uval &= mask;
271 f(uval, lsb + nbits - 1, lsb);
272 }
273
rf(Register r,int lsb)274 void rf(Register r, int lsb) {
275 f(r->encoding_nocheck(), lsb + 4, lsb);
276 }
277
278 // reg|ZR
zrf(Register r,int lsb)279 void zrf(Register r, int lsb) {
280 f(r->encoding_nocheck() - (r == zr), lsb + 4, lsb);
281 }
282
283 // reg|SP
srf(Register r,int lsb)284 void srf(Register r, int lsb) {
285 f(r == sp ? 31 : r->encoding_nocheck(), lsb + 4, lsb);
286 }
287
rf(FloatRegister r,int lsb)288 void rf(FloatRegister r, int lsb) {
289 f(r->encoding_nocheck(), lsb + 4, lsb);
290 }
291
prf(PRegister r,int lsb)292 void prf(PRegister r, int lsb) {
293 f(r->encoding_nocheck(), lsb + 3, lsb);
294 }
295
pgrf(PRegister r,int lsb)296 void pgrf(PRegister r, int lsb) {
297 f(r->encoding_nocheck(), lsb + 2, lsb);
298 }
299
get(int msb=31,int lsb=0)300 unsigned get(int msb = 31, int lsb = 0) {
301 int nbits = msb - lsb + 1;
302 unsigned mask = checked_cast<unsigned>(right_n_bits(nbits)) << lsb;
303 assert_cond((bits & mask) == mask);
304 return (insn & mask) >> lsb;
305 }
306
fixed(unsigned value,unsigned mask)307 void fixed(unsigned value, unsigned mask) {
308 assert_cond ((mask & bits) == 0);
309 #ifdef ASSERT
310 bits |= mask;
311 #endif
312 insn |= value;
313 }
314 };
315
316 #define starti Instruction_aarch64 do_not_use(this); set_current(&do_not_use)
317
318 class PrePost {
319 int _offset;
320 Register _r;
321 public:
PrePost(Register reg,int o)322 PrePost(Register reg, int o) : _offset(o), _r(reg) { }
offset()323 int offset() { return _offset; }
reg()324 Register reg() { return _r; }
325 };
326
327 class Pre : public PrePost {
328 public:
Pre(Register reg,int o)329 Pre(Register reg, int o) : PrePost(reg, o) { }
330 };
331 class Post : public PrePost {
332 Register _idx;
333 bool _is_postreg;
334 public:
Post(Register reg,int o)335 Post(Register reg, int o) : PrePost(reg, o) { _idx = NULL; _is_postreg = false; }
Post(Register reg,Register idx)336 Post(Register reg, Register idx) : PrePost(reg, 0) { _idx = idx; _is_postreg = true; }
idx_reg()337 Register idx_reg() { return _idx; }
is_postreg()338 bool is_postreg() {return _is_postreg; }
339 };
340
341 namespace ext
342 {
343 enum operation { uxtb, uxth, uxtw, uxtx, sxtb, sxth, sxtw, sxtx };
344 };
345
346 // Addressing modes
347 class Address {
348 public:
349
350 enum mode { no_mode, base_plus_offset, pre, post, post_reg, pcrel,
351 base_plus_offset_reg, literal };
352
353 // Shift and extend for base reg + reg offset addressing
354 class extend {
355 int _option, _shift;
356 ext::operation _op;
357 public:
extend()358 extend() { }
extend(int s,int o,ext::operation op)359 extend(int s, int o, ext::operation op) : _option(o), _shift(s), _op(op) { }
option() const360 int option() const{ return _option; }
shift() const361 int shift() const { return _shift; }
op() const362 ext::operation op() const { return _op; }
363 };
364 class uxtw : public extend {
365 public:
uxtw(int shift=-1)366 uxtw(int shift = -1): extend(shift, 0b010, ext::uxtw) { }
367 };
368 class lsl : public extend {
369 public:
lsl(int shift=-1)370 lsl(int shift = -1): extend(shift, 0b011, ext::uxtx) { }
371 };
372 class sxtw : public extend {
373 public:
sxtw(int shift=-1)374 sxtw(int shift = -1): extend(shift, 0b110, ext::sxtw) { }
375 };
376 class sxtx : public extend {
377 public:
sxtx(int shift=-1)378 sxtx(int shift = -1): extend(shift, 0b111, ext::sxtx) { }
379 };
380
381 private:
382 Register _base;
383 Register _index;
384 int64_t _offset;
385 enum mode _mode;
386 extend _ext;
387
388 RelocationHolder _rspec;
389
390 // Typically we use AddressLiterals we want to use their rval
391 // However in some situations we want the lval (effect address) of
392 // the item. We provide a special factory for making those lvals.
393 bool _is_lval;
394
395 // If the target is far we'll need to load the ea of this to a
396 // register to reach it. Otherwise if near we can do PC-relative
397 // addressing.
398 address _target;
399
400 public:
Address()401 Address()
402 : _mode(no_mode) { }
Address(Register r)403 Address(Register r)
404 : _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(0) { }
Address(Register r,int o)405 Address(Register r, int o)
406 : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
Address(Register r,long o)407 Address(Register r, long o)
408 : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
Address(Register r,long long o)409 Address(Register r, long long o)
410 : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
Address(Register r,unsigned int o)411 Address(Register r, unsigned int o)
412 : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
Address(Register r,unsigned long o)413 Address(Register r, unsigned long o)
414 : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
Address(Register r,unsigned long long o)415 Address(Register r, unsigned long long o)
416 : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
Address(Register r,ByteSize disp)417 Address(Register r, ByteSize disp)
418 : Address(r, in_bytes(disp)) { }
Address(Register r,Register r1,extend ext=lsl ())419 Address(Register r, Register r1, extend ext = lsl())
420 : _base(r), _index(r1), _offset(0), _mode(base_plus_offset_reg),
421 _ext(ext), _target(0) { }
Address(Pre p)422 Address(Pre p)
423 : _base(p.reg()), _offset(p.offset()), _mode(pre) { }
Address(Post p)424 Address(Post p)
425 : _base(p.reg()), _index(p.idx_reg()), _offset(p.offset()),
426 _mode(p.is_postreg() ? post_reg : post), _target(0) { }
Address(address target,RelocationHolder const & rspec)427 Address(address target, RelocationHolder const& rspec)
428 : _mode(literal),
429 _rspec(rspec),
430 _is_lval(false),
431 _target(target) { }
432 Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);
Address(Register base,RegisterOrConstant index,extend ext=lsl ())433 Address(Register base, RegisterOrConstant index, extend ext = lsl())
434 : _base (base),
435 _offset(0), _ext(ext), _target(0) {
436 if (index.is_register()) {
437 _mode = base_plus_offset_reg;
438 _index = index.as_register();
439 } else {
440 guarantee(ext.option() == ext::uxtx, "should be");
441 assert(index.is_constant(), "should be");
442 _mode = base_plus_offset;
443 _offset = index.as_constant() << ext.shift();
444 }
445 }
446
base() const447 Register base() const {
448 guarantee((_mode == base_plus_offset || _mode == base_plus_offset_reg
449 || _mode == post || _mode == post_reg),
450 "wrong mode");
451 return _base;
452 }
offset() const453 int64_t offset() const {
454 return _offset;
455 }
index() const456 Register index() const {
457 return _index;
458 }
getMode() const459 mode getMode() const {
460 return _mode;
461 }
uses(Register reg) const462 bool uses(Register reg) const { return _base == reg || _index == reg; }
target() const463 address target() const { return _target; }
rspec() const464 const RelocationHolder& rspec() const { return _rspec; }
465
encode(Instruction_aarch64 * i) const466 void encode(Instruction_aarch64 *i) const {
467 i->f(0b111, 29, 27);
468 i->srf(_base, 5);
469
470 switch(_mode) {
471 case base_plus_offset:
472 {
473 unsigned size = i->get(31, 30);
474 if (i->get(26, 26) && i->get(23, 23)) {
475 // SIMD Q Type - Size = 128 bits
476 assert(size == 0, "bad size");
477 size = 0b100;
478 }
479 unsigned mask = (1 << size) - 1;
480 if (_offset < 0 || _offset & mask)
481 {
482 i->f(0b00, 25, 24);
483 i->f(0, 21), i->f(0b00, 11, 10);
484 i->sf(_offset, 20, 12);
485 } else {
486 i->f(0b01, 25, 24);
487 i->f(_offset >> size, 21, 10);
488 }
489 }
490 break;
491
492 case base_plus_offset_reg:
493 {
494 i->f(0b00, 25, 24);
495 i->f(1, 21);
496 i->rf(_index, 16);
497 i->f(_ext.option(), 15, 13);
498 unsigned size = i->get(31, 30);
499 if (i->get(26, 26) && i->get(23, 23)) {
500 // SIMD Q Type - Size = 128 bits
501 assert(size == 0, "bad size");
502 size = 0b100;
503 }
504 if (size == 0) // It's a byte
505 i->f(_ext.shift() >= 0, 12);
506 else {
507 assert(_ext.shift() <= 0 || _ext.shift() == (int)size, "bad shift");
508 i->f(_ext.shift() > 0, 12);
509 }
510 i->f(0b10, 11, 10);
511 }
512 break;
513
514 case pre:
515 i->f(0b00, 25, 24);
516 i->f(0, 21), i->f(0b11, 11, 10);
517 i->sf(_offset, 20, 12);
518 break;
519
520 case post:
521 i->f(0b00, 25, 24);
522 i->f(0, 21), i->f(0b01, 11, 10);
523 i->sf(_offset, 20, 12);
524 break;
525
526 default:
527 ShouldNotReachHere();
528 }
529 }
530
encode_pair(Instruction_aarch64 * i) const531 void encode_pair(Instruction_aarch64 *i) const {
532 switch(_mode) {
533 case base_plus_offset:
534 i->f(0b010, 25, 23);
535 break;
536 case pre:
537 i->f(0b011, 25, 23);
538 break;
539 case post:
540 i->f(0b001, 25, 23);
541 break;
542 default:
543 ShouldNotReachHere();
544 }
545
546 unsigned size; // Operand shift in 32-bit words
547
548 if (i->get(26, 26)) { // float
549 switch(i->get(31, 30)) {
550 case 0b10:
551 size = 2; break;
552 case 0b01:
553 size = 1; break;
554 case 0b00:
555 size = 0; break;
556 default:
557 ShouldNotReachHere();
558 size = 0; // unreachable
559 }
560 } else {
561 size = i->get(31, 31);
562 }
563
564 size = 4 << size;
565 guarantee(_offset % size == 0, "bad offset");
566 i->sf(_offset / size, 21, 15);
567 i->srf(_base, 5);
568 }
569
encode_nontemporal_pair(Instruction_aarch64 * i) const570 void encode_nontemporal_pair(Instruction_aarch64 *i) const {
571 // Only base + offset is allowed
572 i->f(0b000, 25, 23);
573 unsigned size = i->get(31, 31);
574 size = 4 << size;
575 guarantee(_offset % size == 0, "bad offset");
576 i->sf(_offset / size, 21, 15);
577 i->srf(_base, 5);
578 guarantee(_mode == Address::base_plus_offset,
579 "Bad addressing mode for non-temporal op");
580 }
581
582 void lea(MacroAssembler *, Register) const;
583
584 static bool offset_ok_for_immed(int64_t offset, uint shift);
585
offset_ok_for_sve_immed(long offset,int shift,int vl)586 static bool offset_ok_for_sve_immed(long offset, int shift, int vl /* sve vector length */) {
587 if (offset % vl == 0) {
588 // Convert address offset into sve imm offset (MUL VL).
589 int sve_offset = offset / vl;
590 if (((-(1 << (shift - 1))) <= sve_offset) && (sve_offset < (1 << (shift - 1)))) {
591 // sve_offset can be encoded
592 return true;
593 }
594 }
595 return false;
596 }
597 };
598
599 // Convience classes
600 class RuntimeAddress: public Address {
601
602 public:
603
RuntimeAddress(address target)604 RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {}
605
606 };
607
608 class OopAddress: public Address {
609
610 public:
611
OopAddress(address target)612 OopAddress(address target) : Address(target, relocInfo::oop_type){}
613
614 };
615
616 class ExternalAddress: public Address {
617 private:
reloc_for_target(address target)618 static relocInfo::relocType reloc_for_target(address target) {
619 // Sometimes ExternalAddress is used for values which aren't
620 // exactly addresses, like the card table base.
621 // external_word_type can't be used for values in the first page
622 // so just skip the reloc in that case.
623 return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
624 }
625
626 public:
627
ExternalAddress(address target)628 ExternalAddress(address target) : Address(target, reloc_for_target(target)) {}
629
630 };
631
632 class InternalAddress: public Address {
633
634 public:
635
InternalAddress(address target)636 InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}
637 };
638
639 const int FPUStateSizeInWords = FloatRegisterImpl::number_of_registers *
640 FloatRegisterImpl::save_slots_per_register;
641
642 typedef enum {
643 PLDL1KEEP = 0b00000, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
644 PSTL1KEEP = 0b10000, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM,
645 PLIL1KEEP = 0b01000, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM
646 } prfop;
647
648 class Assembler : public AbstractAssembler {
649
650 #ifndef PRODUCT
651 static const uintptr_t asm_bp;
652
emit_long(jint x)653 void emit_long(jint x) {
654 if ((uintptr_t)pc() == asm_bp)
655 NOP();
656 AbstractAssembler::emit_int32(x);
657 }
658 #else
659 void emit_long(jint x) {
660 AbstractAssembler::emit_int32(x);
661 }
662 #endif
663
664 public:
665
666 enum { instruction_size = 4 };
667
668 //---< calculate length of instruction >---
669 // We just use the values set above.
670 // instruction must start at passed address
instr_len(unsigned char * instr)671 static unsigned int instr_len(unsigned char *instr) { return instruction_size; }
672
673 //---< longest instructions >---
instr_maxlen()674 static unsigned int instr_maxlen() { return instruction_size; }
675
adjust(Register base,int offset,bool preIncrement)676 Address adjust(Register base, int offset, bool preIncrement) {
677 if (preIncrement)
678 return Address(Pre(base, offset));
679 else
680 return Address(Post(base, offset));
681 }
682
pre(Register base,int offset)683 Address pre(Register base, int offset) {
684 return adjust(base, offset, true);
685 }
686
post(Register base,int offset)687 Address post(Register base, int offset) {
688 return adjust(base, offset, false);
689 }
690
post(Register base,Register idx)691 Address post(Register base, Register idx) {
692 return Address(Post(base, idx));
693 }
694
695 static address locate_next_instruction(address inst);
696
697 Instruction_aarch64* current;
698
set_current(Instruction_aarch64 * i)699 void set_current(Instruction_aarch64* i) { current = i; }
700
f(unsigned val,int msb,int lsb)701 void f(unsigned val, int msb, int lsb) {
702 current->f(val, msb, lsb);
703 }
f(unsigned val,int msb)704 void f(unsigned val, int msb) {
705 current->f(val, msb, msb);
706 }
sf(int64_t val,int msb,int lsb)707 void sf(int64_t val, int msb, int lsb) {
708 current->sf(val, msb, lsb);
709 }
rf(Register reg,int lsb)710 void rf(Register reg, int lsb) {
711 current->rf(reg, lsb);
712 }
srf(Register reg,int lsb)713 void srf(Register reg, int lsb) {
714 current->srf(reg, lsb);
715 }
zrf(Register reg,int lsb)716 void zrf(Register reg, int lsb) {
717 current->zrf(reg, lsb);
718 }
rf(FloatRegister reg,int lsb)719 void rf(FloatRegister reg, int lsb) {
720 current->rf(reg, lsb);
721 }
prf(PRegister reg,int lsb)722 void prf(PRegister reg, int lsb) {
723 current->prf(reg, lsb);
724 }
pgrf(PRegister reg,int lsb)725 void pgrf(PRegister reg, int lsb) {
726 current->pgrf(reg, lsb);
727 }
fixed(unsigned value,unsigned mask)728 void fixed(unsigned value, unsigned mask) {
729 current->fixed(value, mask);
730 }
731
emit()732 void emit() {
733 emit_long(current->get_insn());
734 assert_cond(current->get_bits() == 0xffffffff);
735 current = NULL;
736 }
737
738 typedef void (Assembler::* uncond_branch_insn)(address dest);
739 typedef void (Assembler::* compare_and_branch_insn)(Register Rt, address dest);
740 typedef void (Assembler::* test_and_branch_insn)(Register Rt, int bitpos, address dest);
741 typedef void (Assembler::* prefetch_insn)(address target, prfop);
742
743 void wrap_label(Label &L, uncond_branch_insn insn);
744 void wrap_label(Register r, Label &L, compare_and_branch_insn insn);
745 void wrap_label(Register r, int bitpos, Label &L, test_and_branch_insn insn);
746 void wrap_label(Label &L, prfop, prefetch_insn insn);
747
748 // PC-rel. addressing
749
750 void adr(Register Rd, address dest);
751 void _adrp(Register Rd, address dest);
752
753 void adr(Register Rd, const Address &dest);
754 void _adrp(Register Rd, const Address &dest);
755
adr(Register Rd,Label & L)756 void adr(Register Rd, Label &L) {
757 wrap_label(Rd, L, &Assembler::Assembler::adr);
758 }
_adrp(Register Rd,Label & L)759 void _adrp(Register Rd, Label &L) {
760 wrap_label(Rd, L, &Assembler::_adrp);
761 }
762
763 void adrp(Register Rd, const Address &dest, uint64_t &offset);
764
765 #undef INSN
766
767 void add_sub_immediate(Register Rd, Register Rn, unsigned uimm, int op,
768 int negated_op);
769
770 // Add/subtract (immediate)
771 #define INSN(NAME, decode, negated) \
772 void NAME(Register Rd, Register Rn, unsigned imm, unsigned shift) { \
773 starti; \
774 f(decode, 31, 29), f(0b10001, 28, 24), f(shift, 23, 22), f(imm, 21, 10); \
775 zrf(Rd, 0), srf(Rn, 5); \
776 } \
777 \
778 void NAME(Register Rd, Register Rn, unsigned imm) { \
779 starti; \
780 add_sub_immediate(Rd, Rn, imm, decode, negated); \
781 }
782
783 INSN(addsw, 0b001, 0b011);
784 INSN(subsw, 0b011, 0b001);
785 INSN(adds, 0b101, 0b111);
786 INSN(subs, 0b111, 0b101);
787
788 #undef INSN
789
790 #define INSN(NAME, decode, negated) \
791 void NAME(Register Rd, Register Rn, unsigned imm) { \
792 starti; \
793 add_sub_immediate(Rd, Rn, imm, decode, negated); \
794 }
795
796 INSN(addw, 0b000, 0b010);
797 INSN(subw, 0b010, 0b000);
798 INSN(add, 0b100, 0b110);
799 INSN(sub, 0b110, 0b100);
800
801 #undef INSN
802
803 // Logical (immediate)
804 #define INSN(NAME, decode, is32) \
805 void NAME(Register Rd, Register Rn, uint64_t imm) { \
806 starti; \
807 uint32_t val = encode_logical_immediate(is32, imm); \
808 f(decode, 31, 29), f(0b100100, 28, 23), f(val, 22, 10); \
809 srf(Rd, 0), zrf(Rn, 5); \
810 }
811
812 INSN(andw, 0b000, true);
813 INSN(orrw, 0b001, true);
814 INSN(eorw, 0b010, true);
815 INSN(andr, 0b100, false);
816 INSN(orr, 0b101, false);
817 INSN(eor, 0b110, false);
818
819 #undef INSN
820
821 #define INSN(NAME, decode, is32) \
822 void NAME(Register Rd, Register Rn, uint64_t imm) { \
823 starti; \
824 uint32_t val = encode_logical_immediate(is32, imm); \
825 f(decode, 31, 29), f(0b100100, 28, 23), f(val, 22, 10); \
826 zrf(Rd, 0), zrf(Rn, 5); \
827 }
828
829 INSN(ands, 0b111, false);
830 INSN(andsw, 0b011, true);
831
832 #undef INSN
833
834 // Move wide (immediate)
835 #define INSN(NAME, opcode) \
836 void NAME(Register Rd, unsigned imm, unsigned shift = 0) { \
837 assert_cond((shift/16)*16 == shift); \
838 starti; \
839 f(opcode, 31, 29), f(0b100101, 28, 23), f(shift/16, 22, 21), \
840 f(imm, 20, 5); \
841 rf(Rd, 0); \
842 }
843
844 INSN(movnw, 0b000);
845 INSN(movzw, 0b010);
846 INSN(movkw, 0b011);
847 INSN(movn, 0b100);
848 INSN(movz, 0b110);
849 INSN(movk, 0b111);
850
851 #undef INSN
852
853 // Bitfield
854 #define INSN(NAME, opcode, size) \
855 void NAME(Register Rd, Register Rn, unsigned immr, unsigned imms) { \
856 starti; \
857 guarantee(size == 1 || (immr < 32 && imms < 32), "incorrect immr/imms");\
858 f(opcode, 31, 22), f(immr, 21, 16), f(imms, 15, 10); \
859 zrf(Rn, 5), rf(Rd, 0); \
860 }
861
862 INSN(sbfmw, 0b0001001100, 0);
863 INSN(bfmw, 0b0011001100, 0);
864 INSN(ubfmw, 0b0101001100, 0);
865 INSN(sbfm, 0b1001001101, 1);
866 INSN(bfm, 0b1011001101, 1);
867 INSN(ubfm, 0b1101001101, 1);
868
869 #undef INSN
870
871 // Extract
872 #define INSN(NAME, opcode, size) \
873 void NAME(Register Rd, Register Rn, Register Rm, unsigned imms) { \
874 starti; \
875 guarantee(size == 1 || imms < 32, "incorrect imms"); \
876 f(opcode, 31, 21), f(imms, 15, 10); \
877 zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \
878 }
879
880 INSN(extrw, 0b00010011100, 0);
881 INSN(extr, 0b10010011110, 1);
882
883 #undef INSN
884
885 // The maximum range of a branch is fixed for the AArch64
886 // architecture. In debug mode we shrink it in order to test
887 // trampolines, but not so small that branches in the interpreter
888 // are out of range.
889 static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M);
890
reachable_from_branch_at(address branch,address target)891 static bool reachable_from_branch_at(address branch, address target) {
892 return uabs(target - branch) < branch_range;
893 }
894
895 // Unconditional branch (immediate)
896 #define INSN(NAME, opcode) \
897 void NAME(address dest) { \
898 starti; \
899 int64_t offset = (dest - pc()) >> 2; \
900 DEBUG_ONLY(assert(reachable_from_branch_at(pc(), dest), "debug only")); \
901 f(opcode, 31), f(0b00101, 30, 26), sf(offset, 25, 0); \
902 } \
903 void NAME(Label &L) { \
904 wrap_label(L, &Assembler::NAME); \
905 } \
906 void NAME(const Address &dest);
907
908 INSN(b, 0);
909 INSN(bl, 1);
910
911 #undef INSN
912
913 // Compare & branch (immediate)
914 #define INSN(NAME, opcode) \
915 void NAME(Register Rt, address dest) { \
916 int64_t offset = (dest - pc()) >> 2; \
917 starti; \
918 f(opcode, 31, 24), sf(offset, 23, 5), rf(Rt, 0); \
919 } \
920 void NAME(Register Rt, Label &L) { \
921 wrap_label(Rt, L, &Assembler::NAME); \
922 }
923
924 INSN(cbzw, 0b00110100);
925 INSN(cbnzw, 0b00110101);
926 INSN(cbz, 0b10110100);
927 INSN(cbnz, 0b10110101);
928
929 #undef INSN
930
931 // Test & branch (immediate)
932 #define INSN(NAME, opcode) \
933 void NAME(Register Rt, int bitpos, address dest) { \
934 int64_t offset = (dest - pc()) >> 2; \
935 int b5 = bitpos >> 5; \
936 bitpos &= 0x1f; \
937 starti; \
938 f(b5, 31), f(opcode, 30, 24), f(bitpos, 23, 19), sf(offset, 18, 5); \
939 rf(Rt, 0); \
940 } \
941 void NAME(Register Rt, int bitpos, Label &L) { \
942 wrap_label(Rt, bitpos, L, &Assembler::NAME); \
943 }
944
945 INSN(tbz, 0b0110110);
946 INSN(tbnz, 0b0110111);
947
948 #undef INSN
949
950 // Conditional branch (immediate)
951 enum Condition
952 {EQ, NE, HS, CS=HS, LO, CC=LO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV};
953
br(Condition cond,address dest)954 void br(Condition cond, address dest) {
955 int64_t offset = (dest - pc()) >> 2;
956 starti;
957 f(0b0101010, 31, 25), f(0, 24), sf(offset, 23, 5), f(0, 4), f(cond, 3, 0);
958 }
959
960 #define INSN(NAME, cond) \
961 void NAME(address dest) { \
962 br(cond, dest); \
963 }
964
965 INSN(beq, EQ);
966 INSN(bne, NE);
967 INSN(bhs, HS);
968 INSN(bcs, CS);
969 INSN(blo, LO);
970 INSN(bcc, CC);
971 INSN(bmi, MI);
972 INSN(bpl, PL);
973 INSN(bvs, VS);
974 INSN(bvc, VC);
975 INSN(bhi, HI);
976 INSN(bls, LS);
977 INSN(bge, GE);
978 INSN(blt, LT);
979 INSN(bgt, GT);
980 INSN(ble, LE);
981 INSN(bal, AL);
982 INSN(bnv, NV);
983
984 void br(Condition cc, Label &L);
985
986 #undef INSN
987
988 // Exception generation
generate_exception(int opc,int op2,int LL,unsigned imm)989 void generate_exception(int opc, int op2, int LL, unsigned imm) {
990 starti;
991 f(0b11010100, 31, 24);
992 f(opc, 23, 21), f(imm, 20, 5), f(op2, 4, 2), f(LL, 1, 0);
993 }
994
995 #define INSN(NAME, opc, op2, LL) \
996 void NAME(unsigned imm) { \
997 generate_exception(opc, op2, LL, imm); \
998 }
999
1000 INSN(svc, 0b000, 0, 0b01);
1001 INSN(hvc, 0b000, 0, 0b10);
1002 INSN(smc, 0b000, 0, 0b11);
1003 INSN(brk, 0b001, 0, 0b00);
1004 INSN(hlt, 0b010, 0, 0b00);
1005 INSN(dcps1, 0b101, 0, 0b01);
1006 INSN(dcps2, 0b101, 0, 0b10);
1007 INSN(dcps3, 0b101, 0, 0b11);
1008
1009 #undef INSN
1010
1011 // System
system(int op0,int op1,int CRn,int CRm,int op2,Register rt=dummy_reg)1012 void system(int op0, int op1, int CRn, int CRm, int op2,
1013 Register rt = dummy_reg)
1014 {
1015 starti;
1016 f(0b11010101000, 31, 21);
1017 f(op0, 20, 19);
1018 f(op1, 18, 16);
1019 f(CRn, 15, 12);
1020 f(CRm, 11, 8);
1021 f(op2, 7, 5);
1022 rf(rt, 0);
1023 }
1024
hint(int imm)1025 void hint(int imm) {
1026 system(0b00, 0b011, 0b0010, 0b0000, imm);
1027 }
1028
nop()1029 void nop() {
1030 hint(0);
1031 }
1032
yield()1033 void yield() {
1034 hint(1);
1035 }
1036
wfe()1037 void wfe() {
1038 hint(2);
1039 }
1040
wfi()1041 void wfi() {
1042 hint(3);
1043 }
1044
sev()1045 void sev() {
1046 hint(4);
1047 }
1048
sevl()1049 void sevl() {
1050 hint(5);
1051 }
1052
1053 // we only provide mrs and msr for the special purpose system
1054 // registers where op1 (instr[20:19]) == 11 and, (currently) only
1055 // use it for FPSR n.b msr has L (instr[21]) == 0 mrs has L == 1
1056
msr(int op1,int CRn,int CRm,int op2,Register rt)1057 void msr(int op1, int CRn, int CRm, int op2, Register rt) {
1058 starti;
1059 f(0b1101010100011, 31, 19);
1060 f(op1, 18, 16);
1061 f(CRn, 15, 12);
1062 f(CRm, 11, 8);
1063 f(op2, 7, 5);
1064 // writing zr is ok
1065 zrf(rt, 0);
1066 }
1067
mrs(int op1,int CRn,int CRm,int op2,Register rt)1068 void mrs(int op1, int CRn, int CRm, int op2, Register rt) {
1069 starti;
1070 f(0b1101010100111, 31, 19);
1071 f(op1, 18, 16);
1072 f(CRn, 15, 12);
1073 f(CRm, 11, 8);
1074 f(op2, 7, 5);
1075 // reading to zr is a mistake
1076 rf(rt, 0);
1077 }
1078
1079 enum barrier {OSHLD = 0b0001, OSHST, OSH, NSHLD=0b0101, NSHST, NSH,
1080 ISHLD = 0b1001, ISHST, ISH, LD=0b1101, ST, SY};
1081
dsb(barrier imm)1082 void dsb(barrier imm) {
1083 system(0b00, 0b011, 0b00011, imm, 0b100);
1084 }
1085
dmb(barrier imm)1086 void dmb(barrier imm) {
1087 system(0b00, 0b011, 0b00011, imm, 0b101);
1088 }
1089
isb()1090 void isb() {
1091 system(0b00, 0b011, 0b00011, SY, 0b110);
1092 }
1093
sys(int op1,int CRn,int CRm,int op2,Register rt=(Register)0b11111)1094 void sys(int op1, int CRn, int CRm, int op2,
1095 Register rt = (Register)0b11111) {
1096 system(0b01, op1, CRn, CRm, op2, rt);
1097 }
1098
1099 // Only implement operations accessible from EL0 or higher, i.e.,
1100 // op1 CRn CRm op2
1101 // IC IVAU 3 7 5 1
1102 // DC CVAC 3 7 10 1
1103 // DC CVAP 3 7 12 1
1104 // DC CVAU 3 7 11 1
1105 // DC CIVAC 3 7 14 1
1106 // DC ZVA 3 7 4 1
1107 // So only deal with the CRm field.
1108 enum icache_maintenance {IVAU = 0b0101};
1109 enum dcache_maintenance {CVAC = 0b1010, CVAP = 0b1100, CVAU = 0b1011, CIVAC = 0b1110, ZVA = 0b100};
1110
dc(dcache_maintenance cm,Register Rt)1111 void dc(dcache_maintenance cm, Register Rt) {
1112 sys(0b011, 0b0111, cm, 0b001, Rt);
1113 }
1114
ic(icache_maintenance cm,Register Rt)1115 void ic(icache_maintenance cm, Register Rt) {
1116 sys(0b011, 0b0111, cm, 0b001, Rt);
1117 }
1118
1119 // A more convenient access to dmb for our purposes
1120 enum Membar_mask_bits {
1121 // We can use ISH for a barrier because the ARM ARM says "This
1122 // architecture assumes that all Processing Elements that use the
1123 // same operating system or hypervisor are in the same Inner
1124 // Shareable shareability domain."
1125 StoreStore = ISHST,
1126 LoadStore = ISHLD,
1127 LoadLoad = ISHLD,
1128 StoreLoad = ISH,
1129 AnyAny = ISH
1130 };
1131
membar(Membar_mask_bits order_constraint)1132 void membar(Membar_mask_bits order_constraint) {
1133 dmb(Assembler::barrier(order_constraint));
1134 }
1135
1136 // Unconditional branch (register)
branch_reg(Register R,int opc)1137 void branch_reg(Register R, int opc) {
1138 starti;
1139 f(0b1101011, 31, 25);
1140 f(opc, 24, 21);
1141 f(0b11111000000, 20, 10);
1142 rf(R, 5);
1143 f(0b00000, 4, 0);
1144 }
1145
1146 #define INSN(NAME, opc) \
1147 void NAME(Register R) { \
1148 branch_reg(R, opc); \
1149 }
1150
1151 INSN(br, 0b0000);
1152 INSN(blr, 0b0001);
1153 INSN(ret, 0b0010);
1154
1155 void ret(void *p); // This forces a compile-time error for ret(0)
1156
1157 #undef INSN
1158
1159 #define INSN(NAME, opc) \
1160 void NAME() { \
1161 branch_reg(dummy_reg, opc); \
1162 }
1163
1164 INSN(eret, 0b0100);
1165 INSN(drps, 0b0101);
1166
1167 #undef INSN
1168
1169 // Load/store exclusive
1170 enum operand_size { byte, halfword, word, xword };
1171
load_store_exclusive(Register Rs,Register Rt1,Register Rt2,Register Rn,enum operand_size sz,int op,bool ordered)1172 void load_store_exclusive(Register Rs, Register Rt1, Register Rt2,
1173 Register Rn, enum operand_size sz, int op, bool ordered) {
1174 starti;
1175 f(sz, 31, 30), f(0b001000, 29, 24), f(op, 23, 21);
1176 rf(Rs, 16), f(ordered, 15), zrf(Rt2, 10), srf(Rn, 5), zrf(Rt1, 0);
1177 }
1178
load_exclusive(Register dst,Register addr,enum operand_size sz,bool ordered)1179 void load_exclusive(Register dst, Register addr,
1180 enum operand_size sz, bool ordered) {
1181 load_store_exclusive(dummy_reg, dst, dummy_reg, addr,
1182 sz, 0b010, ordered);
1183 }
1184
store_exclusive(Register status,Register new_val,Register addr,enum operand_size sz,bool ordered)1185 void store_exclusive(Register status, Register new_val, Register addr,
1186 enum operand_size sz, bool ordered) {
1187 load_store_exclusive(status, new_val, dummy_reg, addr,
1188 sz, 0b000, ordered);
1189 }
1190
1191 #define INSN4(NAME, sz, op, o0) /* Four registers */ \
1192 void NAME(Register Rs, Register Rt1, Register Rt2, Register Rn) { \
1193 guarantee(Rs != Rn && Rs != Rt1 && Rs != Rt2, "unpredictable instruction"); \
1194 load_store_exclusive(Rs, Rt1, Rt2, Rn, sz, op, o0); \
1195 }
1196
1197 #define INSN3(NAME, sz, op, o0) /* Three registers */ \
1198 void NAME(Register Rs, Register Rt, Register Rn) { \
1199 guarantee(Rs != Rn && Rs != Rt, "unpredictable instruction"); \
1200 load_store_exclusive(Rs, Rt, dummy_reg, Rn, sz, op, o0); \
1201 }
1202
1203 #define INSN2(NAME, sz, op, o0) /* Two registers */ \
1204 void NAME(Register Rt, Register Rn) { \
1205 load_store_exclusive(dummy_reg, Rt, dummy_reg, \
1206 Rn, sz, op, o0); \
1207 }
1208
1209 #define INSN_FOO(NAME, sz, op, o0) /* Three registers, encoded differently */ \
1210 void NAME(Register Rt1, Register Rt2, Register Rn) { \
1211 guarantee(Rt1 != Rt2, "unpredictable instruction"); \
1212 load_store_exclusive(dummy_reg, Rt1, Rt2, Rn, sz, op, o0); \
1213 }
1214
1215 // bytes
1216 INSN3(stxrb, byte, 0b000, 0);
1217 INSN3(stlxrb, byte, 0b000, 1);
1218 INSN2(ldxrb, byte, 0b010, 0);
1219 INSN2(ldaxrb, byte, 0b010, 1);
1220 INSN2(stlrb, byte, 0b100, 1);
1221 INSN2(ldarb, byte, 0b110, 1);
1222
1223 // halfwords
1224 INSN3(stxrh, halfword, 0b000, 0);
1225 INSN3(stlxrh, halfword, 0b000, 1);
1226 INSN2(ldxrh, halfword, 0b010, 0);
1227 INSN2(ldaxrh, halfword, 0b010, 1);
1228 INSN2(stlrh, halfword, 0b100, 1);
1229 INSN2(ldarh, halfword, 0b110, 1);
1230
1231 // words
1232 INSN3(stxrw, word, 0b000, 0);
1233 INSN3(stlxrw, word, 0b000, 1);
1234 INSN4(stxpw, word, 0b001, 0);
1235 INSN4(stlxpw, word, 0b001, 1);
1236 INSN2(ldxrw, word, 0b010, 0);
1237 INSN2(ldaxrw, word, 0b010, 1);
1238 INSN_FOO(ldxpw, word, 0b011, 0);
1239 INSN_FOO(ldaxpw, word, 0b011, 1);
1240 INSN2(stlrw, word, 0b100, 1);
1241 INSN2(ldarw, word, 0b110, 1);
1242
1243 // xwords
1244 INSN3(stxr, xword, 0b000, 0);
1245 INSN3(stlxr, xword, 0b000, 1);
1246 INSN4(stxp, xword, 0b001, 0);
1247 INSN4(stlxp, xword, 0b001, 1);
1248 INSN2(ldxr, xword, 0b010, 0);
1249 INSN2(ldaxr, xword, 0b010, 1);
1250 INSN_FOO(ldxp, xword, 0b011, 0);
1251 INSN_FOO(ldaxp, xword, 0b011, 1);
1252 INSN2(stlr, xword, 0b100, 1);
1253 INSN2(ldar, xword, 0b110, 1);
1254
1255 #undef INSN2
1256 #undef INSN3
1257 #undef INSN4
1258 #undef INSN_FOO
1259
1260 // 8.1 Compare and swap extensions
lse_cas(Register Rs,Register Rt,Register Rn,enum operand_size sz,bool a,bool r,bool not_pair)1261 void lse_cas(Register Rs, Register Rt, Register Rn,
1262 enum operand_size sz, bool a, bool r, bool not_pair) {
1263 starti;
1264 if (! not_pair) { // Pair
1265 assert(sz == word || sz == xword, "invalid size");
1266 /* The size bit is in bit 30, not 31 */
1267 sz = (operand_size)(sz == word ? 0b00:0b01);
1268 }
1269 f(sz, 31, 30), f(0b001000, 29, 24), f(not_pair ? 1 : 0, 23), f(a, 22), f(1, 21);
1270 zrf(Rs, 16), f(r, 15), f(0b11111, 14, 10), srf(Rn, 5), zrf(Rt, 0);
1271 }
1272
1273 // CAS
1274 #define INSN(NAME, a, r) \
1275 void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1276 assert(Rs != Rn && Rs != Rt, "unpredictable instruction"); \
1277 lse_cas(Rs, Rt, Rn, sz, a, r, true); \
1278 }
INSN(cas,false,false)1279 INSN(cas, false, false)
1280 INSN(casa, true, false)
1281 INSN(casl, false, true)
1282 INSN(casal, true, true)
1283 #undef INSN
1284
1285 // CASP
1286 #define INSN(NAME, a, r) \
1287 void NAME(operand_size sz, Register Rs, Register Rs1, \
1288 Register Rt, Register Rt1, Register Rn) { \
1289 assert((Rs->encoding() & 1) == 0 && (Rt->encoding() & 1) == 0 && \
1290 Rs->successor() == Rs1 && Rt->successor() == Rt1 && \
1291 Rs != Rn && Rs1 != Rn && Rs != Rt, "invalid registers"); \
1292 lse_cas(Rs, Rt, Rn, sz, a, r, false); \
1293 }
1294 INSN(casp, false, false)
1295 INSN(caspa, true, false)
1296 INSN(caspl, false, true)
1297 INSN(caspal, true, true)
1298 #undef INSN
1299
1300 // 8.1 Atomic operations
1301 void lse_atomic(Register Rs, Register Rt, Register Rn,
1302 enum operand_size sz, int op1, int op2, bool a, bool r) {
1303 starti;
1304 f(sz, 31, 30), f(0b111000, 29, 24), f(a, 23), f(r, 22), f(1, 21);
1305 zrf(Rs, 16), f(op1, 15), f(op2, 14, 12), f(0, 11, 10), srf(Rn, 5), zrf(Rt, 0);
1306 }
1307
1308 #define INSN(NAME, NAME_A, NAME_L, NAME_AL, op1, op2) \
1309 void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1310 lse_atomic(Rs, Rt, Rn, sz, op1, op2, false, false); \
1311 } \
1312 void NAME_A(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1313 lse_atomic(Rs, Rt, Rn, sz, op1, op2, true, false); \
1314 } \
1315 void NAME_L(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1316 lse_atomic(Rs, Rt, Rn, sz, op1, op2, false, true); \
1317 } \
1318 void NAME_AL(operand_size sz, Register Rs, Register Rt, Register Rn) {\
1319 lse_atomic(Rs, Rt, Rn, sz, op1, op2, true, true); \
1320 }
1321 INSN(ldadd, ldadda, ldaddl, ldaddal, 0, 0b000);
1322 INSN(ldbic, ldbica, ldbicl, ldbical, 0, 0b001);
1323 INSN(ldeor, ldeora, ldeorl, ldeoral, 0, 0b010);
1324 INSN(ldorr, ldorra, ldorrl, ldorral, 0, 0b011);
1325 INSN(ldsmax, ldsmaxa, ldsmaxl, ldsmaxal, 0, 0b100);
1326 INSN(ldsmin, ldsmina, ldsminl, ldsminal, 0, 0b101);
1327 INSN(ldumax, ldumaxa, ldumaxl, ldumaxal, 0, 0b110);
1328 INSN(ldumin, ldumina, lduminl, lduminal, 0, 0b111);
1329 INSN(swp, swpa, swpl, swpal, 1, 0b000);
1330 #undef INSN
1331
1332 // Load register (literal)
1333 #define INSN(NAME, opc, V) \
1334 void NAME(Register Rt, address dest) { \
1335 int64_t offset = (dest - pc()) >> 2; \
1336 starti; \
1337 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1338 sf(offset, 23, 5); \
1339 rf(Rt, 0); \
1340 } \
1341 void NAME(Register Rt, address dest, relocInfo::relocType rtype) { \
1342 InstructionMark im(this); \
1343 guarantee(rtype == relocInfo::internal_word_type, \
1344 "only internal_word_type relocs make sense here"); \
1345 code_section()->relocate(inst_mark(), InternalAddress(dest).rspec()); \
1346 NAME(Rt, dest); \
1347 } \
1348 void NAME(Register Rt, Label &L) { \
1349 wrap_label(Rt, L, &Assembler::NAME); \
1350 }
1351
1352 INSN(ldrw, 0b00, 0);
1353 INSN(ldr, 0b01, 0);
1354 INSN(ldrsw, 0b10, 0);
1355
1356 #undef INSN
1357
1358 #define INSN(NAME, opc, V) \
1359 void NAME(FloatRegister Rt, address dest) { \
1360 int64_t offset = (dest - pc()) >> 2; \
1361 starti; \
1362 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1363 sf(offset, 23, 5); \
1364 rf((Register)Rt, 0); \
1365 }
1366
1367 INSN(ldrs, 0b00, 1);
1368 INSN(ldrd, 0b01, 1);
1369 INSN(ldrq, 0b10, 1);
1370
1371 #undef INSN
1372
1373 #define INSN(NAME, size, opc) \
1374 void NAME(FloatRegister Rt, Register Rn) { \
1375 starti; \
1376 f(size, 31, 30), f(0b111100, 29, 24), f(opc, 23, 22), f(0, 21); \
1377 f(0, 20, 12), f(0b01, 11, 10); \
1378 rf(Rn, 5), rf((Register)Rt, 0); \
1379 }
1380
1381 INSN(ldrs, 0b10, 0b01);
1382 INSN(ldrd, 0b11, 0b01);
1383 INSN(ldrq, 0b00, 0b11);
1384
1385 #undef INSN
1386
1387
1388 #define INSN(NAME, opc, V) \
1389 void NAME(address dest, prfop op = PLDL1KEEP) { \
1390 int64_t offset = (dest - pc()) >> 2; \
1391 starti; \
1392 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1393 sf(offset, 23, 5); \
1394 f(op, 4, 0); \
1395 } \
1396 void NAME(Label &L, prfop op = PLDL1KEEP) { \
1397 wrap_label(L, op, &Assembler::NAME); \
1398 }
1399
1400 INSN(prfm, 0b11, 0);
1401
1402 #undef INSN
1403
1404 // Load/store
ld_st1(int opc,int p1,int V,int L,Register Rt1,Register Rt2,Address adr,bool no_allocate)1405 void ld_st1(int opc, int p1, int V, int L,
1406 Register Rt1, Register Rt2, Address adr, bool no_allocate) {
1407 starti;
1408 f(opc, 31, 30), f(p1, 29, 27), f(V, 26), f(L, 22);
1409 zrf(Rt2, 10), zrf(Rt1, 0);
1410 if (no_allocate) {
1411 adr.encode_nontemporal_pair(current);
1412 } else {
1413 adr.encode_pair(current);
1414 }
1415 }
1416
1417 // Load/store register pair (offset)
1418 #define INSN(NAME, size, p1, V, L, no_allocate) \
1419 void NAME(Register Rt1, Register Rt2, Address adr) { \
1420 ld_st1(size, p1, V, L, Rt1, Rt2, adr, no_allocate); \
1421 }
1422
1423 INSN(stpw, 0b00, 0b101, 0, 0, false);
1424 INSN(ldpw, 0b00, 0b101, 0, 1, false);
1425 INSN(ldpsw, 0b01, 0b101, 0, 1, false);
1426 INSN(stp, 0b10, 0b101, 0, 0, false);
1427 INSN(ldp, 0b10, 0b101, 0, 1, false);
1428
1429 // Load/store no-allocate pair (offset)
1430 INSN(stnpw, 0b00, 0b101, 0, 0, true);
1431 INSN(ldnpw, 0b00, 0b101, 0, 1, true);
1432 INSN(stnp, 0b10, 0b101, 0, 0, true);
1433 INSN(ldnp, 0b10, 0b101, 0, 1, true);
1434
1435 #undef INSN
1436
1437 #define INSN(NAME, size, p1, V, L, no_allocate) \
1438 void NAME(FloatRegister Rt1, FloatRegister Rt2, Address adr) { \
1439 ld_st1(size, p1, V, L, (Register)Rt1, (Register)Rt2, adr, no_allocate); \
1440 }
1441
1442 INSN(stps, 0b00, 0b101, 1, 0, false);
1443 INSN(ldps, 0b00, 0b101, 1, 1, false);
1444 INSN(stpd, 0b01, 0b101, 1, 0, false);
1445 INSN(ldpd, 0b01, 0b101, 1, 1, false);
1446 INSN(stpq, 0b10, 0b101, 1, 0, false);
1447 INSN(ldpq, 0b10, 0b101, 1, 1, false);
1448
1449 #undef INSN
1450
1451 // Load/store register (all modes)
ld_st2(Register Rt,const Address & adr,int size,int op,int V=0)1452 void ld_st2(Register Rt, const Address &adr, int size, int op, int V = 0) {
1453 starti;
1454
1455 f(V, 26); // general reg?
1456 zrf(Rt, 0);
1457
1458 // Encoding for literal loads is done here (rather than pushed
1459 // down into Address::encode) because the encoding of this
1460 // instruction is too different from all of the other forms to
1461 // make it worth sharing.
1462 if (adr.getMode() == Address::literal) {
1463 assert(size == 0b10 || size == 0b11, "bad operand size in ldr");
1464 assert(op == 0b01, "literal form can only be used with loads");
1465 f(size & 0b01, 31, 30), f(0b011, 29, 27), f(0b00, 25, 24);
1466 int64_t offset = (adr.target() - pc()) >> 2;
1467 sf(offset, 23, 5);
1468 code_section()->relocate(pc(), adr.rspec());
1469 return;
1470 }
1471
1472 f(size, 31, 30);
1473 f(op, 23, 22); // str
1474 adr.encode(current);
1475 }
1476
1477 #define INSN(NAME, size, op) \
1478 void NAME(Register Rt, const Address &adr) { \
1479 ld_st2(Rt, adr, size, op); \
1480 } \
1481
1482 INSN(str, 0b11, 0b00);
1483 INSN(strw, 0b10, 0b00);
1484 INSN(strb, 0b00, 0b00);
1485 INSN(strh, 0b01, 0b00);
1486
1487 INSN(ldr, 0b11, 0b01);
1488 INSN(ldrw, 0b10, 0b01);
1489 INSN(ldrb, 0b00, 0b01);
1490 INSN(ldrh, 0b01, 0b01);
1491
1492 INSN(ldrsb, 0b00, 0b10);
1493 INSN(ldrsbw, 0b00, 0b11);
1494 INSN(ldrsh, 0b01, 0b10);
1495 INSN(ldrshw, 0b01, 0b11);
1496 INSN(ldrsw, 0b10, 0b10);
1497
1498 #undef INSN
1499
1500 #define INSN(NAME, size, op) \
1501 void NAME(const Address &adr, prfop pfop = PLDL1KEEP) { \
1502 ld_st2((Register)pfop, adr, size, op); \
1503 }
1504
1505 INSN(prfm, 0b11, 0b10); // FIXME: PRFM should not be used with
1506 // writeback modes, but the assembler
1507 // doesn't enfore that.
1508
1509 #undef INSN
1510
1511 #define INSN(NAME, size, op) \
1512 void NAME(FloatRegister Rt, const Address &adr) { \
1513 ld_st2((Register)Rt, adr, size, op, 1); \
1514 }
1515
1516 INSN(strd, 0b11, 0b00);
1517 INSN(strs, 0b10, 0b00);
1518 INSN(ldrd, 0b11, 0b01);
1519 INSN(ldrs, 0b10, 0b01);
1520 INSN(strq, 0b00, 0b10);
1521 INSN(ldrq, 0x00, 0b11);
1522
1523 #undef INSN
1524
1525 /* SIMD extensions
1526 *
1527 * We just use FloatRegister in the following. They are exactly the same
1528 * as SIMD registers.
1529 */
1530 public:
1531
1532 enum SIMD_Arrangement {
1533 T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q
1534 };
1535
1536 enum SIMD_RegVariant {
1537 B, H, S, D, Q, INVALID
1538 };
1539
1540 enum shift_kind { LSL, LSR, ASR, ROR };
1541
op_shifted_reg(unsigned decode,enum shift_kind kind,unsigned shift,unsigned size,unsigned op)1542 void op_shifted_reg(unsigned decode,
1543 enum shift_kind kind, unsigned shift,
1544 unsigned size, unsigned op) {
1545 f(size, 31);
1546 f(op, 30, 29);
1547 f(decode, 28, 24);
1548 f(shift, 15, 10);
1549 f(kind, 23, 22);
1550 }
1551
1552 // Logical (shifted register)
1553 #define INSN(NAME, size, op, N) \
1554 void NAME(Register Rd, Register Rn, Register Rm, \
1555 enum shift_kind kind = LSL, unsigned shift = 0) { \
1556 starti; \
1557 guarantee(size == 1 || shift < 32, "incorrect shift"); \
1558 f(N, 21); \
1559 zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \
1560 op_shifted_reg(0b01010, kind, shift, size, op); \
1561 }
1562
1563 INSN(andr, 1, 0b00, 0);
1564 INSN(orr, 1, 0b01, 0);
1565 INSN(eor, 1, 0b10, 0);
1566 INSN(ands, 1, 0b11, 0);
1567 INSN(andw, 0, 0b00, 0);
1568 INSN(orrw, 0, 0b01, 0);
1569 INSN(eorw, 0, 0b10, 0);
1570 INSN(andsw, 0, 0b11, 0);
1571
1572 #undef INSN
1573
1574 #define INSN(NAME, size, op, N) \
1575 void NAME(Register Rd, Register Rn, Register Rm, \
1576 enum shift_kind kind = LSL, unsigned shift = 0) { \
1577 starti; \
1578 f(N, 21); \
1579 zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \
1580 op_shifted_reg(0b01010, kind, shift, size, op); \
1581 } \
1582 \
1583 /* These instructions have no immediate form. Provide an overload so \
1584 that if anyone does try to use an immediate operand -- this has \
1585 happened! -- we'll get a compile-time error. */ \
1586 void NAME(Register Rd, Register Rn, unsigned imm, \
1587 enum shift_kind kind = LSL, unsigned shift = 0) { \
1588 assert(false, " can't be used with immediate operand"); \
1589 }
1590
1591 INSN(bic, 1, 0b00, 1);
1592 INSN(orn, 1, 0b01, 1);
1593 INSN(eon, 1, 0b10, 1);
1594 INSN(bics, 1, 0b11, 1);
1595 INSN(bicw, 0, 0b00, 1);
1596 INSN(ornw, 0, 0b01, 1);
1597 INSN(eonw, 0, 0b10, 1);
1598 INSN(bicsw, 0, 0b11, 1);
1599
1600 #undef INSN
1601
1602 #ifdef _WIN64
1603 // In MSVC, `mvn` is defined as a macro and it affects compilation
1604 #undef mvn
1605 #endif
1606
1607 // Aliases for short forms of orn
mvn(Register Rd,Register Rm,enum shift_kind kind=LSL,unsigned shift=0)1608 void mvn(Register Rd, Register Rm,
1609 enum shift_kind kind = LSL, unsigned shift = 0) {
1610 orn(Rd, zr, Rm, kind, shift);
1611 }
1612
mvnw(Register Rd,Register Rm,enum shift_kind kind=LSL,unsigned shift=0)1613 void mvnw(Register Rd, Register Rm,
1614 enum shift_kind kind = LSL, unsigned shift = 0) {
1615 ornw(Rd, zr, Rm, kind, shift);
1616 }
1617
1618 // Add/subtract (shifted register)
1619 #define INSN(NAME, size, op) \
1620 void NAME(Register Rd, Register Rn, Register Rm, \
1621 enum shift_kind kind, unsigned shift = 0) { \
1622 starti; \
1623 f(0, 21); \
1624 assert_cond(kind != ROR); \
1625 guarantee(size == 1 || shift < 32, "incorrect shift");\
1626 zrf(Rd, 0), zrf(Rn, 5), zrf(Rm, 16); \
1627 op_shifted_reg(0b01011, kind, shift, size, op); \
1628 }
1629
1630 INSN(add, 1, 0b000);
1631 INSN(sub, 1, 0b10);
1632 INSN(addw, 0, 0b000);
1633 INSN(subw, 0, 0b10);
1634
1635 INSN(adds, 1, 0b001);
1636 INSN(subs, 1, 0b11);
1637 INSN(addsw, 0, 0b001);
1638 INSN(subsw, 0, 0b11);
1639
1640 #undef INSN
1641
1642 // Add/subtract (extended register)
1643 #define INSN(NAME, op) \
1644 void NAME(Register Rd, Register Rn, Register Rm, \
1645 ext::operation option, int amount = 0) { \
1646 starti; \
1647 zrf(Rm, 16), srf(Rn, 5), srf(Rd, 0); \
1648 add_sub_extended_reg(op, 0b01011, Rd, Rn, Rm, 0b00, option, amount); \
1649 }
1650
add_sub_extended_reg(unsigned op,unsigned decode,Register Rd,Register Rn,Register Rm,unsigned opt,ext::operation option,unsigned imm)1651 void add_sub_extended_reg(unsigned op, unsigned decode,
1652 Register Rd, Register Rn, Register Rm,
1653 unsigned opt, ext::operation option, unsigned imm) {
1654 guarantee(imm <= 4, "shift amount must be <= 4");
1655 f(op, 31, 29), f(decode, 28, 24), f(opt, 23, 22), f(1, 21);
1656 f(option, 15, 13), f(imm, 12, 10);
1657 }
1658
1659 INSN(addw, 0b000);
1660 INSN(subw, 0b010);
1661 INSN(add, 0b100);
1662 INSN(sub, 0b110);
1663
1664 #undef INSN
1665
1666 #define INSN(NAME, op) \
1667 void NAME(Register Rd, Register Rn, Register Rm, \
1668 ext::operation option, int amount = 0) { \
1669 starti; \
1670 zrf(Rm, 16), srf(Rn, 5), zrf(Rd, 0); \
1671 add_sub_extended_reg(op, 0b01011, Rd, Rn, Rm, 0b00, option, amount); \
1672 }
1673
1674 INSN(addsw, 0b001);
1675 INSN(subsw, 0b011);
1676 INSN(adds, 0b101);
1677 INSN(subs, 0b111);
1678
1679 #undef INSN
1680
1681 // Aliases for short forms of add and sub
1682 #define INSN(NAME) \
1683 void NAME(Register Rd, Register Rn, Register Rm) { \
1684 if (Rd == sp || Rn == sp) \
1685 NAME(Rd, Rn, Rm, ext::uxtx); \
1686 else \
1687 NAME(Rd, Rn, Rm, LSL); \
1688 }
1689
1690 INSN(addw);
1691 INSN(subw);
1692 INSN(add);
1693 INSN(sub);
1694
1695 INSN(addsw);
1696 INSN(subsw);
1697 INSN(adds);
1698 INSN(subs);
1699
1700 #undef INSN
1701
1702 // Add/subtract (with carry)
add_sub_carry(unsigned op,Register Rd,Register Rn,Register Rm)1703 void add_sub_carry(unsigned op, Register Rd, Register Rn, Register Rm) {
1704 starti;
1705 f(op, 31, 29);
1706 f(0b11010000, 28, 21);
1707 f(0b000000, 15, 10);
1708 zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0);
1709 }
1710
1711 #define INSN(NAME, op) \
1712 void NAME(Register Rd, Register Rn, Register Rm) { \
1713 add_sub_carry(op, Rd, Rn, Rm); \
1714 }
1715
1716 INSN(adcw, 0b000);
1717 INSN(adcsw, 0b001);
1718 INSN(sbcw, 0b010);
1719 INSN(sbcsw, 0b011);
1720 INSN(adc, 0b100);
1721 INSN(adcs, 0b101);
1722 INSN(sbc,0b110);
1723 INSN(sbcs, 0b111);
1724
1725 #undef INSN
1726
1727 // Conditional compare (both kinds)
conditional_compare(unsigned op,int o1,int o2,int o3,Register Rn,unsigned imm5,unsigned nzcv,unsigned cond)1728 void conditional_compare(unsigned op, int o1, int o2, int o3,
1729 Register Rn, unsigned imm5, unsigned nzcv,
1730 unsigned cond) {
1731 starti;
1732 f(op, 31, 29);
1733 f(0b11010010, 28, 21);
1734 f(cond, 15, 12);
1735 f(o1, 11);
1736 f(o2, 10);
1737 f(o3, 4);
1738 f(nzcv, 3, 0);
1739 f(imm5, 20, 16), zrf(Rn, 5);
1740 }
1741
1742 #define INSN(NAME, op) \
1743 void NAME(Register Rn, Register Rm, int imm, Condition cond) { \
1744 int regNumber = (Rm == zr ? 31 : (uintptr_t)Rm); \
1745 conditional_compare(op, 0, 0, 0, Rn, regNumber, imm, cond); \
1746 } \
1747 \
1748 void NAME(Register Rn, int imm5, int imm, Condition cond) { \
1749 conditional_compare(op, 1, 0, 0, Rn, imm5, imm, cond); \
1750 }
1751
1752 INSN(ccmnw, 0b001);
1753 INSN(ccmpw, 0b011);
1754 INSN(ccmn, 0b101);
1755 INSN(ccmp, 0b111);
1756
1757 #undef INSN
1758
1759 // Conditional select
conditional_select(unsigned op,unsigned op2,Register Rd,Register Rn,Register Rm,unsigned cond)1760 void conditional_select(unsigned op, unsigned op2,
1761 Register Rd, Register Rn, Register Rm,
1762 unsigned cond) {
1763 starti;
1764 f(op, 31, 29);
1765 f(0b11010100, 28, 21);
1766 f(cond, 15, 12);
1767 f(op2, 11, 10);
1768 zrf(Rm, 16), zrf(Rn, 5), rf(Rd, 0);
1769 }
1770
1771 #define INSN(NAME, op, op2) \
1772 void NAME(Register Rd, Register Rn, Register Rm, Condition cond) { \
1773 conditional_select(op, op2, Rd, Rn, Rm, cond); \
1774 }
1775
1776 INSN(cselw, 0b000, 0b00);
1777 INSN(csincw, 0b000, 0b01);
1778 INSN(csinvw, 0b010, 0b00);
1779 INSN(csnegw, 0b010, 0b01);
1780 INSN(csel, 0b100, 0b00);
1781 INSN(csinc, 0b100, 0b01);
1782 INSN(csinv, 0b110, 0b00);
1783 INSN(csneg, 0b110, 0b01);
1784
1785 #undef INSN
1786
1787 // Data processing
data_processing(unsigned op29,unsigned opcode,Register Rd,Register Rn)1788 void data_processing(unsigned op29, unsigned opcode,
1789 Register Rd, Register Rn) {
1790 f(op29, 31, 29), f(0b11010110, 28, 21);
1791 f(opcode, 15, 10);
1792 rf(Rn, 5), rf(Rd, 0);
1793 }
1794
1795 // (1 source)
1796 #define INSN(NAME, op29, opcode2, opcode) \
1797 void NAME(Register Rd, Register Rn) { \
1798 starti; \
1799 f(opcode2, 20, 16); \
1800 data_processing(op29, opcode, Rd, Rn); \
1801 }
1802
1803 INSN(rbitw, 0b010, 0b00000, 0b00000);
1804 INSN(rev16w, 0b010, 0b00000, 0b00001);
1805 INSN(revw, 0b010, 0b00000, 0b00010);
1806 INSN(clzw, 0b010, 0b00000, 0b00100);
1807 INSN(clsw, 0b010, 0b00000, 0b00101);
1808
1809 INSN(rbit, 0b110, 0b00000, 0b00000);
1810 INSN(rev16, 0b110, 0b00000, 0b00001);
1811 INSN(rev32, 0b110, 0b00000, 0b00010);
1812 INSN(rev, 0b110, 0b00000, 0b00011);
1813 INSN(clz, 0b110, 0b00000, 0b00100);
1814 INSN(cls, 0b110, 0b00000, 0b00101);
1815
1816 #undef INSN
1817
1818 // (2 sources)
1819 #define INSN(NAME, op29, opcode) \
1820 void NAME(Register Rd, Register Rn, Register Rm) { \
1821 starti; \
1822 rf(Rm, 16); \
1823 data_processing(op29, opcode, Rd, Rn); \
1824 }
1825
1826 INSN(udivw, 0b000, 0b000010);
1827 INSN(sdivw, 0b000, 0b000011);
1828 INSN(lslvw, 0b000, 0b001000);
1829 INSN(lsrvw, 0b000, 0b001001);
1830 INSN(asrvw, 0b000, 0b001010);
1831 INSN(rorvw, 0b000, 0b001011);
1832
1833 INSN(udiv, 0b100, 0b000010);
1834 INSN(sdiv, 0b100, 0b000011);
1835 INSN(lslv, 0b100, 0b001000);
1836 INSN(lsrv, 0b100, 0b001001);
1837 INSN(asrv, 0b100, 0b001010);
1838 INSN(rorv, 0b100, 0b001011);
1839
1840 #undef INSN
1841
1842 // (3 sources)
data_processing(unsigned op54,unsigned op31,unsigned o0,Register Rd,Register Rn,Register Rm,Register Ra)1843 void data_processing(unsigned op54, unsigned op31, unsigned o0,
1844 Register Rd, Register Rn, Register Rm,
1845 Register Ra) {
1846 starti;
1847 f(op54, 31, 29), f(0b11011, 28, 24);
1848 f(op31, 23, 21), f(o0, 15);
1849 zrf(Rm, 16), zrf(Ra, 10), zrf(Rn, 5), zrf(Rd, 0);
1850 }
1851
1852 #define INSN(NAME, op54, op31, o0) \
1853 void NAME(Register Rd, Register Rn, Register Rm, Register Ra) { \
1854 data_processing(op54, op31, o0, Rd, Rn, Rm, Ra); \
1855 }
1856
1857 INSN(maddw, 0b000, 0b000, 0);
1858 INSN(msubw, 0b000, 0b000, 1);
1859 INSN(madd, 0b100, 0b000, 0);
1860 INSN(msub, 0b100, 0b000, 1);
1861 INSN(smaddl, 0b100, 0b001, 0);
1862 INSN(smsubl, 0b100, 0b001, 1);
1863 INSN(umaddl, 0b100, 0b101, 0);
1864 INSN(umsubl, 0b100, 0b101, 1);
1865
1866 #undef INSN
1867
1868 #define INSN(NAME, op54, op31, o0) \
1869 void NAME(Register Rd, Register Rn, Register Rm) { \
1870 data_processing(op54, op31, o0, Rd, Rn, Rm, (Register)31); \
1871 }
1872
1873 INSN(smulh, 0b100, 0b010, 0);
1874 INSN(umulh, 0b100, 0b110, 0);
1875
1876 #undef INSN
1877
1878 // Floating-point data-processing (1 source)
data_processing(unsigned op31,unsigned type,unsigned opcode,FloatRegister Vd,FloatRegister Vn)1879 void data_processing(unsigned op31, unsigned type, unsigned opcode,
1880 FloatRegister Vd, FloatRegister Vn) {
1881 starti;
1882 f(op31, 31, 29);
1883 f(0b11110, 28, 24);
1884 f(type, 23, 22), f(1, 21), f(opcode, 20, 15), f(0b10000, 14, 10);
1885 rf(Vn, 5), rf(Vd, 0);
1886 }
1887
1888 #define INSN(NAME, op31, type, opcode) \
1889 void NAME(FloatRegister Vd, FloatRegister Vn) { \
1890 data_processing(op31, type, opcode, Vd, Vn); \
1891 }
1892
1893 private:
1894 INSN(i_fmovs, 0b000, 0b00, 0b000000);
1895 public:
1896 INSN(fabss, 0b000, 0b00, 0b000001);
1897 INSN(fnegs, 0b000, 0b00, 0b000010);
1898 INSN(fsqrts, 0b000, 0b00, 0b000011);
1899 INSN(fcvts, 0b000, 0b00, 0b000101); // Single-precision to double-precision
1900
1901 private:
1902 INSN(i_fmovd, 0b000, 0b01, 0b000000);
1903 public:
1904 INSN(fabsd, 0b000, 0b01, 0b000001);
1905 INSN(fnegd, 0b000, 0b01, 0b000010);
1906 INSN(fsqrtd, 0b000, 0b01, 0b000011);
1907 INSN(fcvtd, 0b000, 0b01, 0b000100); // Double-precision to single-precision
1908
fmovd(FloatRegister Vd,FloatRegister Vn)1909 void fmovd(FloatRegister Vd, FloatRegister Vn) {
1910 assert(Vd != Vn, "should be");
1911 i_fmovd(Vd, Vn);
1912 }
1913
fmovs(FloatRegister Vd,FloatRegister Vn)1914 void fmovs(FloatRegister Vd, FloatRegister Vn) {
1915 assert(Vd != Vn, "should be");
1916 i_fmovs(Vd, Vn);
1917 }
1918
1919 private:
_fcvt_narrow_extend(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb,bool do_extend)1920 void _fcvt_narrow_extend(FloatRegister Vd, SIMD_Arrangement Ta,
1921 FloatRegister Vn, SIMD_Arrangement Tb, bool do_extend) {
1922 assert((do_extend && (Tb >> 1) + 1 == (Ta >> 1))
1923 || (!do_extend && (Ta >> 1) + 1 == (Tb >> 1)), "Incompatible arrangement");
1924 starti;
1925 int op30 = (do_extend ? Tb : Ta) & 1;
1926 int op22 = ((do_extend ? Ta : Tb) >> 1) & 1;
1927 f(0, 31), f(op30, 30), f(0b0011100, 29, 23), f(op22, 22);
1928 f(0b100001011, 21, 13), f(do_extend ? 1 : 0, 12), f(0b10, 11, 10);
1929 rf(Vn, 5), rf(Vd, 0);
1930 }
1931
1932 public:
fcvtl(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb)1933 void fcvtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
1934 assert(Tb == T4H || Tb == T8H|| Tb == T2S || Tb == T4S, "invalid arrangement");
1935 _fcvt_narrow_extend(Vd, Ta, Vn, Tb, true);
1936 }
1937
fcvtn(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb)1938 void fcvtn(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
1939 assert(Ta == T4H || Ta == T8H|| Ta == T2S || Ta == T4S, "invalid arrangement");
1940 _fcvt_narrow_extend(Vd, Ta, Vn, Tb, false);
1941 }
1942
1943 #undef INSN
1944
1945 // Floating-point data-processing (2 source)
data_processing(unsigned op31,unsigned type,unsigned opcode,FloatRegister Vd,FloatRegister Vn,FloatRegister Vm)1946 void data_processing(unsigned op31, unsigned type, unsigned opcode,
1947 FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) {
1948 starti;
1949 f(op31, 31, 29);
1950 f(0b11110, 28, 24);
1951 f(type, 23, 22), f(1, 21), f(opcode, 15, 10);
1952 rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
1953 }
1954
1955 #define INSN(NAME, op31, type, opcode) \
1956 void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
1957 data_processing(op31, type, opcode, Vd, Vn, Vm); \
1958 }
1959
1960 INSN(fabds, 0b011, 0b10, 0b110101);
1961 INSN(fmuls, 0b000, 0b00, 0b000010);
1962 INSN(fdivs, 0b000, 0b00, 0b000110);
1963 INSN(fadds, 0b000, 0b00, 0b001010);
1964 INSN(fsubs, 0b000, 0b00, 0b001110);
1965 INSN(fmaxs, 0b000, 0b00, 0b010010);
1966 INSN(fmins, 0b000, 0b00, 0b010110);
1967 INSN(fnmuls, 0b000, 0b00, 0b100010);
1968
1969 INSN(fabdd, 0b011, 0b11, 0b110101);
1970 INSN(fmuld, 0b000, 0b01, 0b000010);
1971 INSN(fdivd, 0b000, 0b01, 0b000110);
1972 INSN(faddd, 0b000, 0b01, 0b001010);
1973 INSN(fsubd, 0b000, 0b01, 0b001110);
1974 INSN(fmaxd, 0b000, 0b01, 0b010010);
1975 INSN(fmind, 0b000, 0b01, 0b010110);
1976 INSN(fnmuld, 0b000, 0b01, 0b100010);
1977
1978 #undef INSN
1979
1980 // Floating-point data-processing (3 source)
data_processing(unsigned op31,unsigned type,unsigned o1,unsigned o0,FloatRegister Vd,FloatRegister Vn,FloatRegister Vm,FloatRegister Va)1981 void data_processing(unsigned op31, unsigned type, unsigned o1, unsigned o0,
1982 FloatRegister Vd, FloatRegister Vn, FloatRegister Vm,
1983 FloatRegister Va) {
1984 starti;
1985 f(op31, 31, 29);
1986 f(0b11111, 28, 24);
1987 f(type, 23, 22), f(o1, 21), f(o0, 15);
1988 rf(Vm, 16), rf(Va, 10), rf(Vn, 5), rf(Vd, 0);
1989 }
1990
1991 #define INSN(NAME, op31, type, o1, o0) \
1992 void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, \
1993 FloatRegister Va) { \
1994 data_processing(op31, type, o1, o0, Vd, Vn, Vm, Va); \
1995 }
1996
1997 INSN(fmadds, 0b000, 0b00, 0, 0);
1998 INSN(fmsubs, 0b000, 0b00, 0, 1);
1999 INSN(fnmadds, 0b000, 0b00, 1, 0);
2000 INSN(fnmsubs, 0b000, 0b00, 1, 1);
2001
2002 INSN(fmaddd, 0b000, 0b01, 0, 0);
2003 INSN(fmsubd, 0b000, 0b01, 0, 1);
2004 INSN(fnmaddd, 0b000, 0b01, 1, 0);
2005 INSN(fnmsub, 0b000, 0b01, 1, 1);
2006
2007 #undef INSN
2008
2009 // Floating-point conditional select
fp_conditional_select(unsigned op31,unsigned type,unsigned op1,unsigned op2,Condition cond,FloatRegister Vd,FloatRegister Vn,FloatRegister Vm)2010 void fp_conditional_select(unsigned op31, unsigned type,
2011 unsigned op1, unsigned op2,
2012 Condition cond, FloatRegister Vd,
2013 FloatRegister Vn, FloatRegister Vm) {
2014 starti;
2015 f(op31, 31, 29);
2016 f(0b11110, 28, 24);
2017 f(type, 23, 22);
2018 f(op1, 21, 21);
2019 f(op2, 11, 10);
2020 f(cond, 15, 12);
2021 rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
2022 }
2023
2024 #define INSN(NAME, op31, type, op1, op2) \
2025 void NAME(FloatRegister Vd, FloatRegister Vn, \
2026 FloatRegister Vm, Condition cond) { \
2027 fp_conditional_select(op31, type, op1, op2, cond, Vd, Vn, Vm); \
2028 }
2029
2030 INSN(fcsels, 0b000, 0b00, 0b1, 0b11);
2031 INSN(fcseld, 0b000, 0b01, 0b1, 0b11);
2032
2033 #undef INSN
2034
2035 // Floating-point<->integer conversions
float_int_convert(unsigned op31,unsigned type,unsigned rmode,unsigned opcode,Register Rd,Register Rn)2036 void float_int_convert(unsigned op31, unsigned type,
2037 unsigned rmode, unsigned opcode,
2038 Register Rd, Register Rn) {
2039 starti;
2040 f(op31, 31, 29);
2041 f(0b11110, 28, 24);
2042 f(type, 23, 22), f(1, 21), f(rmode, 20, 19);
2043 f(opcode, 18, 16), f(0b000000, 15, 10);
2044 zrf(Rn, 5), zrf(Rd, 0);
2045 }
2046
2047 #define INSN(NAME, op31, type, rmode, opcode) \
2048 void NAME(Register Rd, FloatRegister Vn) { \
2049 float_int_convert(op31, type, rmode, opcode, Rd, (Register)Vn); \
2050 }
2051
2052 INSN(fcvtzsw, 0b000, 0b00, 0b11, 0b000);
2053 INSN(fcvtzs, 0b100, 0b00, 0b11, 0b000);
2054 INSN(fcvtzdw, 0b000, 0b01, 0b11, 0b000);
2055 INSN(fcvtzd, 0b100, 0b01, 0b11, 0b000);
2056
2057 INSN(fmovs, 0b000, 0b00, 0b00, 0b110);
2058 INSN(fmovd, 0b100, 0b01, 0b00, 0b110);
2059
2060 // INSN(fmovhid, 0b100, 0b10, 0b01, 0b110);
2061
2062 #undef INSN
2063
2064 #define INSN(NAME, op31, type, rmode, opcode) \
2065 void NAME(FloatRegister Vd, Register Rn) { \
2066 float_int_convert(op31, type, rmode, opcode, (Register)Vd, Rn); \
2067 }
2068
2069 INSN(fmovs, 0b000, 0b00, 0b00, 0b111);
2070 INSN(fmovd, 0b100, 0b01, 0b00, 0b111);
2071
2072 INSN(scvtfws, 0b000, 0b00, 0b00, 0b010);
2073 INSN(scvtfs, 0b100, 0b00, 0b00, 0b010);
2074 INSN(scvtfwd, 0b000, 0b01, 0b00, 0b010);
2075 INSN(scvtfd, 0b100, 0b01, 0b00, 0b010);
2076
2077 // INSN(fmovhid, 0b100, 0b10, 0b01, 0b111);
2078
2079 #undef INSN
2080
2081 enum sign_kind { SIGNED, UNSIGNED };
2082
2083 private:
_xcvtf_scalar_integer(sign_kind sign,unsigned sz,FloatRegister Rd,FloatRegister Rn)2084 void _xcvtf_scalar_integer(sign_kind sign, unsigned sz,
2085 FloatRegister Rd, FloatRegister Rn) {
2086 starti;
2087 f(0b01, 31, 30), f(sign == SIGNED ? 0 : 1, 29);
2088 f(0b111100, 27, 23), f((sz >> 1) & 1, 22), f(0b100001110110, 21, 10);
2089 rf(Rn, 5), rf(Rd, 0);
2090 }
2091
2092 public:
2093 #define INSN(NAME, sign, sz) \
2094 void NAME(FloatRegister Rd, FloatRegister Rn) { \
2095 _xcvtf_scalar_integer(sign, sz, Rd, Rn); \
2096 }
2097
2098 INSN(scvtfs, SIGNED, 0);
2099 INSN(scvtfd, SIGNED, 1);
2100
2101 #undef INSN
2102
2103 private:
_xcvtf_vector_integer(sign_kind sign,SIMD_Arrangement T,FloatRegister Rd,FloatRegister Rn)2104 void _xcvtf_vector_integer(sign_kind sign, SIMD_Arrangement T,
2105 FloatRegister Rd, FloatRegister Rn) {
2106 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement");
2107 starti;
2108 f(0, 31), f(T & 1, 30), f(sign == SIGNED ? 0 : 1, 29);
2109 f(0b011100, 28, 23), f((T >> 1) & 1, 22), f(0b100001110110, 21, 10);
2110 rf(Rn, 5), rf(Rd, 0);
2111 }
2112
2113 public:
scvtfv(SIMD_Arrangement T,FloatRegister Rd,FloatRegister Rn)2114 void scvtfv(SIMD_Arrangement T, FloatRegister Rd, FloatRegister Rn) {
2115 _xcvtf_vector_integer(SIGNED, T, Rd, Rn);
2116 }
2117
2118 // Floating-point compare
float_compare(unsigned op31,unsigned type,unsigned op,unsigned op2,FloatRegister Vn,FloatRegister Vm=(FloatRegister)0)2119 void float_compare(unsigned op31, unsigned type,
2120 unsigned op, unsigned op2,
2121 FloatRegister Vn, FloatRegister Vm = (FloatRegister)0) {
2122 starti;
2123 f(op31, 31, 29);
2124 f(0b11110, 28, 24);
2125 f(type, 23, 22), f(1, 21);
2126 f(op, 15, 14), f(0b1000, 13, 10), f(op2, 4, 0);
2127 rf(Vn, 5), rf(Vm, 16);
2128 }
2129
2130
2131 #define INSN(NAME, op31, type, op, op2) \
2132 void NAME(FloatRegister Vn, FloatRegister Vm) { \
2133 float_compare(op31, type, op, op2, Vn, Vm); \
2134 }
2135
2136 #define INSN1(NAME, op31, type, op, op2) \
2137 void NAME(FloatRegister Vn, double d) { \
2138 assert_cond(d == 0.0); \
2139 float_compare(op31, type, op, op2, Vn); \
2140 }
2141
2142 INSN(fcmps, 0b000, 0b00, 0b00, 0b00000);
2143 INSN1(fcmps, 0b000, 0b00, 0b00, 0b01000);
2144 // INSN(fcmpes, 0b000, 0b00, 0b00, 0b10000);
2145 // INSN1(fcmpes, 0b000, 0b00, 0b00, 0b11000);
2146
2147 INSN(fcmpd, 0b000, 0b01, 0b00, 0b00000);
2148 INSN1(fcmpd, 0b000, 0b01, 0b00, 0b01000);
2149 // INSN(fcmped, 0b000, 0b01, 0b00, 0b10000);
2150 // INSN1(fcmped, 0b000, 0b01, 0b00, 0b11000);
2151
2152 #undef INSN
2153 #undef INSN1
2154
2155 // Floating-point compare. 3-registers versions (scalar).
2156 #define INSN(NAME, sz, e) \
2157 void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
2158 starti; \
2159 f(0b01111110, 31, 24), f(e, 23), f(sz, 22), f(1, 21), rf(Vm, 16); \
2160 f(0b111011, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2161 } \
2162
2163 INSN(facged, 1, 0); // facge-double
2164 INSN(facges, 0, 0); // facge-single
2165 INSN(facgtd, 1, 1); // facgt-double
2166 INSN(facgts, 0, 1); // facgt-single
2167
2168 #undef INSN
2169
2170 // Floating-point Move (immediate)
2171 private:
2172 unsigned pack(double value);
2173
fmov_imm(FloatRegister Vn,double value,unsigned size)2174 void fmov_imm(FloatRegister Vn, double value, unsigned size) {
2175 starti;
2176 f(0b00011110, 31, 24), f(size, 23, 22), f(1, 21);
2177 f(pack(value), 20, 13), f(0b10000000, 12, 5);
2178 rf(Vn, 0);
2179 }
2180
2181 public:
2182
fmovs(FloatRegister Vn,double value)2183 void fmovs(FloatRegister Vn, double value) {
2184 if (value)
2185 fmov_imm(Vn, value, 0b00);
2186 else
2187 fmovs(Vn, zr);
2188 }
fmovd(FloatRegister Vn,double value)2189 void fmovd(FloatRegister Vn, double value) {
2190 if (value)
2191 fmov_imm(Vn, value, 0b01);
2192 else
2193 fmovd(Vn, zr);
2194 }
2195
2196 // Floating-point rounding
2197 // type: half-precision = 11
2198 // single = 00
2199 // double = 01
2200 // rmode: A = Away = 100
2201 // I = current = 111
2202 // M = MinusInf = 010
2203 // N = eveN = 000
2204 // P = PlusInf = 001
2205 // X = eXact = 110
2206 // Z = Zero = 011
float_round(unsigned type,unsigned rmode,FloatRegister Rd,FloatRegister Rn)2207 void float_round(unsigned type, unsigned rmode, FloatRegister Rd, FloatRegister Rn) {
2208 starti;
2209 f(0b00011110, 31, 24);
2210 f(type, 23, 22);
2211 f(0b1001, 21, 18);
2212 f(rmode, 17, 15);
2213 f(0b10000, 14, 10);
2214 rf(Rn, 5), rf(Rd, 0);
2215 }
2216 #define INSN(NAME, type, rmode) \
2217 void NAME(FloatRegister Vd, FloatRegister Vn) { \
2218 float_round(type, rmode, Vd, Vn); \
2219 }
2220
2221 public:
2222 INSN(frintah, 0b11, 0b100);
2223 INSN(frintih, 0b11, 0b111);
2224 INSN(frintmh, 0b11, 0b010);
2225 INSN(frintnh, 0b11, 0b000);
2226 INSN(frintph, 0b11, 0b001);
2227 INSN(frintxh, 0b11, 0b110);
2228 INSN(frintzh, 0b11, 0b011);
2229
2230 INSN(frintas, 0b00, 0b100);
2231 INSN(frintis, 0b00, 0b111);
2232 INSN(frintms, 0b00, 0b010);
2233 INSN(frintns, 0b00, 0b000);
2234 INSN(frintps, 0b00, 0b001);
2235 INSN(frintxs, 0b00, 0b110);
2236 INSN(frintzs, 0b00, 0b011);
2237
2238 INSN(frintad, 0b01, 0b100);
2239 INSN(frintid, 0b01, 0b111);
2240 INSN(frintmd, 0b01, 0b010);
2241 INSN(frintnd, 0b01, 0b000);
2242 INSN(frintpd, 0b01, 0b001);
2243 INSN(frintxd, 0b01, 0b110);
2244 INSN(frintzd, 0b01, 0b011);
2245 #undef INSN
2246
2247 private:
2248 static short SIMD_Size_in_bytes[];
2249
2250 public:
2251 #define INSN(NAME, op) \
2252 void NAME(FloatRegister Rt, SIMD_RegVariant T, const Address &adr) { \
2253 ld_st2((Register)Rt, adr, (int)T & 3, op + ((T==Q) ? 0b10:0b00), 1); \
2254 } \
2255
2256 INSN(ldr, 1);
2257 INSN(str, 0);
2258
2259 #undef INSN
2260
2261 private:
2262
ld_st(FloatRegister Vt,SIMD_Arrangement T,Register Xn,int op1,int op2)2263 void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn, int op1, int op2) {
2264 starti;
2265 f(0,31), f((int)T & 1, 30);
2266 f(op1, 29, 21), f(0, 20, 16), f(op2, 15, 12);
2267 f((int)T >> 1, 11, 10), srf(Xn, 5), rf(Vt, 0);
2268 }
ld_st(FloatRegister Vt,SIMD_Arrangement T,Register Xn,int imm,int op1,int op2,int regs)2269 void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn,
2270 int imm, int op1, int op2, int regs) {
2271
2272 bool replicate = op2 >> 2 == 3;
2273 // post-index value (imm) is formed differently for replicate/non-replicate ld* instructions
2274 int expectedImmediate = replicate ? regs * (1 << (T >> 1)) : SIMD_Size_in_bytes[T] * regs;
2275 guarantee(T < T1Q , "incorrect arrangement");
2276 guarantee(imm == expectedImmediate, "bad offset");
2277 starti;
2278 f(0,31), f((int)T & 1, 30);
2279 f(op1 | 0b100, 29, 21), f(0b11111, 20, 16), f(op2, 15, 12);
2280 f((int)T >> 1, 11, 10), srf(Xn, 5), rf(Vt, 0);
2281 }
ld_st(FloatRegister Vt,SIMD_Arrangement T,Register Xn,Register Xm,int op1,int op2)2282 void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn,
2283 Register Xm, int op1, int op2) {
2284 starti;
2285 f(0,31), f((int)T & 1, 30);
2286 f(op1 | 0b100, 29, 21), rf(Xm, 16), f(op2, 15, 12);
2287 f((int)T >> 1, 11, 10), srf(Xn, 5), rf(Vt, 0);
2288 }
2289
ld_st(FloatRegister Vt,SIMD_Arrangement T,Address a,int op1,int op2,int regs)2290 void ld_st(FloatRegister Vt, SIMD_Arrangement T, Address a, int op1, int op2, int regs) {
2291 switch (a.getMode()) {
2292 case Address::base_plus_offset:
2293 guarantee(a.offset() == 0, "no offset allowed here");
2294 ld_st(Vt, T, a.base(), op1, op2);
2295 break;
2296 case Address::post:
2297 ld_st(Vt, T, a.base(), a.offset(), op1, op2, regs);
2298 break;
2299 case Address::post_reg:
2300 ld_st(Vt, T, a.base(), a.index(), op1, op2);
2301 break;
2302 default:
2303 ShouldNotReachHere();
2304 }
2305 }
2306
2307 public:
2308
2309 #define INSN1(NAME, op1, op2) \
2310 void NAME(FloatRegister Vt, SIMD_Arrangement T, const Address &a) { \
2311 ld_st(Vt, T, a, op1, op2, 1); \
2312 }
2313
2314 #define INSN2(NAME, op1, op2) \
2315 void NAME(FloatRegister Vt, FloatRegister Vt2, SIMD_Arrangement T, const Address &a) { \
2316 assert(Vt->successor() == Vt2, "Registers must be ordered"); \
2317 ld_st(Vt, T, a, op1, op2, 2); \
2318 }
2319
2320 #define INSN3(NAME, op1, op2) \
2321 void NAME(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, \
2322 SIMD_Arrangement T, const Address &a) { \
2323 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3, \
2324 "Registers must be ordered"); \
2325 ld_st(Vt, T, a, op1, op2, 3); \
2326 }
2327
2328 #define INSN4(NAME, op1, op2) \
2329 void NAME(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, \
2330 FloatRegister Vt4, SIMD_Arrangement T, const Address &a) { \
2331 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 && \
2332 Vt3->successor() == Vt4, "Registers must be ordered"); \
2333 ld_st(Vt, T, a, op1, op2, 4); \
2334 }
2335
2336 INSN1(ld1, 0b001100010, 0b0111);
2337 INSN2(ld1, 0b001100010, 0b1010);
2338 INSN3(ld1, 0b001100010, 0b0110);
2339 INSN4(ld1, 0b001100010, 0b0010);
2340
2341 INSN2(ld2, 0b001100010, 0b1000);
2342 INSN3(ld3, 0b001100010, 0b0100);
2343 INSN4(ld4, 0b001100010, 0b0000);
2344
2345 INSN1(st1, 0b001100000, 0b0111);
2346 INSN2(st1, 0b001100000, 0b1010);
2347 INSN3(st1, 0b001100000, 0b0110);
2348 INSN4(st1, 0b001100000, 0b0010);
2349
2350 INSN2(st2, 0b001100000, 0b1000);
2351 INSN3(st3, 0b001100000, 0b0100);
2352 INSN4(st4, 0b001100000, 0b0000);
2353
2354 INSN1(ld1r, 0b001101010, 0b1100);
2355 INSN2(ld2r, 0b001101011, 0b1100);
2356 INSN3(ld3r, 0b001101010, 0b1110);
2357 INSN4(ld4r, 0b001101011, 0b1110);
2358
2359 #undef INSN1
2360 #undef INSN2
2361 #undef INSN3
2362 #undef INSN4
2363
2364 #define INSN(NAME, opc) \
2365 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2366 starti; \
2367 assert(T == T8B || T == T16B, "must be T8B or T16B"); \
2368 f(0, 31), f((int)T & 1, 30), f(opc, 29, 21); \
2369 rf(Vm, 16), f(0b000111, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2370 }
2371
2372 INSN(eor, 0b101110001);
2373 INSN(orr, 0b001110101);
2374 INSN(andr, 0b001110001);
2375 INSN(bic, 0b001110011);
2376 INSN(bif, 0b101110111);
2377 INSN(bit, 0b101110101);
2378 INSN(bsl, 0b101110011);
2379 INSN(orn, 0b001110111);
2380
2381 #undef INSN
2382
2383 #define INSN(NAME, opc, opc2, acceptT2D) \
2384 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2385 guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \
2386 if (!acceptT2D) guarantee(T != T2D, "incorrect arrangement"); \
2387 starti; \
2388 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2389 f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10); \
2390 rf(Vn, 5), rf(Vd, 0); \
2391 }
2392
2393 INSN(addv, 0, 0b100001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2394 INSN(subv, 1, 0b100001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2395 INSN(mulv, 0, 0b100111, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2396 INSN(mlav, 0, 0b100101, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2397 INSN(mlsv, 1, 0b100101, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2398 INSN(sshl, 0, 0b010001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2399 INSN(ushl, 1, 0b010001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2400 INSN(addpv, 0, 0b101111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2401 INSN(smullv, 0, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2402 INSN(umullv, 1, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2403 INSN(umlalv, 1, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2404 INSN(maxv, 0, 0b011001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2405 INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2406 INSN(cmeq, 1, 0b100011, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2407 INSN(cmgt, 0, 0b001101, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2408 INSN(cmge, 0, 0b001111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2409
2410 #undef INSN
2411
2412 #define INSN(NAME, opc, opc2, accepted) \
2413 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2414 guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \
2415 if (accepted < 3) guarantee(T != T2D, "incorrect arrangement"); \
2416 if (accepted < 2) guarantee(T != T2S, "incorrect arrangement"); \
2417 if (accepted < 1) guarantee(T == T8B || T == T16B, "incorrect arrangement"); \
2418 starti; \
2419 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2420 f((int)T >> 1, 23, 22), f(opc2, 21, 10); \
2421 rf(Vn, 5), rf(Vd, 0); \
2422 }
2423
2424 INSN(absr, 0, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2425 INSN(negr, 1, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2426 INSN(notr, 1, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2427 INSN(addv, 0, 0b110001101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2428 INSN(smaxv, 0, 0b110000101010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2429 INSN(sminv, 0, 0b110001101010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2430 INSN(cls, 0, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2431 INSN(clz, 1, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2432 INSN(cnt, 0, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2433 INSN(uaddlp, 1, 0b100000001010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2434 INSN(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2435
2436 #undef INSN
2437
2438 #define INSN(NAME, opc) \
2439 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2440 starti; \
2441 assert(T == T4S, "arrangement must be T4S"); \
2442 f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24), f(opc, 23), \
2443 f(T == T4S ? 0 : 1, 22), f(0b110000111110, 21, 10); rf(Vn, 5), rf(Vd, 0); \
2444 }
2445
2446 INSN(fmaxv, 0);
2447 INSN(fminv, 1);
2448
2449 #undef INSN
2450
2451 #define INSN(NAME, op0, cmode0) \
2452 void NAME(FloatRegister Vd, SIMD_Arrangement T, unsigned imm8, unsigned lsl = 0) { \
2453 unsigned cmode = cmode0; \
2454 unsigned op = op0; \
2455 starti; \
2456 assert(lsl == 0 || \
2457 ((T == T4H || T == T8H) && lsl == 8) || \
2458 ((T == T2S || T == T4S) && ((lsl >> 3) < 4) && ((lsl & 7) == 0)), "invalid shift");\
2459 cmode |= lsl >> 2; \
2460 if (T == T4H || T == T8H) cmode |= 0b1000; \
2461 if (!(T == T4H || T == T8H || T == T2S || T == T4S)) { \
2462 assert(op == 0 && cmode0 == 0, "must be MOVI"); \
2463 cmode = 0b1110; \
2464 if (T == T1D || T == T2D) op = 1; \
2465 } \
2466 f(0, 31), f((int)T & 1, 30), f(op, 29), f(0b0111100000, 28, 19); \
2467 f(imm8 >> 5, 18, 16), f(cmode, 15, 12), f(0x01, 11, 10), f(imm8 & 0b11111, 9, 5); \
2468 rf(Vd, 0); \
2469 }
2470
2471 INSN(movi, 0, 0);
2472 INSN(orri, 0, 1);
2473 INSN(mvni, 1, 0);
2474 INSN(bici, 1, 1);
2475
2476 #undef INSN
2477
2478 #define INSN(NAME, op1, op2, op3) \
2479 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2480 starti; \
2481 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2482 f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \
2483 f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2484 }
2485
2486 INSN(fabd, 1, 1, 0b110101);
2487 INSN(fadd, 0, 0, 0b110101);
2488 INSN(fdiv, 1, 0, 0b111111);
2489 INSN(fmul, 1, 0, 0b110111);
2490 INSN(fsub, 0, 1, 0b110101);
2491 INSN(fmla, 0, 0, 0b110011);
2492 INSN(fmls, 0, 1, 0b110011);
2493 INSN(fmax, 0, 0, 0b111101);
2494 INSN(fmin, 0, 1, 0b111101);
2495 INSN(fcmeq, 0, 0, 0b111001);
2496 INSN(fcmgt, 1, 1, 0b111001);
2497 INSN(fcmge, 1, 0, 0b111001);
2498
2499 #undef INSN
2500
2501 #define INSN(NAME, opc) \
2502 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2503 starti; \
2504 assert(T == T4S, "arrangement must be T4S"); \
2505 f(0b01011110000, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2506 }
2507
2508 INSN(sha1c, 0b000000);
2509 INSN(sha1m, 0b001000);
2510 INSN(sha1p, 0b000100);
2511 INSN(sha1su0, 0b001100);
2512 INSN(sha256h2, 0b010100);
2513 INSN(sha256h, 0b010000);
2514 INSN(sha256su1, 0b011000);
2515
2516 #undef INSN
2517
2518 #define INSN(NAME, opc) \
2519 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2520 starti; \
2521 assert(T == T4S, "arrangement must be T4S"); \
2522 f(0b0101111000101000, 31, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2523 }
2524
2525 INSN(sha1h, 0b000010);
2526 INSN(sha1su1, 0b000110);
2527 INSN(sha256su0, 0b001010);
2528
2529 #undef INSN
2530
2531 #define INSN(NAME, opc) \
2532 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2533 starti; \
2534 assert(T == T2D, "arrangement must be T2D"); \
2535 f(0b11001110011, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2536 }
2537
2538 INSN(sha512h, 0b100000);
2539 INSN(sha512h2, 0b100001);
2540 INSN(sha512su1, 0b100010);
2541
2542 #undef INSN
2543
2544 #define INSN(NAME, opc) \
2545 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2546 starti; \
2547 assert(T == T2D, "arrangement must be T2D"); \
2548 f(opc, 31, 10), rf(Vn, 5), rf(Vd, 0); \
2549 }
2550
2551 INSN(sha512su0, 0b1100111011000000100000);
2552
2553 #undef INSN
2554
2555 #define INSN(NAME, opc) \
2556 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, FloatRegister Va) { \
2557 starti; \
2558 assert(T == T16B, "arrangement must be T16B"); \
2559 f(0b11001110, 31, 24), f(opc, 23, 21), rf(Vm, 16), f(0b0, 15, 15), rf(Va, 10), rf(Vn, 5), rf(Vd, 0); \
2560 }
2561
2562 INSN(eor3, 0b000);
2563 INSN(bcax, 0b001);
2564
2565 #undef INSN
2566
2567 #define INSN(NAME, opc) \
2568 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, unsigned imm) { \
2569 starti; \
2570 assert(T == T2D, "arrangement must be T2D"); \
2571 f(0b11001110, 31, 24), f(opc, 23, 21), rf(Vm, 16), f(imm, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2572 }
2573
2574 INSN(xar, 0b100);
2575
2576 #undef INSN
2577
2578 #define INSN(NAME, opc) \
2579 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2580 starti; \
2581 assert(T == T2D, "arrangement must be T2D"); \
2582 f(0b11001110, 31, 24), f(opc, 23, 21), rf(Vm, 16), f(0b100011, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2583 }
2584
2585 INSN(rax1, 0b011);
2586
2587 #undef INSN
2588
2589 #define INSN(NAME, opc) \
2590 void NAME(FloatRegister Vd, FloatRegister Vn) { \
2591 starti; \
2592 f(opc, 31, 10), rf(Vn, 5), rf(Vd, 0); \
2593 }
2594
2595 INSN(aese, 0b0100111000101000010010);
2596 INSN(aesd, 0b0100111000101000010110);
2597 INSN(aesmc, 0b0100111000101000011010);
2598 INSN(aesimc, 0b0100111000101000011110);
2599
2600 #undef INSN
2601
2602 #define INSN(NAME, op1, op2) \
2603 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index = 0) { \
2604 starti; \
2605 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2606 assert(index >= 0 && ((T == T2D && index <= 1) || (T != T2D && index <= 3)), "invalid index"); \
2607 f(0, 31), f((int)T & 1, 30), f(op1, 29); f(0b011111, 28, 23); \
2608 f(T == T2D ? 1 : 0, 22), f(T == T2D ? 0 : index & 1, 21), rf(Vm, 16); \
2609 f(op2, 15, 12), f(T == T2D ? index : (index >> 1), 11), f(0, 10); \
2610 rf(Vn, 5), rf(Vd, 0); \
2611 }
2612
2613 // FMLA/FMLS - Vector - Scalar
2614 INSN(fmlavs, 0, 0b0001);
2615 INSN(fmlsvs, 0, 0b0101);
2616 // FMULX - Vector - Scalar
2617 INSN(fmulxvs, 1, 0b1001);
2618
2619 #undef INSN
2620
2621 // Floating-point Reciprocal Estimate
frecpe(FloatRegister Vd,FloatRegister Vn,SIMD_RegVariant type)2622 void frecpe(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2623 assert(type == D || type == S, "Wrong type for frecpe");
2624 starti;
2625 f(0b010111101, 31, 23);
2626 f(type == D ? 1 : 0, 22);
2627 f(0b100001110110, 21, 10);
2628 rf(Vn, 5), rf(Vd, 0);
2629 }
2630
2631 // (long) {a, b} -> (a + b)
addpd(FloatRegister Vd,FloatRegister Vn)2632 void addpd(FloatRegister Vd, FloatRegister Vn) {
2633 starti;
2634 f(0b0101111011110001101110, 31, 10);
2635 rf(Vn, 5), rf(Vd, 0);
2636 }
2637
2638 // (Floating-point) {a, b} -> (a + b)
faddp(FloatRegister Vd,FloatRegister Vn,SIMD_RegVariant type)2639 void faddp(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2640 assert(type == D || type == S, "Wrong type for faddp");
2641 starti;
2642 f(0b011111100, 31, 23);
2643 f(type == D ? 1 : 0, 22);
2644 f(0b110000110110, 21, 10);
2645 rf(Vn, 5), rf(Vd, 0);
2646 }
2647
ins(FloatRegister Vd,SIMD_RegVariant T,FloatRegister Vn,int didx,int sidx)2648 void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
2649 starti;
2650 assert(T != Q, "invalid register variant");
2651 f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
2652 f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
2653 }
2654
2655 #define INSN(NAME, op) \
2656 void NAME(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) { \
2657 starti; \
2658 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21); \
2659 f(((idx<<1)|1)<<(int)T, 20, 16), f(op, 15, 10); \
2660 rf(Vn, 5), rf(Rd, 0); \
2661 }
2662
2663 INSN(umov, 0b001111);
2664 INSN(smov, 0b001011);
2665 #undef INSN
2666
2667 #define INSN(NAME, opc, opc2, isSHR) \
2668 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
2669 starti; \
2670 /* The encodings for the immh:immb fields (bits 22:16) in *SHR are \
2671 * 0001 xxx 8B/16B, shift = 16 - UInt(immh:immb) \
2672 * 001x xxx 4H/8H, shift = 32 - UInt(immh:immb) \
2673 * 01xx xxx 2S/4S, shift = 64 - UInt(immh:immb) \
2674 * 1xxx xxx 1D/2D, shift = 128 - UInt(immh:immb) \
2675 * (1D is RESERVED) \
2676 * for SHL shift is calculated as: \
2677 * 0001 xxx 8B/16B, shift = UInt(immh:immb) - 8 \
2678 * 001x xxx 4H/8H, shift = UInt(immh:immb) - 16 \
2679 * 01xx xxx 2S/4S, shift = UInt(immh:immb) - 32 \
2680 * 1xxx xxx 1D/2D, shift = UInt(immh:immb) - 64 \
2681 * (1D is RESERVED) \
2682 */ \
2683 assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
2684 int cVal = (1 << (((T >> 1) + 3) + (isSHR ? 1 : 0))); \
2685 int encodedShift = isSHR ? cVal - shift : cVal + shift; \
2686 f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
2687 f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2688 }
2689
2690 INSN(shl, 0, 0b010101, /* isSHR = */ false);
2691 INSN(sshr, 0, 0b000001, /* isSHR = */ true);
2692 INSN(ushr, 1, 0b000001, /* isSHR = */ true);
2693 INSN(usra, 1, 0b000101, /* isSHR = */ true);
2694 INSN(ssra, 0, 0b000101, /* isSHR = */ true);
2695
2696 #undef INSN
2697
2698 #define INSN(NAME, opc, opc2, isSHR) \
2699 void NAME(FloatRegister Vd, FloatRegister Vn, int shift){ \
2700 starti; \
2701 int encodedShift = isSHR ? 128 - shift : 64 + shift; \
2702 f(0b01, 31, 30), f(opc, 29), f(0b111110, 28, 23), \
2703 f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2704 }
2705
2706 INSN(shld, 0, 0b010101, /* isSHR = */ false);
2707 INSN(sshrd, 0, 0b000001, /* isSHR = */ true);
2708 INSN(ushrd, 1, 0b000001, /* isSHR = */ true);
2709
2710 #undef INSN
2711
2712 private:
_xshll(sign_kind sign,FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb,int shift)2713 void _xshll(sign_kind sign, FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2714 starti;
2715 /* The encodings for the immh:immb fields (bits 22:16) are
2716 * 0001 xxx 8H, 8B/16B shift = xxx
2717 * 001x xxx 4S, 4H/8H shift = xxxx
2718 * 01xx xxx 2D, 2S/4S shift = xxxxx
2719 * 1xxx xxx RESERVED
2720 */
2721 assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement");
2722 assert((1 << ((Tb>>1)+3)) > shift, "Invalid shift value");
2723 f(0, 31), f(Tb & 1, 30), f(sign == SIGNED ? 0 : 1, 29), f(0b011110, 28, 23);
2724 f((1 << ((Tb>>1)+3))|shift, 22, 16);
2725 f(0b101001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2726 }
2727
2728 public:
ushll(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb,int shift)2729 void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2730 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2731 _xshll(UNSIGNED, Vd, Ta, Vn, Tb, shift);
2732 }
2733
ushll2(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb,int shift)2734 void ushll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2735 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2736 _xshll(UNSIGNED, Vd, Ta, Vn, Tb, shift);
2737 }
2738
uxtl(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb)2739 void uxtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
2740 ushll(Vd, Ta, Vn, Tb, 0);
2741 }
2742
sshll(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb,int shift)2743 void sshll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2744 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2745 _xshll(SIGNED, Vd, Ta, Vn, Tb, shift);
2746 }
2747
sshll2(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb,int shift)2748 void sshll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2749 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2750 _xshll(SIGNED, Vd, Ta, Vn, Tb, shift);
2751 }
2752
sxtl(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,SIMD_Arrangement Tb)2753 void sxtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
2754 sshll(Vd, Ta, Vn, Tb, 0);
2755 }
2756
2757 // Move from general purpose register
2758 // mov Vd.T[index], Rn
mov(FloatRegister Vd,SIMD_Arrangement T,int index,Register Xn)2759 void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) {
2760 starti;
2761 f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2762 f(0b000111, 15, 10), zrf(Xn, 5), rf(Vd, 0);
2763 }
2764
2765 // Move to general purpose register
2766 // mov Rd, Vn.T[index]
mov(Register Xd,FloatRegister Vn,SIMD_Arrangement T,int index)2767 void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) {
2768 guarantee(T >= T2S && T < T1Q, "only D and S arrangements are supported");
2769 starti;
2770 f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21);
2771 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2772 f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0);
2773 }
2774
2775 private:
_pmull(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,FloatRegister Vm,SIMD_Arrangement Tb)2776 void _pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2777 starti;
2778 assert((Ta == T1Q && (Tb == T1D || Tb == T2D)) ||
2779 (Ta == T8H && (Tb == T8B || Tb == T16B)), "Invalid Size specifier");
2780 int size = (Ta == T1Q) ? 0b11 : 0b00;
2781 f(0, 31), f(Tb & 1, 30), f(0b001110, 29, 24), f(size, 23, 22);
2782 f(1, 21), rf(Vm, 16), f(0b111000, 15, 10), rf(Vn, 5), rf(Vd, 0);
2783 }
2784
2785 public:
pmull(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,FloatRegister Vm,SIMD_Arrangement Tb)2786 void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2787 assert(Tb == T1D || Tb == T8B, "pmull assumes T1D or T8B as the second size specifier");
2788 _pmull(Vd, Ta, Vn, Vm, Tb);
2789 }
2790
pmull2(FloatRegister Vd,SIMD_Arrangement Ta,FloatRegister Vn,FloatRegister Vm,SIMD_Arrangement Tb)2791 void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2792 assert(Tb == T2D || Tb == T16B, "pmull2 assumes T2D or T16B as the second size specifier");
2793 _pmull(Vd, Ta, Vn, Vm, Tb);
2794 }
2795
uqxtn(FloatRegister Vd,SIMD_Arrangement Tb,FloatRegister Vn,SIMD_Arrangement Ta)2796 void uqxtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2797 starti;
2798 int size_b = (int)Tb >> 1;
2799 int size_a = (int)Ta >> 1;
2800 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2801 f(0, 31), f(Tb & 1, 30), f(0b101110, 29, 24), f(size_b, 23, 22);
2802 f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2803 }
2804
xtn(FloatRegister Vd,SIMD_Arrangement Tb,FloatRegister Vn,SIMD_Arrangement Ta)2805 void xtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2806 starti;
2807 int size_b = (int)Tb >> 1;
2808 int size_a = (int)Ta >> 1;
2809 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2810 f(0, 31), f(Tb & 1, 30), f(0b001110, 29, 24), f(size_b, 23, 22);
2811 f(0b100001001010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2812 }
2813
dup(FloatRegister Vd,SIMD_Arrangement T,Register Xs)2814 void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
2815 {
2816 starti;
2817 assert(T != T1D, "reserved encoding");
2818 f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2819 f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), zrf(Xs, 5), rf(Vd, 0);
2820 }
2821
dup(FloatRegister Vd,SIMD_Arrangement T,FloatRegister Vn,int index=0)2822 void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
2823 {
2824 starti;
2825 assert(T != T1D, "reserved encoding");
2826 f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2827 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2828 f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2829 }
2830
2831 // AdvSIMD ZIP/UZP/TRN
2832 #define INSN(NAME, opcode) \
2833 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2834 guarantee(T != T1D && T != T1Q, "invalid arrangement"); \
2835 starti; \
2836 f(0, 31), f(0b001110, 29, 24), f(0, 21), f(0, 15); \
2837 f(opcode, 14, 12), f(0b10, 11, 10); \
2838 rf(Vm, 16), rf(Vn, 5), rf(Vd, 0); \
2839 f(T & 1, 30), f(T >> 1, 23, 22); \
2840 }
2841
2842 INSN(uzp1, 0b001);
2843 INSN(trn1, 0b010);
2844 INSN(zip1, 0b011);
2845 INSN(uzp2, 0b101);
2846 INSN(trn2, 0b110);
2847 INSN(zip2, 0b111);
2848
2849 #undef INSN
2850
2851 // CRC32 instructions
2852 #define INSN(NAME, c, sf, sz) \
2853 void NAME(Register Rd, Register Rn, Register Rm) { \
2854 starti; \
2855 f(sf, 31), f(0b0011010110, 30, 21), f(0b010, 15, 13), f(c, 12); \
2856 f(sz, 11, 10), rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); \
2857 }
2858
2859 INSN(crc32b, 0, 0, 0b00);
2860 INSN(crc32h, 0, 0, 0b01);
2861 INSN(crc32w, 0, 0, 0b10);
2862 INSN(crc32x, 0, 1, 0b11);
2863 INSN(crc32cb, 1, 0, 0b00);
2864 INSN(crc32ch, 1, 0, 0b01);
2865 INSN(crc32cw, 1, 0, 0b10);
2866 INSN(crc32cx, 1, 1, 0b11);
2867
2868 #undef INSN
2869
2870 // Table vector lookup
2871 #define INSN(NAME, op) \
2872 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, unsigned registers, FloatRegister Vm) { \
2873 starti; \
2874 assert(T == T8B || T == T16B, "invalid arrangement"); \
2875 assert(0 < registers && registers <= 4, "invalid number of registers"); \
2876 f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21), rf(Vm, 16), f(0, 15); \
2877 f(registers - 1, 14, 13), f(op, 12),f(0b00, 11, 10), rf(Vn, 5), rf(Vd, 0); \
2878 }
2879
2880 INSN(tbl, 0);
2881 INSN(tbx, 1);
2882
2883 #undef INSN
2884
2885 // AdvSIMD two-reg misc
2886 // In this instruction group, the 2 bits in the size field ([23:22]) may be
2887 // fixed or determined by the "SIMD_Arrangement T", or both. The additional
2888 // parameter "tmask" is a 2-bit mask used to indicate which bits in the size
2889 // field are determined by the SIMD_Arrangement. The bit of "tmask" should be
2890 // set to 1 if corresponding bit marked as "x" in the ArmARM.
2891 #define INSN(NAME, U, size, tmask, opcode) \
2892 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2893 starti; \
2894 assert((ASSERTION), MSG); \
2895 f(0, 31), f((int)T & 1, 30), f(U, 29), f(0b01110, 28, 24); \
2896 f(size | ((int)(T >> 1) & tmask), 23, 22), f(0b10000, 21, 17); \
2897 f(opcode, 16, 12), f(0b10, 11, 10), rf(Vn, 5), rf(Vd, 0); \
2898 }
2899
2900 #define MSG "invalid arrangement"
2901
2902 #define ASSERTION (T == T2S || T == T4S || T == T2D)
2903 INSN(fsqrt, 1, 0b10, 0b01, 0b11111);
2904 INSN(fabs, 0, 0b10, 0b01, 0b01111);
2905 INSN(fneg, 1, 0b10, 0b01, 0b01111);
2906 INSN(frintn, 0, 0b00, 0b01, 0b11000);
2907 INSN(frintm, 0, 0b00, 0b01, 0b11001);
2908 INSN(frintp, 0, 0b10, 0b01, 0b11000);
2909 #undef ASSERTION
2910
2911 #define ASSERTION (T == T8B || T == T16B || T == T4H || T == T8H || T == T2S || T == T4S)
2912 INSN(rev64, 0, 0b00, 0b11, 0b00000);
2913 #undef ASSERTION
2914
2915 #define ASSERTION (T == T8B || T == T16B || T == T4H || T == T8H)
2916 INSN(rev32, 1, 0b00, 0b11, 0b00000);
2917 #undef ASSERTION
2918
2919 #define ASSERTION (T == T8B || T == T16B)
2920 INSN(rev16, 0, 0b00, 0b11, 0b00001);
2921 INSN(rbit, 1, 0b01, 0b00, 0b00101);
2922 #undef ASSERTION
2923
2924 #undef MSG
2925
2926 #undef INSN
2927
ext(FloatRegister Vd,SIMD_Arrangement T,FloatRegister Vn,FloatRegister Vm,int index)2928 void ext(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index)
2929 {
2930 starti;
2931 assert(T == T8B || T == T16B, "invalid arrangement");
2932 assert((T == T8B && index <= 0b0111) || (T == T16B && index <= 0b1111), "Invalid index value");
2933 f(0, 31), f((int)T & 1, 30), f(0b101110000, 29, 21);
2934 rf(Vm, 16), f(0, 15), f(index, 14, 11);
2935 f(0, 10), rf(Vn, 5), rf(Vd, 0);
2936 }
2937
2938 // SVE arithmetics - unpredicated
2939 #define INSN(NAME, opcode) \
2940 void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, FloatRegister Zm) { \
2941 starti; \
2942 assert(T != Q, "invalid register variant"); \
2943 f(0b00000100, 31, 24), f(T, 23, 22), f(1, 21), \
2944 rf(Zm, 16), f(0, 15, 13), f(opcode, 12, 10), rf(Zn, 5), rf(Zd, 0); \
2945 }
2946 INSN(sve_add, 0b000);
2947 INSN(sve_sub, 0b001);
2948 #undef INSN
2949
2950 // SVE floating-point arithmetic - unpredicated
2951 #define INSN(NAME, opcode) \
2952 void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, FloatRegister Zm) { \
2953 starti; \
2954 assert(T == S || T == D, "invalid register variant"); \
2955 f(0b01100101, 31, 24), f(T, 23, 22), f(0, 21), \
2956 rf(Zm, 16), f(0, 15, 13), f(opcode, 12, 10), rf(Zn, 5), rf(Zd, 0); \
2957 }
2958
2959 INSN(sve_fadd, 0b000);
2960 INSN(sve_fmul, 0b010);
2961 INSN(sve_fsub, 0b001);
2962 #undef INSN
2963
2964 private:
sve_predicate_reg_insn(unsigned op24,unsigned op13,FloatRegister Zd_or_Vd,SIMD_RegVariant T,PRegister Pg,FloatRegister Zn_or_Vn)2965 void sve_predicate_reg_insn(unsigned op24, unsigned op13,
2966 FloatRegister Zd_or_Vd, SIMD_RegVariant T,
2967 PRegister Pg, FloatRegister Zn_or_Vn) {
2968 starti;
2969 f(op24, 31, 24), f(T, 23, 22), f(op13, 21, 13);
2970 pgrf(Pg, 10), rf(Zn_or_Vn, 5), rf(Zd_or_Vd, 0);
2971 }
2972
2973 public:
2974
2975 // SVE integer arithmetics - predicate
2976 #define INSN(NAME, op1, op2) \
2977 void NAME(FloatRegister Zdn_or_Zd_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Znm_or_Vn) { \
2978 assert(T != Q, "invalid register variant"); \
2979 sve_predicate_reg_insn(op1, op2, Zdn_or_Zd_or_Vd, T, Pg, Znm_or_Vn); \
2980 }
2981
2982 INSN(sve_abs, 0b00000100, 0b010110101); // vector abs, unary
2983 INSN(sve_add, 0b00000100, 0b000000000); // vector add
2984 INSN(sve_andv, 0b00000100, 0b011010001); // bitwise and reduction to scalar
2985 INSN(sve_asr, 0b00000100, 0b010000100); // vector arithmetic shift right
2986 INSN(sve_cnt, 0b00000100, 0b011010101) // count non-zero bits
2987 INSN(sve_cpy, 0b00000101, 0b100000100); // copy scalar to each active vector element
2988 INSN(sve_eorv, 0b00000100, 0b011001001); // bitwise xor reduction to scalar
2989 INSN(sve_lsl, 0b00000100, 0b010011100); // vector logical shift left
2990 INSN(sve_lsr, 0b00000100, 0b010001100); // vector logical shift right
2991 INSN(sve_mul, 0b00000100, 0b010000000); // vector mul
2992 INSN(sve_neg, 0b00000100, 0b010111101); // vector neg, unary
2993 INSN(sve_not, 0b00000100, 0b011110101); // bitwise invert vector, unary
2994 INSN(sve_orv, 0b00000100, 0b011000001); // bitwise or reduction to scalar
2995 INSN(sve_smax, 0b00000100, 0b001000000); // signed maximum vectors
2996 INSN(sve_smaxv, 0b00000100, 0b001000001); // signed maximum reduction to scalar
2997 INSN(sve_smin, 0b00000100, 0b001010000); // signed minimum vectors
2998 INSN(sve_sminv, 0b00000100, 0b001010001); // signed minimum reduction to scalar
2999 INSN(sve_sub, 0b00000100, 0b000001000); // vector sub
3000 INSN(sve_uaddv, 0b00000100, 0b000001001); // unsigned add reduction to scalar
3001 #undef INSN
3002
3003 // SVE floating-point arithmetics - predicate
3004 #define INSN(NAME, op1, op2) \
3005 void NAME(FloatRegister Zd_or_Zdn_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn_or_Zm) { \
3006 assert(T == S || T == D, "invalid register variant"); \
3007 sve_predicate_reg_insn(op1, op2, Zd_or_Zdn_or_Vd, T, Pg, Zn_or_Zm); \
3008 }
3009
3010 INSN(sve_fabs, 0b00000100, 0b011100101);
3011 INSN(sve_fadd, 0b01100101, 0b000000100);
3012 INSN(sve_fadda, 0b01100101, 0b011000001); // add strictly-ordered reduction to scalar Vd
3013 INSN(sve_fdiv, 0b01100101, 0b001101100);
3014 INSN(sve_fmax, 0b01100101, 0b000110100); // floating-point maximum
3015 INSN(sve_fmaxv, 0b01100101, 0b000110001); // floating-point maximum recursive reduction to scalar
3016 INSN(sve_fmin, 0b01100101, 0b000111100); // floating-point minimum
3017 INSN(sve_fminv, 0b01100101, 0b000111001); // floating-point minimum recursive reduction to scalar
3018 INSN(sve_fmul, 0b01100101, 0b000010100);
3019 INSN(sve_fneg, 0b00000100, 0b011101101);
3020 INSN(sve_frintm, 0b01100101, 0b000010101); // floating-point round to integral value, toward minus infinity
3021 INSN(sve_frintn, 0b01100101, 0b000000101); // floating-point round to integral value, nearest with ties to even
3022 INSN(sve_frintp, 0b01100101, 0b000001101); // floating-point round to integral value, toward plus infinity
3023 INSN(sve_fsqrt, 0b01100101, 0b001101101);
3024 INSN(sve_fsub, 0b01100101, 0b000001100);
3025 #undef INSN
3026
3027 // SVE multiple-add/sub - predicated
3028 #define INSN(NAME, op0, op1, op2) \
3029 void NAME(FloatRegister Zda, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn, FloatRegister Zm) { \
3030 starti; \
3031 assert(T != Q, "invalid size"); \
3032 f(op0, 31, 24), f(T, 23, 22), f(op1, 21), rf(Zm, 16); \
3033 f(op2, 15, 13), pgrf(Pg, 10), rf(Zn, 5), rf(Zda, 0); \
3034 }
3035
3036 INSN(sve_fmla, 0b01100101, 1, 0b000); // floating-point fused multiply-add: Zda = Zda + Zn * Zm
3037 INSN(sve_fmls, 0b01100101, 1, 0b001); // floating-point fused multiply-subtract: Zda = Zda + -Zn * Zm
3038 INSN(sve_fnmla, 0b01100101, 1, 0b010); // floating-point negated fused multiply-add: Zda = -Zda + -Zn * Zm
3039 INSN(sve_fnmls, 0b01100101, 1, 0b011); // floating-point negated fused multiply-subtract: Zda = -Zda + Zn * Zm
3040 INSN(sve_mla, 0b00000100, 0, 0b010); // multiply-add: Zda = Zda + Zn*Zm
3041 INSN(sve_mls, 0b00000100, 0, 0b011); // multiply-subtract: Zda = Zda + -Zn*Zm
3042 #undef INSN
3043
3044 // SVE bitwise logical - unpredicated
3045 #define INSN(NAME, opc) \
3046 void NAME(FloatRegister Zd, FloatRegister Zn, FloatRegister Zm) { \
3047 starti; \
3048 f(0b00000100, 31, 24), f(opc, 23, 22), f(1, 21), \
3049 rf(Zm, 16), f(0b001100, 15, 10), rf(Zn, 5), rf(Zd, 0); \
3050 }
3051 INSN(sve_and, 0b00);
3052 INSN(sve_eor, 0b10);
3053 INSN(sve_orr, 0b01);
3054 #undef INSN
3055
3056 // SVE shift immediate - unpredicated
3057 #define INSN(NAME, opc, isSHR) \
3058 void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, int shift) { \
3059 starti; \
3060 /* The encodings for the tszh:tszl:imm3 fields (bits 23:22 20:19 18:16) \
3061 * for shift right is calculated as: \
3062 * 0001 xxx B, shift = 16 - UInt(tszh:tszl:imm3) \
3063 * 001x xxx H, shift = 32 - UInt(tszh:tszl:imm3) \
3064 * 01xx xxx S, shift = 64 - UInt(tszh:tszl:imm3) \
3065 * 1xxx xxx D, shift = 128 - UInt(tszh:tszl:imm3) \
3066 * for shift left is calculated as: \
3067 * 0001 xxx B, shift = UInt(tszh:tszl:imm3) - 8 \
3068 * 001x xxx H, shift = UInt(tszh:tszl:imm3) - 16 \
3069 * 01xx xxx S, shift = UInt(tszh:tszl:imm3) - 32 \
3070 * 1xxx xxx D, shift = UInt(tszh:tszl:imm3) - 64 \
3071 */ \
3072 assert(T != Q, "Invalid register variant"); \
3073 if (isSHR) { \
3074 assert(((1 << (T + 3)) >= shift) && (shift > 0) , "Invalid shift value"); \
3075 } else { \
3076 assert(((1 << (T + 3)) > shift) && (shift >= 0) , "Invalid shift value"); \
3077 } \
3078 int cVal = (1 << ((T + 3) + (isSHR ? 1 : 0))); \
3079 int encodedShift = isSHR ? cVal - shift : cVal + shift; \
3080 int tszh = encodedShift >> 5; \
3081 int tszl_imm = encodedShift & 0x1f; \
3082 f(0b00000100, 31, 24); \
3083 f(tszh, 23, 22), f(1,21), f(tszl_imm, 20, 16); \
3084 f(0b100, 15, 13), f(opc, 12, 10), rf(Zn, 5), rf(Zd, 0); \
3085 }
3086
3087 INSN(sve_asr, 0b100, /* isSHR = */ true);
3088 INSN(sve_lsl, 0b111, /* isSHR = */ false);
3089 INSN(sve_lsr, 0b101, /* isSHR = */ true);
3090 #undef INSN
3091
3092 private:
3093
3094 // Scalar base + immediate index
sve_ld_st1(FloatRegister Zt,Register Xn,int imm,PRegister Pg,SIMD_RegVariant T,int op1,int type,int op2)3095 void sve_ld_st1(FloatRegister Zt, Register Xn, int imm, PRegister Pg,
3096 SIMD_RegVariant T, int op1, int type, int op2) {
3097 starti;
3098 assert_cond(T >= type);
3099 f(op1, 31, 25), f(type, 24, 23), f(T, 22, 21);
3100 f(0, 20), sf(imm, 19, 16), f(op2, 15, 13);
3101 pgrf(Pg, 10), srf(Xn, 5), rf(Zt, 0);
3102 }
3103
3104 // Scalar base + scalar index
sve_ld_st1(FloatRegister Zt,Register Xn,Register Xm,PRegister Pg,SIMD_RegVariant T,int op1,int type,int op2)3105 void sve_ld_st1(FloatRegister Zt, Register Xn, Register Xm, PRegister Pg,
3106 SIMD_RegVariant T, int op1, int type, int op2) {
3107 starti;
3108 assert_cond(T >= type);
3109 f(op1, 31, 25), f(type, 24, 23), f(T, 22, 21);
3110 rf(Xm, 16), f(op2, 15, 13);
3111 pgrf(Pg, 10), srf(Xn, 5), rf(Zt, 0);
3112 }
3113
sve_ld_st1(FloatRegister Zt,PRegister Pg,SIMD_RegVariant T,const Address & a,int op1,int type,int imm_op2,int scalar_op2)3114 void sve_ld_st1(FloatRegister Zt, PRegister Pg,
3115 SIMD_RegVariant T, const Address &a,
3116 int op1, int type, int imm_op2, int scalar_op2) {
3117 switch (a.getMode()) {
3118 case Address::base_plus_offset:
3119 sve_ld_st1(Zt, a.base(), a.offset(), Pg, T, op1, type, imm_op2);
3120 break;
3121 case Address::base_plus_offset_reg:
3122 sve_ld_st1(Zt, a.base(), a.index(), Pg, T, op1, type, scalar_op2);
3123 break;
3124 default:
3125 ShouldNotReachHere();
3126 }
3127 }
3128
3129 public:
3130
3131 // SVE load/store - predicated
3132 #define INSN(NAME, op1, type, imm_op2, scalar_op2) \
3133 void NAME(FloatRegister Zt, SIMD_RegVariant T, PRegister Pg, const Address &a) { \
3134 assert(T != Q, "invalid register variant"); \
3135 sve_ld_st1(Zt, Pg, T, a, op1, type, imm_op2, scalar_op2); \
3136 }
3137
3138 INSN(sve_ld1b, 0b1010010, 0b00, 0b101, 0b010);
3139 INSN(sve_st1b, 0b1110010, 0b00, 0b111, 0b010);
3140 INSN(sve_ld1h, 0b1010010, 0b01, 0b101, 0b010);
3141 INSN(sve_st1h, 0b1110010, 0b01, 0b111, 0b010);
3142 INSN(sve_ld1w, 0b1010010, 0b10, 0b101, 0b010);
3143 INSN(sve_st1w, 0b1110010, 0b10, 0b111, 0b010);
3144 INSN(sve_ld1d, 0b1010010, 0b11, 0b101, 0b010);
3145 INSN(sve_st1d, 0b1110010, 0b11, 0b111, 0b010);
3146 #undef INSN
3147
3148 // SVE load/store - unpredicated
3149 #define INSN(NAME, op1) \
3150 void NAME(FloatRegister Zt, const Address &a) { \
3151 starti; \
3152 assert(a.index() == noreg, "invalid address variant"); \
3153 f(op1, 31, 29), f(0b0010110, 28, 22), sf(a.offset() >> 3, 21, 16), \
3154 f(0b010, 15, 13), f(a.offset() & 0x7, 12, 10), srf(a.base(), 5), rf(Zt, 0); \
3155 }
3156
3157 INSN(sve_ldr, 0b100); // LDR (vector)
3158 INSN(sve_str, 0b111); // STR (vector)
3159 #undef INSN
3160
3161 #define INSN(NAME, op) \
3162 void NAME(Register Xd, Register Xn, int imm6) { \
3163 starti; \
3164 f(0b000001000, 31, 23), f(op, 22, 21); \
3165 srf(Xn, 16), f(0b01010, 15, 11), sf(imm6, 10, 5), srf(Xd, 0); \
3166 }
3167
3168 INSN(sve_addvl, 0b01);
3169 INSN(sve_addpl, 0b11);
3170 #undef INSN
3171
3172 // SVE inc/dec register by element count
3173 #define INSN(NAME, op) \
3174 void NAME(Register Xdn, SIMD_RegVariant T, unsigned imm4 = 1, int pattern = 0b11111) { \
3175 starti; \
3176 assert(T != Q, "invalid size"); \
3177 f(0b00000100,31, 24), f(T, 23, 22), f(0b11, 21, 20); \
3178 f(imm4 - 1, 19, 16), f(0b11100, 15, 11), f(op, 10), f(pattern, 9, 5), rf(Xdn, 0); \
3179 }
3180
3181 INSN(sve_inc, 0);
3182 INSN(sve_dec, 1);
3183 #undef INSN
3184
3185 // SVE predicate count
sve_cntp(Register Xd,SIMD_RegVariant T,PRegister Pg,PRegister Pn)3186 void sve_cntp(Register Xd, SIMD_RegVariant T, PRegister Pg, PRegister Pn) {
3187 starti;
3188 assert(T != Q, "invalid size");
3189 f(0b00100101, 31, 24), f(T, 23, 22), f(0b10000010, 21, 14);
3190 prf(Pg, 10), f(0, 9), prf(Pn, 5), rf(Xd, 0);
3191 }
3192
3193 // SVE dup scalar
sve_dup(FloatRegister Zd,SIMD_RegVariant T,Register Rn)3194 void sve_dup(FloatRegister Zd, SIMD_RegVariant T, Register Rn) {
3195 starti;
3196 assert(T != Q, "invalid size");
3197 f(0b00000101, 31, 24), f(T, 23, 22), f(0b100000001110, 21, 10);
3198 srf(Rn, 5), rf(Zd, 0);
3199 }
3200
3201 // SVE dup imm
sve_dup(FloatRegister Zd,SIMD_RegVariant T,int imm8)3202 void sve_dup(FloatRegister Zd, SIMD_RegVariant T, int imm8) {
3203 starti;
3204 assert(T != Q, "invalid size");
3205 int sh = 0;
3206 if (imm8 <= 127 && imm8 >= -128) {
3207 sh = 0;
3208 } else if (T != B && imm8 <= 32512 && imm8 >= -32768 && (imm8 & 0xff) == 0) {
3209 sh = 1;
3210 imm8 = (imm8 >> 8);
3211 } else {
3212 guarantee(false, "invalid immediate");
3213 }
3214 f(0b00100101, 31, 24), f(T, 23, 22), f(0b11100011, 21, 14);
3215 f(sh, 13), sf(imm8, 12, 5), rf(Zd, 0);
3216 }
3217
sve_ptrue(PRegister pd,SIMD_RegVariant esize,int pattern=0b11111)3218 void sve_ptrue(PRegister pd, SIMD_RegVariant esize, int pattern = 0b11111) {
3219 starti;
3220 f(0b00100101, 31, 24), f(esize, 23, 22), f(0b011000111000, 21, 10);
3221 f(pattern, 9, 5), f(0b0, 4), prf(pd, 0);
3222 }
3223
Assembler(CodeBuffer * code)3224 Assembler(CodeBuffer* code) : AbstractAssembler(code) {
3225 }
3226
3227 // Stack overflow checking
3228 virtual void bang_stack_with_offset(int offset);
3229
3230 static bool operand_valid_for_logical_immediate(bool is32, uint64_t imm);
3231 static bool operand_valid_for_add_sub_immediate(int64_t imm);
3232 static bool operand_valid_for_float_immediate(double imm);
3233
3234 void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0);
3235 void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0);
3236 };
3237
operator |(Assembler::Membar_mask_bits a,Assembler::Membar_mask_bits b)3238 inline Assembler::Membar_mask_bits operator|(Assembler::Membar_mask_bits a,
3239 Assembler::Membar_mask_bits b) {
3240 return Assembler::Membar_mask_bits(unsigned(a)|unsigned(b));
3241 }
3242
~Instruction_aarch64()3243 Instruction_aarch64::~Instruction_aarch64() {
3244 assem->emit();
3245 }
3246
3247 #undef starti
3248
3249 // Invert a condition
operator ~(const Assembler::Condition cond)3250 inline const Assembler::Condition operator~(const Assembler::Condition cond) {
3251 return Assembler::Condition(int(cond) ^ 1);
3252 }
3253
3254 class BiasedLockingCounters;
3255
3256 extern "C" void das(uint64_t start, int len);
3257
3258 #endif // CPU_AARCH64_ASSEMBLER_AARCH64_HPP
3259