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