Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/hotspot/cpu/aarch64/assembler_aarch64.cpp
64440 views
1
/*
2
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2014, 2020 Red Hat Inc. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*/
24
25
#include "precompiled.hpp"
26
#include "asm/assembler.hpp"
27
#include "asm/assembler.inline.hpp"
28
#include "asm/macroAssembler.hpp"
29
#include "compiler/disassembler.hpp"
30
#include "immediate_aarch64.hpp"
31
#include "memory/resourceArea.hpp"
32
33
#ifndef PRODUCT
34
const uintptr_t Assembler::asm_bp = 0x00007fffee09ac88;
35
#endif
36
37
static float unpack(unsigned value);
38
39
short Assembler::SIMD_Size_in_bytes[] = {
40
// T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q
41
8, 16, 8, 16, 8, 16, 8, 16, 16
42
};
43
44
Assembler::SIMD_Arrangement Assembler::_esize2arrangement_table[9][2] = {
45
// esize isQ:false isQ:true
46
/* 0 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},
47
/* 1 */ {T8B, T16B},
48
/* 2 */ {T4H, T8H},
49
/* 3 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},
50
/* 4 */ {T2S, T4S},
51
/* 5 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},
52
/* 6 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},
53
/* 7 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},
54
/* 8 */ {T1D, T2D}
55
};
56
57
58
Assembler::SIMD_Arrangement Assembler::esize2arrangement(int esize, bool isQ) {
59
guarantee(esize == 1 || esize == 2 || esize == 4 || esize == 8, "unsupported element size");
60
return _esize2arrangement_table[esize][isQ];
61
}
62
63
void Assembler::emit_data64(jlong data,
64
relocInfo::relocType rtype,
65
int format) {
66
if (rtype == relocInfo::none) {
67
emit_int64(data);
68
} else {
69
emit_data64(data, Relocation::spec_simple(rtype), format);
70
}
71
}
72
73
void Assembler::emit_data64(jlong data,
74
RelocationHolder const& rspec,
75
int format) {
76
77
assert(inst_mark() != NULL, "must be inside InstructionMark");
78
// Do not use AbstractAssembler::relocate, which is not intended for
79
// embedded words. Instead, relocate to the enclosing instruction.
80
code_section()->relocate(inst_mark(), rspec, format);
81
emit_int64(data);
82
}
83
84
extern "C" {
85
void das(uint64_t start, int len) {
86
ResourceMark rm;
87
len <<= 2;
88
if (len < 0)
89
Disassembler::decode((address)start + len, (address)start);
90
else
91
Disassembler::decode((address)start, (address)start + len);
92
}
93
94
JNIEXPORT void das1(uintptr_t insn) {
95
das(insn, 1);
96
}
97
}
98
99
#define __ as->
100
101
void Address::lea(MacroAssembler *as, Register r) const {
102
Relocation* reloc = _rspec.reloc();
103
relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();
104
105
switch(_mode) {
106
case base_plus_offset: {
107
if (_offset == 0 && _base == r) // it's a nop
108
break;
109
if (_offset > 0)
110
__ add(r, _base, _offset);
111
else
112
__ sub(r, _base, -_offset);
113
break;
114
}
115
case base_plus_offset_reg: {
116
__ add(r, _base, _index, _ext.op(), MAX2(_ext.shift(), 0));
117
break;
118
}
119
case literal: {
120
if (rtype == relocInfo::none)
121
__ mov(r, target());
122
else
123
__ movptr(r, (uint64_t)target());
124
break;
125
}
126
default:
127
ShouldNotReachHere();
128
}
129
}
130
131
void Assembler::adrp(Register reg1, const Address &dest, uint64_t &byte_offset) {
132
ShouldNotReachHere();
133
}
134
135
#undef __
136
137
#define starti Instruction_aarch64 do_not_use(this); set_current(&do_not_use)
138
139
void Assembler::adr(Register Rd, address adr) {
140
intptr_t offset = adr - pc();
141
int offset_lo = offset & 3;
142
offset >>= 2;
143
starti;
144
f(0, 31), f(offset_lo, 30, 29), f(0b10000, 28, 24), sf(offset, 23, 5);
145
rf(Rd, 0);
146
}
147
148
void Assembler::_adrp(Register Rd, address adr) {
149
uint64_t pc_page = (uint64_t)pc() >> 12;
150
uint64_t adr_page = (uint64_t)adr >> 12;
151
intptr_t offset = adr_page - pc_page;
152
int offset_lo = offset & 3;
153
offset >>= 2;
154
starti;
155
f(1, 31), f(offset_lo, 30, 29), f(0b10000, 28, 24), sf(offset, 23, 5);
156
rf(Rd, 0);
157
}
158
159
#undef starti
160
161
Address::Address(address target, relocInfo::relocType rtype) : _mode(literal){
162
_is_lval = false;
163
_target = target;
164
switch (rtype) {
165
case relocInfo::oop_type:
166
case relocInfo::metadata_type:
167
// Oops are a special case. Normally they would be their own section
168
// but in cases like icBuffer they are literals in the code stream that
169
// we don't have a section for. We use none so that we get a literal address
170
// which is always patchable.
171
break;
172
case relocInfo::external_word_type:
173
_rspec = external_word_Relocation::spec(target);
174
break;
175
case relocInfo::internal_word_type:
176
_rspec = internal_word_Relocation::spec(target);
177
break;
178
case relocInfo::opt_virtual_call_type:
179
_rspec = opt_virtual_call_Relocation::spec();
180
break;
181
case relocInfo::static_call_type:
182
_rspec = static_call_Relocation::spec();
183
break;
184
case relocInfo::runtime_call_type:
185
_rspec = runtime_call_Relocation::spec();
186
break;
187
case relocInfo::poll_type:
188
case relocInfo::poll_return_type:
189
_rspec = Relocation::spec_simple(rtype);
190
break;
191
case relocInfo::none:
192
_rspec = RelocationHolder::none;
193
break;
194
default:
195
ShouldNotReachHere();
196
break;
197
}
198
}
199
200
void Assembler::b(const Address &dest) {
201
code_section()->relocate(pc(), dest.rspec());
202
b(dest.target());
203
}
204
205
void Assembler::bl(const Address &dest) {
206
code_section()->relocate(pc(), dest.rspec());
207
bl(dest.target());
208
}
209
210
void Assembler::adr(Register r, const Address &dest) {
211
code_section()->relocate(pc(), dest.rspec());
212
adr(r, dest.target());
213
}
214
215
void Assembler::br(Condition cc, Label &L) {
216
if (L.is_bound()) {
217
br(cc, target(L));
218
} else {
219
L.add_patch_at(code(), locator());
220
br(cc, pc());
221
}
222
}
223
224
void Assembler::wrap_label(Label &L,
225
Assembler::uncond_branch_insn insn) {
226
if (L.is_bound()) {
227
(this->*insn)(target(L));
228
} else {
229
L.add_patch_at(code(), locator());
230
(this->*insn)(pc());
231
}
232
}
233
234
void Assembler::wrap_label(Register r, Label &L,
235
compare_and_branch_insn insn) {
236
if (L.is_bound()) {
237
(this->*insn)(r, target(L));
238
} else {
239
L.add_patch_at(code(), locator());
240
(this->*insn)(r, pc());
241
}
242
}
243
244
void Assembler::wrap_label(Register r, int bitpos, Label &L,
245
test_and_branch_insn insn) {
246
if (L.is_bound()) {
247
(this->*insn)(r, bitpos, target(L));
248
} else {
249
L.add_patch_at(code(), locator());
250
(this->*insn)(r, bitpos, pc());
251
}
252
}
253
254
void Assembler::wrap_label(Label &L, prfop op, prefetch_insn insn) {
255
if (L.is_bound()) {
256
(this->*insn)(target(L), op);
257
} else {
258
L.add_patch_at(code(), locator());
259
(this->*insn)(pc(), op);
260
}
261
}
262
263
// An "all-purpose" add/subtract immediate, per ARM documentation:
264
// A "programmer-friendly" assembler may accept a negative immediate
265
// between -(2^24 -1) and -1 inclusive, causing it to convert a
266
// requested ADD operation to a SUB, or vice versa, and then encode
267
// the absolute value of the immediate as for uimm24.
268
void Assembler::add_sub_immediate(Register Rd, Register Rn, unsigned uimm, int op,
269
int negated_op) {
270
bool sets_flags = op & 1; // this op sets flags
271
union {
272
unsigned u;
273
int imm;
274
};
275
u = uimm;
276
bool shift = false;
277
bool neg = imm < 0;
278
if (neg) {
279
imm = -imm;
280
op = negated_op;
281
}
282
assert(Rd != sp || imm % 16 == 0, "misaligned stack");
283
if (imm >= (1 << 11)
284
&& ((imm >> 12) << 12 == imm)) {
285
imm >>= 12;
286
shift = true;
287
}
288
f(op, 31, 29), f(0b10001, 28, 24), f(shift, 23, 22), f(imm, 21, 10);
289
290
// add/subtract immediate ops with the S bit set treat r31 as zr;
291
// with S unset they use sp.
292
if (sets_flags)
293
zrf(Rd, 0);
294
else
295
srf(Rd, 0);
296
297
srf(Rn, 5);
298
}
299
300
bool Assembler::operand_valid_for_add_sub_immediate(int64_t imm) {
301
bool shift = false;
302
uint64_t uimm = (uint64_t)uabs((jlong)imm);
303
if (uimm < (1 << 12))
304
return true;
305
if (uimm < (1 << 24)
306
&& ((uimm >> 12) << 12 == uimm)) {
307
return true;
308
}
309
return false;
310
}
311
312
bool Assembler::operand_valid_for_logical_immediate(bool is32, uint64_t imm) {
313
return encode_logical_immediate(is32, imm) != 0xffffffff;
314
}
315
316
static uint64_t doubleTo64Bits(jdouble d) {
317
union {
318
jdouble double_value;
319
uint64_t double_bits;
320
};
321
322
double_value = d;
323
return double_bits;
324
}
325
326
bool Assembler::operand_valid_for_float_immediate(double imm) {
327
// If imm is all zero bits we can use ZR as the source of a
328
// floating-point value.
329
if (doubleTo64Bits(imm) == 0)
330
return true;
331
332
// Otherwise try to encode imm then convert the encoded value back
333
// and make sure it's the exact same bit pattern.
334
unsigned result = encoding_for_fp_immediate(imm);
335
return doubleTo64Bits(imm) == fp_immediate_for_encoding(result, true);
336
}
337
338
int AbstractAssembler::code_fill_byte() {
339
return 0;
340
}
341
342
// n.b. this is implemented in subclass MacroAssembler
343
void Assembler::bang_stack_with_offset(int offset) { Unimplemented(); }
344
345
346
// and now the routines called by the assembler which encapsulate the
347
// above encode and decode functions
348
349
uint32_t
350
asm_util::encode_logical_immediate(bool is32, uint64_t imm)
351
{
352
if (is32) {
353
/* Allow all zeros or all ones in top 32-bits, so that
354
constant expressions like ~1 are permitted. */
355
if (imm >> 32 != 0 && imm >> 32 != 0xffffffff)
356
return 0xffffffff;
357
/* Replicate the 32 lower bits to the 32 upper bits. */
358
imm &= 0xffffffff;
359
imm |= imm << 32;
360
}
361
362
return encoding_for_logical_immediate(imm);
363
}
364
365
unsigned Assembler::pack(double value) {
366
float val = (float)value;
367
unsigned result = encoding_for_fp_immediate(val);
368
guarantee(unpack(result) == value,
369
"Invalid floating-point immediate operand");
370
return result;
371
}
372
373
// Packed operands for Floating-point Move (immediate)
374
375
static float unpack(unsigned value) {
376
union {
377
unsigned ival;
378
float val;
379
};
380
ival = fp_immediate_for_encoding(value, 0);
381
return val;
382
}
383
384
address Assembler::locate_next_instruction(address inst) {
385
return inst + Assembler::instruction_size;
386
}
387
388