Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp
32285 views
1
/*
2
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2013, 2019, 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_VM_ASSEMBLER_AARCH64_HPP
27
#define CPU_AARCH64_VM_ASSEMBLER_AARCH64_HPP
28
29
#include "asm/register.hpp"
30
31
// definitions of various symbolic names for machine registers
32
33
// First intercalls between C and Java which use 8 general registers
34
// and 8 floating registers
35
36
// we also have to copy between x86 and ARM registers but that's a
37
// secondary complication -- not all code employing C call convention
38
// executes as x86 code though -- we generate some of it
39
40
class Argument VALUE_OBJ_CLASS_SPEC {
41
public:
42
enum {
43
n_int_register_parameters_c = 8, // r0, r1, ... r7 (c_rarg0, c_rarg1, ...)
44
n_float_register_parameters_c = 8, // v0, v1, ... v7 (c_farg0, c_farg1, ... )
45
46
n_int_register_parameters_j = 8, // r1, ... r7, r0 (rj_rarg0, j_rarg1, ...
47
n_float_register_parameters_j = 8 // v0, v1, ... v7 (j_farg0, j_farg1, ...
48
};
49
};
50
51
REGISTER_DECLARATION(Register, c_rarg0, r0);
52
REGISTER_DECLARATION(Register, c_rarg1, r1);
53
REGISTER_DECLARATION(Register, c_rarg2, r2);
54
REGISTER_DECLARATION(Register, c_rarg3, r3);
55
REGISTER_DECLARATION(Register, c_rarg4, r4);
56
REGISTER_DECLARATION(Register, c_rarg5, r5);
57
REGISTER_DECLARATION(Register, c_rarg6, r6);
58
REGISTER_DECLARATION(Register, c_rarg7, r7);
59
60
REGISTER_DECLARATION(FloatRegister, c_farg0, v0);
61
REGISTER_DECLARATION(FloatRegister, c_farg1, v1);
62
REGISTER_DECLARATION(FloatRegister, c_farg2, v2);
63
REGISTER_DECLARATION(FloatRegister, c_farg3, v3);
64
REGISTER_DECLARATION(FloatRegister, c_farg4, v4);
65
REGISTER_DECLARATION(FloatRegister, c_farg5, v5);
66
REGISTER_DECLARATION(FloatRegister, c_farg6, v6);
67
REGISTER_DECLARATION(FloatRegister, c_farg7, v7);
68
69
// Symbolically name the register arguments used by the Java calling convention.
70
// We have control over the convention for java so we can do what we please.
71
// What pleases us is to offset the java calling convention so that when
72
// we call a suitable jni method the arguments are lined up and we don't
73
// have to do much shuffling. A suitable jni method is non-static and a
74
// small number of arguments
75
//
76
// |--------------------------------------------------------------------|
77
// | c_rarg0 c_rarg1 c_rarg2 c_rarg3 c_rarg4 c_rarg5 c_rarg6 c_rarg7 |
78
// |--------------------------------------------------------------------|
79
// | r0 r1 r2 r3 r4 r5 r6 r7 |
80
// |--------------------------------------------------------------------|
81
// | j_rarg7 j_rarg0 j_rarg1 j_rarg2 j_rarg3 j_rarg4 j_rarg5 j_rarg6 |
82
// |--------------------------------------------------------------------|
83
84
85
REGISTER_DECLARATION(Register, j_rarg0, c_rarg1);
86
REGISTER_DECLARATION(Register, j_rarg1, c_rarg2);
87
REGISTER_DECLARATION(Register, j_rarg2, c_rarg3);
88
REGISTER_DECLARATION(Register, j_rarg3, c_rarg4);
89
REGISTER_DECLARATION(Register, j_rarg4, c_rarg5);
90
REGISTER_DECLARATION(Register, j_rarg5, c_rarg6);
91
REGISTER_DECLARATION(Register, j_rarg6, c_rarg7);
92
REGISTER_DECLARATION(Register, j_rarg7, c_rarg0);
93
94
// Java floating args are passed as per C
95
96
REGISTER_DECLARATION(FloatRegister, j_farg0, v0);
97
REGISTER_DECLARATION(FloatRegister, j_farg1, v1);
98
REGISTER_DECLARATION(FloatRegister, j_farg2, v2);
99
REGISTER_DECLARATION(FloatRegister, j_farg3, v3);
100
REGISTER_DECLARATION(FloatRegister, j_farg4, v4);
101
REGISTER_DECLARATION(FloatRegister, j_farg5, v5);
102
REGISTER_DECLARATION(FloatRegister, j_farg6, v6);
103
REGISTER_DECLARATION(FloatRegister, j_farg7, v7);
104
105
// registers used to hold VM data either temporarily within a method
106
// or across method calls
107
108
// volatile (caller-save) registers
109
110
// r8 is used for indirect result location return
111
// we use it and r9 as scratch registers
112
REGISTER_DECLARATION(Register, rscratch1, r8);
113
REGISTER_DECLARATION(Register, rscratch2, r9);
114
115
// current method -- must be in a call-clobbered register
116
REGISTER_DECLARATION(Register, rmethod, r12);
117
118
// non-volatile (callee-save) registers are r16-29
119
// of which the following are dedicated global state
120
121
// link register
122
REGISTER_DECLARATION(Register, lr, r30);
123
// frame pointer
124
REGISTER_DECLARATION(Register, rfp, r29);
125
// current thread
126
REGISTER_DECLARATION(Register, rthread, r28);
127
// base of heap
128
REGISTER_DECLARATION(Register, rheapbase, r27);
129
// constant pool cache
130
REGISTER_DECLARATION(Register, rcpool, r26);
131
// monitors allocated on stack
132
REGISTER_DECLARATION(Register, rmonitors, r25);
133
// locals on stack
134
REGISTER_DECLARATION(Register, rlocals, r24);
135
// bytecode pointer
136
REGISTER_DECLARATION(Register, rbcp, r22);
137
// Dispatch table base
138
REGISTER_DECLARATION(Register, rdispatch, r21);
139
// Java stack pointer
140
REGISTER_DECLARATION(Register, esp, r20);
141
142
// TODO : x86 uses rbp to save SP in method handle code
143
// we may need to do the same with fp
144
// JSR 292 fixed register usages:
145
//REGISTER_DECLARATION(Register, r_mh_SP_save, r29);
146
147
#define assert_cond(ARG1) assert(ARG1, #ARG1)
148
149
namespace asm_util {
150
uint32_t encode_logical_immediate(bool is32, uint64_t imm);
151
};
152
153
using namespace asm_util;
154
155
156
class Assembler;
157
158
class Instruction_aarch64 {
159
unsigned insn;
160
#ifdef ASSERT
161
unsigned bits;
162
#endif
163
Assembler *assem;
164
165
public:
166
167
Instruction_aarch64(class Assembler *as) {
168
#ifdef ASSERT
169
bits = 0;
170
#endif
171
insn = 0;
172
assem = as;
173
}
174
175
inline ~Instruction_aarch64();
176
177
unsigned &get_insn() { return insn; }
178
#ifdef ASSERT
179
unsigned &get_bits() { return bits; }
180
#endif
181
182
static inline int32_t extend(unsigned val, int hi = 31, int lo = 0) {
183
union {
184
unsigned u;
185
int n;
186
};
187
188
u = val << (31 - hi);
189
n = n >> (31 - hi + lo);
190
return n;
191
}
192
193
static inline uint32_t extract(uint32_t val, int msb, int lsb) {
194
int nbits = msb - lsb + 1;
195
assert_cond(msb >= lsb);
196
uint32_t mask = (1U << nbits) - 1;
197
uint32_t result = val >> lsb;
198
result &= mask;
199
return result;
200
}
201
202
static inline int32_t sextract(uint32_t val, int msb, int lsb) {
203
uint32_t uval = extract(val, msb, lsb);
204
return extend(uval, msb - lsb);
205
}
206
207
static void patch(address a, int msb, int lsb, unsigned long val) {
208
int nbits = msb - lsb + 1;
209
guarantee(val < (1U << nbits), "Field too big for insn");
210
assert_cond(msb >= lsb);
211
unsigned mask = (1U << nbits) - 1;
212
val <<= lsb;
213
mask <<= lsb;
214
unsigned target = *(unsigned *)a;
215
target &= ~mask;
216
target |= val;
217
*(unsigned *)a = target;
218
}
219
220
static void spatch(address a, int msb, int lsb, long val) {
221
int nbits = msb - lsb + 1;
222
long chk = val >> (nbits - 1);
223
guarantee (chk == -1 || chk == 0, "Field too big for insn");
224
unsigned uval = val;
225
unsigned mask = (1U << nbits) - 1;
226
uval &= mask;
227
uval <<= lsb;
228
mask <<= lsb;
229
unsigned target = *(unsigned *)a;
230
target &= ~mask;
231
target |= uval;
232
*(unsigned *)a = target;
233
}
234
235
void f(unsigned val, int msb, int lsb) {
236
int nbits = msb - lsb + 1;
237
guarantee(val < (1U << nbits), "Field too big for insn");
238
assert_cond(msb >= lsb);
239
unsigned mask = (1U << nbits) - 1;
240
val <<= lsb;
241
mask <<= lsb;
242
insn |= val;
243
assert_cond((bits & mask) == 0);
244
#ifdef ASSERT
245
bits |= mask;
246
#endif
247
}
248
249
void f(unsigned val, int bit) {
250
f(val, bit, bit);
251
}
252
253
void sf(long val, int msb, int lsb) {
254
int nbits = msb - lsb + 1;
255
long chk = val >> (nbits - 1);
256
guarantee (chk == -1 || chk == 0, "Field too big for insn");
257
unsigned uval = val;
258
unsigned mask = (1U << nbits) - 1;
259
uval &= mask;
260
f(uval, lsb + nbits - 1, lsb);
261
}
262
263
void rf(Register r, int lsb) {
264
f(r->encoding_nocheck(), lsb + 4, lsb);
265
}
266
267
// reg|ZR
268
void zrf(Register r, int lsb) {
269
f(r->encoding_nocheck() - (r == zr), lsb + 4, lsb);
270
}
271
272
// reg|SP
273
void srf(Register r, int lsb) {
274
f(r == sp ? 31 : r->encoding_nocheck(), lsb + 4, lsb);
275
}
276
277
void rf(FloatRegister r, int lsb) {
278
f(r->encoding_nocheck(), lsb + 4, lsb);
279
}
280
281
unsigned get(int msb = 31, int lsb = 0) {
282
int nbits = msb - lsb + 1;
283
unsigned mask = ((1U << nbits) - 1) << lsb;
284
assert_cond((bits & mask) == mask);
285
return (insn & mask) >> lsb;
286
}
287
288
void fixed(unsigned value, unsigned mask) {
289
assert_cond ((mask & bits) == 0);
290
#ifdef ASSERT
291
bits |= mask;
292
#endif
293
insn |= value;
294
}
295
};
296
297
#define starti Instruction_aarch64 do_not_use(this); set_current(&do_not_use)
298
299
class PrePost {
300
int _offset;
301
Register _r;
302
public:
303
PrePost(Register reg, int o) : _r(reg), _offset(o) { }
304
int offset() { return _offset; }
305
Register reg() { return _r; }
306
};
307
308
class Pre : public PrePost {
309
public:
310
Pre(Register reg, int o) : PrePost(reg, o) { }
311
};
312
class Post : public PrePost {
313
public:
314
Post(Register reg, int o) : PrePost(reg, o) { }
315
};
316
317
namespace ext
318
{
319
enum operation { uxtb, uxth, uxtw, uxtx, sxtb, sxth, sxtw, sxtx };
320
};
321
322
// Addressing modes
323
class Address VALUE_OBJ_CLASS_SPEC {
324
public:
325
326
enum mode { no_mode, base_plus_offset, pre, post, pcrel,
327
base_plus_offset_reg, literal };
328
329
// Shift and extend for base reg + reg offset addressing
330
class extend {
331
int _option, _shift;
332
ext::operation _op;
333
public:
334
extend() { }
335
extend(int s, int o, ext::operation op) : _shift(s), _option(o), _op(op) { }
336
int option() const{ return _option; }
337
int shift() const { return _shift; }
338
ext::operation op() const { return _op; }
339
};
340
class uxtw : public extend {
341
public:
342
uxtw(int shift = -1): extend(shift, 0b010, ext::uxtw) { }
343
};
344
class lsl : public extend {
345
public:
346
lsl(int shift = -1): extend(shift, 0b011, ext::uxtx) { }
347
};
348
class sxtw : public extend {
349
public:
350
sxtw(int shift = -1): extend(shift, 0b110, ext::sxtw) { }
351
};
352
class sxtx : public extend {
353
public:
354
sxtx(int shift = -1): extend(shift, 0b111, ext::sxtx) { }
355
};
356
357
private:
358
Register _base;
359
Register _index;
360
long _offset;
361
enum mode _mode;
362
extend _ext;
363
364
RelocationHolder _rspec;
365
366
// Typically we use AddressLiterals we want to use their rval
367
// However in some situations we want the lval (effect address) of
368
// the item. We provide a special factory for making those lvals.
369
bool _is_lval;
370
371
// If the target is far we'll need to load the ea of this to a
372
// register to reach it. Otherwise if near we can do PC-relative
373
// addressing.
374
address _target;
375
376
public:
377
Address()
378
: _mode(no_mode) { }
379
Address(Register r)
380
: _mode(base_plus_offset), _base(r), _offset(0), _index(noreg), _target(0) { }
381
Address(Register r, int o)
382
: _mode(base_plus_offset), _base(r), _offset(o), _index(noreg), _target(0) { }
383
Address(Register r, long o)
384
: _mode(base_plus_offset), _base(r), _offset(o), _index(noreg), _target(0) { }
385
Address(Register r, unsigned long o)
386
: _mode(base_plus_offset), _base(r), _offset(o), _index(noreg), _target(0) { }
387
#ifdef ASSERT
388
Address(Register r, ByteSize disp)
389
: _mode(base_plus_offset), _base(r), _offset(in_bytes(disp)),
390
_index(noreg), _target(0) { }
391
#endif
392
Address(Register r, Register r1, extend ext = lsl())
393
: _mode(base_plus_offset_reg), _base(r), _index(r1),
394
_ext(ext), _offset(0), _target(0) { }
395
Address(Pre p)
396
: _mode(pre), _base(p.reg()), _offset(p.offset()) { }
397
Address(Post p)
398
: _mode(post), _base(p.reg()), _offset(p.offset()), _target(0) { }
399
Address(address target, RelocationHolder const& rspec)
400
: _mode(literal),
401
_rspec(rspec),
402
_is_lval(false),
403
_target(target) { }
404
Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);
405
Address(Register base, RegisterOrConstant index, extend ext = lsl())
406
: _base (base),
407
_ext(ext), _offset(0), _target(0) {
408
if (index.is_register()) {
409
_mode = base_plus_offset_reg;
410
_index = index.as_register();
411
} else {
412
guarantee(ext.option() == ext::uxtx, "should be");
413
assert(index.is_constant(), "should be");
414
_mode = base_plus_offset;
415
_offset = index.as_constant() << ext.shift();
416
}
417
}
418
419
Register base() const {
420
guarantee((_mode == base_plus_offset | _mode == base_plus_offset_reg
421
| _mode == post),
422
"wrong mode");
423
return _base;
424
}
425
long offset() const {
426
return _offset;
427
}
428
Register index() const {
429
return _index;
430
}
431
mode getMode() const {
432
return _mode;
433
}
434
bool uses(Register reg) const { return _base == reg || _index == reg; }
435
address target() const { return _target; }
436
const RelocationHolder& rspec() const { return _rspec; }
437
438
void encode(Instruction_aarch64 *i) const {
439
i->f(0b111, 29, 27);
440
i->srf(_base, 5);
441
442
switch(_mode) {
443
case base_plus_offset:
444
{
445
unsigned size = i->get(31, 30);
446
if (i->get(26, 26) && i->get(23, 23)) {
447
// SIMD Q Type - Size = 128 bits
448
assert(size == 0, "bad size");
449
size = 0b100;
450
}
451
unsigned mask = (1 << size) - 1;
452
if (_offset < 0 || _offset & mask)
453
{
454
i->f(0b00, 25, 24);
455
i->f(0, 21), i->f(0b00, 11, 10);
456
i->sf(_offset, 20, 12);
457
} else {
458
i->f(0b01, 25, 24);
459
i->f(_offset >> size, 21, 10);
460
}
461
}
462
break;
463
464
case base_plus_offset_reg:
465
{
466
i->f(0b00, 25, 24);
467
i->f(1, 21);
468
i->rf(_index, 16);
469
i->f(_ext.option(), 15, 13);
470
unsigned size = i->get(31, 30);
471
if (i->get(26, 26) && i->get(23, 23)) {
472
// SIMD Q Type - Size = 128 bits
473
assert(size == 0, "bad size");
474
size = 0b100;
475
}
476
if (size == 0) // It's a byte
477
i->f(_ext.shift() >= 0, 12);
478
else {
479
if (_ext.shift() > 0)
480
assert(_ext.shift() == (int)size, "bad shift");
481
i->f(_ext.shift() > 0, 12);
482
}
483
i->f(0b10, 11, 10);
484
}
485
break;
486
487
case pre:
488
i->f(0b00, 25, 24);
489
i->f(0, 21), i->f(0b11, 11, 10);
490
i->sf(_offset, 20, 12);
491
break;
492
493
case post:
494
i->f(0b00, 25, 24);
495
i->f(0, 21), i->f(0b01, 11, 10);
496
i->sf(_offset, 20, 12);
497
break;
498
499
default:
500
ShouldNotReachHere();
501
}
502
}
503
504
void encode_pair(Instruction_aarch64 *i) const {
505
switch(_mode) {
506
case base_plus_offset:
507
i->f(0b010, 25, 23);
508
break;
509
case pre:
510
i->f(0b011, 25, 23);
511
break;
512
case post:
513
i->f(0b001, 25, 23);
514
break;
515
default:
516
ShouldNotReachHere();
517
}
518
519
unsigned size; // Operand shift in 32-bit words
520
521
if (i->get(26, 26)) { // float
522
switch(i->get(31, 30)) {
523
case 0b10:
524
size = 2; break;
525
case 0b01:
526
size = 1; break;
527
case 0b00:
528
size = 0; break;
529
default:
530
ShouldNotReachHere();
531
}
532
} else {
533
size = i->get(31, 31);
534
}
535
536
size = 4 << size;
537
guarantee(_offset % size == 0, "bad offset");
538
i->sf(_offset / size, 21, 15);
539
i->srf(_base, 5);
540
}
541
542
void encode_nontemporal_pair(Instruction_aarch64 *i) const {
543
// Only base + offset is allowed
544
i->f(0b000, 25, 23);
545
unsigned size = i->get(31, 31);
546
size = 4 << size;
547
guarantee(_offset % size == 0, "bad offset");
548
i->sf(_offset / size, 21, 15);
549
i->srf(_base, 5);
550
guarantee(_mode == Address::base_plus_offset,
551
"Bad addressing mode for non-temporal op");
552
}
553
554
void lea(MacroAssembler *, Register) const;
555
556
static bool offset_ok_for_immed(long offset, int shift = 0) {
557
unsigned mask = (1 << shift) - 1;
558
if (offset < 0 || offset & mask) {
559
return (uabs(offset) < (1 << (20 - 12))); // Unscaled offset
560
} else {
561
return ((offset >> shift) < (1 << (21 - 10 + 1))); // Scaled, unsigned offset
562
}
563
}
564
};
565
566
// Convience classes
567
class RuntimeAddress: public Address {
568
569
public:
570
571
RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {}
572
573
};
574
575
class OopAddress: public Address {
576
577
public:
578
579
OopAddress(address target) : Address(target, relocInfo::oop_type){}
580
581
};
582
583
class ExternalAddress: public Address {
584
private:
585
static relocInfo::relocType reloc_for_target(address target) {
586
// Sometimes ExternalAddress is used for values which aren't
587
// exactly addresses, like the card table base.
588
// external_word_type can't be used for values in the first page
589
// so just skip the reloc in that case.
590
return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
591
}
592
593
public:
594
595
ExternalAddress(address target) : Address(target, reloc_for_target(target)) {}
596
597
};
598
599
class InternalAddress: public Address {
600
601
public:
602
603
InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}
604
};
605
606
const int FPUStateSizeInWords = 32 * 2;
607
typedef enum {
608
PLDL1KEEP = 0b00000, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
609
PSTL1KEEP = 0b10000, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM,
610
PLIL1KEEP = 0b01000, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM
611
} prfop;
612
613
class Assembler : public AbstractAssembler {
614
615
#ifndef PRODUCT
616
static const unsigned long asm_bp;
617
618
void emit_long(jint x) {
619
if ((unsigned long)pc() == asm_bp)
620
asm volatile ("nop");
621
AbstractAssembler::emit_int32(x);
622
}
623
#else
624
void emit_long(jint x) {
625
AbstractAssembler::emit_int32(x);
626
}
627
#endif
628
629
public:
630
631
enum { instruction_size = 4 };
632
633
Address adjust(Register base, int offset, bool preIncrement) {
634
if (preIncrement)
635
return Address(Pre(base, offset));
636
else
637
return Address(Post(base, offset));
638
}
639
640
Address pre(Register base, int offset) {
641
return adjust(base, offset, true);
642
}
643
644
Address post (Register base, int offset) {
645
return adjust(base, offset, false);
646
}
647
648
Instruction_aarch64* current;
649
650
void set_current(Instruction_aarch64* i) { current = i; }
651
652
void f(unsigned val, int msb, int lsb) {
653
current->f(val, msb, lsb);
654
}
655
void f(unsigned val, int msb) {
656
current->f(val, msb, msb);
657
}
658
void sf(long val, int msb, int lsb) {
659
current->sf(val, msb, lsb);
660
}
661
void rf(Register reg, int lsb) {
662
current->rf(reg, lsb);
663
}
664
void srf(Register reg, int lsb) {
665
current->srf(reg, lsb);
666
}
667
void zrf(Register reg, int lsb) {
668
current->zrf(reg, lsb);
669
}
670
void rf(FloatRegister reg, int lsb) {
671
current->rf(reg, lsb);
672
}
673
void fixed(unsigned value, unsigned mask) {
674
current->fixed(value, mask);
675
}
676
677
void emit() {
678
emit_long(current->get_insn());
679
assert_cond(current->get_bits() == 0xffffffff);
680
current = NULL;
681
}
682
683
typedef void (Assembler::* uncond_branch_insn)(address dest);
684
typedef void (Assembler::* compare_and_branch_insn)(Register Rt, address dest);
685
typedef void (Assembler::* test_and_branch_insn)(Register Rt, int bitpos, address dest);
686
typedef void (Assembler::* prefetch_insn)(address target, prfop);
687
688
void wrap_label(Label &L, uncond_branch_insn insn);
689
void wrap_label(Register r, Label &L, compare_and_branch_insn insn);
690
void wrap_label(Register r, int bitpos, Label &L, test_and_branch_insn insn);
691
void wrap_label(Label &L, prfop, prefetch_insn insn);
692
693
// PC-rel. addressing
694
695
void adr(Register Rd, address dest);
696
void _adrp(Register Rd, address dest);
697
698
void adr(Register Rd, const Address &dest);
699
void _adrp(Register Rd, const Address &dest);
700
701
void adr(Register Rd, Label &L) {
702
wrap_label(Rd, L, &Assembler::Assembler::adr);
703
}
704
void _adrp(Register Rd, Label &L) {
705
wrap_label(Rd, L, &Assembler::_adrp);
706
}
707
708
void adrp(Register Rd, const Address &dest, unsigned long &offset);
709
710
#undef INSN
711
712
void add_sub_immediate(Register Rd, Register Rn, unsigned uimm, int op,
713
int negated_op);
714
715
// Add/subtract (immediate)
716
#define INSN(NAME, decode, negated) \
717
void NAME(Register Rd, Register Rn, unsigned imm, unsigned shift) { \
718
starti; \
719
f(decode, 31, 29), f(0b10001, 28, 24), f(shift, 23, 22), f(imm, 21, 10); \
720
zrf(Rd, 0), srf(Rn, 5); \
721
} \
722
\
723
void NAME(Register Rd, Register Rn, unsigned imm) { \
724
starti; \
725
add_sub_immediate(Rd, Rn, imm, decode, negated); \
726
}
727
728
INSN(addsw, 0b001, 0b011);
729
INSN(subsw, 0b011, 0b001);
730
INSN(adds, 0b101, 0b111);
731
INSN(subs, 0b111, 0b101);
732
733
#undef INSN
734
735
#define INSN(NAME, decode, negated) \
736
void NAME(Register Rd, Register Rn, unsigned imm) { \
737
starti; \
738
add_sub_immediate(Rd, Rn, imm, decode, negated); \
739
}
740
741
INSN(addw, 0b000, 0b010);
742
INSN(subw, 0b010, 0b000);
743
INSN(add, 0b100, 0b110);
744
INSN(sub, 0b110, 0b100);
745
746
#undef INSN
747
748
// Logical (immediate)
749
#define INSN(NAME, decode, is32) \
750
void NAME(Register Rd, Register Rn, uint64_t imm) { \
751
starti; \
752
uint32_t val = encode_logical_immediate(is32, imm); \
753
f(decode, 31, 29), f(0b100100, 28, 23), f(val, 22, 10); \
754
srf(Rd, 0), zrf(Rn, 5); \
755
}
756
757
INSN(andw, 0b000, true);
758
INSN(orrw, 0b001, true);
759
INSN(eorw, 0b010, true);
760
INSN(andr, 0b100, false);
761
INSN(orr, 0b101, false);
762
INSN(eor, 0b110, false);
763
764
#undef INSN
765
766
#define INSN(NAME, decode, is32) \
767
void NAME(Register Rd, Register Rn, uint64_t imm) { \
768
starti; \
769
uint32_t val = encode_logical_immediate(is32, imm); \
770
f(decode, 31, 29), f(0b100100, 28, 23), f(val, 22, 10); \
771
zrf(Rd, 0), zrf(Rn, 5); \
772
}
773
774
INSN(ands, 0b111, false);
775
INSN(andsw, 0b011, true);
776
777
#undef INSN
778
779
// Move wide (immediate)
780
#define INSN(NAME, opcode) \
781
void NAME(Register Rd, unsigned imm, unsigned shift = 0) { \
782
assert_cond((shift/16)*16 == shift); \
783
starti; \
784
f(opcode, 31, 29), f(0b100101, 28, 23), f(shift/16, 22, 21), \
785
f(imm, 20, 5); \
786
rf(Rd, 0); \
787
}
788
789
INSN(movnw, 0b000);
790
INSN(movzw, 0b010);
791
INSN(movkw, 0b011);
792
INSN(movn, 0b100);
793
INSN(movz, 0b110);
794
INSN(movk, 0b111);
795
796
#undef INSN
797
798
// Bitfield
799
#define INSN(NAME, opcode) \
800
void NAME(Register Rd, Register Rn, unsigned immr, unsigned imms) { \
801
starti; \
802
f(opcode, 31, 22), f(immr, 21, 16), f(imms, 15, 10); \
803
rf(Rn, 5), rf(Rd, 0); \
804
}
805
806
INSN(sbfmw, 0b0001001100);
807
INSN(bfmw, 0b0011001100);
808
INSN(ubfmw, 0b0101001100);
809
INSN(sbfm, 0b1001001101);
810
INSN(bfm, 0b1011001101);
811
INSN(ubfm, 0b1101001101);
812
813
#undef INSN
814
815
// Extract
816
#define INSN(NAME, opcode) \
817
void NAME(Register Rd, Register Rn, Register Rm, unsigned imms) { \
818
starti; \
819
f(opcode, 31, 21), f(imms, 15, 10); \
820
rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); \
821
}
822
823
INSN(extrw, 0b00010011100);
824
INSN(extr, 0b10010011110);
825
826
#undef INSN
827
828
// The maximum range of a branch is fixed for the AArch64
829
// architecture. In debug mode we shrink it in order to test
830
// trampolines, but not so small that branches in the interpreter
831
// are out of range.
832
static const unsigned long branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M);
833
834
static bool reachable_from_branch_at(address branch, address target) {
835
return uabs(target - branch) < branch_range;
836
}
837
838
// Unconditional branch (immediate)
839
840
#define INSN(NAME, opcode) \
841
void NAME(address dest) { \
842
starti; \
843
long offset = (dest - pc()) >> 2; \
844
DEBUG_ONLY(assert(reachable_from_branch_at(pc(), dest), "debug only")); \
845
f(opcode, 31), f(0b00101, 30, 26), sf(offset, 25, 0); \
846
} \
847
void NAME(Label &L) { \
848
wrap_label(L, &Assembler::NAME); \
849
} \
850
void NAME(const Address &dest);
851
852
INSN(b, 0);
853
INSN(bl, 1);
854
855
#undef INSN
856
857
// Compare & branch (immediate)
858
#define INSN(NAME, opcode) \
859
void NAME(Register Rt, address dest) { \
860
long offset = (dest - pc()) >> 2; \
861
starti; \
862
f(opcode, 31, 24), sf(offset, 23, 5), rf(Rt, 0); \
863
} \
864
void NAME(Register Rt, Label &L) { \
865
wrap_label(Rt, L, &Assembler::NAME); \
866
}
867
868
INSN(cbzw, 0b00110100);
869
INSN(cbnzw, 0b00110101);
870
INSN(cbz, 0b10110100);
871
INSN(cbnz, 0b10110101);
872
873
#undef INSN
874
875
// Test & branch (immediate)
876
#define INSN(NAME, opcode) \
877
void NAME(Register Rt, int bitpos, address dest) { \
878
long offset = (dest - pc()) >> 2; \
879
int b5 = bitpos >> 5; \
880
bitpos &= 0x1f; \
881
starti; \
882
f(b5, 31), f(opcode, 30, 24), f(bitpos, 23, 19), sf(offset, 18, 5); \
883
rf(Rt, 0); \
884
} \
885
void NAME(Register Rt, int bitpos, Label &L) { \
886
wrap_label(Rt, bitpos, L, &Assembler::NAME); \
887
}
888
889
INSN(tbz, 0b0110110);
890
INSN(tbnz, 0b0110111);
891
892
#undef INSN
893
894
// Conditional branch (immediate)
895
enum Condition
896
{EQ, NE, HS, CS=HS, LO, CC=LO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV};
897
898
void br(Condition cond, address dest) {
899
long offset = (dest - pc()) >> 2;
900
starti;
901
f(0b0101010, 31, 25), f(0, 24), sf(offset, 23, 5), f(0, 4), f(cond, 3, 0);
902
}
903
904
#define INSN(NAME, cond) \
905
void NAME(address dest) { \
906
br(cond, dest); \
907
}
908
909
INSN(beq, EQ);
910
INSN(bne, NE);
911
INSN(bhs, HS);
912
INSN(bcs, CS);
913
INSN(blo, LO);
914
INSN(bcc, CC);
915
INSN(bmi, MI);
916
INSN(bpl, PL);
917
INSN(bvs, VS);
918
INSN(bvc, VC);
919
INSN(bhi, HI);
920
INSN(bls, LS);
921
INSN(bge, GE);
922
INSN(blt, LT);
923
INSN(bgt, GT);
924
INSN(ble, LE);
925
INSN(bal, AL);
926
INSN(bnv, NV);
927
928
void br(Condition cc, Label &L);
929
930
#undef INSN
931
932
// Exception generation
933
void generate_exception(int opc, int op2, int LL, unsigned imm) {
934
starti;
935
f(0b11010100, 31, 24);
936
f(opc, 23, 21), f(imm, 20, 5), f(op2, 4, 2), f(LL, 1, 0);
937
}
938
939
#define INSN(NAME, opc, op2, LL) \
940
void NAME(unsigned imm) { \
941
generate_exception(opc, op2, LL, imm); \
942
}
943
944
INSN(svc, 0b000, 0, 0b01);
945
INSN(hvc, 0b000, 0, 0b10);
946
INSN(smc, 0b000, 0, 0b11);
947
INSN(brk, 0b001, 0, 0b00);
948
INSN(hlt, 0b010, 0, 0b00);
949
INSN(dpcs1, 0b101, 0, 0b01);
950
INSN(dpcs2, 0b101, 0, 0b10);
951
INSN(dpcs3, 0b101, 0, 0b11);
952
953
#undef INSN
954
955
// System
956
void system(int op0, int op1, int CRn, int CRm, int op2,
957
Register rt = dummy_reg)
958
{
959
starti;
960
f(0b11010101000, 31, 21);
961
f(op0, 20, 19);
962
f(op1, 18, 16);
963
f(CRn, 15, 12);
964
f(CRm, 11, 8);
965
f(op2, 7, 5);
966
rf(rt, 0);
967
}
968
969
void hint(int imm) {
970
system(0b00, 0b011, 0b0010, imm, 0b000);
971
}
972
973
void nop() {
974
hint(0);
975
}
976
// we only provide mrs and msr for the special purpose system
977
// registers where op1 (instr[20:19]) == 11 and, (currently) only
978
// use it for FPSR n.b msr has L (instr[21]) == 0 mrs has L == 1
979
980
void msr(int op1, int CRn, int CRm, int op2, Register rt) {
981
starti;
982
f(0b1101010100011, 31, 19);
983
f(op1, 18, 16);
984
f(CRn, 15, 12);
985
f(CRm, 11, 8);
986
f(op2, 7, 5);
987
// writing zr is ok
988
zrf(rt, 0);
989
}
990
991
void mrs(int op1, int CRn, int CRm, int op2, Register rt) {
992
starti;
993
f(0b1101010100111, 31, 19);
994
f(op1, 18, 16);
995
f(CRn, 15, 12);
996
f(CRm, 11, 8);
997
f(op2, 7, 5);
998
// reading to zr is a mistake
999
rf(rt, 0);
1000
}
1001
1002
enum barrier {OSHLD = 0b0001, OSHST, OSH, NSHLD=0b0101, NSHST, NSH,
1003
ISHLD = 0b1001, ISHST, ISH, LD=0b1101, ST, SY};
1004
1005
void dsb(barrier imm) {
1006
system(0b00, 0b011, 0b00011, imm, 0b100);
1007
}
1008
1009
void dmb(barrier imm) {
1010
system(0b00, 0b011, 0b00011, imm, 0b101);
1011
}
1012
1013
void isb() {
1014
system(0b00, 0b011, 0b00011, SY, 0b110);
1015
}
1016
1017
void sys(int op1, int CRn, int CRm, int op2,
1018
Register rt = (Register)0b11111) {
1019
system(0b01, op1, CRn, CRm, op2, rt);
1020
}
1021
1022
// Only implement operations accessible from EL0 or higher, i.e.,
1023
// op1 CRn CRm op2
1024
// IC IVAU 3 7 5 1
1025
// DC CVAC 3 7 10 1
1026
// DC CVAU 3 7 11 1
1027
// DC CIVAC 3 7 14 1
1028
// DC ZVA 3 7 4 1
1029
// So only deal with the CRm field.
1030
enum icache_maintenance {IVAU = 0b0101};
1031
enum dcache_maintenance {CVAC = 0b1010, CVAU = 0b1011, CIVAC = 0b1110, ZVA = 0b100};
1032
1033
void dc(dcache_maintenance cm, Register Rt) {
1034
sys(0b011, 0b0111, cm, 0b001, Rt);
1035
}
1036
1037
void ic(icache_maintenance cm, Register Rt) {
1038
sys(0b011, 0b0111, cm, 0b001, Rt);
1039
}
1040
1041
// A more convenient access to dmb for our purposes
1042
enum Membar_mask_bits {
1043
// We can use ISH for a barrier because the ARM ARM says "This
1044
// architecture assumes that all Processing Elements that use the
1045
// same operating system or hypervisor are in the same Inner
1046
// Shareable shareability domain."
1047
StoreStore = ISHST,
1048
LoadStore = ISHLD,
1049
LoadLoad = ISHLD,
1050
StoreLoad = ISH,
1051
AnyAny = ISH
1052
};
1053
1054
void membar(Membar_mask_bits order_constraint) {
1055
dmb(Assembler::barrier(order_constraint));
1056
}
1057
1058
// Unconditional branch (register)
1059
void branch_reg(Register R, int opc) {
1060
starti;
1061
f(0b1101011, 31, 25);
1062
f(opc, 24, 21);
1063
f(0b11111000000, 20, 10);
1064
rf(R, 5);
1065
f(0b00000, 4, 0);
1066
}
1067
1068
#define INSN(NAME, opc) \
1069
void NAME(Register R) { \
1070
branch_reg(R, opc); \
1071
}
1072
1073
INSN(br, 0b0000);
1074
INSN(blr, 0b0001);
1075
INSN(ret, 0b0010);
1076
1077
void ret(void *p); // This forces a compile-time error for ret(0)
1078
1079
#undef INSN
1080
1081
#define INSN(NAME, opc) \
1082
void NAME() { \
1083
branch_reg(dummy_reg, opc); \
1084
}
1085
1086
INSN(eret, 0b0100);
1087
INSN(drps, 0b0101);
1088
1089
#undef INSN
1090
1091
// Load/store exclusive
1092
enum operand_size { byte, halfword, word, xword };
1093
1094
void load_store_exclusive(Register Rs, Register Rt1, Register Rt2,
1095
Register Rn, enum operand_size sz, int op, bool ordered) {
1096
starti;
1097
f(sz, 31, 30), f(0b001000, 29, 24), f(op, 23, 21);
1098
rf(Rs, 16), f(ordered, 15), rf(Rt2, 10), srf(Rn, 5), zrf(Rt1, 0);
1099
}
1100
1101
void load_exclusive(Register dst, Register addr,
1102
enum operand_size sz, bool ordered) {
1103
load_store_exclusive(dummy_reg, dst, dummy_reg, addr,
1104
sz, 0b010, ordered);
1105
}
1106
1107
void store_exclusive(Register status, Register new_val, Register addr,
1108
enum operand_size sz, bool ordered) {
1109
load_store_exclusive(status, new_val, dummy_reg, addr,
1110
sz, 0b000, ordered);
1111
}
1112
1113
#define INSN4(NAME, sz, op, o0) /* Four registers */ \
1114
void NAME(Register Rs, Register Rt1, Register Rt2, Register Rn) { \
1115
guarantee(Rs != Rn && Rs != Rt1 && Rs != Rt2, "unpredictable instruction"); \
1116
load_store_exclusive(Rs, Rt1, Rt2, Rn, sz, op, o0); \
1117
}
1118
1119
#define INSN3(NAME, sz, op, o0) /* Three registers */ \
1120
void NAME(Register Rs, Register Rt, Register Rn) { \
1121
guarantee(Rs != Rn && Rs != Rt, "unpredictable instruction"); \
1122
load_store_exclusive(Rs, Rt, dummy_reg, Rn, sz, op, o0); \
1123
}
1124
1125
#define INSN2(NAME, sz, op, o0) /* Two registers */ \
1126
void NAME(Register Rt, Register Rn) { \
1127
load_store_exclusive(dummy_reg, Rt, dummy_reg, \
1128
Rn, sz, op, o0); \
1129
}
1130
1131
#define INSN_FOO(NAME, sz, op, o0) /* Three registers, encoded differently */ \
1132
void NAME(Register Rt1, Register Rt2, Register Rn) { \
1133
guarantee(Rt1 != Rt2, "unpredictable instruction"); \
1134
load_store_exclusive(dummy_reg, Rt1, Rt2, Rn, sz, op, o0); \
1135
}
1136
1137
// bytes
1138
INSN3(stxrb, byte, 0b000, 0);
1139
INSN3(stlxrb, byte, 0b000, 1);
1140
INSN2(ldxrb, byte, 0b010, 0);
1141
INSN2(ldaxrb, byte, 0b010, 1);
1142
INSN2(stlrb, byte, 0b100, 1);
1143
INSN2(ldarb, byte, 0b110, 1);
1144
1145
// halfwords
1146
INSN3(stxrh, halfword, 0b000, 0);
1147
INSN3(stlxrh, halfword, 0b000, 1);
1148
INSN2(ldxrh, halfword, 0b010, 0);
1149
INSN2(ldaxrh, halfword, 0b010, 1);
1150
INSN2(stlrh, halfword, 0b100, 1);
1151
INSN2(ldarh, halfword, 0b110, 1);
1152
1153
// words
1154
INSN3(stxrw, word, 0b000, 0);
1155
INSN3(stlxrw, word, 0b000, 1);
1156
INSN4(stxpw, word, 0b001, 0);
1157
INSN4(stlxpw, word, 0b001, 1);
1158
INSN2(ldxrw, word, 0b010, 0);
1159
INSN2(ldaxrw, word, 0b010, 1);
1160
INSN_FOO(ldxpw, word, 0b011, 0);
1161
INSN_FOO(ldaxpw, word, 0b011, 1);
1162
INSN2(stlrw, word, 0b100, 1);
1163
INSN2(ldarw, word, 0b110, 1);
1164
1165
// xwords
1166
INSN3(stxr, xword, 0b000, 0);
1167
INSN3(stlxr, xword, 0b000, 1);
1168
INSN4(stxp, xword, 0b001, 0);
1169
INSN4(stlxp, xword, 0b001, 1);
1170
INSN2(ldxr, xword, 0b010, 0);
1171
INSN2(ldaxr, xword, 0b010, 1);
1172
INSN_FOO(ldxp, xword, 0b011, 0);
1173
INSN_FOO(ldaxp, xword, 0b011, 1);
1174
INSN2(stlr, xword, 0b100, 1);
1175
INSN2(ldar, xword, 0b110, 1);
1176
1177
#undef INSN2
1178
#undef INSN3
1179
#undef INSN4
1180
#undef INSN_FOO
1181
1182
// 8.1 Compare and swap extensions
1183
void lse_cas(Register Rs, Register Rt, Register Rn,
1184
enum operand_size sz, bool a, bool r, bool not_pair) {
1185
starti;
1186
if (! not_pair) { // Pair
1187
assert(sz == word || sz == xword, "invalid size");
1188
/* The size bit is in bit 30, not 31 */
1189
sz = (operand_size)(sz == word ? 0b00:0b01);
1190
}
1191
f(sz, 31, 30), f(0b001000, 29, 24), f(1, 23), f(a, 22), f(1, 21);
1192
rf(Rs, 16), f(r, 15), f(0b11111, 14, 10), rf(Rn, 5), rf(Rt, 0);
1193
}
1194
1195
// CAS
1196
#define INSN(NAME, a, r) \
1197
void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1198
assert(Rs != Rn && Rs != Rt, "unpredictable instruction"); \
1199
lse_cas(Rs, Rt, Rn, sz, a, r, true); \
1200
}
1201
INSN(cas, false, false)
1202
INSN(casa, true, false)
1203
INSN(casl, false, true)
1204
INSN(casal, true, true)
1205
#undef INSN
1206
1207
// CASP
1208
#define INSN(NAME, a, r) \
1209
void NAME(operand_size sz, Register Rs, Register Rs1, \
1210
Register Rt, Register Rt1, Register Rn) { \
1211
assert((Rs->encoding() & 1) == 0 && (Rt->encoding() & 1) == 0 && \
1212
Rs->successor() == Rs1 && Rt->successor() == Rt1 && \
1213
Rs != Rn && Rs1 != Rn && Rs != Rt, "invalid registers"); \
1214
lse_cas(Rs, Rt, Rn, sz, a, r, false); \
1215
}
1216
INSN(casp, false, false)
1217
INSN(caspa, true, false)
1218
INSN(caspl, false, true)
1219
INSN(caspal, true, true)
1220
#undef INSN
1221
1222
// 8.1 Atomic operations
1223
void lse_atomic(Register Rs, Register Rt, Register Rn,
1224
enum operand_size sz, int op1, int op2, bool a, bool r) {
1225
starti;
1226
f(sz, 31, 30), f(0b111000, 29, 24), f(a, 23), f(r, 22), f(1, 21);
1227
rf(Rs, 16), f(op1, 15), f(op2, 14, 12), f(0, 11, 10), rf(Rn, 5), zrf(Rt, 0);
1228
}
1229
1230
#define INSN(NAME, NAME_A, NAME_L, NAME_AL, op1, op2) \
1231
void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1232
lse_atomic(Rs, Rt, Rn, sz, op1, op2, false, false); \
1233
} \
1234
void NAME_A(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1235
lse_atomic(Rs, Rt, Rn, sz, op1, op2, true, false); \
1236
} \
1237
void NAME_L(operand_size sz, Register Rs, Register Rt, Register Rn) { \
1238
lse_atomic(Rs, Rt, Rn, sz, op1, op2, false, true); \
1239
} \
1240
void NAME_AL(operand_size sz, Register Rs, Register Rt, Register Rn) {\
1241
lse_atomic(Rs, Rt, Rn, sz, op1, op2, true, true); \
1242
}
1243
INSN(ldadd, ldadda, ldaddl, ldaddal, 0, 0b000);
1244
INSN(ldbic, ldbica, ldbicl, ldbical, 0, 0b001);
1245
INSN(ldeor, ldeora, ldeorl, ldeoral, 0, 0b010);
1246
INSN(ldorr, ldorra, ldorrl, ldorral, 0, 0b011);
1247
INSN(ldsmax, ldsmaxa, ldsmaxl, ldsmaxal, 0, 0b100);
1248
INSN(ldsmin, ldsmina, ldsminl, ldsminal, 0, 0b101);
1249
INSN(ldumax, ldumaxa, ldumaxl, ldumaxal, 0, 0b110);
1250
INSN(ldumin, ldumina, lduminl, lduminal, 0, 0b111);
1251
INSN(swp, swpa, swpl, swpal, 1, 0b000);
1252
#undef INSN
1253
1254
// Load register (literal)
1255
#define INSN(NAME, opc, V) \
1256
void NAME(Register Rt, address dest) { \
1257
long offset = (dest - pc()) >> 2; \
1258
starti; \
1259
f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1260
sf(offset, 23, 5); \
1261
rf(Rt, 0); \
1262
} \
1263
void NAME(Register Rt, address dest, relocInfo::relocType rtype) { \
1264
InstructionMark im(this); \
1265
guarantee(rtype == relocInfo::internal_word_type, \
1266
"only internal_word_type relocs make sense here"); \
1267
code_section()->relocate(inst_mark(), InternalAddress(dest).rspec()); \
1268
NAME(Rt, dest); \
1269
} \
1270
void NAME(Register Rt, Label &L) { \
1271
wrap_label(Rt, L, &Assembler::NAME); \
1272
}
1273
1274
INSN(ldrw, 0b00, 0);
1275
INSN(ldr, 0b01, 0);
1276
INSN(ldrsw, 0b10, 0);
1277
1278
#undef INSN
1279
1280
#define INSN(NAME, opc, V) \
1281
void NAME(FloatRegister Rt, address dest) { \
1282
long offset = (dest - pc()) >> 2; \
1283
starti; \
1284
f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1285
sf(offset, 23, 5); \
1286
rf((Register)Rt, 0); \
1287
}
1288
1289
INSN(ldrs, 0b00, 1);
1290
INSN(ldrd, 0b01, 1);
1291
INSN(ldrq, 0x10, 1);
1292
1293
#undef INSN
1294
1295
#define INSN(NAME, opc, V) \
1296
void NAME(address dest, prfop op = PLDL1KEEP) { \
1297
long offset = (dest - pc()) >> 2; \
1298
starti; \
1299
f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1300
sf(offset, 23, 5); \
1301
f(op, 4, 0); \
1302
} \
1303
void NAME(Label &L, prfop op = PLDL1KEEP) { \
1304
wrap_label(L, op, &Assembler::NAME); \
1305
}
1306
1307
INSN(prfm, 0b11, 0);
1308
1309
#undef INSN
1310
1311
// Load/store
1312
void ld_st1(int opc, int p1, int V, int L,
1313
Register Rt1, Register Rt2, Address adr, bool no_allocate) {
1314
starti;
1315
f(opc, 31, 30), f(p1, 29, 27), f(V, 26), f(L, 22);
1316
zrf(Rt2, 10), zrf(Rt1, 0);
1317
if (no_allocate) {
1318
adr.encode_nontemporal_pair(current);
1319
} else {
1320
adr.encode_pair(current);
1321
}
1322
}
1323
1324
// Load/store register pair (offset)
1325
#define INSN(NAME, size, p1, V, L, no_allocate) \
1326
void NAME(Register Rt1, Register Rt2, Address adr) { \
1327
ld_st1(size, p1, V, L, Rt1, Rt2, adr, no_allocate); \
1328
}
1329
1330
INSN(stpw, 0b00, 0b101, 0, 0, false);
1331
INSN(ldpw, 0b00, 0b101, 0, 1, false);
1332
INSN(ldpsw, 0b01, 0b101, 0, 1, false);
1333
INSN(stp, 0b10, 0b101, 0, 0, false);
1334
INSN(ldp, 0b10, 0b101, 0, 1, false);
1335
1336
// Load/store no-allocate pair (offset)
1337
INSN(stnpw, 0b00, 0b101, 0, 0, true);
1338
INSN(ldnpw, 0b00, 0b101, 0, 1, true);
1339
INSN(stnp, 0b10, 0b101, 0, 0, true);
1340
INSN(ldnp, 0b10, 0b101, 0, 1, true);
1341
1342
#undef INSN
1343
1344
#define INSN(NAME, size, p1, V, L, no_allocate) \
1345
void NAME(FloatRegister Rt1, FloatRegister Rt2, Address adr) { \
1346
ld_st1(size, p1, V, L, (Register)Rt1, (Register)Rt2, adr, no_allocate); \
1347
}
1348
1349
INSN(stps, 0b00, 0b101, 1, 0, false);
1350
INSN(ldps, 0b00, 0b101, 1, 1, false);
1351
INSN(stpd, 0b01, 0b101, 1, 0, false);
1352
INSN(ldpd, 0b01, 0b101, 1, 1, false);
1353
INSN(stpq, 0b10, 0b101, 1, 0, false);
1354
INSN(ldpq, 0b10, 0b101, 1, 1, false);
1355
1356
#undef INSN
1357
1358
// Load/store register (all modes)
1359
void ld_st2(Register Rt, const Address &adr, int size, int op, int V = 0) {
1360
starti;
1361
1362
f(V, 26); // general reg?
1363
zrf(Rt, 0);
1364
1365
// Encoding for literal loads is done here (rather than pushed
1366
// down into Address::encode) because the encoding of this
1367
// instruction is too different from all of the other forms to
1368
// make it worth sharing.
1369
if (adr.getMode() == Address::literal) {
1370
assert(size == 0b10 || size == 0b11, "bad operand size in ldr");
1371
assert(op == 0b01, "literal form can only be used with loads");
1372
f(size & 0b01, 31, 30), f(0b011, 29, 27), f(0b00, 25, 24);
1373
long offset = (adr.target() - pc()) >> 2;
1374
sf(offset, 23, 5);
1375
code_section()->relocate(pc(), adr.rspec());
1376
return;
1377
}
1378
1379
f(size, 31, 30);
1380
f(op, 23, 22); // str
1381
adr.encode(current);
1382
}
1383
1384
#define INSN(NAME, size, op) \
1385
void NAME(Register Rt, const Address &adr) { \
1386
ld_st2(Rt, adr, size, op); \
1387
} \
1388
1389
INSN(str, 0b11, 0b00);
1390
INSN(strw, 0b10, 0b00);
1391
INSN(strb, 0b00, 0b00);
1392
INSN(strh, 0b01, 0b00);
1393
1394
INSN(ldr, 0b11, 0b01);
1395
INSN(ldrw, 0b10, 0b01);
1396
INSN(ldrb, 0b00, 0b01);
1397
INSN(ldrh, 0b01, 0b01);
1398
1399
INSN(ldrsb, 0b00, 0b10);
1400
INSN(ldrsbw, 0b00, 0b11);
1401
INSN(ldrsh, 0b01, 0b10);
1402
INSN(ldrshw, 0b01, 0b11);
1403
INSN(ldrsw, 0b10, 0b10);
1404
1405
#undef INSN
1406
1407
#define INSN(NAME, size, op) \
1408
void NAME(const Address &adr, prfop pfop = PLDL1KEEP) { \
1409
ld_st2((Register)pfop, adr, size, op); \
1410
}
1411
1412
INSN(prfm, 0b11, 0b10); // FIXME: PRFM should not be used with
1413
// writeback modes, but the assembler
1414
// doesn't enfore that.
1415
1416
#undef INSN
1417
1418
#define INSN(NAME, size, op) \
1419
void NAME(FloatRegister Rt, const Address &adr) { \
1420
ld_st2((Register)Rt, adr, size, op, 1); \
1421
}
1422
1423
INSN(strd, 0b11, 0b00);
1424
INSN(strs, 0b10, 0b00);
1425
INSN(ldrd, 0b11, 0b01);
1426
INSN(ldrs, 0b10, 0b01);
1427
INSN(strq, 0b00, 0b10);
1428
INSN(ldrq, 0x00, 0b11);
1429
1430
#undef INSN
1431
1432
enum shift_kind { LSL, LSR, ASR, ROR };
1433
1434
void op_shifted_reg(unsigned decode,
1435
enum shift_kind kind, unsigned shift,
1436
unsigned size, unsigned op) {
1437
f(size, 31);
1438
f(op, 30, 29);
1439
f(decode, 28, 24);
1440
f(shift, 15, 10);
1441
f(kind, 23, 22);
1442
}
1443
1444
// Logical (shifted register)
1445
#define INSN(NAME, size, op, N) \
1446
void NAME(Register Rd, Register Rn, Register Rm, \
1447
enum shift_kind kind = LSL, unsigned shift = 0) { \
1448
starti; \
1449
f(N, 21); \
1450
zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \
1451
op_shifted_reg(0b01010, kind, shift, size, op); \
1452
}
1453
1454
INSN(andr, 1, 0b00, 0);
1455
INSN(orr, 1, 0b01, 0);
1456
INSN(eor, 1, 0b10, 0);
1457
INSN(ands, 1, 0b11, 0);
1458
INSN(andw, 0, 0b00, 0);
1459
INSN(orrw, 0, 0b01, 0);
1460
INSN(eorw, 0, 0b10, 0);
1461
INSN(andsw, 0, 0b11, 0);
1462
1463
INSN(bic, 1, 0b00, 1);
1464
INSN(orn, 1, 0b01, 1);
1465
INSN(eon, 1, 0b10, 1);
1466
INSN(bics, 1, 0b11, 1);
1467
INSN(bicw, 0, 0b00, 1);
1468
INSN(ornw, 0, 0b01, 1);
1469
INSN(eonw, 0, 0b10, 1);
1470
INSN(bicsw, 0, 0b11, 1);
1471
1472
#undef INSN
1473
1474
// Add/subtract (shifted register)
1475
#define INSN(NAME, size, op) \
1476
void NAME(Register Rd, Register Rn, Register Rm, \
1477
enum shift_kind kind, unsigned shift = 0) { \
1478
starti; \
1479
f(0, 21); \
1480
assert_cond(kind != ROR); \
1481
zrf(Rd, 0), zrf(Rn, 5), zrf(Rm, 16); \
1482
op_shifted_reg(0b01011, kind, shift, size, op); \
1483
}
1484
1485
INSN(add, 1, 0b000);
1486
INSN(sub, 1, 0b10);
1487
INSN(addw, 0, 0b000);
1488
INSN(subw, 0, 0b10);
1489
1490
INSN(adds, 1, 0b001);
1491
INSN(subs, 1, 0b11);
1492
INSN(addsw, 0, 0b001);
1493
INSN(subsw, 0, 0b11);
1494
1495
#undef INSN
1496
1497
// Add/subtract (extended register)
1498
#define INSN(NAME, op) \
1499
void NAME(Register Rd, Register Rn, Register Rm, \
1500
ext::operation option, int amount = 0) { \
1501
starti; \
1502
zrf(Rm, 16), srf(Rn, 5), srf(Rd, 0); \
1503
add_sub_extended_reg(op, 0b01011, Rd, Rn, Rm, 0b00, option, amount); \
1504
}
1505
1506
void add_sub_extended_reg(unsigned op, unsigned decode,
1507
Register Rd, Register Rn, Register Rm,
1508
unsigned opt, ext::operation option, unsigned imm) {
1509
guarantee(imm <= 4, "shift amount must be < 4");
1510
f(op, 31, 29), f(decode, 28, 24), f(opt, 23, 22), f(1, 21);
1511
f(option, 15, 13), f(imm, 12, 10);
1512
}
1513
1514
INSN(addw, 0b000);
1515
INSN(subw, 0b010);
1516
INSN(add, 0b100);
1517
INSN(sub, 0b110);
1518
1519
#undef INSN
1520
1521
#define INSN(NAME, op) \
1522
void NAME(Register Rd, Register Rn, Register Rm, \
1523
ext::operation option, int amount = 0) { \
1524
starti; \
1525
zrf(Rm, 16), srf(Rn, 5), zrf(Rd, 0); \
1526
add_sub_extended_reg(op, 0b01011, Rd, Rn, Rm, 0b00, option, amount); \
1527
}
1528
1529
INSN(addsw, 0b001);
1530
INSN(subsw, 0b011);
1531
INSN(adds, 0b101);
1532
INSN(subs, 0b111);
1533
1534
#undef INSN
1535
1536
// Aliases for short forms of add and sub
1537
#define INSN(NAME) \
1538
void NAME(Register Rd, Register Rn, Register Rm) { \
1539
if (Rd == sp || Rn == sp) \
1540
NAME(Rd, Rn, Rm, ext::uxtx); \
1541
else \
1542
NAME(Rd, Rn, Rm, LSL); \
1543
}
1544
1545
INSN(addw);
1546
INSN(subw);
1547
INSN(add);
1548
INSN(sub);
1549
1550
INSN(addsw);
1551
INSN(subsw);
1552
INSN(adds);
1553
INSN(subs);
1554
1555
#undef INSN
1556
1557
// Add/subtract (with carry)
1558
void add_sub_carry(unsigned op, Register Rd, Register Rn, Register Rm) {
1559
starti;
1560
f(op, 31, 29);
1561
f(0b11010000, 28, 21);
1562
f(0b000000, 15, 10);
1563
zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0);
1564
}
1565
1566
#define INSN(NAME, op) \
1567
void NAME(Register Rd, Register Rn, Register Rm) { \
1568
add_sub_carry(op, Rd, Rn, Rm); \
1569
}
1570
1571
INSN(adcw, 0b000);
1572
INSN(adcsw, 0b001);
1573
INSN(sbcw, 0b010);
1574
INSN(sbcsw, 0b011);
1575
INSN(adc, 0b100);
1576
INSN(adcs, 0b101);
1577
INSN(sbc,0b110);
1578
INSN(sbcs, 0b111);
1579
1580
#undef INSN
1581
1582
// Conditional compare (both kinds)
1583
void conditional_compare(unsigned op, int o2, int o3,
1584
Register Rn, unsigned imm5, unsigned nzcv,
1585
unsigned cond) {
1586
f(op, 31, 29);
1587
f(0b11010010, 28, 21);
1588
f(cond, 15, 12);
1589
f(o2, 10);
1590
f(o3, 4);
1591
f(nzcv, 3, 0);
1592
f(imm5, 20, 16), rf(Rn, 5);
1593
}
1594
1595
#define INSN(NAME, op) \
1596
void NAME(Register Rn, Register Rm, int imm, Condition cond) { \
1597
starti; \
1598
f(0, 11); \
1599
conditional_compare(op, 0, 0, Rn, (uintptr_t)Rm, imm, cond); \
1600
} \
1601
\
1602
void NAME(Register Rn, int imm5, int imm, Condition cond) { \
1603
starti; \
1604
f(1, 11); \
1605
conditional_compare(op, 0, 0, Rn, imm5, imm, cond); \
1606
}
1607
1608
INSN(ccmnw, 0b001);
1609
INSN(ccmpw, 0b011);
1610
INSN(ccmn, 0b101);
1611
INSN(ccmp, 0b111);
1612
1613
#undef INSN
1614
1615
// Conditional select
1616
void conditional_select(unsigned op, unsigned op2,
1617
Register Rd, Register Rn, Register Rm,
1618
unsigned cond) {
1619
starti;
1620
f(op, 31, 29);
1621
f(0b11010100, 28, 21);
1622
f(cond, 15, 12);
1623
f(op2, 11, 10);
1624
zrf(Rm, 16), zrf(Rn, 5), rf(Rd, 0);
1625
}
1626
1627
#define INSN(NAME, op, op2) \
1628
void NAME(Register Rd, Register Rn, Register Rm, Condition cond) { \
1629
conditional_select(op, op2, Rd, Rn, Rm, cond); \
1630
}
1631
1632
INSN(cselw, 0b000, 0b00);
1633
INSN(csincw, 0b000, 0b01);
1634
INSN(csinvw, 0b010, 0b00);
1635
INSN(csnegw, 0b010, 0b01);
1636
INSN(csel, 0b100, 0b00);
1637
INSN(csinc, 0b100, 0b01);
1638
INSN(csinv, 0b110, 0b00);
1639
INSN(csneg, 0b110, 0b01);
1640
1641
#undef INSN
1642
1643
// Data processing
1644
void data_processing(unsigned op29, unsigned opcode,
1645
Register Rd, Register Rn) {
1646
f(op29, 31, 29), f(0b11010110, 28, 21);
1647
f(opcode, 15, 10);
1648
rf(Rn, 5), rf(Rd, 0);
1649
}
1650
1651
// (1 source)
1652
#define INSN(NAME, op29, opcode2, opcode) \
1653
void NAME(Register Rd, Register Rn) { \
1654
starti; \
1655
f(opcode2, 20, 16); \
1656
data_processing(op29, opcode, Rd, Rn); \
1657
}
1658
1659
INSN(rbitw, 0b010, 0b00000, 0b00000);
1660
INSN(rev16w, 0b010, 0b00000, 0b00001);
1661
INSN(revw, 0b010, 0b00000, 0b00010);
1662
INSN(clzw, 0b010, 0b00000, 0b00100);
1663
INSN(clsw, 0b010, 0b00000, 0b00101);
1664
1665
INSN(rbit, 0b110, 0b00000, 0b00000);
1666
INSN(rev16, 0b110, 0b00000, 0b00001);
1667
INSN(rev32, 0b110, 0b00000, 0b00010);
1668
INSN(rev, 0b110, 0b00000, 0b00011);
1669
INSN(clz, 0b110, 0b00000, 0b00100);
1670
INSN(cls, 0b110, 0b00000, 0b00101);
1671
1672
#undef INSN
1673
1674
// (2 sources)
1675
#define INSN(NAME, op29, opcode) \
1676
void NAME(Register Rd, Register Rn, Register Rm) { \
1677
starti; \
1678
rf(Rm, 16); \
1679
data_processing(op29, opcode, Rd, Rn); \
1680
}
1681
1682
INSN(udivw, 0b000, 0b000010);
1683
INSN(sdivw, 0b000, 0b000011);
1684
INSN(lslvw, 0b000, 0b001000);
1685
INSN(lsrvw, 0b000, 0b001001);
1686
INSN(asrvw, 0b000, 0b001010);
1687
INSN(rorvw, 0b000, 0b001011);
1688
1689
INSN(udiv, 0b100, 0b000010);
1690
INSN(sdiv, 0b100, 0b000011);
1691
INSN(lslv, 0b100, 0b001000);
1692
INSN(lsrv, 0b100, 0b001001);
1693
INSN(asrv, 0b100, 0b001010);
1694
INSN(rorv, 0b100, 0b001011);
1695
1696
#undef INSN
1697
1698
// (3 sources)
1699
void data_processing(unsigned op54, unsigned op31, unsigned o0,
1700
Register Rd, Register Rn, Register Rm,
1701
Register Ra) {
1702
starti;
1703
f(op54, 31, 29), f(0b11011, 28, 24);
1704
f(op31, 23, 21), f(o0, 15);
1705
zrf(Rm, 16), zrf(Ra, 10), zrf(Rn, 5), zrf(Rd, 0);
1706
}
1707
1708
#define INSN(NAME, op54, op31, o0) \
1709
void NAME(Register Rd, Register Rn, Register Rm, Register Ra) { \
1710
data_processing(op54, op31, o0, Rd, Rn, Rm, Ra); \
1711
}
1712
1713
INSN(maddw, 0b000, 0b000, 0);
1714
INSN(msubw, 0b000, 0b000, 1);
1715
INSN(madd, 0b100, 0b000, 0);
1716
INSN(msub, 0b100, 0b000, 1);
1717
INSN(smaddl, 0b100, 0b001, 0);
1718
INSN(smsubl, 0b100, 0b001, 1);
1719
INSN(umaddl, 0b100, 0b101, 0);
1720
INSN(umsubl, 0b100, 0b101, 1);
1721
1722
#undef INSN
1723
1724
#define INSN(NAME, op54, op31, o0) \
1725
void NAME(Register Rd, Register Rn, Register Rm) { \
1726
data_processing(op54, op31, o0, Rd, Rn, Rm, (Register)31); \
1727
}
1728
1729
INSN(smulh, 0b100, 0b010, 0);
1730
INSN(umulh, 0b100, 0b110, 0);
1731
1732
#undef INSN
1733
1734
// Floating-point data-processing (1 source)
1735
void data_processing(unsigned op31, unsigned type, unsigned opcode,
1736
FloatRegister Vd, FloatRegister Vn) {
1737
starti;
1738
f(op31, 31, 29);
1739
f(0b11110, 28, 24);
1740
f(type, 23, 22), f(1, 21), f(opcode, 20, 15), f(0b10000, 14, 10);
1741
rf(Vn, 5), rf(Vd, 0);
1742
}
1743
1744
#define INSN(NAME, op31, type, opcode) \
1745
void NAME(FloatRegister Vd, FloatRegister Vn) { \
1746
data_processing(op31, type, opcode, Vd, Vn); \
1747
}
1748
1749
private:
1750
INSN(i_fmovs, 0b000, 0b00, 0b000000);
1751
public:
1752
INSN(fabss, 0b000, 0b00, 0b000001);
1753
INSN(fnegs, 0b000, 0b00, 0b000010);
1754
INSN(fsqrts, 0b000, 0b00, 0b000011);
1755
INSN(fcvts, 0b000, 0b00, 0b000101); // Single-precision to double-precision
1756
1757
private:
1758
INSN(i_fmovd, 0b000, 0b01, 0b000000);
1759
public:
1760
INSN(fabsd, 0b000, 0b01, 0b000001);
1761
INSN(fnegd, 0b000, 0b01, 0b000010);
1762
INSN(fsqrtd, 0b000, 0b01, 0b000011);
1763
INSN(fcvtd, 0b000, 0b01, 0b000100); // Double-precision to single-precision
1764
1765
void fmovd(FloatRegister Vd, FloatRegister Vn) {
1766
assert(Vd != Vn, "should be");
1767
i_fmovd(Vd, Vn);
1768
}
1769
1770
void fmovs(FloatRegister Vd, FloatRegister Vn) {
1771
assert(Vd != Vn, "should be");
1772
i_fmovs(Vd, Vn);
1773
}
1774
1775
#undef INSN
1776
1777
// Floating-point data-processing (2 source)
1778
void data_processing(unsigned op31, unsigned type, unsigned opcode,
1779
FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) {
1780
starti;
1781
f(op31, 31, 29);
1782
f(0b11110, 28, 24);
1783
f(type, 23, 22), f(1, 21), f(opcode, 15, 12), f(0b10, 11, 10);
1784
rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
1785
}
1786
1787
#define INSN(NAME, op31, type, opcode) \
1788
void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
1789
data_processing(op31, type, opcode, Vd, Vn, Vm); \
1790
}
1791
1792
INSN(fmuls, 0b000, 0b00, 0b0000);
1793
INSN(fdivs, 0b000, 0b00, 0b0001);
1794
INSN(fadds, 0b000, 0b00, 0b0010);
1795
INSN(fsubs, 0b000, 0b00, 0b0011);
1796
INSN(fnmuls, 0b000, 0b00, 0b1000);
1797
1798
INSN(fmuld, 0b000, 0b01, 0b0000);
1799
INSN(fdivd, 0b000, 0b01, 0b0001);
1800
INSN(faddd, 0b000, 0b01, 0b0010);
1801
INSN(fsubd, 0b000, 0b01, 0b0011);
1802
INSN(fnmuld, 0b000, 0b01, 0b1000);
1803
1804
#undef INSN
1805
1806
// Floating-point data-processing (3 source)
1807
void data_processing(unsigned op31, unsigned type, unsigned o1, unsigned o0,
1808
FloatRegister Vd, FloatRegister Vn, FloatRegister Vm,
1809
FloatRegister Va) {
1810
starti;
1811
f(op31, 31, 29);
1812
f(0b11111, 28, 24);
1813
f(type, 23, 22), f(o1, 21), f(o0, 15);
1814
rf(Vm, 16), rf(Va, 10), rf(Vn, 5), rf(Vd, 0);
1815
}
1816
1817
#define INSN(NAME, op31, type, o1, o0) \
1818
void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, \
1819
FloatRegister Va) { \
1820
data_processing(op31, type, o1, o0, Vd, Vn, Vm, Va); \
1821
}
1822
1823
INSN(fmadds, 0b000, 0b00, 0, 0);
1824
INSN(fmsubs, 0b000, 0b00, 0, 1);
1825
INSN(fnmadds, 0b000, 0b00, 1, 0);
1826
INSN(fnmsubs, 0b000, 0b00, 1, 1);
1827
1828
INSN(fmaddd, 0b000, 0b01, 0, 0);
1829
INSN(fmsubd, 0b000, 0b01, 0, 1);
1830
INSN(fnmaddd, 0b000, 0b01, 1, 0);
1831
INSN(fnmsub, 0b000, 0b01, 1, 1);
1832
1833
#undef INSN
1834
1835
// Floating-point conditional select
1836
void fp_conditional_select(unsigned op31, unsigned type,
1837
unsigned op1, unsigned op2,
1838
Condition cond, FloatRegister Vd,
1839
FloatRegister Vn, FloatRegister Vm) {
1840
starti;
1841
f(op31, 31, 29);
1842
f(0b11110, 28, 24);
1843
f(type, 23, 22);
1844
f(op1, 21, 21);
1845
f(op2, 11, 10);
1846
f(cond, 15, 12);
1847
rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
1848
}
1849
1850
#define INSN(NAME, op31, type, op1, op2) \
1851
void NAME(FloatRegister Vd, FloatRegister Vn, \
1852
FloatRegister Vm, Condition cond) { \
1853
fp_conditional_select(op31, type, op1, op2, cond, Vd, Vn, Vm); \
1854
}
1855
1856
INSN(fcsels, 0b000, 0b00, 0b1, 0b11);
1857
INSN(fcseld, 0b000, 0b01, 0b1, 0b11);
1858
1859
#undef INSN
1860
1861
// Floating-point<->integer conversions
1862
void float_int_convert(unsigned op31, unsigned type,
1863
unsigned rmode, unsigned opcode,
1864
Register Rd, Register Rn) {
1865
starti;
1866
f(op31, 31, 29);
1867
f(0b11110, 28, 24);
1868
f(type, 23, 22), f(1, 21), f(rmode, 20, 19);
1869
f(opcode, 18, 16), f(0b000000, 15, 10);
1870
zrf(Rn, 5), zrf(Rd, 0);
1871
}
1872
1873
#define INSN(NAME, op31, type, rmode, opcode) \
1874
void NAME(Register Rd, FloatRegister Vn) { \
1875
float_int_convert(op31, type, rmode, opcode, Rd, (Register)Vn); \
1876
}
1877
1878
INSN(fcvtzsw, 0b000, 0b00, 0b11, 0b000);
1879
INSN(fcvtzs, 0b100, 0b00, 0b11, 0b000);
1880
INSN(fcvtzdw, 0b000, 0b01, 0b11, 0b000);
1881
INSN(fcvtzd, 0b100, 0b01, 0b11, 0b000);
1882
1883
INSN(fmovs, 0b000, 0b00, 0b00, 0b110);
1884
INSN(fmovd, 0b100, 0b01, 0b00, 0b110);
1885
1886
// INSN(fmovhid, 0b100, 0b10, 0b01, 0b110);
1887
1888
#undef INSN
1889
1890
#define INSN(NAME, op31, type, rmode, opcode) \
1891
void NAME(FloatRegister Vd, Register Rn) { \
1892
float_int_convert(op31, type, rmode, opcode, (Register)Vd, Rn); \
1893
}
1894
1895
INSN(fmovs, 0b000, 0b00, 0b00, 0b111);
1896
INSN(fmovd, 0b100, 0b01, 0b00, 0b111);
1897
1898
INSN(scvtfws, 0b000, 0b00, 0b00, 0b010);
1899
INSN(scvtfs, 0b100, 0b00, 0b00, 0b010);
1900
INSN(scvtfwd, 0b000, 0b01, 0b00, 0b010);
1901
INSN(scvtfd, 0b100, 0b01, 0b00, 0b010);
1902
1903
// INSN(fmovhid, 0b100, 0b10, 0b01, 0b111);
1904
1905
#undef INSN
1906
1907
// Floating-point compare
1908
void float_compare(unsigned op31, unsigned type,
1909
unsigned op, unsigned op2,
1910
FloatRegister Vn, FloatRegister Vm = (FloatRegister)0) {
1911
starti;
1912
f(op31, 31, 29);
1913
f(0b11110, 28, 24);
1914
f(type, 23, 22), f(1, 21);
1915
f(op, 15, 14), f(0b1000, 13, 10), f(op2, 4, 0);
1916
rf(Vn, 5), rf(Vm, 16);
1917
}
1918
1919
1920
#define INSN(NAME, op31, type, op, op2) \
1921
void NAME(FloatRegister Vn, FloatRegister Vm) { \
1922
float_compare(op31, type, op, op2, Vn, Vm); \
1923
}
1924
1925
#define INSN1(NAME, op31, type, op, op2) \
1926
void NAME(FloatRegister Vn, double d) { \
1927
assert_cond(d == 0.0); \
1928
float_compare(op31, type, op, op2, Vn); \
1929
}
1930
1931
INSN(fcmps, 0b000, 0b00, 0b00, 0b00000);
1932
INSN1(fcmps, 0b000, 0b00, 0b00, 0b01000);
1933
// INSN(fcmpes, 0b000, 0b00, 0b00, 0b10000);
1934
// INSN1(fcmpes, 0b000, 0b00, 0b00, 0b11000);
1935
1936
INSN(fcmpd, 0b000, 0b01, 0b00, 0b00000);
1937
INSN1(fcmpd, 0b000, 0b01, 0b00, 0b01000);
1938
// INSN(fcmped, 0b000, 0b01, 0b00, 0b10000);
1939
// INSN1(fcmped, 0b000, 0b01, 0b00, 0b11000);
1940
1941
#undef INSN
1942
#undef INSN1
1943
1944
// Floating-point Move (immediate)
1945
private:
1946
unsigned pack(double value);
1947
1948
void fmov_imm(FloatRegister Vn, double value, unsigned size) {
1949
starti;
1950
f(0b00011110, 31, 24), f(size, 23, 22), f(1, 21);
1951
f(pack(value), 20, 13), f(0b10000000, 12, 5);
1952
rf(Vn, 0);
1953
}
1954
1955
public:
1956
1957
void fmovs(FloatRegister Vn, double value) {
1958
if (value)
1959
fmov_imm(Vn, value, 0b00);
1960
else
1961
fmovs(Vn, zr);
1962
}
1963
void fmovd(FloatRegister Vn, double value) {
1964
if (value)
1965
fmov_imm(Vn, value, 0b01);
1966
else
1967
fmovd(Vn, zr);
1968
}
1969
1970
/* SIMD extensions
1971
*
1972
* We just use FloatRegister in the following. They are exactly the same
1973
* as SIMD registers.
1974
*/
1975
public:
1976
1977
enum SIMD_Arrangement {
1978
T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D
1979
};
1980
1981
enum SIMD_RegVariant {
1982
B, H, S, D, Q
1983
};
1984
1985
#define INSN(NAME, op) \
1986
void NAME(FloatRegister Rt, SIMD_RegVariant T, const Address &adr) { \
1987
ld_st2((Register)Rt, adr, (int)T & 3, op + ((T==Q) ? 0b10:0b00), 1); \
1988
} \
1989
1990
INSN(ldr, 1);
1991
INSN(str, 0);
1992
1993
#undef INSN
1994
1995
private:
1996
1997
void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn, int op1, int op2) {
1998
starti;
1999
f(0,31), f((int)T & 1, 30);
2000
f(op1, 29, 21), f(0, 20, 16), f(op2, 15, 12);
2001
f((int)T >> 1, 11, 10), rf(Xn, 5), rf(Vt, 0);
2002
}
2003
void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn,
2004
int imm, int op1, int op2) {
2005
starti;
2006
f(0,31), f((int)T & 1, 30);
2007
f(op1 | 0b100, 29, 21), f(0b11111, 20, 16), f(op2, 15, 12);
2008
f((int)T >> 1, 11, 10), rf(Xn, 5), rf(Vt, 0);
2009
}
2010
void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn,
2011
Register Xm, int op1, int op2) {
2012
starti;
2013
f(0,31), f((int)T & 1, 30);
2014
f(op1 | 0b100, 29, 21), rf(Xm, 16), f(op2, 15, 12);
2015
f((int)T >> 1, 11, 10), rf(Xn, 5), rf(Vt, 0);
2016
}
2017
2018
void ld_st(FloatRegister Vt, SIMD_Arrangement T, Address a, int op1, int op2) {
2019
switch (a.getMode()) {
2020
case Address::base_plus_offset:
2021
guarantee(a.offset() == 0, "no offset allowed here");
2022
ld_st(Vt, T, a.base(), op1, op2);
2023
break;
2024
case Address::post:
2025
ld_st(Vt, T, a.base(), a.offset(), op1, op2);
2026
break;
2027
case Address::base_plus_offset_reg:
2028
ld_st(Vt, T, a.base(), a.index(), op1, op2);
2029
break;
2030
default:
2031
ShouldNotReachHere();
2032
}
2033
}
2034
2035
public:
2036
2037
#define INSN1(NAME, op1, op2) \
2038
void NAME(FloatRegister Vt, SIMD_Arrangement T, const Address &a) { \
2039
ld_st(Vt, T, a, op1, op2); \
2040
}
2041
2042
#define INSN2(NAME, op1, op2) \
2043
void NAME(FloatRegister Vt, FloatRegister Vt2, SIMD_Arrangement T, const Address &a) { \
2044
assert(Vt->successor() == Vt2, "Registers must be ordered"); \
2045
ld_st(Vt, T, a, op1, op2); \
2046
}
2047
2048
#define INSN3(NAME, op1, op2) \
2049
void NAME(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, \
2050
SIMD_Arrangement T, const Address &a) { \
2051
assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3, \
2052
"Registers must be ordered"); \
2053
ld_st(Vt, T, a, op1, op2); \
2054
}
2055
2056
#define INSN4(NAME, op1, op2) \
2057
void NAME(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, \
2058
FloatRegister Vt4, SIMD_Arrangement T, const Address &a) { \
2059
assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 && \
2060
Vt3->successor() == Vt4, "Registers must be ordered"); \
2061
ld_st(Vt, T, a, op1, op2); \
2062
}
2063
2064
INSN1(ld1, 0b001100010, 0b0111);
2065
INSN2(ld1, 0b001100010, 0b1010);
2066
INSN3(ld1, 0b001100010, 0b0110);
2067
INSN4(ld1, 0b001100010, 0b0010);
2068
2069
INSN2(ld2, 0b001100010, 0b1000);
2070
INSN3(ld3, 0b001100010, 0b0100);
2071
INSN4(ld4, 0b001100010, 0b0000);
2072
2073
INSN1(st1, 0b001100000, 0b0111);
2074
INSN2(st1, 0b001100000, 0b1010);
2075
INSN3(st1, 0b001100000, 0b0110);
2076
INSN4(st1, 0b001100000, 0b0010);
2077
2078
INSN2(st2, 0b001100000, 0b1000);
2079
INSN3(st3, 0b001100000, 0b0100);
2080
INSN4(st4, 0b001100000, 0b0000);
2081
2082
INSN1(ld1r, 0b001101010, 0b1100);
2083
INSN2(ld2r, 0b001101011, 0b1100);
2084
INSN3(ld3r, 0b001101010, 0b1110);
2085
INSN4(ld4r, 0b001101011, 0b1110);
2086
2087
#undef INSN1
2088
#undef INSN2
2089
#undef INSN3
2090
#undef INSN4
2091
2092
#define INSN(NAME, opc) \
2093
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2094
starti; \
2095
assert(T == T8B || T == T16B, "must be T8B or T16B"); \
2096
f(0, 31), f((int)T & 1, 30), f(opc, 29, 21); \
2097
rf(Vm, 16), f(0b000111, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2098
}
2099
2100
INSN(eor, 0b101110001);
2101
INSN(orr, 0b001110101);
2102
INSN(andr, 0b001110001);
2103
INSN(bic, 0b001110011);
2104
INSN(bif, 0b101110111);
2105
INSN(bit, 0b101110101);
2106
INSN(bsl, 0b101110011);
2107
INSN(orn, 0b001110111);
2108
2109
#undef INSN
2110
2111
#define INSN(NAME, opc, opc2) \
2112
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2113
starti; \
2114
f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2115
f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10); \
2116
rf(Vn, 5), rf(Vd, 0); \
2117
}
2118
2119
INSN(addv, 0, 0b100001);
2120
INSN(subv, 1, 0b100001);
2121
INSN(mulv, 0, 0b100111);
2122
INSN(mlav, 0, 0b100101);
2123
INSN(mlsv, 1, 0b100101);
2124
INSN(sshl, 0, 0b010001);
2125
INSN(ushl, 1, 0b010001);
2126
2127
#undef INSN
2128
2129
#define INSN(NAME, opc, opc2) \
2130
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2131
starti; \
2132
f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2133
f((int)T >> 1, 23, 22), f(opc2, 21, 10); \
2134
rf(Vn, 5), rf(Vd, 0); \
2135
}
2136
2137
INSN(absr, 0, 0b100000101110);
2138
INSN(negr, 1, 0b100000101110);
2139
INSN(notr, 1, 0b100000010110);
2140
INSN(addv, 0, 0b110001101110);
2141
INSN(cls, 0, 0b100000010010);
2142
INSN(clz, 1, 0b100000010010);
2143
INSN(cnt, 0, 0b100000010110);
2144
2145
#undef INSN
2146
2147
#define INSN(NAME, op0, cmode0) \
2148
void NAME(FloatRegister Vd, SIMD_Arrangement T, unsigned imm8, unsigned lsl = 0) { \
2149
unsigned cmode = cmode0; \
2150
unsigned op = op0; \
2151
starti; \
2152
assert(lsl == 0 || \
2153
((T == T4H || T == T8H) && lsl == 8) || \
2154
((T == T2S || T == T4S) && ((lsl >> 3) < 4)), "invalid shift"); \
2155
cmode |= lsl >> 2; \
2156
if (T == T4H || T == T8H) cmode |= 0b1000; \
2157
if (!(T == T4H || T == T8H || T == T2S || T == T4S)) { \
2158
assert(op == 0 && cmode0 == 0, "must be MOVI"); \
2159
cmode = 0b1110; \
2160
if (T == T1D || T == T2D) op = 1; \
2161
} \
2162
f(0, 31), f((int)T & 1, 30), f(op, 29), f(0b0111100000, 28, 19); \
2163
f(imm8 >> 5, 18, 16), f(cmode, 15, 12), f(0x01, 11, 10), f(imm8 & 0b11111, 9, 5); \
2164
rf(Vd, 0); \
2165
}
2166
2167
INSN(movi, 0, 0);
2168
INSN(orri, 0, 1);
2169
INSN(mvni, 1, 0);
2170
INSN(bici, 1, 1);
2171
2172
#undef INSN
2173
2174
#define INSN(NAME, op1, op2, op3) \
2175
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2176
starti; \
2177
assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2178
f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \
2179
f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2180
}
2181
2182
INSN(fadd, 0, 0, 0b110101);
2183
INSN(fdiv, 1, 0, 0b111111);
2184
INSN(fmul, 1, 0, 0b110111);
2185
INSN(fsub, 0, 1, 0b110101);
2186
2187
#undef INSN
2188
2189
#define INSN(NAME, opc) \
2190
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2191
starti; \
2192
assert(T == T4S, "arrangement must be T4S"); \
2193
f(0b01011110000, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2194
}
2195
2196
INSN(sha1c, 0b000000);
2197
INSN(sha1m, 0b001000);
2198
INSN(sha1p, 0b000100);
2199
INSN(sha1su0, 0b001100);
2200
INSN(sha256h2, 0b010100);
2201
INSN(sha256h, 0b010000);
2202
INSN(sha256su1, 0b011000);
2203
2204
#undef INSN
2205
2206
#define INSN(NAME, opc) \
2207
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2208
starti; \
2209
assert(T == T4S, "arrangement must be T4S"); \
2210
f(0b0101111000101000, 31, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2211
}
2212
2213
INSN(sha1h, 0b000010);
2214
INSN(sha1su1, 0b000110);
2215
INSN(sha256su0, 0b001010);
2216
2217
#undef INSN
2218
2219
#define INSN(NAME, opc) \
2220
void NAME(FloatRegister Vd, FloatRegister Vn) { \
2221
starti; \
2222
f(opc, 31, 10), rf(Vn, 5), rf(Vd, 0); \
2223
}
2224
2225
INSN(aese, 0b0100111000101000010010);
2226
INSN(aesd, 0b0100111000101000010110);
2227
INSN(aesmc, 0b0100111000101000011010);
2228
INSN(aesimc, 0b0100111000101000011110);
2229
2230
#undef INSN
2231
2232
void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
2233
starti;
2234
assert(T != Q, "invalid register variant");
2235
f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
2236
f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
2237
}
2238
2239
void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2240
starti;
2241
f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2242
f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
2243
rf(Vn, 5), rf(Rd, 0);
2244
}
2245
2246
#define INSN(NAME, opc, opc2) \
2247
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
2248
starti; \
2249
/* The encodings for the immh:immb fields (bits 22:16) are \
2250
* 0001 xxx 8B/16B, shift = xxx \
2251
* 001x xxx 4H/8H, shift = xxxx \
2252
* 01xx xxx 2S/4S, shift = xxxxx \
2253
* 1xxx xxx 1D/2D, shift = xxxxxx (1D is RESERVED) \
2254
*/ \
2255
assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
2256
f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
2257
f((1 << ((T>>1)+3))|shift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2258
}
2259
2260
INSN(shl, 0, 0b010101);
2261
INSN(sshr, 0, 0b000001);
2262
INSN(ushr, 1, 0b000001);
2263
2264
#undef INSN
2265
2266
void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2267
starti;
2268
/* The encodings for the immh:immb fields (bits 22:16) are
2269
* 0001 xxx 8H, 8B/16b shift = xxx
2270
* 001x xxx 4S, 4H/8H shift = xxxx
2271
* 01xx xxx 2D, 2S/4S shift = xxxxx
2272
* 1xxx xxx RESERVED
2273
*/
2274
assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement");
2275
assert((1 << ((Tb>>1)+3)) > shift, "Invalid shift value");
2276
f(0, 31), f(Tb & 1, 30), f(0b1011110, 29, 23), f((1 << ((Tb>>1)+3))|shift, 22, 16);
2277
f(0b101001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2278
}
2279
void ushll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2280
ushll(Vd, Ta, Vn, Tb, shift);
2281
}
2282
2283
void uzp1(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement T, int op = 0){
2284
starti;
2285
f(0, 31), f((T & 0x1), 30), f(0b001110, 29, 24), f((T >> 1), 23, 22), f(0, 21);
2286
rf(Vm, 16), f(0, 15), f(op, 14), f(0b0110, 13, 10), rf(Vn, 5), rf(Vd, 0);
2287
}
2288
void uzp2(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement T){
2289
uzp1(Vd, Vn, Vm, T, 1);
2290
}
2291
2292
// Move from general purpose register
2293
// mov Vd.T[index], Rn
2294
void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) {
2295
starti;
2296
f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2297
f(0b000111, 15, 10), rf(Xn, 5), rf(Vd, 0);
2298
}
2299
2300
// Move to general purpose register
2301
// mov Rd, Vn.T[index]
2302
void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) {
2303
starti;
2304
f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21);
2305
f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2306
f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0);
2307
}
2308
2309
// We do not handle the 1Q arrangement.
2310
void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2311
starti;
2312
assert(Ta == T8H && (Tb == T8B || Tb == T16B), "Invalid Size specifier");
2313
f(0, 31), f(Tb & 1, 30), f(0b001110001, 29, 21), rf(Vm, 16), f(0b111000, 15, 10);
2314
rf(Vn, 5), rf(Vd, 0);
2315
}
2316
void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2317
pmull(Vd, Ta, Vn, Vm, Tb);
2318
}
2319
2320
void uqxtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2321
starti;
2322
int size_b = (int)Tb >> 1;
2323
int size_a = (int)Ta >> 1;
2324
assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2325
f(0, 31), f(Tb & 1, 30), f(0b101110, 29, 24), f(size_b, 23, 22);
2326
f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2327
}
2328
2329
void rev32(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn)
2330
{
2331
starti;
2332
assert(T <= T8H, "must be one of T8B, T16B, T4H, T8H");
2333
f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24);
2334
f(T <= T16B ? 0b00 : 0b01, 23, 22), f(0b100000000010, 21, 10);
2335
rf(Vn, 5), rf(Vd, 0);
2336
}
2337
2338
void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
2339
{
2340
starti;
2341
assert(T != T1D, "reserved encoding");
2342
f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2343
f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), rf(Xs, 5), rf(Vd, 0);
2344
}
2345
2346
void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
2347
{
2348
starti;
2349
assert(T != T1D, "reserved encoding");
2350
f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2351
f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2352
f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2353
}
2354
2355
// CRC32 instructions
2356
#define INSN(NAME, sf, sz) \
2357
void NAME(Register Rd, Register Rn, Register Rm) { \
2358
starti; \
2359
f(sf, 31), f(0b0011010110, 30, 21), f(0b0100, 15, 12), f(sz, 11, 10); \
2360
rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); \
2361
}
2362
2363
INSN(crc32b, 0, 0b00);
2364
INSN(crc32h, 0, 0b01);
2365
INSN(crc32w, 0, 0b10);
2366
INSN(crc32x, 1, 0b11);
2367
2368
#undef INSN
2369
2370
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
2371
}
2372
2373
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
2374
Register tmp,
2375
int offset) {
2376
ShouldNotCallThis();
2377
return RegisterOrConstant();
2378
}
2379
2380
// Stack overflow checking
2381
virtual void bang_stack_with_offset(int offset);
2382
2383
static bool operand_valid_for_logical_immediate(bool is32, uint64_t imm);
2384
static bool operand_valid_for_add_sub_immediate(long imm);
2385
static bool operand_valid_for_float_immediate(double imm);
2386
2387
void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0);
2388
void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0);
2389
};
2390
2391
inline Assembler::Membar_mask_bits operator|(Assembler::Membar_mask_bits a,
2392
Assembler::Membar_mask_bits b) {
2393
return Assembler::Membar_mask_bits(unsigned(a)|unsigned(b));
2394
}
2395
2396
Instruction_aarch64::~Instruction_aarch64() {
2397
assem->emit();
2398
}
2399
2400
#undef starti
2401
2402
// Invert a condition
2403
inline const Assembler::Condition operator~(const Assembler::Condition cond) {
2404
return Assembler::Condition(int(cond) ^ 1);
2405
}
2406
2407
class BiasedLockingCounters;
2408
2409
extern "C" void das(uint64_t start, int len);
2410
2411
#endif // CPU_AARCH64_VM_ASSEMBLER_AARCH64_HPP
2412
2413