1 /* 2 * Copyright (c) 2008, 2016, 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_VM_ASSEMBLER_ARM_64_HPP 26 #define CPU_ARM_VM_ASSEMBLER_ARM_64_HPP 27 28 enum AsmShift12 { 29 lsl0, lsl12 30 }; 31 32 enum AsmPrefetchOp { 33 pldl1keep = 0b00000, 34 pldl1strm, 35 pldl2keep, 36 pldl2strm, 37 pldl3keep, 38 pldl3strm, 39 40 plil1keep = 0b01000, 41 plil1strm, 42 plil2keep, 43 plil2strm, 44 plil3keep, 45 plil3strm, 46 47 pstl1keep = 0b10000, 48 pstl1strm, 49 pstl2keep, 50 pstl2strm, 51 pstl3keep, 52 pstl3strm, 53 }; 54 55 // Shifted register operand for data processing instructions. 56 class AsmOperand VALUE_OBJ_CLASS_SPEC { 57 private: 58 Register _reg; 59 AsmShift _shift; 60 int _shift_imm; 61 62 public: 63 AsmOperand(Register reg) { 64 assert(reg != SP, "SP is not allowed in shifted register operand"); 65 _reg = reg; 66 _shift = lsl; 67 _shift_imm = 0; 68 } 69 70 AsmOperand(Register reg, AsmShift shift, int shift_imm) { 71 assert(reg != SP, "SP is not allowed in shifted register operand"); 72 assert(shift_imm >= 0, "shift amount should be non-negative"); 73 _reg = reg; 74 _shift = shift; 75 _shift_imm = shift_imm; 76 } 77 78 Register reg() const { 79 return _reg; 80 } 81 82 AsmShift shift() const { 83 return _shift; 84 } 85 86 int shift_imm() const { 87 return _shift_imm; 88 } 89 }; 90 91 92 class Assembler : public AbstractAssembler { 93 94 public: 95 96 static const int LogInstructionSize = 2; 97 static const int InstructionSize = 1 << LogInstructionSize; 98 99 Assembler(CodeBuffer* code) : AbstractAssembler(code) {} 100 101 static inline AsmCondition inverse(AsmCondition cond) { 102 assert ((cond != al) && (cond != nv), "AL and NV conditions cannot be inversed"); 103 return (AsmCondition)((int)cond ^ 1); 104 } 105 106 // Returns value of nzcv flags conforming to the given condition. 107 static inline int flags_for_condition(AsmCondition cond) { 108 switch(cond) { // NZCV 109 case mi: case lt: return 0b1000; 110 case eq: case le: return 0b0100; 111 case hs: case hi: return 0b0010; 112 case vs: return 0b0001; 113 default: return 0b0000; 114 } 115 } 116 117 // Immediate, encoded into logical instructions. 118 class LogicalImmediate { 119 private: 120 bool _encoded; 121 bool _is32bit; 122 int _immN; 123 int _immr; 124 int _imms; 125 126 static inline bool has_equal_subpatterns(uintx imm, int size); 127 static inline int least_pattern_size(uintx imm); 128 static inline int population_count(uintx x); 129 static inline uintx set_least_zeroes(uintx x); 130 131 #ifdef ASSERT 132 uintx decode(); 133 #endif 134 135 void construct(uintx imm, bool is32); 136 137 public: 138 LogicalImmediate(uintx imm, bool is32 = false) { construct(imm, is32); } 139 140 // Returns true if given immediate can be used in AArch64 logical instruction. 141 bool is_encoded() const { return _encoded; } 142 143 bool is32bit() const { return _is32bit; } 144 int immN() const { assert(_encoded, "should be"); return _immN; } 145 int immr() const { assert(_encoded, "should be"); return _immr; } 146 int imms() const { assert(_encoded, "should be"); return _imms; } 147 }; 148 149 // Immediate, encoded into arithmetic add/sub instructions. 150 class ArithmeticImmediate { 151 private: 152 bool _encoded; 153 int _imm; 154 AsmShift12 _shift; 155 156 public: 157 ArithmeticImmediate(intx x) { 158 if (is_unsigned_imm_in_range(x, 12, 0)) { 159 _encoded = true; 160 _imm = x; 161 _shift = lsl0; 162 } else if (is_unsigned_imm_in_range(x, 12, 12)) { 163 _encoded = true; 164 _imm = x >> 12; 165 _shift = lsl12; 166 } else { 167 _encoded = false; 168 } 169 } 170 171 ArithmeticImmediate(intx x, AsmShift12 sh) { 172 if (is_unsigned_imm_in_range(x, 12, 0)) { 173 _encoded = true; 174 _imm = x; 175 _shift = sh; 176 } else { 177 _encoded = false; 178 } 179 } 180 181 // Returns true if this immediate can be used in AArch64 arithmetic (add/sub/cmp/cmn) instructions. 182 bool is_encoded() const { return _encoded; } 183 184 int imm() const { assert(_encoded, "should be"); return _imm; } 185 AsmShift12 shift() const { assert(_encoded, "should be"); return _shift; } 186 }; 187 188 static inline bool is_imm_in_range(intx value, int bits, int align_bits) { 189 intx sign_bits = (value >> (bits + align_bits - 1)); 190 return ((value & right_n_bits(align_bits)) == 0) && ((sign_bits == 0) || (sign_bits == -1)); 191 } 192 193 static inline int encode_imm(intx value, int bits, int align_bits, int low_bit_in_encoding) { 194 assert (is_imm_in_range(value, bits, align_bits), "immediate value is out of range"); 195 return ((value >> align_bits) & right_n_bits(bits)) << low_bit_in_encoding; 196 } 197 198 static inline bool is_unsigned_imm_in_range(intx value, int bits, int align_bits) { 199 return (value >= 0) && ((value & right_n_bits(align_bits)) == 0) && ((value >> (align_bits + bits)) == 0); 200 } 201 202 static inline int encode_unsigned_imm(intx value, int bits, int align_bits, int low_bit_in_encoding) { 203 assert (is_unsigned_imm_in_range(value, bits, align_bits), "immediate value is out of range"); 204 return (value >> align_bits) << low_bit_in_encoding; 205 } 206 207 static inline bool is_offset_in_range(intx offset, int bits) { 208 assert (bits == 14 || bits == 19 || bits == 26, "wrong bits number"); 209 return is_imm_in_range(offset, bits, 2); 210 } 211 212 static inline int encode_offset(intx offset, int bits, int low_bit_in_encoding) { 213 return encode_imm(offset, bits, 2, low_bit_in_encoding); 214 } 215 216 // Returns true if given value can be used as immediate in arithmetic (add/sub/cmp/cmn) instructions. 217 static inline bool is_arith_imm_in_range(intx value) { 218 return ArithmeticImmediate(value).is_encoded(); 219 } 220 221 222 // Load/store instructions 223 224 #define F(mnemonic, opc) \ 225 void mnemonic(Register rd, address literal_addr) { \ 226 intx offset = literal_addr - pc(); \ 227 assert (opc != 0b01 || offset == 0 || ((uintx)literal_addr & 7) == 0, "ldr target should be aligned"); \ 228 assert (is_offset_in_range(offset, 19), "offset is out of range"); \ 229 emit_int32(opc << 30 | 0b011 << 27 | encode_offset(offset, 19, 5) | rd->encoding_with_zr()); \ 230 } 231 232 F(ldr_w, 0b00) 233 F(ldr, 0b01) 234 F(ldrsw, 0b10) 235 #undef F 236 237 #define F(mnemonic, opc) \ 238 void mnemonic(FloatRegister rt, address literal_addr) { \ 239 intx offset = literal_addr - pc(); \ 240 assert (offset == 0 || ((uintx)literal_addr & right_n_bits(2 + opc)) == 0, "ldr target should be aligned"); \ 241 assert (is_offset_in_range(offset, 19), "offset is out of range"); \ 242 emit_int32(opc << 30 | 0b011100 << 24 | encode_offset(offset, 19, 5) | rt->encoding()); \ 243 } 244 245 F(ldr_s, 0b00) 246 F(ldr_d, 0b01) 247 F(ldr_q, 0b10) 248 #undef F 249 250 #define F(mnemonic, size, o2, L, o1, o0) \ 251 void mnemonic(Register rt, Register rn) { \ 252 emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | 0b11111 << 16 | \ 253 o0 << 15 | 0b11111 << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 254 } 255 256 F(ldxrb, 0b00, 0, 1, 0, 0) 257 F(ldaxrb, 0b00, 0, 1, 0, 1) 258 F(ldarb, 0b00, 1, 1, 0, 1) 259 F(ldxrh, 0b01, 0, 1, 0, 0) 260 F(ldaxrh, 0b01, 0, 1, 0, 1) 261 F(ldarh, 0b01, 1, 1, 0, 1) 262 F(ldxr_w, 0b10, 0, 1, 0, 0) 263 F(ldaxr_w, 0b10, 0, 1, 0, 1) 264 F(ldar_w, 0b10, 1, 1, 0, 1) 265 F(ldxr, 0b11, 0, 1, 0, 0) 266 F(ldaxr, 0b11, 0, 1, 0, 1) 267 F(ldar, 0b11, 1, 1, 0, 1) 268 269 F(stlrb, 0b00, 1, 0, 0, 1) 270 F(stlrh, 0b01, 1, 0, 0, 1) 271 F(stlr_w, 0b10, 1, 0, 0, 1) 272 F(stlr, 0b11, 1, 0, 0, 1) 273 #undef F 274 275 #define F(mnemonic, size, o2, L, o1, o0) \ 276 void mnemonic(Register rs, Register rt, Register rn) { \ 277 assert (rs != rt, "should be different"); \ 278 assert (rs != rn, "should be different"); \ 279 emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | rs->encoding_with_zr() << 16 | \ 280 o0 << 15 | 0b11111 << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 281 } 282 283 F(stxrb, 0b00, 0, 0, 0, 0) 284 F(stlxrb, 0b00, 0, 0, 0, 1) 285 F(stxrh, 0b01, 0, 0, 0, 0) 286 F(stlxrh, 0b01, 0, 0, 0, 1) 287 F(stxr_w, 0b10, 0, 0, 0, 0) 288 F(stlxr_w, 0b10, 0, 0, 0, 1) 289 F(stxr, 0b11, 0, 0, 0, 0) 290 F(stlxr, 0b11, 0, 0, 0, 1) 291 #undef F 292 293 #define F(mnemonic, size, o2, L, o1, o0) \ 294 void mnemonic(Register rt, Register rt2, Register rn) { \ 295 assert (rt != rt2, "should be different"); \ 296 emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | 0b11111 << 16 | \ 297 o0 << 15 | rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 298 } 299 300 F(ldxp_w, 0b10, 0, 1, 1, 0) 301 F(ldaxp_w, 0b10, 0, 1, 1, 1) 302 F(ldxp, 0b11, 0, 1, 1, 0) 303 F(ldaxp, 0b11, 0, 1, 1, 1) 304 #undef F 305 306 #define F(mnemonic, size, o2, L, o1, o0) \ 307 void mnemonic(Register rs, Register rt, Register rt2, Register rn) { \ 308 assert (rs != rt, "should be different"); \ 309 assert (rs != rt2, "should be different"); \ 310 assert (rs != rn, "should be different"); \ 311 emit_int32(size << 30 | 0b001000 << 24 | o2 << 23 | L << 22 | o1 << 21 | rs->encoding_with_zr() << 16 | \ 312 o0 << 15 | rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 313 } 314 315 F(stxp_w, 0b10, 0, 0, 1, 0) 316 F(stlxp_w, 0b10, 0, 0, 1, 1) 317 F(stxp, 0b11, 0, 0, 1, 0) 318 F(stlxp, 0b11, 0, 0, 1, 1) 319 #undef F 320 321 #define F(mnemonic, opc, V, L) \ 322 void mnemonic(Register rt, Register rt2, Register rn, int offset = 0) { \ 323 assert (!L || rt != rt2, "should be different"); \ 324 int align_bits = 2 + (opc >> 1); \ 325 assert (is_imm_in_range(offset, 7, align_bits), "offset is out of range"); \ 326 emit_int32(opc << 30 | 0b101 << 27 | V << 26 | L << 22 | encode_imm(offset, 7, align_bits, 15) | \ 327 rt2->encoding_with_zr() << 10 | rn->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 328 } 329 330 F(stnp_w, 0b00, 0, 0) 331 F(ldnp_w, 0b00, 0, 1) 332 F(stnp, 0b10, 0, 0) 333 F(ldnp, 0b10, 0, 1) 334 #undef F 335 336 #define F(mnemonic, opc, V, L) \ 337 void mnemonic(FloatRegister rt, FloatRegister rt2, Register rn, int offset = 0) { \ 338 assert (!L || (rt != rt2), "should be different"); \ 339 int align_bits = 2 + opc; \ 340 assert (is_imm_in_range(offset, 7, align_bits), "offset is out of range"); \ 341 emit_int32(opc << 30 | 0b101 << 27 | V << 26 | L << 22 | encode_imm(offset, 7, align_bits, 15) | \ 342 rt2->encoding() << 10 | rn->encoding_with_sp() << 5 | rt->encoding()); \ 343 } 344 345 F(stnp_s, 0b00, 1, 0) 346 F(stnp_d, 0b01, 1, 0) 347 F(stnp_q, 0b10, 1, 0) 348 F(ldnp_s, 0b00, 1, 1) 349 F(ldnp_d, 0b01, 1, 1) 350 F(ldnp_q, 0b10, 1, 1) 351 #undef F 352 353 #define F(mnemonic, size, V, opc) \ 354 void mnemonic(Register rt, Address addr) { \ 355 assert((addr.mode() == basic_offset) || (rt != addr.base()), "should be different"); \ 356 if (addr.index() == noreg) { \ 357 if ((addr.mode() == basic_offset) && is_unsigned_imm_in_range(addr.disp(), 12, size)) { \ 358 emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 | \ 359 encode_unsigned_imm(addr.disp(), 12, size, 10) | \ 360 addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 361 } else { \ 362 assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range"); \ 363 emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) | \ 364 addr.mode() << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 365 } \ 366 } else { \ 367 assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode"); \ 368 assert ((addr.shift_imm() == 0) || (addr.shift_imm() == size), "invalid shift amount"); \ 369 emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 | \ 370 addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 | \ 371 0b10 << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 372 } \ 373 } 374 375 F(strb, 0b00, 0, 0b00) 376 F(ldrb, 0b00, 0, 0b01) 377 F(ldrsb, 0b00, 0, 0b10) 378 F(ldrsb_w, 0b00, 0, 0b11) 379 380 F(strh, 0b01, 0, 0b00) 381 F(ldrh, 0b01, 0, 0b01) 382 F(ldrsh, 0b01, 0, 0b10) 383 F(ldrsh_w, 0b01, 0, 0b11) 384 385 F(str_w, 0b10, 0, 0b00) 386 F(ldr_w, 0b10, 0, 0b01) 387 F(ldrsw, 0b10, 0, 0b10) 388 389 F(str, 0b11, 0, 0b00) 390 F(ldr, 0b11, 0, 0b01) 391 #undef F 392 393 #define F(mnemonic, size, V, opc) \ 394 void mnemonic(AsmPrefetchOp prfop, Address addr) { \ 395 assert (addr.mode() == basic_offset, #mnemonic " supports only basic_offset address mode"); \ 396 if (addr.index() == noreg) { \ 397 if (is_unsigned_imm_in_range(addr.disp(), 12, size)) { \ 398 emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 | \ 399 encode_unsigned_imm(addr.disp(), 12, size, 10) | \ 400 addr.base()->encoding_with_sp() << 5 | prfop); \ 401 } else { \ 402 assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range"); \ 403 emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) | \ 404 addr.base()->encoding_with_sp() << 5 | prfop); \ 405 } \ 406 } else { \ 407 assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode"); \ 408 assert ((addr.shift_imm() == 0) || (addr.shift_imm() == size), "invalid shift amount"); \ 409 emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 | \ 410 addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 | \ 411 0b10 << 10 | addr.base()->encoding_with_sp() << 5 | prfop); \ 412 } \ 413 } 414 415 F(prfm, 0b11, 0, 0b10) 416 #undef F 417 418 #define F(mnemonic, size, V, opc) \ 419 void mnemonic(FloatRegister rt, Address addr) { \ 420 int align_bits = (((opc & 0b10) >> 1) << 2) | size; \ 421 if (addr.index() == noreg) { \ 422 if ((addr.mode() == basic_offset) && is_unsigned_imm_in_range(addr.disp(), 12, align_bits)) { \ 423 emit_int32(size << 30 | 0b111 << 27 | V << 26 | 0b01 << 24 | opc << 22 | \ 424 encode_unsigned_imm(addr.disp(), 12, align_bits, 10) | \ 425 addr.base()->encoding_with_sp() << 5 | rt->encoding()); \ 426 } else { \ 427 assert(is_imm_in_range(addr.disp(), 9, 0), "offset is out of range"); \ 428 emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | encode_imm(addr.disp(), 9, 0, 12) | \ 429 addr.mode() << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding()); \ 430 } \ 431 } else { \ 432 assert (addr.disp() == 0, "non-zero displacement for [reg + reg] address mode"); \ 433 assert ((addr.shift_imm() == 0) || (addr.shift_imm() == align_bits), "invalid shift amount"); \ 434 emit_int32(size << 30 | 0b111 << 27 | V << 26 | opc << 22 | 1 << 21 | \ 435 addr.index()->encoding_with_zr() << 16 | addr.extend() << 13 | (addr.shift_imm() != 0) << 12 | \ 436 0b10 << 10 | addr.base()->encoding_with_sp() << 5 | rt->encoding()); \ 437 } \ 438 } 439 440 F(str_b, 0b00, 1, 0b00) 441 F(ldr_b, 0b00, 1, 0b01) 442 F(str_h, 0b01, 1, 0b00) 443 F(ldr_h, 0b01, 1, 0b01) 444 F(str_s, 0b10, 1, 0b00) 445 F(ldr_s, 0b10, 1, 0b01) 446 F(str_d, 0b11, 1, 0b00) 447 F(ldr_d, 0b11, 1, 0b01) 448 F(str_q, 0b00, 1, 0b10) 449 F(ldr_q, 0b00, 1, 0b11) 450 #undef F 451 452 #define F(mnemonic, opc, V, L) \ 453 void mnemonic(Register rt, Register rt2, Address addr) { \ 454 assert((addr.mode() == basic_offset) || ((rt != addr.base()) && (rt2 != addr.base())), "should be different"); \ 455 assert(!L || (rt != rt2), "should be different"); \ 456 assert(addr.index() == noreg, "[reg + reg] address mode is not available for load/store pair"); \ 457 int align_bits = 2 + (opc >> 1); \ 458 int mode_encoding = (addr.mode() == basic_offset) ? 0b10 : addr.mode(); \ 459 assert(is_imm_in_range(addr.disp(), 7, align_bits), "offset is out of range"); \ 460 emit_int32(opc << 30 | 0b101 << 27 | V << 26 | mode_encoding << 23 | L << 22 | \ 461 encode_imm(addr.disp(), 7, align_bits, 15) | rt2->encoding_with_zr() << 10 | \ 462 addr.base()->encoding_with_sp() << 5 | rt->encoding_with_zr()); \ 463 } 464 465 F(stp_w, 0b00, 0, 0) 466 F(ldp_w, 0b00, 0, 1) 467 F(ldpsw, 0b01, 0, 1) 468 F(stp, 0b10, 0, 0) 469 F(ldp, 0b10, 0, 1) 470 #undef F 471 472 #define F(mnemonic, opc, V, L) \ 473 void mnemonic(FloatRegister rt, FloatRegister rt2, Address addr) { \ 474 assert(!L || (rt != rt2), "should be different"); \ 475 assert(addr.index() == noreg, "[reg + reg] address mode is not available for load/store pair"); \ 476 int align_bits = 2 + opc; \ 477 int mode_encoding = (addr.mode() == basic_offset) ? 0b10 : addr.mode(); \ 478 assert(is_imm_in_range(addr.disp(), 7, align_bits), "offset is out of range"); \ 479 emit_int32(opc << 30 | 0b101 << 27 | V << 26 | mode_encoding << 23 | L << 22 | \ 480 encode_imm(addr.disp(), 7, align_bits, 15) | rt2->encoding() << 10 | \ 481 addr.base()->encoding_with_sp() << 5 | rt->encoding()); \ 482 } 483 484 F(stp_s, 0b00, 1, 0) 485 F(ldp_s, 0b00, 1, 1) 486 F(stp_d, 0b01, 1, 0) 487 F(ldp_d, 0b01, 1, 1) 488 F(stp_q, 0b10, 1, 0) 489 F(ldp_q, 0b10, 1, 1) 490 #undef F 491 492 // Data processing instructions 493 494 #define F(mnemonic, sf, opc) \ 495 void mnemonic(Register rd, Register rn, const LogicalImmediate& imm) { \ 496 assert (imm.is_encoded(), "illegal immediate for logical instruction"); \ 497 assert (imm.is32bit() == (sf == 0), "immediate size does not match instruction size"); \ 498 emit_int32(sf << 31 | opc << 29 | 0b100100 << 23 | imm.immN() << 22 | imm.immr() << 16 | \ 499 imm.imms() << 10 | rn->encoding_with_zr() << 5 | \ 500 ((opc == 0b11) ? rd->encoding_with_zr() : rd->encoding_with_sp())); \ 501 } \ 502 void mnemonic(Register rd, Register rn, uintx imm) { \ 503 LogicalImmediate limm(imm, (sf == 0)); \ 504 mnemonic(rd, rn, limm); \ 505 } \ 506 void mnemonic(Register rd, Register rn, unsigned int imm) { \ 507 mnemonic(rd, rn, (uintx)imm); \ 508 } 509 510 F(andr_w, 0, 0b00) 511 F(orr_w, 0, 0b01) 512 F(eor_w, 0, 0b10) 513 F(ands_w, 0, 0b11) 514 515 F(andr, 1, 0b00) 516 F(orr, 1, 0b01) 517 F(eor, 1, 0b10) 518 F(ands, 1, 0b11) 519 #undef F 520 521 void tst(Register rn, unsigned int imm) { 522 ands(ZR, rn, imm); 523 } 524 525 void tst_w(Register rn, unsigned int imm) { 526 ands_w(ZR, rn, imm); 527 } 528 529 #define F(mnemonic, sf, opc, N) \ 530 void mnemonic(Register rd, Register rn, AsmOperand operand) { \ 531 assert (operand.shift_imm() >> (5 + sf) == 0, "shift amount is too large"); \ 532 emit_int32(sf << 31 | opc << 29 | 0b01010 << 24 | operand.shift() << 22 | N << 21 | \ 533 operand.reg()->encoding_with_zr() << 16 | operand.shift_imm() << 10 | \ 534 rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 535 } 536 537 F(andr_w, 0, 0b00, 0) 538 F(bic_w, 0, 0b00, 1) 539 F(orr_w, 0, 0b01, 0) 540 F(orn_w, 0, 0b01, 1) 541 F(eor_w, 0, 0b10, 0) 542 F(eon_w, 0, 0b10, 1) 543 F(ands_w, 0, 0b11, 0) 544 F(bics_w, 0, 0b11, 1) 545 546 F(andr, 1, 0b00, 0) 547 F(bic, 1, 0b00, 1) 548 F(orr, 1, 0b01, 0) 549 F(orn, 1, 0b01, 1) 550 F(eor, 1, 0b10, 0) 551 F(eon, 1, 0b10, 1) 552 F(ands, 1, 0b11, 0) 553 F(bics, 1, 0b11, 1) 554 #undef F 555 556 void tst(Register rn, AsmOperand operand) { 557 ands(ZR, rn, operand); 558 } 559 560 void tst_w(Register rn, AsmOperand operand) { 561 ands_w(ZR, rn, operand); 562 } 563 564 void mvn(Register rd, AsmOperand operand) { 565 orn(rd, ZR, operand); 566 } 567 568 void mvn_w(Register rd, AsmOperand operand) { 569 orn_w(rd, ZR, operand); 570 } 571 572 #define F(mnemonic, sf, op, S) \ 573 void mnemonic(Register rd, Register rn, const ArithmeticImmediate& imm) { \ 574 assert(imm.is_encoded(), "immediate is out of range"); \ 575 emit_int32(sf << 31 | op << 30 | S << 29 | 0b10001 << 24 | imm.shift() << 22 | \ 576 imm.imm() << 10 | rn->encoding_with_sp() << 5 | \ 577 (S == 1 ? rd->encoding_with_zr() : rd->encoding_with_sp())); \ 578 } \ 579 void mnemonic(Register rd, Register rn, int imm) { \ 580 mnemonic(rd, rn, ArithmeticImmediate(imm)); \ 581 } \ 582 void mnemonic(Register rd, Register rn, int imm, AsmShift12 shift) { \ 583 mnemonic(rd, rn, ArithmeticImmediate(imm, shift)); \ 584 } \ 585 void mnemonic(Register rd, Register rn, Register rm, AsmExtendOp extend, int shift_imm = 0) { \ 586 assert ((0 <= shift_imm) && (shift_imm <= 4), "shift amount is out of range"); \ 587 emit_int32(sf << 31 | op << 30 | S << 29 | 0b01011001 << 21 | rm->encoding_with_zr() << 16 | \ 588 extend << 13 | shift_imm << 10 | rn->encoding_with_sp() << 5 | \ 589 (S == 1 ? rd->encoding_with_zr() : rd->encoding_with_sp())); \ 590 } \ 591 void mnemonic(Register rd, Register rn, AsmOperand operand) { \ 592 assert (operand.shift() != ror, "illegal shift type"); \ 593 assert (operand.shift_imm() >> (5 + sf) == 0, "shift amount is too large"); \ 594 emit_int32(sf << 31 | op << 30 | S << 29 | 0b01011 << 24 | operand.shift() << 22 | \ 595 operand.reg()->encoding_with_zr() << 16 | operand.shift_imm() << 10 | \ 596 rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 597 } 598 599 F(add_w, 0, 0, 0) 600 F(adds_w, 0, 0, 1) 601 F(sub_w, 0, 1, 0) 602 F(subs_w, 0, 1, 1) 603 604 F(add, 1, 0, 0) 605 F(adds, 1, 0, 1) 606 F(sub, 1, 1, 0) 607 F(subs, 1, 1, 1) 608 #undef F 609 610 void mov(Register rd, Register rm) { 611 if ((rd == SP) || (rm == SP)) { 612 add(rd, rm, 0); 613 } else { 614 orr(rd, ZR, rm); 615 } 616 } 617 618 void mov_w(Register rd, Register rm) { 619 if ((rd == SP) || (rm == SP)) { 620 add_w(rd, rm, 0); 621 } else { 622 orr_w(rd, ZR, rm); 623 } 624 } 625 626 void cmp(Register rn, int imm) { 627 subs(ZR, rn, imm); 628 } 629 630 void cmp_w(Register rn, int imm) { 631 subs_w(ZR, rn, imm); 632 } 633 634 void cmp(Register rn, Register rm) { 635 assert (rm != SP, "SP should not be used as the 2nd operand of cmp"); 636 if (rn == SP) { 637 subs(ZR, rn, rm, ex_uxtx); 638 } else { 639 subs(ZR, rn, rm); 640 } 641 } 642 643 void cmp_w(Register rn, Register rm) { 644 assert ((rn != SP) && (rm != SP), "SP should not be used in 32-bit cmp"); 645 subs_w(ZR, rn, rm); 646 } 647 648 void cmp(Register rn, AsmOperand operand) { 649 assert (rn != SP, "SP is not allowed in cmp with shifted register (AsmOperand)"); 650 subs(ZR, rn, operand); 651 } 652 653 void cmn(Register rn, int imm) { 654 adds(ZR, rn, imm); 655 } 656 657 void cmn_w(Register rn, int imm) { 658 adds_w(ZR, rn, imm); 659 } 660 661 void cmn(Register rn, Register rm) { 662 assert (rm != SP, "SP should not be used as the 2nd operand of cmp"); 663 if (rn == SP) { 664 adds(ZR, rn, rm, ex_uxtx); 665 } else { 666 adds(ZR, rn, rm); 667 } 668 } 669 670 void cmn_w(Register rn, Register rm) { 671 assert ((rn != SP) && (rm != SP), "SP should not be used in 32-bit cmp"); 672 adds_w(ZR, rn, rm); 673 } 674 675 void neg(Register rd, Register rm) { 676 sub(rd, ZR, rm); 677 } 678 679 void neg_w(Register rd, Register rm) { 680 sub_w(rd, ZR, rm); 681 } 682 683 #define F(mnemonic, sf, op, S) \ 684 void mnemonic(Register rd, Register rn, Register rm) { \ 685 emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010000 << 21 | rm->encoding_with_zr() << 16 | \ 686 rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 687 } 688 689 F(adc_w, 0, 0, 0) 690 F(adcs_w, 0, 0, 1) 691 F(sbc_w, 0, 1, 0) 692 F(sbcs_w, 0, 1, 1) 693 694 F(adc, 1, 0, 0) 695 F(adcs, 1, 0, 1) 696 F(sbc, 1, 1, 0) 697 F(sbcs, 1, 1, 1) 698 #undef F 699 700 #define F(mnemonic, sf, N) \ 701 void mnemonic(Register rd, Register rn, Register rm, int lsb) { \ 702 assert ((lsb >> (5 + sf)) == 0, "illegal least significant bit position"); \ 703 emit_int32(sf << 31 | 0b100111 << 23 | N << 22 | rm->encoding_with_zr() << 16 | \ 704 lsb << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 705 } 706 707 F(extr_w, 0, 0) 708 F(extr, 1, 1) 709 #undef F 710 711 #define F(mnemonic, sf, opc) \ 712 void mnemonic(Register rd, int imm, int shift) { \ 713 assert ((imm >> 16) == 0, "immediate is out of range"); \ 714 assert (((shift & 0xf) == 0) && ((shift >> (5 + sf)) == 0), "invalid shift"); \ 715 emit_int32(sf << 31 | opc << 29 | 0b100101 << 23 | (shift >> 4) << 21 | \ 716 imm << 5 | rd->encoding_with_zr()); \ 717 } 718 719 F(movn_w, 0, 0b00) 720 F(movz_w, 0, 0b10) 721 F(movk_w, 0, 0b11) 722 F(movn, 1, 0b00) 723 F(movz, 1, 0b10) 724 F(movk, 1, 0b11) 725 #undef F 726 727 void mov(Register rd, int imm) { 728 assert ((imm >> 16) == 0, "immediate is out of range"); 729 movz(rd, imm, 0); 730 } 731 732 void mov_w(Register rd, int imm) { 733 assert ((imm >> 16) == 0, "immediate is out of range"); 734 movz_w(rd, imm, 0); 735 } 736 737 #define F(mnemonic, sf, op, S) \ 738 void mnemonic(Register rn, int imm, int nzcv, AsmCondition cond) { \ 739 assert ((imm >> 5) == 0, "immediate is out of range"); \ 740 assert ((nzcv >> 4) == 0, "illegal nzcv"); \ 741 emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010010 << 21 | imm << 16 | \ 742 cond << 12 | 1 << 11 | rn->encoding_with_zr() << 5 | nzcv); \ 743 } 744 745 F(ccmn_w, 0, 0, 1) 746 F(ccmp_w, 0, 1, 1) 747 F(ccmn, 1, 0, 1) 748 F(ccmp, 1, 1, 1) 749 #undef F 750 751 #define F(mnemonic, sf, op, S) \ 752 void mnemonic(Register rn, Register rm, int nzcv, AsmCondition cond) { \ 753 assert ((nzcv >> 4) == 0, "illegal nzcv"); \ 754 emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010010 << 21 | rm->encoding_with_zr() << 16 | \ 755 cond << 12 | rn->encoding_with_zr() << 5 | nzcv); \ 756 } 757 758 F(ccmn_w, 0, 0, 1) 759 F(ccmp_w, 0, 1, 1) 760 F(ccmn, 1, 0, 1) 761 F(ccmp, 1, 1, 1) 762 #undef F 763 764 #define F(mnemonic, sf, op, S, op2) \ 765 void mnemonic(Register rd, Register rn, Register rm, AsmCondition cond) { \ 766 emit_int32(sf << 31 | op << 30 | S << 29 | 0b11010100 << 21 | rm->encoding_with_zr() << 16 | \ 767 cond << 12 | op2 << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 768 } 769 770 F(csel_w, 0, 0, 0, 0b00) 771 F(csinc_w, 0, 0, 0, 0b01) 772 F(csinv_w, 0, 1, 0, 0b00) 773 F(csneg_w, 0, 1, 0, 0b01) 774 775 F(csel, 1, 0, 0, 0b00) 776 F(csinc, 1, 0, 0, 0b01) 777 F(csinv, 1, 1, 0, 0b00) 778 F(csneg, 1, 1, 0, 0b01) 779 #undef F 780 781 void cset(Register rd, AsmCondition cond) { 782 csinc(rd, ZR, ZR, inverse(cond)); 783 } 784 785 void cset_w(Register rd, AsmCondition cond) { 786 csinc_w(rd, ZR, ZR, inverse(cond)); 787 } 788 789 void csetm(Register rd, AsmCondition cond) { 790 csinv(rd, ZR, ZR, inverse(cond)); 791 } 792 793 void csetm_w(Register rd, AsmCondition cond) { 794 csinv_w(rd, ZR, ZR, inverse(cond)); 795 } 796 797 void cinc(Register rd, Register rn, AsmCondition cond) { 798 csinc(rd, rn, rn, inverse(cond)); 799 } 800 801 void cinc_w(Register rd, Register rn, AsmCondition cond) { 802 csinc_w(rd, rn, rn, inverse(cond)); 803 } 804 805 void cinv(Register rd, Register rn, AsmCondition cond) { 806 csinv(rd, rn, rn, inverse(cond)); 807 } 808 809 void cinv_w(Register rd, Register rn, AsmCondition cond) { 810 csinv_w(rd, rn, rn, inverse(cond)); 811 } 812 813 #define F(mnemonic, sf, S, opcode) \ 814 void mnemonic(Register rd, Register rn) { \ 815 emit_int32(sf << 31 | 1 << 30 | S << 29 | 0b11010110 << 21 | opcode << 10 | \ 816 rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 817 } 818 819 F(rbit_w, 0, 0, 0b000000) 820 F(rev16_w, 0, 0, 0b000001) 821 F(rev_w, 0, 0, 0b000010) 822 F(clz_w, 0, 0, 0b000100) 823 F(cls_w, 0, 0, 0b000101) 824 825 F(rbit, 1, 0, 0b000000) 826 F(rev16, 1, 0, 0b000001) 827 F(rev32, 1, 0, 0b000010) 828 F(rev, 1, 0, 0b000011) 829 F(clz, 1, 0, 0b000100) 830 F(cls, 1, 0, 0b000101) 831 #undef F 832 833 #define F(mnemonic, sf, S, opcode) \ 834 void mnemonic(Register rd, Register rn, Register rm) { \ 835 emit_int32(sf << 31 | S << 29 | 0b11010110 << 21 | rm->encoding_with_zr() << 16 | \ 836 opcode << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 837 } 838 839 F(udiv_w, 0, 0, 0b000010) 840 F(sdiv_w, 0, 0, 0b000011) 841 F(lslv_w, 0, 0, 0b001000) 842 F(lsrv_w, 0, 0, 0b001001) 843 F(asrv_w, 0, 0, 0b001010) 844 F(rorv_w, 0, 0, 0b001011) 845 846 F(udiv, 1, 0, 0b000010) 847 F(sdiv, 1, 0, 0b000011) 848 F(lslv, 1, 0, 0b001000) 849 F(lsrv, 1, 0, 0b001001) 850 F(asrv, 1, 0, 0b001010) 851 F(rorv, 1, 0, 0b001011) 852 #undef F 853 854 #define F(mnemonic, sf, op31, o0) \ 855 void mnemonic(Register rd, Register rn, Register rm, Register ra) { \ 856 emit_int32(sf << 31 | 0b11011 << 24 | op31 << 21 | rm->encoding_with_zr() << 16 | \ 857 o0 << 15 | ra->encoding_with_zr() << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 858 } 859 860 F(madd_w, 0, 0b000, 0) 861 F(msub_w, 0, 0b000, 1) 862 F(madd, 1, 0b000, 0) 863 F(msub, 1, 0b000, 1) 864 865 F(smaddl, 1, 0b001, 0) 866 F(smsubl, 1, 0b001, 1) 867 F(umaddl, 1, 0b101, 0) 868 F(umsubl, 1, 0b101, 1) 869 #undef F 870 871 void mul(Register rd, Register rn, Register rm) { 872 madd(rd, rn, rm, ZR); 873 } 874 875 void mul_w(Register rd, Register rn, Register rm) { 876 madd_w(rd, rn, rm, ZR); 877 } 878 879 #define F(mnemonic, sf, op31, o0) \ 880 void mnemonic(Register rd, Register rn, Register rm) { \ 881 emit_int32(sf << 31 | 0b11011 << 24 | op31 << 21 | rm->encoding_with_zr() << 16 | \ 882 o0 << 15 | 0b11111 << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 883 } 884 885 F(smulh, 1, 0b010, 0) 886 F(umulh, 1, 0b110, 0) 887 #undef F 888 889 #define F(mnemonic, op) \ 890 void mnemonic(Register rd, address addr) { \ 891 intx offset; \ 892 if (op == 0) { \ 893 offset = addr - pc(); \ 894 } else { \ 895 offset = (((intx)addr) - (((intx)pc()) & ~0xfff)) >> 12; \ 896 } \ 897 assert (is_imm_in_range(offset, 21, 0), "offset is out of range"); \ 898 emit_int32(op << 31 | (offset & 3) << 29 | 0b10000 << 24 | \ 899 encode_imm(offset >> 2, 19, 0, 5) | rd->encoding_with_zr()); \ 900 } \ 901 902 F(adr, 0) 903 F(adrp, 1) 904 #undef F 905 906 void adr(Register rd, Label& L) { 907 adr(rd, target(L)); 908 } 909 910 #define F(mnemonic, sf, opc, N) \ 911 void mnemonic(Register rd, Register rn, int immr, int imms) { \ 912 assert ((immr >> (5 + sf)) == 0, "immr is out of range"); \ 913 assert ((imms >> (5 + sf)) == 0, "imms is out of range"); \ 914 emit_int32(sf << 31 | opc << 29 | 0b100110 << 23 | N << 22 | immr << 16 | \ 915 imms << 10 | rn->encoding_with_zr() << 5 | rd->encoding_with_zr()); \ 916 } 917 918 F(sbfm_w, 0, 0b00, 0) 919 F(bfm_w, 0, 0b01, 0) 920 F(ubfm_w, 0, 0b10, 0) 921 922 F(sbfm, 1, 0b00, 1) 923 F(bfm, 1, 0b01, 1) 924 F(ubfm, 1, 0b10, 1) 925 #undef F 926 927 #define F(alias, mnemonic, sf, immr, imms) \ 928 void alias(Register rd, Register rn, int lsb, int width) { \ 929 assert ((lsb >> (5 + sf)) == 0, "lsb is out of range"); \ 930 assert ((1 <= width) && (width <= (32 << sf) - lsb), "width is out of range"); \ 931 mnemonic(rd, rn, immr, imms); \ 932 } 933 934 F(bfi_w, bfm_w, 0, (-lsb) & 0x1f, width - 1) 935 F(bfi, bfm, 1, (-lsb) & 0x3f, width - 1) 936 F(bfxil_w, bfm_w, 0, lsb, lsb + width - 1) 937 F(bfxil, bfm, 1, lsb, lsb + width - 1) 938 F(sbfiz_w, sbfm_w, 0, (-lsb) & 0x1f, width - 1) 939 F(sbfiz, sbfm, 1, (-lsb) & 0x3f, width - 1) 940 F(sbfx_w, sbfm_w, 0, lsb, lsb + width - 1) 941 F(sbfx, sbfm, 1, lsb, lsb + width - 1) 942 F(ubfiz_w, ubfm_w, 0, (-lsb) & 0x1f, width - 1) 943 F(ubfiz, ubfm, 1, (-lsb) & 0x3f, width - 1) 944 F(ubfx_w, ubfm_w, 0, lsb, lsb + width - 1) 945 F(ubfx, ubfm, 1, lsb, lsb + width - 1) 946 #undef F 947 948 #define F(alias, mnemonic, sf, immr, imms) \ 949 void alias(Register rd, Register rn, int shift) { \ 950 assert ((shift >> (5 + sf)) == 0, "shift is out of range"); \ 951 mnemonic(rd, rn, immr, imms); \ 952 } 953 954 F(_asr_w, sbfm_w, 0, shift, 31) 955 F(_asr, sbfm, 1, shift, 63) 956 F(_lsl_w, ubfm_w, 0, (-shift) & 0x1f, 31 - shift) 957 F(_lsl, ubfm, 1, (-shift) & 0x3f, 63 - shift) 958 F(_lsr_w, ubfm_w, 0, shift, 31) 959 F(_lsr, ubfm, 1, shift, 63) 960 #undef F 961 962 #define F(alias, mnemonic, immr, imms) \ 963 void alias(Register rd, Register rn) { \ 964 mnemonic(rd, rn, immr, imms); \ 965 } 966 967 F(sxtb_w, sbfm_w, 0, 7) 968 F(sxtb, sbfm, 0, 7) 969 F(sxth_w, sbfm_w, 0, 15) 970 F(sxth, sbfm, 0, 15) 971 F(sxtw, sbfm, 0, 31) 972 F(uxtb_w, ubfm_w, 0, 7) 973 F(uxtb, ubfm, 0, 7) 974 F(uxth_w, ubfm_w, 0, 15) 975 F(uxth, ubfm, 0, 15) 976 #undef F 977 978 // Branch instructions 979 980 #define F(mnemonic, op) \ 981 void mnemonic(Register rn) { \ 982 emit_int32(0b1101011 << 25 | op << 21 | 0b11111 << 16 | rn->encoding_with_zr() << 5); \ 983 } 984 985 F(br, 0b00) 986 F(blr, 0b01) 987 F(ret, 0b10) 988 #undef F 989 990 void ret() { 991 ret(LR); 992 } 993 994 #define F(mnemonic, op) \ 995 void mnemonic(address target) { \ 996 intx offset = target - pc(); \ 997 assert (is_offset_in_range(offset, 26), "offset is out of range"); \ 998 emit_int32(op << 31 | 0b00101 << 26 | encode_offset(offset, 26, 0)); \ 999 } 1000 1001 F(b, 0) 1002 F(bl, 1) 1003 #undef F 1004 1005 void b(address target, AsmCondition cond) { 1006 if (cond == al) { 1007 b(target); 1008 } else { 1009 intx offset = target - pc(); 1010 assert (is_offset_in_range(offset, 19), "offset is out of range"); 1011 emit_int32(0b0101010 << 25 | encode_offset(offset, 19, 5) | cond); 1012 } 1013 } 1014 1015 1016 #define F(mnemonic, sf, op) \ 1017 void mnemonic(Register rt, address target) { \ 1018 intx offset = target - pc(); \ 1019 assert (is_offset_in_range(offset, 19), "offset is out of range"); \ 1020 emit_int32(sf << 31 | 0b011010 << 25 | op << 24 | encode_offset(offset, 19, 5) | rt->encoding_with_zr()); \ 1021 } \ 1022 1023 F(cbz_w, 0, 0) 1024 F(cbnz_w, 0, 1) 1025 F(cbz, 1, 0) 1026 F(cbnz, 1, 1) 1027 #undef F 1028 1029 #define F(mnemonic, op) \ 1030 void mnemonic(Register rt, int bit, address target) { \ 1031 intx offset = target - pc(); \ 1032 assert (is_offset_in_range(offset, 14), "offset is out of range"); \ 1033 assert (0 <= bit && bit < 64, "bit number is out of range"); \ 1034 emit_int32((bit >> 5) << 31 | 0b011011 << 25 | op << 24 | (bit & 0x1f) << 19 | \ 1035 encode_offset(offset, 14, 5) | rt->encoding_with_zr()); \ 1036 } \ 1037 1038 F(tbz, 0) 1039 F(tbnz, 1) 1040 #undef F 1041 1042 // System instructions 1043 1044 enum DMB_Opt { 1045 DMB_ld = 0b1101, 1046 DMB_st = 0b1110, 1047 DMB_all = 0b1111 1048 }; 1049 1050 #define F(mnemonic, L, op0, op1, CRn, op2, Rt) \ 1051 void mnemonic(DMB_Opt option) { \ 1052 emit_int32(0b1101010100 << 22 | L << 21 | op0 << 19 | op1 << 16 | \ 1053 CRn << 12 | option << 8 | op2 << 5 | Rt); \ 1054 } 1055 1056 F(dsb, 0, 0b00, 0b011, 0b0011, 0b100, 0b11111) 1057 F(dmb, 0, 0b00, 0b011, 0b0011, 0b101, 0b11111) 1058 #undef F 1059 1060 #define F(mnemonic, L, op0, op1, CRn, Rt) \ 1061 void mnemonic(int imm) { \ 1062 assert ((imm >> 7) == 0, "immediate is out of range"); \ 1063 emit_int32(0b1101010100 << 22 | L << 21 | op0 << 19 | op1 << 16 | \ 1064 CRn << 12 | imm << 5 | Rt); \ 1065 } 1066 1067 F(hint, 0, 0b00, 0b011, 0b0010, 0b11111) 1068 #undef F 1069 1070 void nop() { 1071 hint(0); 1072 } 1073 1074 void yield() { 1075 hint(1); 1076 } 1077 1078 #define F(mnemonic, opc, op2, LL) \ 1079 void mnemonic(int imm = 0) { \ 1080 assert ((imm >> 16) == 0, "immediate is out of range"); \ 1081 emit_int32(0b11010100 << 24 | opc << 21 | imm << 5 | op2 << 2 | LL); \ 1082 } 1083 1084 F(brk, 0b001, 0b000, 0b00) 1085 F(hlt, 0b010, 0b000, 0b00) 1086 F(dpcs1, 0b101, 0b000, 0b01) 1087 #undef F 1088 1089 enum SystemRegister { // o0<1> op1<3> CRn<4> CRm<4> op2<3> 1090 SysReg_NZCV = 0b101101000010000, 1091 SysReg_FPCR = 0b101101000100000, 1092 }; 1093 1094 void mrs(Register rt, SystemRegister systemReg) { 1095 assert ((systemReg >> 15) == 0, "systemReg is out of range"); 1096 emit_int32(0b110101010011 << 20 | systemReg << 5 | rt->encoding_with_zr()); 1097 } 1098 1099 void msr(SystemRegister systemReg, Register rt) { 1100 assert ((systemReg >> 15) == 0, "systemReg is out of range"); 1101 emit_int32(0b110101010001 << 20 | systemReg << 5 | rt->encoding_with_zr()); 1102 } 1103 1104 // Floating-point instructions 1105 1106 #define F(mnemonic, M, S, type, opcode2) \ 1107 void mnemonic(FloatRegister rn, FloatRegister rm) { \ 1108 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1109 rm->encoding() << 16 | 0b1000 << 10 | rn->encoding() << 5 | opcode2); \ 1110 } 1111 1112 F(fcmp_s, 0, 0, 0b00, 0b00000) 1113 F(fcmpe_s, 0, 0, 0b00, 0b01000) 1114 F(fcmp_d, 0, 0, 0b01, 0b00000) 1115 F(fcmpe_d, 0, 0, 0b01, 0b10000) 1116 #undef F 1117 1118 #define F(mnemonic, M, S, type, opcode2) \ 1119 void mnemonic(FloatRegister rn) { \ 1120 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1121 0b1000 << 10 | rn->encoding() << 5 | opcode2); \ 1122 } 1123 1124 F(fcmp0_s, 0, 0, 0b00, 0b01000) 1125 F(fcmpe0_s, 0, 0, 0b00, 0b11000) 1126 F(fcmp0_d, 0, 0, 0b01, 0b01000) 1127 F(fcmpe0_d, 0, 0, 0b01, 0b11000) 1128 #undef F 1129 1130 #define F(mnemonic, M, S, type, op) \ 1131 void mnemonic(FloatRegister rn, FloatRegister rm, int nzcv, AsmCondition cond) { \ 1132 assert ((nzcv >> 4) == 0, "illegal nzcv"); \ 1133 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1134 rm->encoding() << 16 | cond << 12 | 0b01 << 10 | rn->encoding() << 5 | op << 4 | nzcv); \ 1135 } 1136 1137 F(fccmp_s, 0, 0, 0b00, 0) 1138 F(fccmpe_s, 0, 0, 0b00, 1) 1139 F(fccmp_d, 0, 0, 0b01, 0) 1140 F(fccmpe_d, 0, 0, 0b01, 1) 1141 #undef F 1142 1143 #define F(mnemonic, M, S, type) \ 1144 void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, AsmCondition cond) { \ 1145 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1146 rm->encoding() << 16 | cond << 12 | 0b11 << 10 | rn->encoding() << 5 | rd->encoding()); \ 1147 } 1148 1149 F(fcsel_s, 0, 0, 0b00) 1150 F(fcsel_d, 0, 0, 0b01) 1151 #undef F 1152 1153 #define F(mnemonic, M, S, type, opcode) \ 1154 void mnemonic(FloatRegister rd, FloatRegister rn) { \ 1155 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1156 opcode << 15 | 0b10000 << 10 | rn->encoding() << 5 | rd->encoding()); \ 1157 } 1158 1159 F(fmov_s, 0, 0, 0b00, 0b000000) 1160 F(fabs_s, 0, 0, 0b00, 0b000001) 1161 F(fneg_s, 0, 0, 0b00, 0b000010) 1162 F(fsqrt_s, 0, 0, 0b00, 0b000011) 1163 F(fcvt_ds, 0, 0, 0b00, 0b000101) 1164 F(fcvt_hs, 0, 0, 0b00, 0b000111) 1165 F(frintn_s, 0, 0, 0b00, 0b001000) 1166 F(frintp_s, 0, 0, 0b00, 0b001001) 1167 F(frintm_s, 0, 0, 0b00, 0b001010) 1168 F(frintz_s, 0, 0, 0b00, 0b001011) 1169 F(frinta_s, 0, 0, 0b00, 0b001100) 1170 F(frintx_s, 0, 0, 0b00, 0b001110) 1171 F(frinti_s, 0, 0, 0b00, 0b001111) 1172 1173 F(fmov_d, 0, 0, 0b01, 0b000000) 1174 F(fabs_d, 0, 0, 0b01, 0b000001) 1175 F(fneg_d, 0, 0, 0b01, 0b000010) 1176 F(fsqrt_d, 0, 0, 0b01, 0b000011) 1177 F(fcvt_sd, 0, 0, 0b01, 0b000100) 1178 F(fcvt_hd, 0, 0, 0b01, 0b000111) 1179 F(frintn_d, 0, 0, 0b01, 0b001000) 1180 F(frintp_d, 0, 0, 0b01, 0b001001) 1181 F(frintm_d, 0, 0, 0b01, 0b001010) 1182 F(frintz_d, 0, 0, 0b01, 0b001011) 1183 F(frinta_d, 0, 0, 0b01, 0b001100) 1184 F(frintx_d, 0, 0, 0b01, 0b001110) 1185 F(frinti_d, 0, 0, 0b01, 0b001111) 1186 1187 F(fcvt_sh, 0, 0, 0b11, 0b000100) 1188 F(fcvt_dh, 0, 0, 0b11, 0b000101) 1189 #undef F 1190 1191 #define F(mnemonic, M, S, type, opcode) \ 1192 void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm) { \ 1193 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1194 rm->encoding() << 16 | opcode << 12 | 0b10 << 10 | rn->encoding() << 5 | rd->encoding()); \ 1195 } 1196 1197 F(fmul_s, 0, 0, 0b00, 0b0000) 1198 F(fdiv_s, 0, 0, 0b00, 0b0001) 1199 F(fadd_s, 0, 0, 0b00, 0b0010) 1200 F(fsub_s, 0, 0, 0b00, 0b0011) 1201 F(fmax_s, 0, 0, 0b00, 0b0100) 1202 F(fmin_s, 0, 0, 0b00, 0b0101) 1203 F(fmaxnm_s, 0, 0, 0b00, 0b0110) 1204 F(fminnm_s, 0, 0, 0b00, 0b0111) 1205 F(fnmul_s, 0, 0, 0b00, 0b1000) 1206 1207 F(fmul_d, 0, 0, 0b01, 0b0000) 1208 F(fdiv_d, 0, 0, 0b01, 0b0001) 1209 F(fadd_d, 0, 0, 0b01, 0b0010) 1210 F(fsub_d, 0, 0, 0b01, 0b0011) 1211 F(fmax_d, 0, 0, 0b01, 0b0100) 1212 F(fmin_d, 0, 0, 0b01, 0b0101) 1213 F(fmaxnm_d, 0, 0, 0b01, 0b0110) 1214 F(fminnm_d, 0, 0, 0b01, 0b0111) 1215 F(fnmul_d, 0, 0, 0b01, 0b1000) 1216 #undef F 1217 1218 #define F(mnemonic, M, S, type, o1, o0) \ 1219 void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, FloatRegister ra) { \ 1220 emit_int32(M << 31 | S << 29 | 0b11111 << 24 | type << 22 | o1 << 21 | rm->encoding() << 16 | \ 1221 o0 << 15 | ra->encoding() << 10 | rn->encoding() << 5 | rd->encoding()); \ 1222 } 1223 1224 F(fmadd_s, 0, 0, 0b00, 0, 0) 1225 F(fmsub_s, 0, 0, 0b00, 0, 1) 1226 F(fnmadd_s, 0, 0, 0b00, 1, 0) 1227 F(fnmsub_s, 0, 0, 0b00, 1, 1) 1228 1229 F(fmadd_d, 0, 0, 0b01, 0, 0) 1230 F(fmsub_d, 0, 0, 0b01, 0, 1) 1231 F(fnmadd_d, 0, 0, 0b01, 1, 0) 1232 F(fnmsub_d, 0, 0, 0b01, 1, 1) 1233 #undef F 1234 1235 #define F(mnemonic, M, S, type) \ 1236 void mnemonic(FloatRegister rd, int imm8) { \ 1237 assert ((imm8 >> 8) == 0, "immediate is out of range"); \ 1238 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1239 imm8 << 13 | 0b100 << 10 | rd->encoding()); \ 1240 } 1241 1242 F(fmov_s, 0, 0, 0b00) 1243 F(fmov_d, 0, 0, 0b01) 1244 #undef F 1245 1246 #define F(mnemonic, sf, S, type, rmode, opcode) \ 1247 void mnemonic(Register rd, FloatRegister rn) { \ 1248 emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1249 rmode << 19 | opcode << 16 | rn->encoding() << 5 | rd->encoding_with_zr()); \ 1250 } 1251 1252 F(fcvtns_ws, 0, 0, 0b00, 0b00, 0b000) 1253 F(fcvtnu_ws, 0, 0, 0b00, 0b00, 0b001) 1254 F(fcvtas_ws, 0, 0, 0b00, 0b00, 0b100) 1255 F(fcvtau_ws, 0, 0, 0b00, 0b00, 0b101) 1256 F(fmov_ws, 0, 0, 0b00, 0b00, 0b110) 1257 F(fcvtps_ws, 0, 0, 0b00, 0b01, 0b000) 1258 F(fcvtpu_ws, 0, 0, 0b00, 0b01, 0b001) 1259 F(fcvtms_ws, 0, 0, 0b00, 0b10, 0b000) 1260 F(fcvtmu_ws, 0, 0, 0b00, 0b10, 0b001) 1261 F(fcvtzs_ws, 0, 0, 0b00, 0b11, 0b000) 1262 F(fcvtzu_ws, 0, 0, 0b00, 0b11, 0b001) 1263 1264 F(fcvtns_wd, 0, 0, 0b01, 0b00, 0b000) 1265 F(fcvtnu_wd, 0, 0, 0b01, 0b00, 0b001) 1266 F(fcvtas_wd, 0, 0, 0b01, 0b00, 0b100) 1267 F(fcvtau_wd, 0, 0, 0b01, 0b00, 0b101) 1268 F(fcvtps_wd, 0, 0, 0b01, 0b01, 0b000) 1269 F(fcvtpu_wd, 0, 0, 0b01, 0b01, 0b001) 1270 F(fcvtms_wd, 0, 0, 0b01, 0b10, 0b000) 1271 F(fcvtmu_wd, 0, 0, 0b01, 0b10, 0b001) 1272 F(fcvtzs_wd, 0, 0, 0b01, 0b11, 0b000) 1273 F(fcvtzu_wd, 0, 0, 0b01, 0b11, 0b001) 1274 1275 F(fcvtns_xs, 1, 0, 0b00, 0b00, 0b000) 1276 F(fcvtnu_xs, 1, 0, 0b00, 0b00, 0b001) 1277 F(fcvtas_xs, 1, 0, 0b00, 0b00, 0b100) 1278 F(fcvtau_xs, 1, 0, 0b00, 0b00, 0b101) 1279 F(fcvtps_xs, 1, 0, 0b00, 0b01, 0b000) 1280 F(fcvtpu_xs, 1, 0, 0b00, 0b01, 0b001) 1281 F(fcvtms_xs, 1, 0, 0b00, 0b10, 0b000) 1282 F(fcvtmu_xs, 1, 0, 0b00, 0b10, 0b001) 1283 F(fcvtzs_xs, 1, 0, 0b00, 0b11, 0b000) 1284 F(fcvtzu_xs, 1, 0, 0b00, 0b11, 0b001) 1285 1286 F(fcvtns_xd, 1, 0, 0b01, 0b00, 0b000) 1287 F(fcvtnu_xd, 1, 0, 0b01, 0b00, 0b001) 1288 F(fcvtas_xd, 1, 0, 0b01, 0b00, 0b100) 1289 F(fcvtau_xd, 1, 0, 0b01, 0b00, 0b101) 1290 F(fmov_xd, 1, 0, 0b01, 0b00, 0b110) 1291 F(fcvtps_xd, 1, 0, 0b01, 0b01, 0b000) 1292 F(fcvtpu_xd, 1, 0, 0b01, 0b01, 0b001) 1293 F(fcvtms_xd, 1, 0, 0b01, 0b10, 0b000) 1294 F(fcvtmu_xd, 1, 0, 0b01, 0b10, 0b001) 1295 F(fcvtzs_xd, 1, 0, 0b01, 0b11, 0b000) 1296 F(fcvtzu_xd, 1, 0, 0b01, 0b11, 0b001) 1297 1298 F(fmov_xq, 1, 0, 0b10, 0b01, 0b110) 1299 #undef F 1300 1301 #define F(mnemonic, sf, S, type, rmode, opcode) \ 1302 void mnemonic(FloatRegister rd, Register rn) { \ 1303 emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1304 rmode << 19 | opcode << 16 | rn->encoding_with_zr() << 5 | rd->encoding()); \ 1305 } 1306 1307 F(scvtf_sw, 0, 0, 0b00, 0b00, 0b010) 1308 F(ucvtf_sw, 0, 0, 0b00, 0b00, 0b011) 1309 F(fmov_sw, 0, 0, 0b00, 0b00, 0b111) 1310 F(scvtf_dw, 0, 0, 0b01, 0b00, 0b010) 1311 F(ucvtf_dw, 0, 0, 0b01, 0b00, 0b011) 1312 1313 F(scvtf_sx, 1, 0, 0b00, 0b00, 0b010) 1314 F(ucvtf_sx, 1, 0, 0b00, 0b00, 0b011) 1315 F(scvtf_dx, 1, 0, 0b01, 0b00, 0b010) 1316 F(ucvtf_dx, 1, 0, 0b01, 0b00, 0b011) 1317 F(fmov_dx, 1, 0, 0b01, 0b00, 0b111) 1318 1319 F(fmov_qx, 1, 0, 0b10, 0b01, 0b111) 1320 #undef F 1321 1322 #define F(mnemonic, opcode) \ 1323 void mnemonic(FloatRegister Vd, FloatRegister Vn) { \ 1324 emit_int32( opcode << 10 | Vn->encoding() << 5 | Vd->encoding()); \ 1325 } 1326 1327 F(aese, 0b0100111000101000010010); 1328 F(aesd, 0b0100111000101000010110); 1329 F(aesmc, 0b0100111000101000011010); 1330 F(aesimc, 0b0100111000101000011110); 1331 #undef F 1332 1333 #ifdef COMPILER2 1334 typedef VFP::double_num double_num; 1335 typedef VFP::float_num float_num; 1336 #endif 1337 1338 void vcnt(FloatRegister Dd, FloatRegister Dn, int quad = 0, int size = 0) { 1339 // emitted at VM startup to detect whether the instruction is available 1340 assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction"); 1341 assert(size == 0, "illegal size value"); 1342 emit_int32(0x0e205800 | quad << 30 | size << 22 | Dn->encoding() << 5 | Dd->encoding()); 1343 } 1344 1345 #ifdef COMPILER2 1346 void addv(FloatRegister Dd, FloatRegister Dm, int quad, int size) { 1347 // emitted at VM startup to detect whether the instruction is available 1348 assert(VM_Version::has_simd(), "simd instruction"); 1349 assert((quad & ~1) == 0, "illegal value"); 1350 assert(size >= 0 && size < 3, "illegal value"); 1351 assert(((size << 1) | quad) != 4, "illegal values (size 2, quad 0)"); 1352 emit_int32(0x0e31b800 | quad << 30 | size << 22 | Dm->encoding() << 5 | Dd->encoding()); 1353 } 1354 1355 enum VElem_Size { 1356 VELEM_SIZE_8 = 0x00, 1357 VELEM_SIZE_16 = 0x01, 1358 VELEM_SIZE_32 = 0x02, 1359 VELEM_SIZE_64 = 0x03 1360 }; 1361 1362 enum VLD_Type { 1363 VLD1_TYPE_1_REG = 0b0111, 1364 VLD1_TYPE_2_REGS = 0b1010, 1365 VLD1_TYPE_3_REGS = 0b0110, 1366 VLD1_TYPE_4_REGS = 0b0010 1367 }; 1368 1369 enum VFloat_Arith_Size { 1370 VFA_SIZE_F32 = 0b0, 1371 VFA_SIZE_F64 = 0b1 1372 }; 1373 1374 #define F(mnemonic, U, S, P) \ 1375 void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \ 1376 int size, int quad) { \ 1377 assert(VM_Version::has_simd(), "simd instruction"); \ 1378 assert(!(size == VFA_SIZE_F64 && !quad), "reserved"); \ 1379 assert((size & 1) == size, "overflow"); \ 1380 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | \ 1381 S << 23 | size << 22 | 1 << 21 | P << 11 | 1 << 10 | \ 1382 fm->encoding() << 16 | \ 1383 fn->encoding() << 5 | \ 1384 fd->encoding()); \ 1385 } 1386 1387 F(vaddF, 0, 0, 0b11010) // Vd = Vn + Vm (float) 1388 F(vsubF, 0, 1, 0b11010) // Vd = Vn - Vm (float) 1389 F(vmulF, 1, 0, 0b11011) // Vd = Vn - Vm (float) 1390 F(vdivF, 1, 0, 0b11111) // Vd = Vn / Vm (float) 1391 #undef F 1392 1393 #define F(mnemonic, U) \ 1394 void mnemonic(FloatRegister fd, FloatRegister fm, FloatRegister fn, \ 1395 int size, int quad) { \ 1396 assert(VM_Version::has_simd(), "simd instruction"); \ 1397 assert(!(size == VELEM_SIZE_64 && !quad), "reserved"); \ 1398 assert((size & 0b11) == size, "overflow"); \ 1399 int R = 0; /* rounding */ \ 1400 int S = 0; /* saturating */ \ 1401 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 | \ 1402 1 << 21 | R << 12 | S << 11 | 0b10001 << 10 | \ 1403 fm->encoding() << 16 | \ 1404 fn->encoding() << 5 | \ 1405 fd->encoding()); \ 1406 } 1407 1408 F(vshlSI, 0) // Vd = ashift(Vn,Vm) (int) 1409 F(vshlUI, 1) // Vd = lshift(Vn,Vm) (int) 1410 #undef F 1411 1412 #define F(mnemonic, U, P, M) \ 1413 void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \ 1414 int size, int quad) { \ 1415 assert(VM_Version::has_simd(), "simd instruction"); \ 1416 assert(!(size == VELEM_SIZE_64 && !quad), "reserved"); \ 1417 assert(!(size == VELEM_SIZE_64 && M), "reserved"); \ 1418 assert((size & 0b11) == size, "overflow"); \ 1419 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 | \ 1420 1 << 21 | P << 11 | 1 << 10 | \ 1421 fm->encoding() << 16 | \ 1422 fn->encoding() << 5 | \ 1423 fd->encoding()); \ 1424 } 1425 1426 F(vmulI, 0, 0b10011, true) // Vd = Vn * Vm (int) 1427 F(vaddI, 0, 0b10000, false) // Vd = Vn + Vm (int) 1428 F(vsubI, 1, 0b10000, false) // Vd = Vn - Vm (int) 1429 #undef F 1430 1431 #define F(mnemonic, U, O) \ 1432 void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \ 1433 int quad) { \ 1434 assert(VM_Version::has_simd(), "simd instruction"); \ 1435 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | O << 22 | \ 1436 1 << 21 | 0b00011 << 11 | 1 << 10 | \ 1437 fm->encoding() << 16 | \ 1438 fn->encoding() << 5 | \ 1439 fd->encoding()); \ 1440 } 1441 1442 F(vandI, 0, 0b00) // Vd = Vn & Vm (int) 1443 F(vorI, 0, 0b10) // Vd = Vn | Vm (int) 1444 F(vxorI, 1, 0b00) // Vd = Vn ^ Vm (int) 1445 #undef F 1446 1447 void vnegI(FloatRegister fd, FloatRegister fn, int size, int quad) { 1448 int U = 1; 1449 assert(VM_Version::has_simd(), "simd instruction"); 1450 assert(quad || size != VELEM_SIZE_64, "reserved"); 1451 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | 1452 size << 22 | 0b100000101110 << 10 | 1453 fn->encoding() << 5 | 1454 fd->encoding() << 0); 1455 } 1456 1457 void vshli(FloatRegister fd, FloatRegister fn, int esize, int imm, int quad) { 1458 assert(VM_Version::has_simd(), "simd instruction"); 1459 1460 if (imm >= esize) { 1461 // maximum shift gives all zeroes, direction doesn't matter, 1462 // but only available for shift right 1463 vshri(fd, fn, esize, esize, true /* unsigned */, quad); 1464 return; 1465 } 1466 assert(imm >= 0 && imm < esize, "out of range"); 1467 1468 int imm7 = esize + imm; 1469 int immh = imm7 >> 3; 1470 assert(immh != 0, "encoding constraint"); 1471 assert((uint)immh < 16, "sanity"); 1472 assert(((immh >> 2) | quad) != 0b10, "reserved"); 1473 emit_int32(quad << 30 | 0b011110 << 23 | imm7 << 16 | 1474 0b010101 << 10 | fn->encoding() << 5 | fd->encoding() << 0); 1475 } 1476 1477 void vshri(FloatRegister fd, FloatRegister fn, int esize, int imm, 1478 bool U /* unsigned */, int quad) { 1479 assert(VM_Version::has_simd(), "simd instruction"); 1480 assert(imm > 0, "out of range"); 1481 if (imm >= esize) { 1482 // maximum shift (all zeroes) 1483 imm = esize; 1484 } 1485 int imm7 = 2 * esize - imm ; 1486 int immh = imm7 >> 3; 1487 assert(immh != 0, "encoding constraint"); 1488 assert((uint)immh < 16, "sanity"); 1489 assert(((immh >> 2) | quad) != 0b10, "reserved"); 1490 emit_int32(quad << 30 | U << 29 | 0b011110 << 23 | imm7 << 16 | 1491 0b000001 << 10 | fn->encoding() << 5 | fd->encoding() << 0); 1492 } 1493 void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) { 1494 vshri(fd, fm, size, imm, true /* unsigned */, quad); 1495 } 1496 void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) { 1497 vshri(fd, fm, size, imm, false /* signed */, quad); 1498 } 1499 1500 void vld1(FloatRegister Vt, Address addr, VElem_Size size, int bits) { 1501 assert(VM_Version::has_simd(), "simd instruction"); 1502 assert(bits == 128, "unsupported"); 1503 assert(addr.disp() == 0 || addr.disp() == 16, "must be"); 1504 int type = 0b11; // 2D 1505 int quad = 1; 1506 int L = 1; 1507 int opcode = VLD1_TYPE_1_REG; 1508 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1509 Vt->encoding() << 0 | addr.encoding_simd()); 1510 } 1511 1512 void vst1(FloatRegister Vt, Address addr, VElem_Size size, int bits) { 1513 assert(VM_Version::has_simd(), "simd instruction"); 1514 assert(bits == 128, "unsupported"); 1515 assert(addr.disp() == 0 || addr.disp() == 16, "must be"); 1516 int type = 0b11; // 2D 1517 int quad = 1; 1518 int L = 0; 1519 int opcode = VLD1_TYPE_1_REG; 1520 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1521 Vt->encoding() << 0 | addr.encoding_simd()); 1522 } 1523 1524 void vld1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) { 1525 assert(VM_Version::has_simd(), "simd instruction"); 1526 assert(bits == 128, "unsupported"); 1527 assert(Vt->successor() == Vt2, "Registers must be ordered"); 1528 assert(addr.disp() == 0 || addr.disp() == 32, "must be"); 1529 int type = 0b11; // 2D 1530 int quad = 1; 1531 int L = 1; 1532 int opcode = VLD1_TYPE_2_REGS; 1533 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1534 Vt->encoding() << 0 | addr.encoding_simd()); 1535 } 1536 1537 void vst1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) { 1538 assert(VM_Version::has_simd(), "simd instruction"); 1539 assert(Vt->successor() == Vt2, "Registers must be ordered"); 1540 assert(bits == 128, "unsupported"); 1541 assert(addr.disp() == 0 || addr.disp() == 32, "must be"); 1542 int type = 0b11; // 2D 1543 int quad = 1; 1544 int L = 0; 1545 int opcode = VLD1_TYPE_2_REGS; 1546 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1547 Vt->encoding() << 0 | addr.encoding_simd()); 1548 } 1549 1550 void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1551 Address addr, VElem_Size size, int bits) { 1552 assert(VM_Version::has_simd(), "simd instruction"); 1553 assert(bits == 128, "unsupported"); 1554 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3, 1555 "Registers must be ordered"); 1556 assert(addr.disp() == 0 || addr.disp() == 48, "must be"); 1557 int type = 0b11; // 2D 1558 int quad = 1; 1559 int L = 1; 1560 int opcode = VLD1_TYPE_3_REGS; 1561 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1562 Vt->encoding() << 0 | addr.encoding_simd()); 1563 } 1564 1565 void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1566 Address addr, VElem_Size size, int bits) { 1567 assert(VM_Version::has_simd(), "simd instruction"); 1568 assert(bits == 128, "unsupported"); 1569 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3, 1570 "Registers must be ordered"); 1571 assert(addr.disp() == 0 || addr.disp() == 48, "must be"); 1572 int type = 0b11; // 2D 1573 int quad = 1; 1574 int L = 0; 1575 int opcode = VLD1_TYPE_3_REGS; 1576 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1577 Vt->encoding() << 0 | addr.encoding_simd()); 1578 } 1579 1580 void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1581 FloatRegister Vt4, Address addr, VElem_Size size, int bits) { 1582 assert(VM_Version::has_simd(), "simd instruction"); 1583 assert(bits == 128, "unsupported"); 1584 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 && 1585 Vt3->successor() == Vt4, "Registers must be ordered"); 1586 assert(addr.disp() == 0 || addr.disp() == 64, "must be"); 1587 int type = 0b11; // 2D 1588 int quad = 1; 1589 int L = 1; 1590 int opcode = VLD1_TYPE_4_REGS; 1591 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1592 Vt->encoding() << 0 | addr.encoding_simd()); 1593 } 1594 1595 void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1596 FloatRegister Vt4, Address addr, VElem_Size size, int bits) { 1597 assert(VM_Version::has_simd(), "simd instruction"); 1598 assert(bits == 128, "unsupported"); 1599 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 && 1600 Vt3->successor() == Vt4, "Registers must be ordered"); 1601 assert(addr.disp() == 0 || addr.disp() == 64, "must be"); 1602 int type = 0b11; // 2D 1603 int quad = 1; 1604 int L = 0; 1605 int opcode = VLD1_TYPE_4_REGS; 1606 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1607 Vt->encoding() << 0 | addr.encoding_simd()); 1608 } 1609 1610 void rev32(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) { 1611 assert(VM_Version::has_simd(), "simd instruction"); 1612 assert(size == VELEM_SIZE_8 || size == VELEM_SIZE_16, "must be"); 1613 emit_int32(quad << 30 | 0b101110 << 24 | size << 22 | 1614 0b100000000010 << 10 | Vn->encoding() << 5 | Vd->encoding()); 1615 } 1616 1617 void eor(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, VElem_Size size, int quad) { 1618 assert(VM_Version::has_simd(), "simd instruction"); 1619 assert(size == VELEM_SIZE_8, "must be"); 1620 emit_int32(quad << 30 | 0b101110001 << 21 | Vm->encoding() << 16 | 1621 0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding()); 1622 } 1623 1624 void orr(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, VElem_Size size, int quad) { 1625 assert(VM_Version::has_simd(), "simd instruction"); 1626 assert(size == VELEM_SIZE_8, "must be"); 1627 emit_int32(quad << 30 | 0b001110101 << 21 | Vm->encoding() << 16 | 1628 0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding()); 1629 } 1630 1631 void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) { 1632 assert(VM_Version::has_simd(), "simd instruction"); 1633 assert(imm8 >= 0 && imm8 < 256, "out of range"); 1634 int op; 1635 int cmode; 1636 switch (size) { 1637 case VELEM_SIZE_8: 1638 op = 0; 1639 cmode = 0b1110; 1640 break; 1641 case VELEM_SIZE_16: 1642 op = 0; 1643 cmode = 0b1000; 1644 break; 1645 case VELEM_SIZE_32: 1646 op = 0; 1647 cmode = 0b0000; 1648 break; 1649 default: 1650 cmode = 0; 1651 ShouldNotReachHere(); 1652 } 1653 int abc = imm8 >> 5; 1654 int defgh = imm8 & 0b11111; 1655 emit_int32(quad << 30 | op << 29 | 0b1111 << 24 | 1656 abc << 16 | cmode << 12 | 0b01 << 10 | 1657 defgh << 5 | Dd->encoding() << 0); 1658 } 1659 1660 void vdupI(FloatRegister Dd, Register Rn, VElem_Size size, int quad) { 1661 assert(VM_Version::has_simd(), "simd instruction"); 1662 assert(size <= 3, "unallocated encoding"); 1663 assert(size != 3 || quad == 1, "reserved"); 1664 int imm5 = 1 << size; 1665 #ifdef ASSERT 1666 switch (size) { 1667 case VELEM_SIZE_8: 1668 assert(imm5 == 0b00001, "sanity"); 1669 break; 1670 case VELEM_SIZE_16: 1671 assert(imm5 == 0b00010, "sanity"); 1672 break; 1673 case VELEM_SIZE_32: 1674 assert(imm5 == 0b00100, "sanity"); 1675 break; 1676 case VELEM_SIZE_64: 1677 assert(imm5 == 0b01000, "sanity"); 1678 break; 1679 default: 1680 ShouldNotReachHere(); 1681 } 1682 #endif 1683 emit_int32(quad << 30 | 0b111 << 25 | 0b11 << 10 | 1684 imm5 << 16 | Rn->encoding() << 5 | 1685 Dd->encoding() << 0); 1686 } 1687 1688 void vdup(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) { 1689 assert(VM_Version::has_simd(), "simd instruction"); 1690 int index = 0; 1691 int bytes = 1 << size; 1692 int range = 16 / bytes; 1693 assert(index < range, "overflow"); 1694 1695 assert(size != VELEM_SIZE_64 || quad, "reserved"); 1696 assert(8 << VELEM_SIZE_8 == 8, "sanity"); 1697 assert(8 << VELEM_SIZE_16 == 16, "sanity"); 1698 assert(8 << VELEM_SIZE_32 == 32, "sanity"); 1699 assert(8 << VELEM_SIZE_64 == 64, "sanity"); 1700 1701 int imm5 = (index << (size + 1)) | bytes; 1702 1703 emit_int32(quad << 30 | 0b001110000 << 21 | imm5 << 16 | 0b000001 << 10 | 1704 Vn->encoding() << 5 | Vd->encoding() << 0); 1705 } 1706 1707 void vdupF(FloatRegister Vd, FloatRegister Vn, int quad) { 1708 vdup(Vd, Vn, VELEM_SIZE_32, quad); 1709 } 1710 1711 void vdupD(FloatRegister Vd, FloatRegister Vn, int quad) { 1712 vdup(Vd, Vn, VELEM_SIZE_64, quad); 1713 } 1714 #endif 1715 }; 1716 1717 1718 #endif // CPU_ARM_VM_ASSEMBLER_ARM_64_HPP