Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/cpu/arm/assembler_arm_32.hpp
40930 views
1
/*
2
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#ifndef CPU_ARM_ASSEMBLER_ARM_32_HPP
26
#define CPU_ARM_ASSEMBLER_ARM_32_HPP
27
28
// ARM Addressing Mode 1 - Data processing operands
29
class AsmOperand {
30
private:
31
int _encoding;
32
33
void initialize_rotated_imm(unsigned int imm);
34
35
void encode(int imm_8) {
36
if ((imm_8 >> 8) == 0) {
37
_encoding = 1 << 25 | imm_8; // the most common case
38
} else {
39
initialize_rotated_imm((unsigned int)imm_8); // slow case
40
}
41
}
42
43
void encode(Register rm, AsmShift shift, int shift_imm) {
44
assert((shift_imm >> 5) == 0, "encoding constraint");
45
_encoding = shift_imm << 7 | shift << 5 | rm->encoding();
46
}
47
48
public:
49
50
AsmOperand(Register reg) {
51
_encoding = reg->encoding();
52
}
53
54
AsmOperand(int imm_8) {
55
encode(imm_8);
56
}
57
58
AsmOperand(ByteSize bytesize_8) :
59
AsmOperand(in_bytes(bytesize_8)) {}
60
61
AsmOperand(Register rm, AsmShift shift, int shift_imm) {
62
encode(rm,shift,shift_imm);
63
}
64
65
AsmOperand(Register rm, AsmShift shift, Register rs) {
66
assert(rm != PC && rs != PC, "unpredictable instruction");
67
_encoding = rs->encoding() << 8 | shift << 5 | 1 << 4 | rm->encoding();
68
}
69
70
AsmOperand(RegisterOrConstant offset, AsmShift shift = lsl, int shift_imm = 0) {
71
if (offset.is_register()) {
72
encode(offset.as_register(), shift, shift_imm);
73
} else {
74
assert(shift == lsl,"shift type not yet encoded");
75
int imm_8 = ((int)offset.as_constant()) << shift_imm;
76
encode(imm_8);
77
}
78
}
79
80
int encoding() const {
81
return _encoding;
82
}
83
84
bool is_immediate() const {
85
return _encoding & (1 << 25) ? true : false;
86
}
87
88
Register base_register() const {
89
assert(!is_immediate(), "is_immediate, no base reg");
90
return as_Register(_encoding & 15);
91
}
92
93
static bool is_rotated_imm(unsigned int imm);
94
};
95
96
97
// ARM Addressing Mode 4 - Load and store multiple
98
class RegisterSet {
99
private:
100
int _encoding;
101
102
RegisterSet(int encoding) {
103
_encoding = encoding;
104
}
105
106
public:
107
108
RegisterSet(Register reg) {
109
_encoding = 1 << reg->encoding();
110
}
111
112
RegisterSet() {
113
_encoding = 0;
114
}
115
116
RegisterSet(Register first, Register last) {
117
assert(first < last, "encoding constraint");
118
_encoding = (1 << (last->encoding() + 1)) - (1 << first->encoding());
119
}
120
121
friend RegisterSet operator | (const RegisterSet set1, const RegisterSet set2) {
122
assert((set1._encoding & set2._encoding) == 0,
123
"encoding constraint");
124
return RegisterSet(set1._encoding | set2._encoding);
125
}
126
127
int encoding() const {
128
return _encoding;
129
}
130
131
bool contains(Register reg) const {
132
return (_encoding & (1 << reg->encoding())) != 0;
133
}
134
135
// number of registers in the set
136
int size() const {
137
int count = 0;
138
unsigned int remaining = (unsigned int) _encoding;
139
while (remaining != 0) {
140
if ((remaining & 1) != 0) count++;
141
remaining >>= 1;
142
}
143
return count;
144
}
145
};
146
147
#if R9_IS_SCRATCHED
148
#define R9ifScratched RegisterSet(R9)
149
#else
150
#define R9ifScratched RegisterSet()
151
#endif
152
153
// ARM Addressing Mode 5 - Load and store multiple VFP registers
154
class FloatRegisterSet {
155
private:
156
int _encoding;
157
158
public:
159
160
FloatRegisterSet(FloatRegister reg) {
161
if (reg->hi_bit() == 0) {
162
_encoding = reg->hi_bits() << 12 | reg->lo_bit() << 22 | 1;
163
} else {
164
assert (reg->lo_bit() == 0, "impossible encoding");
165
_encoding = reg->hi_bits() << 12 | reg->hi_bit() << 22 | 1;
166
}
167
}
168
169
FloatRegisterSet(FloatRegister first, int count) {
170
assert(count >= 1, "encoding constraint");
171
if (first->hi_bit() == 0) {
172
_encoding = first->hi_bits() << 12 | first->lo_bit() << 22 | count;
173
} else {
174
assert (first->lo_bit() == 0, "impossible encoding");
175
_encoding = first->hi_bits() << 12 | first->hi_bit() << 22 | count;
176
}
177
}
178
179
int encoding_s() const {
180
return _encoding;
181
}
182
183
int encoding_d() const {
184
assert((_encoding & 0xFF) <= 16, "no more than 16 double registers" );
185
return (_encoding & 0xFFFFFF00) | ((_encoding & 0xFF) << 1);
186
}
187
188
};
189
190
191
class Assembler : public AbstractAssembler {
192
193
public:
194
195
static const int LogInstructionSize = 2;
196
static const int InstructionSize = 1 << LogInstructionSize;
197
198
//---< calculate length of instruction >---
199
// We just use the values set above.
200
// instruction must start at passed address
201
static unsigned int instr_len(unsigned char *instr) { return InstructionSize; }
202
203
//---< longest instructions >---
204
static unsigned int instr_maxlen() { return InstructionSize; }
205
206
static inline AsmCondition inverse(AsmCondition cond) {
207
assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed");
208
return (AsmCondition)((int)cond ^ 1);
209
}
210
211
// Returns true if given value can be used as immediate in arithmetic (add/sub/cmp/cmn) instructions.
212
static inline bool is_arith_imm_in_range(intx value) {
213
return AsmOperand::is_rotated_imm(value);
214
}
215
216
// Arithmetic instructions
217
218
#define F(mnemonic, opcode) \
219
void mnemonic(Register rd, Register rn, AsmOperand operand, AsmCondition cond = al) { \
220
emit_int32(cond << 28 | opcode << 21 | rn->encoding() << 16 | \
221
rd->encoding() << 12 | operand.encoding()); \
222
} \
223
void mnemonic##s(Register rd, Register rn, AsmOperand operand, AsmCondition cond = al) { \
224
emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rn->encoding() << 16 | \
225
rd->encoding() << 12 | operand.encoding()); \
226
}
227
228
F(andr, 0)
229
F(eor, 1)
230
F(sub, 2)
231
F(rsb, 3)
232
F(add, 4)
233
F(adc, 5)
234
F(sbc, 6)
235
F(rsc, 7)
236
F(orr, 12)
237
F(bic, 14)
238
#undef F
239
240
#define F(mnemonic, opcode) \
241
void mnemonic(Register rn, AsmOperand operand, AsmCondition cond = al) { \
242
emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rn->encoding() << 16 | \
243
operand.encoding()); \
244
}
245
246
F(tst, 8)
247
F(teq, 9)
248
F(cmp, 10)
249
F(cmn, 11)
250
#undef F
251
252
#define F(mnemonic, opcode) \
253
void mnemonic(Register rd, AsmOperand operand, AsmCondition cond = al) { \
254
emit_int32(cond << 28 | opcode << 21 | rd->encoding() << 12 | \
255
operand.encoding()); \
256
} \
257
void mnemonic##s(Register rd, AsmOperand operand, AsmCondition cond = al) { \
258
emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rd->encoding() << 12 | \
259
operand.encoding()); \
260
}
261
262
F(mov, 13)
263
F(mvn, 15)
264
#undef F
265
266
void msr(uint fields, AsmOperand operand, AsmCondition cond = al) {
267
assert((operand.encoding() & (1<<25)) || ((operand.encoding() & 0xff0) == 0), "invalid addressing mode");
268
emit_int32(cond << 28 | 1 << 24 | 1 << 21 | fields << 16 | 0xf << 12 | operand.encoding());
269
}
270
271
void mrs(uint fields, Register Rd, AsmCondition cond = al) {
272
emit_int32(cond << 28 | 1 << 24 | (fields|0xf) << 16 | (Rd->encoding() << 12));
273
}
274
275
276
enum {
277
CPSR = 0x00, CPSR_c = 0x01, CPSR_x = 0x02, CPSR_xc = 0x03,
278
CPSR_s = 0x004, CPSR_sc = 0x05, CPSR_sx = 0x06, CPSR_sxc = 0x07,
279
CPSR_f = 0x08, CPSR_fc = 0x09, CPSR_fx = 0x0a, CPSR_fxc = 0x0b,
280
CPSR_fs = 0x0c, CPSR_fsc = 0x0d, CPSR_fsx = 0x0e, CPSR_fsxc = 0x0f,
281
SPSR = 0x40, SPSR_c = 0x41, SPSR_x = 0x42, SPSR_xc = 0x43,
282
SPSR_s = 0x44, SPSR_sc = 0x45, SPSR_sx = 0x46, SPSR_sxc = 0x47,
283
SPSR_f = 0x48, SPSR_fc = 0x49, SPSR_fx = 0x4a, SPSR_fxc = 0x4b,
284
SPSR_fs = 0x4c, SPSR_fsc = 0x4d, SPSR_fsx = 0x4e, SPSR_fsxc = 0x4f
285
};
286
287
#define F(mnemonic, opcode) \
288
void mnemonic(Register rdlo, Register rdhi, Register rm, Register rs, \
289
AsmCondition cond = al) { \
290
emit_int32(cond << 28 | opcode << 21 | rdhi->encoding() << 16 | \
291
rdlo->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding()); \
292
} \
293
void mnemonic##s(Register rdlo, Register rdhi, Register rm, Register rs, \
294
AsmCondition cond = al) { \
295
emit_int32(cond << 28 | opcode << 21 | 1 << 20 | rdhi->encoding() << 16 | \
296
rdlo->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding()); \
297
}
298
299
F(umull, 4)
300
F(umlal, 5)
301
F(smull, 6)
302
F(smlal, 7)
303
#undef F
304
305
void mul(Register rd, Register rm, Register rs, AsmCondition cond = al) {
306
emit_int32(cond << 28 | rd->encoding() << 16 |
307
rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
308
}
309
310
void muls(Register rd, Register rm, Register rs, AsmCondition cond = al) {
311
emit_int32(cond << 28 | 1 << 20 | rd->encoding() << 16 |
312
rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
313
}
314
315
void mla(Register rd, Register rm, Register rs, Register rn, AsmCondition cond = al) {
316
emit_int32(cond << 28 | 1 << 21 | rd->encoding() << 16 |
317
rn->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
318
}
319
320
void mlas(Register rd, Register rm, Register rs, Register rn, AsmCondition cond = al) {
321
emit_int32(cond << 28 | 1 << 21 | 1 << 20 | rd->encoding() << 16 |
322
rn->encoding() << 12 | rs->encoding() << 8 | 0x9 << 4 | rm->encoding());
323
}
324
325
// Loads and stores
326
327
#define F(mnemonic, l, b) \
328
void mnemonic(Register rd, Address addr, AsmCondition cond = al) { \
329
emit_int32(cond << 28 | 1 << 26 | b << 22 | l << 20 | \
330
rd->encoding() << 12 | addr.encoding2()); \
331
}
332
333
F(ldr, 1, 0)
334
F(ldrb, 1, 1)
335
F(str, 0, 0)
336
F(strb, 0, 1)
337
#undef F
338
339
#undef F
340
341
#define F(mnemonic, l, sh, even) \
342
void mnemonic(Register rd, Address addr, AsmCondition cond = al) { \
343
assert(!even || (rd->encoding() & 1) == 0, "must be even"); \
344
emit_int32(cond << 28 | l << 20 | rd->encoding() << 12 | \
345
1 << 7 | sh << 5 | 1 << 4 | addr.encoding3()); \
346
}
347
348
F(strh, 0, 1, false)
349
F(ldrh, 1, 1, false)
350
F(ldrsb, 1, 2, false)
351
F(ldrsh, 1, 3, false)
352
F(strd, 0, 3, true)
353
354
#undef F
355
356
void ldrd(Register rd, Address addr, AsmCondition cond = al) {
357
assert((rd->encoding() & 1) == 0, "must be even");
358
assert(!addr.index()->is_valid() ||
359
(addr.index()->encoding() != rd->encoding() &&
360
addr.index()->encoding() != (rd->encoding()+1)), "encoding constraint");
361
emit_int32(cond << 28 | rd->encoding() << 12 | 0xD /* 0b1101 */ << 4 | addr.encoding3());
362
}
363
364
#define F(mnemonic, l, pu) \
365
void mnemonic(Register rn, RegisterSet reg_set, \
366
AsmWriteback w = no_writeback, AsmCondition cond = al) { \
367
assert(reg_set.encoding() != 0 && (w == no_writeback || \
368
(reg_set.encoding() & (1 << rn->encoding())) == 0), \
369
"unpredictable instruction"); \
370
emit_int32(cond << 28 | 4 << 25 | pu << 23 | w << 21 | l << 20 | \
371
rn->encoding() << 16 | reg_set.encoding()); \
372
}
373
374
F(ldmda, 1, 0) F(ldmfa, 1, 0)
375
F(ldmia, 1, 1) F(ldmfd, 1, 1)
376
F(ldmdb, 1, 2) F(ldmea, 1, 2)
377
F(ldmib, 1, 3) F(ldmed, 1, 3)
378
F(stmda, 0, 0) F(stmed, 0, 0)
379
F(stmia, 0, 1) F(stmea, 0, 1)
380
F(stmdb, 0, 2) F(stmfd, 0, 2)
381
F(stmib, 0, 3) F(stmfa, 0, 3)
382
#undef F
383
384
void ldrex(Register rd, Address addr, AsmCondition cond = al) {
385
assert(rd != PC, "unpredictable instruction");
386
emit_int32(cond << 28 | 0x19 << 20 | addr.encoding_ex() |
387
rd->encoding() << 12 | 0xf9f);
388
}
389
390
void strex(Register rs, Register rd, Address addr, AsmCondition cond = al) {
391
assert(rd != PC && rs != PC &&
392
rs != rd && rs != addr.base(), "unpredictable instruction");
393
emit_int32(cond << 28 | 0x18 << 20 | addr.encoding_ex() |
394
rs->encoding() << 12 | 0xf90 | rd->encoding());
395
}
396
397
void ldrexd(Register rd, Address addr, AsmCondition cond = al) {
398
assert(rd != PC, "unpredictable instruction");
399
emit_int32(cond << 28 | 0x1B << 20 | addr.encoding_ex() |
400
rd->encoding() << 12 | 0xf9f);
401
}
402
403
void strexd(Register rs, Register rd, Address addr, AsmCondition cond = al) {
404
assert(rd != PC && rs != PC &&
405
rs != rd && rs != addr.base(), "unpredictable instruction");
406
emit_int32(cond << 28 | 0x1A << 20 | addr.encoding_ex() |
407
rs->encoding() << 12 | 0xf90 | rd->encoding());
408
}
409
410
void clrex() {
411
emit_int32(0xF << 28 | 0x57 << 20 | 0xFF << 12 | 0x01f);
412
}
413
414
// Miscellaneous instructions
415
416
void clz(Register rd, Register rm, AsmCondition cond = al) {
417
emit_int32(cond << 28 | 0x016f0f10 | rd->encoding() << 12 | rm->encoding());
418
}
419
420
void rev(Register rd, Register rm, AsmCondition cond = al) {
421
emit_int32(cond << 28 | 0x06bf0f30 | rd->encoding() << 12 | rm->encoding());
422
}
423
424
void rev16(Register rd, Register rm, AsmCondition cond = al) {
425
emit_int32(cond << 28 | 0x6bf0fb0 | rd->encoding() << 12 | rm->encoding());
426
}
427
428
void revsh(Register rd, Register rm, AsmCondition cond = al) {
429
emit_int32(cond << 28 | 0x6ff0fb0 | rd->encoding() << 12 | rm->encoding());
430
}
431
432
void rbit(Register rd, Register rm, AsmCondition cond = al) {
433
emit_int32(cond << 28 | 0x6ff0f30 | rd->encoding() << 12 | rm->encoding());
434
}
435
436
void pld(Address addr) {
437
emit_int32(0xf550f000 | addr.encoding2());
438
}
439
440
void pldw(Address addr) {
441
assert(!VM_Version::is_initialized() ||
442
(VM_Version::arm_arch() >= 7 && VM_Version::has_multiprocessing_extensions()),
443
"PLDW is available on ARMv7 with Multiprocessing Extensions only");
444
emit_int32(0xf510f000 | addr.encoding2());
445
}
446
447
void svc(int imm_24, AsmCondition cond = al) {
448
assert((imm_24 >> 24) == 0, "encoding constraint");
449
emit_int32(cond << 28 | 0xf << 24 | imm_24);
450
}
451
452
void ubfx(Register rd, Register rn, unsigned int lsb, unsigned int width, AsmCondition cond = al) {
453
assert(VM_Version::arm_arch() >= 7, "no ubfx on this processor");
454
assert(width > 0, "must be");
455
assert(lsb < 32, "must be");
456
emit_int32(cond << 28 | 0x3f << 21 | (width - 1) << 16 | rd->encoding() << 12 |
457
lsb << 7 | 0x5 << 4 | rn->encoding());
458
}
459
460
void uxtb(Register rd, Register rm, unsigned int rotation = 0, AsmCondition cond = al) {
461
assert(VM_Version::arm_arch() >= 7, "no uxtb on this processor");
462
assert((rotation % 8) == 0 && (rotation <= 24), "encoding constraint");
463
emit_int32(cond << 28 | 0x6e << 20 | 0xf << 16 | rd->encoding() << 12 |
464
(rotation >> 3) << 10 | 0x7 << 4 | rm->encoding());
465
}
466
467
// ARM Memory Barriers
468
//
469
// There are two types of memory barriers defined for the ARM processor
470
// DataSynchronizationBarrier and DataMemoryBarrier
471
//
472
// The Linux kernel uses the DataMemoryBarrier for all of it's
473
// memory barrier operations (smp_mb, smp_rmb, smp_wmb)
474
//
475
// There are two forms of each barrier instruction.
476
// The mcr forms are supported on armv5 and newer architectures
477
//
478
// The dmb, dsb instructions were added in armv7
479
// architectures and are compatible with their mcr
480
// predecessors.
481
//
482
// Here are the encodings for future reference:
483
//
484
// DataSynchronizationBarrier (dsb)
485
// on ARMv7 - emit_int32(0xF57FF04F)
486
//
487
// on ARMv5+ - mcr p15, 0, Rtmp, c7, c10, 4 on earlier processors
488
// emit_int32(0xe << 28 | 0xe << 24 | 0x7 << 16 | Rtmp->encoding() << 12 |
489
// 0xf << 8 | 0x9 << 4 | 0xa);
490
//
491
// DataMemoryBarrier (dmb)
492
// on ARMv7 - emit_int32(0xF57FF05F)
493
//
494
// on ARMv5+ - mcr p15, 0, Rtmp, c7, c10, 5 on earlier processors
495
// emit_int32(0xe << 28 | 0xe << 24 | 0x7 << 16 | Rtmp->encoding() << 12 |
496
// 0xf << 8 | 0xb << 4 | 0xa);
497
//
498
499
enum DMB_Opt {
500
DMB_all = 0xf,
501
DMB_st = 0xe,
502
};
503
504
void dmb(DMB_Opt opt, Register reg) {
505
if (VM_Version::arm_arch() >= 7) {
506
emit_int32(0xF57FF050 | opt);
507
} else if (VM_Version::arm_arch() == 6) {
508
bool preserve_tmp = (reg == noreg);
509
if(preserve_tmp) {
510
reg = Rtemp;
511
str(reg, Address(SP, -wordSize, pre_indexed));
512
}
513
mov(reg, 0);
514
// DataMemoryBarrier
515
emit_int32(0xe << 28 |
516
0xe << 24 |
517
0x7 << 16 |
518
reg->encoding() << 12 |
519
0xf << 8 |
520
0xb << 4 |
521
0xa);
522
if(preserve_tmp) {
523
ldr(reg, Address(SP, wordSize, post_indexed));
524
}
525
}
526
}
527
528
void dsb(Register reg) {
529
if (VM_Version::arm_arch() >= 7) {
530
emit_int32(0xF57FF04F);
531
} else {
532
bool preserve_tmp = (reg == noreg);
533
if(preserve_tmp) {
534
reg = Rtemp;
535
str(reg, Address(SP, -wordSize, pre_indexed));
536
}
537
mov(reg, 0);
538
// DataSynchronizationBarrier
539
emit_int32(0xe << 28 |
540
0xe << 24 |
541
0x7 << 16 |
542
reg->encoding() << 12 |
543
0xf << 8 |
544
0x9 << 4 |
545
0xa);
546
if(preserve_tmp) {
547
ldr(reg, Address(SP, wordSize, post_indexed));
548
}
549
}
550
}
551
552
553
#define F(mnemonic, b) \
554
void mnemonic(Register rd, Register rm, Register rn, AsmCondition cond = al) { \
555
assert(rn != rm && rn != rd, "unpredictable instruction"); \
556
emit_int32(cond << 28 | 0x2 << 23 | b << 22 | rn->encoding() << 16 | \
557
rd->encoding() << 12 | 9 << 4 | rm->encoding()); \
558
}
559
560
F(swp, 0)
561
F(swpb, 1)
562
#undef F
563
564
// Branches
565
566
#define F(mnemonic, l) \
567
void mnemonic(Register rm, AsmCondition cond = al) { \
568
emit_int32(cond << 28 | 0x012fff10 | l << 5 | rm->encoding()); \
569
}
570
571
F(bx, 0)
572
F(blx, 1)
573
#undef F
574
575
#define F(mnemonic, l) \
576
void mnemonic(address target, AsmCondition cond = al) { \
577
unsigned int offset = (unsigned int)(target - pc() - 8); \
578
assert((offset & 3) == 0, "bad alignment"); \
579
assert((offset >> 25) == 0 || ((int)offset >> 25) == -1, "offset is too large"); \
580
emit_int32(cond << 28 | l << 24 | offset << 6 >> 8); \
581
}
582
583
F(b, 0xa)
584
F(bl, 0xb)
585
#undef F
586
587
void udf(int imm_16) {
588
assert((imm_16 >> 16) == 0, "encoding constraint");
589
emit_int32(0xe7f000f0 | (imm_16 & 0xfff0) << 8 | (imm_16 & 0xf));
590
}
591
592
// ARMv7 instructions
593
594
#define F(mnemonic, wt) \
595
void mnemonic(Register rd, int imm_16, AsmCondition cond = al) { \
596
assert((imm_16 >> 16) == 0, "encoding constraint"); \
597
emit_int32(cond << 28 | wt << 20 | rd->encoding() << 12 | \
598
(imm_16 & 0xf000) << 4 | (imm_16 & 0xfff)); \
599
}
600
601
F(movw, 0x30)
602
F(movt, 0x34)
603
#undef F
604
605
// VFP Support
606
607
// Checks that VFP instructions are not used in SOFTFP mode.
608
#ifdef __SOFTFP__
609
#define CHECK_VFP_PRESENT ShouldNotReachHere()
610
#else
611
#define CHECK_VFP_PRESENT
612
#endif // __SOFTFP__
613
614
static const int single_cp_num = 0xa00;
615
static const int double_cp_num = 0xb00;
616
617
// Bits P, Q, R, S collectively form the opcode
618
#define F(mnemonic, P, Q, R, S) \
619
void mnemonic##d(FloatRegister fd, FloatRegister fn, FloatRegister fm, \
620
AsmCondition cond = al) { \
621
CHECK_VFP_PRESENT; \
622
assert(fn->lo_bit() == 0 && fd->lo_bit() == 0 && fm->lo_bit() == 0, "single precision register?"); \
623
emit_int32(cond << 28 | 0x7 << 25 | double_cp_num | \
624
P << 23 | Q << 21 | R << 20 | S << 6 | \
625
fn->hi_bits() << 16 | fn->hi_bit() << 7 | \
626
fd->hi_bits() << 12 | fd->hi_bit() << 22 | \
627
fm->hi_bits() | fm->hi_bit() << 5); \
628
} \
629
void mnemonic##s(FloatRegister fd, FloatRegister fn, FloatRegister fm, \
630
AsmCondition cond = al) { \
631
assert(fn->hi_bit() == 0 && fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
632
CHECK_VFP_PRESENT; \
633
emit_int32(cond << 28 | 0x7 << 25 | single_cp_num | \
634
P << 23 | Q << 21 | R << 20 | S << 6 | \
635
fn->hi_bits() << 16 | fn->lo_bit() << 7 | \
636
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
637
fm->hi_bits() | fm->lo_bit() << 5); \
638
}
639
640
F(fmac, 0, 0, 0, 0) // Fd = Fd + (Fn * Fm)
641
F(fnmac, 0, 0, 0, 1) // Fd = Fd - (Fn * Fm)
642
F(fmsc, 0, 0, 1, 0) // Fd = -Fd + (Fn * Fm)
643
F(fnmsc, 0, 0, 1, 1) // Fd = -Fd - (Fn * Fm)
644
645
F(fmul, 0, 1, 0, 0) // Fd = Fn * Fm
646
F(fnmul, 0, 1, 0, 1) // Fd = -(Fn * Fm)
647
F(fadd, 0, 1, 1, 0) // Fd = Fn + Fm
648
F(fsub, 0, 1, 1, 1) // Fd = Fn - Fm
649
F(fdiv, 1, 0, 0, 0) // Fd = Fn / Fm
650
#undef F
651
652
enum VElem_Size {
653
VELEM_SIZE_8 = 0x00,
654
VELEM_SIZE_16 = 0x01,
655
VELEM_SIZE_32 = 0x02,
656
VELEM_SIZE_64 = 0x03
657
};
658
659
enum VLD_Type {
660
VLD1_TYPE_1_REG = 0x7 /* 0b0111 */,
661
VLD1_TYPE_2_REGS = 0xA /* 0b1010 */,
662
VLD1_TYPE_3_REGS = 0x6 /* 0b0110 */,
663
VLD1_TYPE_4_REGS = 0x2 /* 0b0010 */
664
};
665
666
enum VFloat_Arith_Size {
667
VFA_SIZE_F32 = 0x0 /* 0b0 */,
668
};
669
670
// Bits P, Q, R, S collectively form the opcode
671
#define F(mnemonic, P, Q, R, S) \
672
void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \
673
int size, int quad) { \
674
CHECK_VFP_PRESENT; \
675
assert(VM_Version::has_simd(), "simd instruction"); \
676
assert(fn->lo_bit() == 0 && fd->lo_bit() == 0 && fm->lo_bit() == 0, \
677
"single precision register?"); \
678
assert(!quad || ((fn->hi_bits() | fd->hi_bits() | fm->hi_bits()) & 1) == 0, \
679
"quad precision register?"); \
680
emit_int32(0xf << 28 | P << 23 | Q << 8 | R << 4 | \
681
S << 21 | size << 20 | quad << 6 | \
682
fn->hi_bits() << 16 | fn->hi_bit() << 7 | \
683
fd->hi_bits() << 12 | fd->hi_bit() << 22 | \
684
fm->hi_bits() | fm->hi_bit() << 5); \
685
}
686
687
F(vmulI, 0x4 /* 0b0100 */, 0x9 /* 0b1001 */, 1, 0) // Vd = Vn * Vm (int)
688
F(vaddI, 0x4 /* 0b0100 */, 0x8 /* 0b1000 */, 0, 0) // Vd = Vn + Vm (int)
689
F(vsubI, 0x6 /* 0b0110 */, 0x8 /* 0b1000 */, 0, 0) // Vd = Vn - Vm (int)
690
F(vaddF, 0x4 /* 0b0100 */, 0xD /* 0b1101 */, 0, 0) // Vd = Vn + Vm (float)
691
F(vsubF, 0x4 /* 0b0100 */, 0xD /* 0b1101 */, 0, 1) // Vd = Vn - Vm (float)
692
F(vmulF, 0x6 /* 0b0110 */, 0xD /* 0b1101 */, 1, 0) // Vd = Vn * Vm (float)
693
F(vshlSI, 0x4 /* 0b0100 */, 0x4 /* 0b0100 */, 0, 0) // Vd = ashift(Vm,Vn) (int)
694
F(vshlUI, 0x6 /* 0b0110 */, 0x4 /* 0b0100 */, 0, 0) // Vd = lshift(Vm,Vn) (int)
695
F(_vandI, 0x4 /* 0b0100 */, 0x1 /* 0b0001 */, 1, 0) // Vd = Vn & Vm (int)
696
F(_vorI, 0x4 /* 0b0100 */, 0x1 /* 0b0001 */, 1, 1) // Vd = Vn | Vm (int)
697
F(_vxorI, 0x6 /* 0b0110 */, 0x1 /* 0b0001 */, 1, 0) // Vd = Vn ^ Vm (int)
698
#undef F
699
700
void vandI(FloatRegister fd, FloatRegister fn, FloatRegister fm, int quad) {
701
_vandI(fd, fn, fm, 0, quad);
702
}
703
void vorI(FloatRegister fd, FloatRegister fn, FloatRegister fm, int quad) {
704
_vorI(fd, fn, fm, 0, quad);
705
}
706
void vxorI(FloatRegister fd, FloatRegister fn, FloatRegister fm, int quad) {
707
_vxorI(fd, fn, fm, 0, quad);
708
}
709
710
void vneg(FloatRegister fd, FloatRegister fm, int size, int flt, int quad) {
711
CHECK_VFP_PRESENT;
712
assert(VM_Version::has_simd(), "simd instruction");
713
assert(fd->lo_bit() == 0 && fm->lo_bit() == 0,
714
"single precision register?");
715
assert(!quad || ((fd->hi_bits() | fm->hi_bits()) & 1) == 0,
716
"quad precision register?");
717
emit_int32(0xf << 28 | 0x3B /* 0b00111011 */ << 20 | 0x1 /* 0b01 */ << 16 | 0x7 /* 0b111 */ << 7 |
718
size << 18 | quad << 6 | flt << 10 |
719
fd->hi_bits() << 12 | fd->hi_bit() << 22 |
720
fm->hi_bits() << 0 | fm->hi_bit() << 5);
721
}
722
723
void vnegI(FloatRegister fd, FloatRegister fm, int size, int quad) {
724
int flt = 0;
725
vneg(fd, fm, size, flt, quad);
726
}
727
728
void vshli(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
729
CHECK_VFP_PRESENT;
730
assert(VM_Version::has_simd(), "simd instruction");
731
assert(fd->lo_bit() == 0 && fm->lo_bit() == 0,
732
"single precision register?");
733
assert(!quad || ((fd->hi_bits() | fm->hi_bits()) & 1) == 0,
734
"quad precision register?");
735
736
if (imm >= size) {
737
// maximum shift gives all zeroes, direction doesn't matter,
738
// but only available for shift right
739
vshri(fd, fm, size, size, true /* unsigned */, quad);
740
return;
741
}
742
assert(imm >= 0 && imm < size, "out of range");
743
744
int imm6 = 0;
745
int L = 0;
746
switch (size) {
747
case 8:
748
case 16:
749
case 32:
750
imm6 = size + imm ;
751
break;
752
case 64:
753
L = 1;
754
imm6 = imm ;
755
break;
756
default:
757
ShouldNotReachHere();
758
}
759
emit_int32(0xf << 28 | 0x5 /* 0b00101 */ << 23 | 0x51 /* 0b01010001 */ << 4 |
760
imm6 << 16 | L << 7 | quad << 6 |
761
fd->hi_bits() << 12 | fd->hi_bit() << 22 |
762
fm->hi_bits() << 0 | fm->hi_bit() << 5);
763
}
764
765
void vshri(FloatRegister fd, FloatRegister fm, int size, int imm,
766
bool U /* unsigned */, int quad) {
767
CHECK_VFP_PRESENT;
768
assert(VM_Version::has_simd(), "simd instruction");
769
assert(fd->lo_bit() == 0 && fm->lo_bit() == 0,
770
"single precision register?");
771
assert(!quad || ((fd->hi_bits() | fm->hi_bits()) & 1) == 0,
772
"quad precision register?");
773
assert(imm > 0, "out of range");
774
if (imm >= size) {
775
// maximum shift (all zeroes)
776
imm = size;
777
}
778
int imm6 = 0;
779
int L = 0;
780
switch (size) {
781
case 8:
782
case 16:
783
case 32:
784
imm6 = 2 * size - imm ;
785
break;
786
case 64:
787
L = 1;
788
imm6 = 64 - imm ;
789
break;
790
default:
791
ShouldNotReachHere();
792
}
793
emit_int32(0xf << 28 | 0x5 /* 0b00101 */ << 23 | 0x1 /* 0b00000001 */ << 4 |
794
imm6 << 16 | L << 7 | quad << 6 | U << 24 |
795
fd->hi_bits() << 12 | fd->hi_bit() << 22 |
796
fm->hi_bits() << 0 | fm->hi_bit() << 5);
797
}
798
void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
799
vshri(fd, fm, size, imm, true /* unsigned */, quad);
800
}
801
void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) {
802
vshri(fd, fm, size, imm, false /* signed */, quad);
803
}
804
805
// Extension opcodes where P,Q,R,S = 1 opcode is in Fn
806
#define F(mnemonic, N, opcode) \
807
void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
808
CHECK_VFP_PRESENT; \
809
assert(fd->lo_bit() == 0 && fm->hi_bit() == 0, "incorrect register?"); \
810
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
811
double_cp_num | \
812
fd->hi_bits() << 12 | fd->hi_bit() << 22 | \
813
fm->hi_bits() | fm->lo_bit() << 5); \
814
} \
815
void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
816
CHECK_VFP_PRESENT; \
817
assert(fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
818
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
819
single_cp_num | \
820
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
821
fm->hi_bits() | fm->lo_bit() << 5); \
822
}
823
824
F(fuito, 0, 0x8) // Unsigned integer to floating point conversion
825
F(fsito, 1, 0x8) // Signed integer to floating point conversion
826
#undef F
827
828
#define F(mnemonic, N, opcode) \
829
void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
830
CHECK_VFP_PRESENT; \
831
assert(fd->hi_bit() == 0 && fm->lo_bit() == 0, "incorrect register?"); \
832
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
833
double_cp_num | \
834
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
835
fm->hi_bits() | fm->hi_bit() << 5); \
836
} \
837
void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
838
CHECK_VFP_PRESENT; \
839
assert(fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
840
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
841
single_cp_num | \
842
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
843
fm->hi_bits() | fm->lo_bit() << 5); \
844
}
845
846
F(ftoui, 0, 0xc) // Float to unsigned int conversion
847
F(ftouiz, 1, 0xc) // Float to unsigned int conversion, RZ mode
848
F(ftosi, 0, 0xd) // Float to signed int conversion
849
F(ftosiz, 1, 0xd) // Float to signed int conversion, RZ mode
850
#undef F
851
852
#define F(mnemonic, N, opcode) \
853
void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
854
CHECK_VFP_PRESENT; \
855
assert(fd->hi_bit() == 0 && fm->lo_bit() == 0, "incorrect register?"); \
856
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
857
double_cp_num | \
858
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
859
fm->hi_bits() | fm->hi_bit() << 5); \
860
} \
861
void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
862
CHECK_VFP_PRESENT; \
863
assert(fd->lo_bit() == 0 && fm->hi_bit() == 0, "incorrect register?"); \
864
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
865
single_cp_num | \
866
fd->hi_bits() << 12 | fd->hi_bit() << 22 | \
867
fm->hi_bits() | fm->lo_bit() << 5); \
868
}
869
870
F(fcvtd, 1, 0x7) // Single->Double conversion
871
F(fcvts, 1, 0x7) // Double->Single conversion
872
#undef F
873
874
#define F(mnemonic, N, opcode) \
875
void mnemonic##d(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
876
CHECK_VFP_PRESENT; \
877
assert(fd->lo_bit() == 0 && fm->lo_bit() == 0, "single precision register?"); \
878
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
879
double_cp_num | \
880
fd->hi_bits() << 12 | fd->hi_bit() << 22 | \
881
fm->hi_bits() | fm->hi_bit() << 5); \
882
} \
883
void mnemonic##s(FloatRegister fd, FloatRegister fm, AsmCondition cond = al) { \
884
CHECK_VFP_PRESENT; \
885
assert(fd->hi_bit() == 0 && fm->hi_bit() == 0, "double precision register?"); \
886
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
887
single_cp_num | \
888
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
889
fm->hi_bits() | fm->lo_bit() << 5); \
890
}
891
892
F(fcpy, 0, 0x0) // Fd = Fm
893
F(fabs, 1, 0x0) // Fd = abs(Fm)
894
F(fneg, 0, 0x1) // Fd = -Fm
895
F(fsqrt, 1, 0x1) // Fd = sqrt(Fm)
896
F(fcmp, 0, 0x4) // Compare Fd with Fm no exceptions on quiet NANs
897
F(fcmpe, 1, 0x4) // Compare Fd with Fm with exceptions on quiet NANs
898
#undef F
899
900
// Opcodes with one operand only
901
#define F(mnemonic, N, opcode) \
902
void mnemonic##d(FloatRegister fd, AsmCondition cond = al) { \
903
CHECK_VFP_PRESENT; \
904
assert(fd->lo_bit() == 0, "single precision register?"); \
905
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
906
double_cp_num | fd->hi_bits() << 12 | fd->hi_bit() << 22); \
907
} \
908
void mnemonic##s(FloatRegister fd, AsmCondition cond = al) { \
909
CHECK_VFP_PRESENT; \
910
assert(fd->hi_bit() == 0, "double precision register?"); \
911
emit_int32(cond << 28 | 0xeb << 20 | opcode << 16 | N << 7 | 1 << 6 | \
912
single_cp_num | fd->hi_bits() << 12 | fd->lo_bit() << 22); \
913
}
914
915
F(fcmpz, 0, 0x5) // Compare Fd with 0, no exceptions quiet NANs
916
F(fcmpez, 1, 0x5) // Compare Fd with 0, with exceptions quiet NANs
917
#undef F
918
919
// Float loads (L==1) and stores (L==0)
920
#define F(mnemonic, L) \
921
void mnemonic##d(FloatRegister fd, Address addr, AsmCondition cond = al) { \
922
CHECK_VFP_PRESENT; \
923
assert(fd->lo_bit() == 0, "single precision register?"); \
924
emit_int32(cond << 28 | 0xd << 24 | L << 20 | \
925
fd->hi_bits() << 12 | fd->hi_bit() << 22 | \
926
double_cp_num | addr.encoding_vfp()); \
927
} \
928
void mnemonic##s(FloatRegister fd, Address addr, AsmCondition cond = al) { \
929
CHECK_VFP_PRESENT; \
930
assert(fd->hi_bit() == 0, "double precision register?"); \
931
emit_int32(cond << 28 | 0xd << 24 | L << 20 | \
932
fd->hi_bits() << 12 | fd->lo_bit() << 22 | \
933
single_cp_num | addr.encoding_vfp()); \
934
}
935
936
F(fst, 0) // Store 1 register
937
F(fld, 1) // Load 1 register
938
#undef F
939
940
// Float load and store multiple
941
#define F(mnemonic, l, pu) \
942
void mnemonic##d(Register rn, FloatRegisterSet reg_set, \
943
AsmWriteback w = no_writeback, AsmCondition cond = al) { \
944
CHECK_VFP_PRESENT; \
945
assert(w == no_writeback || rn != PC, "unpredictable instruction"); \
946
assert(!(w == no_writeback && pu == 2), "encoding constraint"); \
947
assert((reg_set.encoding_d() & 1) == 0, "encoding constraint"); \
948
emit_int32(cond << 28 | 6 << 25 | pu << 23 | w << 21 | l << 20 | \
949
rn->encoding() << 16 | reg_set.encoding_d() | double_cp_num); \
950
} \
951
void mnemonic##s(Register rn, FloatRegisterSet reg_set, \
952
AsmWriteback w = no_writeback, AsmCondition cond = al) { \
953
CHECK_VFP_PRESENT; \
954
assert(w == no_writeback || rn != PC, "unpredictable instruction"); \
955
assert(!(w == no_writeback && pu == 2), "encoding constraint"); \
956
emit_int32(cond << 28 | 6 << 25 | pu << 23 | w << 21 | l << 20 | \
957
rn->encoding() << 16 | reg_set.encoding_s() | single_cp_num); \
958
}
959
960
F(fldmia, 1, 1) F(fldmfd, 1, 1)
961
F(fldmdb, 1, 2) F(fldmea, 1, 2)
962
F(fstmia, 0, 1) F(fstmea, 0, 1)
963
F(fstmdb, 0, 2) F(fstmfd, 0, 2)
964
#undef F
965
966
// fconst{s,d} encoding:
967
// 31 28 27 23 22 21 20 19 16 15 12 10 9 8 7 4 3 0
968
// | cond | 11101 | D | 11 | imm4H | Vd | 101 | sz | 0000 | imm4L |
969
// sz = 0 for single precision, 1 otherwise
970
// Register number is Vd:D for single precision, D:Vd otherwise
971
// immediate value is imm4H:imm4L
972
973
void fconsts(FloatRegister fd, unsigned char imm_8, AsmCondition cond = al) {
974
CHECK_VFP_PRESENT;
975
assert(fd->hi_bit() == 0, "double precision register?");
976
emit_int32(cond << 28 | 0xeb << 20 | single_cp_num |
977
fd->hi_bits() << 12 | fd->lo_bit() << 22 | (imm_8 & 0xf) | (imm_8 >> 4) << 16);
978
}
979
980
void fconstd(FloatRegister fd, unsigned char imm_8, AsmCondition cond = al) {
981
CHECK_VFP_PRESENT;
982
assert(fd->lo_bit() == 0, "double precision register?");
983
emit_int32(cond << 28 | 0xeb << 20 | double_cp_num |
984
fd->hi_bits() << 12 | fd->hi_bit() << 22 | (imm_8 & 0xf) | (imm_8 >> 4) << 16);
985
}
986
987
// GPR <-> FPR transfers
988
void fmsr(FloatRegister fd, Register rd, AsmCondition cond = al) {
989
CHECK_VFP_PRESENT;
990
assert(fd->hi_bit() == 0, "double precision register?");
991
emit_int32(cond << 28 | 0xe0 << 20 | single_cp_num | 1 << 4 |
992
fd->hi_bits() << 16 | fd->lo_bit() << 7 | rd->encoding() << 12);
993
}
994
995
void fmrs(Register rd, FloatRegister fd, AsmCondition cond = al) {
996
CHECK_VFP_PRESENT;
997
assert(fd->hi_bit() == 0, "double precision register?");
998
emit_int32(cond << 28 | 0xe1 << 20 | single_cp_num | 1 << 4 |
999
fd->hi_bits() << 16 | fd->lo_bit() << 7 | rd->encoding() << 12);
1000
}
1001
1002
void fmdrr(FloatRegister fd, Register rd, Register rn, AsmCondition cond = al) {
1003
CHECK_VFP_PRESENT;
1004
assert(fd->lo_bit() == 0, "single precision register?");
1005
emit_int32(cond << 28 | 0xc4 << 20 | double_cp_num | 1 << 4 |
1006
fd->hi_bits() | fd->hi_bit() << 5 |
1007
rn->encoding() << 16 | rd->encoding() << 12);
1008
}
1009
1010
void fmrrd(Register rd, Register rn, FloatRegister fd, AsmCondition cond = al) {
1011
CHECK_VFP_PRESENT;
1012
assert(fd->lo_bit() == 0, "single precision register?");
1013
emit_int32(cond << 28 | 0xc5 << 20 | double_cp_num | 1 << 4 |
1014
fd->hi_bits() | fd->hi_bit() << 5 |
1015
rn->encoding() << 16 | rd->encoding() << 12);
1016
}
1017
1018
void fmstat(AsmCondition cond = al) {
1019
CHECK_VFP_PRESENT;
1020
emit_int32(cond << 28 | 0xef1fa10);
1021
}
1022
1023
void vmrs(Register rt, VFPSystemRegister sr, AsmCondition cond = al) {
1024
assert((sr->encoding() & (~0xf)) == 0, "what system register is that?");
1025
emit_int32(cond << 28 | rt->encoding() << 12 | sr->encoding() << 16 | 0xef00a10);
1026
}
1027
1028
void vmsr(VFPSystemRegister sr, Register rt, AsmCondition cond = al) {
1029
assert((sr->encoding() & (~0xf)) == 0, "what system register is that?");
1030
emit_int32(cond << 28 | rt->encoding() << 12 | sr->encoding() << 16 | 0xee00a10);
1031
}
1032
1033
void vcnt(FloatRegister Dd, FloatRegister Dm) {
1034
CHECK_VFP_PRESENT;
1035
// emitted at VM startup to detect whether the instruction is available
1036
assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction");
1037
assert(Dd->lo_bit() == 0 && Dm->lo_bit() == 0, "single precision registers?");
1038
emit_int32(0xf3b00500 | Dd->hi_bit() << 22 | Dd->hi_bits() << 12 | Dm->hi_bit() << 5 | Dm->hi_bits());
1039
}
1040
1041
void vpaddl(FloatRegister Dd, FloatRegister Dm, int size, bool s) {
1042
CHECK_VFP_PRESENT;
1043
assert(VM_Version::has_simd(), "simd instruction");
1044
assert(Dd->lo_bit() == 0 && Dm->lo_bit() == 0, "single precision registers?");
1045
assert(size == 8 || size == 16 || size == 32, "unexpected size");
1046
emit_int32(0xf3b00200 | Dd->hi_bit() << 22 | (size >> 4) << 18 | Dd->hi_bits() << 12 | (s ? 0 : 1) << 7 | Dm->hi_bit() << 5 | Dm->hi_bits());
1047
}
1048
1049
void vld1(FloatRegister Dd, Address addr, VElem_Size size, int bits) {
1050
CHECK_VFP_PRESENT;
1051
assert(VM_Version::has_simd(), "simd instruction");
1052
assert(Dd->lo_bit() == 0, "single precision registers?");
1053
int align = 0;
1054
assert(bits == 128, "code assumption");
1055
VLD_Type type = VLD1_TYPE_2_REGS; // 2x64
1056
emit_int32(0xf4200000 | Dd->hi_bit() << 22 | Dd->hi_bits() << 12 | type << 8 | size << 6 | align << 4 | addr.encoding_simd());
1057
}
1058
1059
void vst1(FloatRegister Dd, Address addr, VElem_Size size, int bits) {
1060
CHECK_VFP_PRESENT;
1061
assert(VM_Version::has_simd(), "simd instruction");
1062
assert(Dd->lo_bit() == 0, "single precision registers?");
1063
int align = 0;
1064
assert(bits == 128, "code assumption");
1065
VLD_Type type = VLD1_TYPE_2_REGS; // 2x64
1066
emit_int32(0xf4000000 | Dd->hi_bit() << 22 | Dd->hi_bits() << 12 | type << 8 | size << 6 | align << 4 | addr.encoding_simd());
1067
}
1068
1069
void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) {
1070
CHECK_VFP_PRESENT;
1071
assert(VM_Version::has_simd(), "simd instruction");
1072
assert(Dd->lo_bit() == 0, "single precision register?");
1073
assert(!quad || (Dd->hi_bits() & 1) == 0, "quad precision register?");
1074
assert(imm8 >= 0 && imm8 < 256, "out of range");
1075
int op;
1076
int cmode;
1077
switch (size) {
1078
case VELEM_SIZE_8:
1079
op = 0;
1080
cmode = 0xE /* 0b1110 */;
1081
break;
1082
case VELEM_SIZE_16:
1083
op = 0;
1084
cmode = 0x8 /* 0b1000 */;
1085
break;
1086
case VELEM_SIZE_32:
1087
op = 0;
1088
cmode = 0x0 /* 0b0000 */;
1089
break;
1090
default:
1091
ShouldNotReachHere();
1092
return;
1093
}
1094
emit_int32(0xf << 28 | 0x1 << 25 | 0x1 << 23 | 0x1 << 4 |
1095
(imm8 >> 7) << 24 | ((imm8 & 0x70) >> 4) << 16 | (imm8 & 0xf) |
1096
quad << 6 | op << 5 | cmode << 8 |
1097
Dd->hi_bits() << 12 | Dd->hi_bit() << 22);
1098
}
1099
1100
void vdupI(FloatRegister Dd, Register Rs, VElem_Size size, int quad,
1101
AsmCondition cond = al) {
1102
CHECK_VFP_PRESENT;
1103
assert(VM_Version::has_simd(), "simd instruction");
1104
assert(Dd->lo_bit() == 0, "single precision register?");
1105
assert(!quad || (Dd->hi_bits() & 1) == 0, "quad precision register?");
1106
int b;
1107
int e;
1108
switch (size) {
1109
case VELEM_SIZE_8:
1110
b = 1;
1111
e = 0;
1112
break;
1113
case VELEM_SIZE_16:
1114
b = 0;
1115
e = 1;
1116
break;
1117
case VELEM_SIZE_32:
1118
b = 0;
1119
e = 0;
1120
break;
1121
default:
1122
ShouldNotReachHere();
1123
return;
1124
}
1125
emit_int32(cond << 28 | 0x1D /* 0b11101 */ << 23 | 0xB /* 0b1011 */ << 8 | 0x1 << 4 |
1126
quad << 21 | b << 22 | e << 5 | Rs->encoding() << 12 |
1127
Dd->hi_bits() << 16 | Dd->hi_bit() << 7);
1128
}
1129
1130
void vdup(FloatRegister Dd, FloatRegister Ds, int index, int size, int quad) {
1131
CHECK_VFP_PRESENT;
1132
assert(VM_Version::has_simd(), "simd instruction");
1133
assert(Dd->lo_bit() == 0, "single precision register?");
1134
assert(Ds->lo_bit() == 0, "single precision register?");
1135
assert(!quad || (Dd->hi_bits() & 1) == 0, "quad precision register?");
1136
int range = 64 / size;
1137
assert(index < range, "overflow");
1138
int imm4;
1139
switch (size) {
1140
case 8:
1141
assert((index & 0x7 /* 0b111 */) == index, "overflow");
1142
imm4 = index << 1 | 0x1 /* 0b0001 */;
1143
break;
1144
case 16:
1145
assert((index & 0x3 /* 0b11 */) == index, "overflow");
1146
imm4 = index << 2 | 0x2 /* 0b0010 */;
1147
break;
1148
case 32:
1149
assert((index & 0x1 /* 0b1 */) == index, "overflow");
1150
imm4 = index << 3 | 0x4 /* 0b0100 */;
1151
break;
1152
default:
1153
ShouldNotReachHere();
1154
return;
1155
}
1156
emit_int32(0xF /* 0b1111 */ << 28 | 0x3B /* 0b00111011 */ << 20 | 0x6 /* 0b110 */ << 9 |
1157
quad << 6 | imm4 << 16 |
1158
Dd->hi_bits() << 12 | Dd->hi_bit() << 22 |
1159
Ds->hi_bits() << 00 | Ds->hi_bit() << 5);
1160
}
1161
1162
void vdupF(FloatRegister Dd, FloatRegister Ss, int quad) {
1163
int index = 0;
1164
FloatRegister Ds = as_FloatRegister(Ss->encoding() & ~1);
1165
if (Ss->lo_bit() != 0) {
1166
/* odd S register */
1167
assert(Ds->successor() == Ss, "bad reg");
1168
index = 1;
1169
} else {
1170
/* even S register */
1171
assert(Ds == Ss, "bad reg");
1172
}
1173
vdup(Dd, Ds, index, 32, quad);
1174
}
1175
1176
void vrev(FloatRegister Dd, FloatRegister Dm, int quad, int region_size, VElem_Size size) {
1177
CHECK_VFP_PRESENT;
1178
assert(VM_Version::has_simd(), "simd instruction");
1179
assert(Dd->lo_bit() == 0, "single precision register?");
1180
assert(Dm->lo_bit() == 0, "single precision register?");
1181
assert(!quad || ((Dd->hi_bits() | Dm->hi_bits()) & 1) == 0,
1182
"quad precision register?");
1183
unsigned int op = 0;
1184
switch (region_size) {
1185
case 16: op = 0x2; /*0b10*/ break;
1186
case 32: op = 0x1; /*0b01*/ break;
1187
case 64: op = 0x0; /*0b00*/ break;
1188
default: assert(false, "encoding constraint");
1189
}
1190
emit_int32(0xf << 28 | 0x7 << 23 | Dd->hi_bit() << 22 | 0x3 << 20 |
1191
size << 18 | Dd->hi_bits() << 12 | op << 7 | quad << 6 | Dm->hi_bit() << 5 |
1192
Dm->hi_bits());
1193
}
1194
1195
void veor(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, int quad) {
1196
CHECK_VFP_PRESENT;
1197
assert(VM_Version::has_simd(), "simd instruction");
1198
assert(Dd->lo_bit() == 0, "single precision register?");
1199
assert(Dm->lo_bit() == 0, "single precision register?");
1200
assert(Dn->lo_bit() == 0, "single precision register?");
1201
assert(!quad || ((Dd->hi_bits() | Dm->hi_bits() | Dn->hi_bits()) & 1) == 0,
1202
"quad precision register?");
1203
1204
emit_int32(0xf << 28 | 0x3 << 24 | Dd->hi_bit() << 22 | Dn->hi_bits() << 16 |
1205
Dd->hi_bits() << 12 | 0x1 << 8 | Dn->hi_bit() << 7 | quad << 6 |
1206
Dm->hi_bit() << 5 | 0x1 << 4 | Dm->hi_bits());
1207
}
1208
1209
1210
Assembler(CodeBuffer* code) : AbstractAssembler(code) {}
1211
1212
#ifdef COMPILER2
1213
typedef VFP::double_num double_num;
1214
typedef VFP::float_num float_num;
1215
#endif
1216
};
1217
1218
#ifdef __SOFTFP__
1219
// Soft float function declarations
1220
extern "C" {
1221
extern float __aeabi_fadd(float, float);
1222
extern float __aeabi_fmul(float, float);
1223
extern float __aeabi_fsub(float, float);
1224
extern float __aeabi_fdiv(float, float);
1225
1226
extern double __aeabi_dadd(double, double);
1227
extern double __aeabi_dmul(double, double);
1228
extern double __aeabi_dsub(double, double);
1229
extern double __aeabi_ddiv(double, double);
1230
1231
extern double __aeabi_f2d(float);
1232
extern float __aeabi_d2f(double);
1233
extern float __aeabi_i2f(int);
1234
extern double __aeabi_i2d(int);
1235
extern int __aeabi_f2iz(float);
1236
1237
extern int __aeabi_fcmpeq(float, float);
1238
extern int __aeabi_fcmplt(float, float);
1239
extern int __aeabi_fcmple(float, float);
1240
extern int __aeabi_fcmpge(float, float);
1241
extern int __aeabi_fcmpgt(float, float);
1242
1243
extern int __aeabi_dcmpeq(double, double);
1244
extern int __aeabi_dcmplt(double, double);
1245
extern int __aeabi_dcmple(double, double);
1246
extern int __aeabi_dcmpge(double, double);
1247
extern int __aeabi_dcmpgt(double, double);
1248
1249
// Imported code from glibc soft-fp bundle for
1250
// calculation accuracy improvement. See CR 6757269.
1251
extern double __aeabi_fadd_glibc(float, float);
1252
extern double __aeabi_fsub_glibc(float, float);
1253
extern double __aeabi_dadd_glibc(double, double);
1254
extern double __aeabi_dsub_glibc(double, double);
1255
};
1256
#endif // __SOFTFP__
1257
1258
1259
#endif // CPU_ARM_ASSEMBLER_ARM_32_HPP
1260
1261