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 #undef F 1087 1088 enum SystemRegister { // o0<1> op1<3> CRn<4> CRm<4> op2<3> 1089 SysReg_NZCV = 0b101101000010000, 1090 SysReg_FPCR = 0b101101000100000, 1091 }; 1092 1093 void mrs(Register rt, SystemRegister systemReg) { 1094 assert ((systemReg >> 15) == 0, "systemReg is out of range"); 1095 emit_int32(0b110101010011 << 20 | systemReg << 5 | rt->encoding_with_zr()); 1096 } 1097 1098 void msr(SystemRegister systemReg, Register rt) { 1099 assert ((systemReg >> 15) == 0, "systemReg is out of range"); 1100 emit_int32(0b110101010001 << 20 | systemReg << 5 | rt->encoding_with_zr()); 1101 } 1102 1103 // Floating-point instructions 1104 1105 #define F(mnemonic, M, S, type, opcode2) \ 1106 void mnemonic(FloatRegister rn, FloatRegister rm) { \ 1107 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1108 rm->encoding() << 16 | 0b1000 << 10 | rn->encoding() << 5 | opcode2); \ 1109 } 1110 1111 F(fcmp_s, 0, 0, 0b00, 0b00000) 1112 F(fcmpe_s, 0, 0, 0b00, 0b01000) 1113 F(fcmp_d, 0, 0, 0b01, 0b00000) 1114 F(fcmpe_d, 0, 0, 0b01, 0b10000) 1115 #undef F 1116 1117 #define F(mnemonic, M, S, type, opcode2) \ 1118 void mnemonic(FloatRegister rn) { \ 1119 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1120 0b1000 << 10 | rn->encoding() << 5 | opcode2); \ 1121 } 1122 1123 F(fcmp0_s, 0, 0, 0b00, 0b01000) 1124 F(fcmpe0_s, 0, 0, 0b00, 0b11000) 1125 F(fcmp0_d, 0, 0, 0b01, 0b01000) 1126 F(fcmpe0_d, 0, 0, 0b01, 0b11000) 1127 #undef F 1128 1129 #define F(mnemonic, M, S, type, op) \ 1130 void mnemonic(FloatRegister rn, FloatRegister rm, int nzcv, AsmCondition cond) { \ 1131 assert ((nzcv >> 4) == 0, "illegal nzcv"); \ 1132 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1133 rm->encoding() << 16 | cond << 12 | 0b01 << 10 | rn->encoding() << 5 | op << 4 | nzcv); \ 1134 } 1135 1136 F(fccmp_s, 0, 0, 0b00, 0) 1137 F(fccmpe_s, 0, 0, 0b00, 1) 1138 F(fccmp_d, 0, 0, 0b01, 0) 1139 F(fccmpe_d, 0, 0, 0b01, 1) 1140 #undef F 1141 1142 #define F(mnemonic, M, S, type) \ 1143 void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, AsmCondition cond) { \ 1144 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1145 rm->encoding() << 16 | cond << 12 | 0b11 << 10 | rn->encoding() << 5 | rd->encoding()); \ 1146 } 1147 1148 F(fcsel_s, 0, 0, 0b00) 1149 F(fcsel_d, 0, 0, 0b01) 1150 #undef F 1151 1152 #define F(mnemonic, M, S, type, opcode) \ 1153 void mnemonic(FloatRegister rd, FloatRegister rn) { \ 1154 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1155 opcode << 15 | 0b10000 << 10 | rn->encoding() << 5 | rd->encoding()); \ 1156 } 1157 1158 F(fmov_s, 0, 0, 0b00, 0b000000) 1159 F(fabs_s, 0, 0, 0b00, 0b000001) 1160 F(fneg_s, 0, 0, 0b00, 0b000010) 1161 F(fsqrt_s, 0, 0, 0b00, 0b000011) 1162 F(fcvt_ds, 0, 0, 0b00, 0b000101) 1163 F(fcvt_hs, 0, 0, 0b00, 0b000111) 1164 F(frintn_s, 0, 0, 0b00, 0b001000) 1165 F(frintp_s, 0, 0, 0b00, 0b001001) 1166 F(frintm_s, 0, 0, 0b00, 0b001010) 1167 F(frintz_s, 0, 0, 0b00, 0b001011) 1168 F(frinta_s, 0, 0, 0b00, 0b001100) 1169 F(frintx_s, 0, 0, 0b00, 0b001110) 1170 F(frinti_s, 0, 0, 0b00, 0b001111) 1171 1172 F(fmov_d, 0, 0, 0b01, 0b000000) 1173 F(fabs_d, 0, 0, 0b01, 0b000001) 1174 F(fneg_d, 0, 0, 0b01, 0b000010) 1175 F(fsqrt_d, 0, 0, 0b01, 0b000011) 1176 F(fcvt_sd, 0, 0, 0b01, 0b000100) 1177 F(fcvt_hd, 0, 0, 0b01, 0b000111) 1178 F(frintn_d, 0, 0, 0b01, 0b001000) 1179 F(frintp_d, 0, 0, 0b01, 0b001001) 1180 F(frintm_d, 0, 0, 0b01, 0b001010) 1181 F(frintz_d, 0, 0, 0b01, 0b001011) 1182 F(frinta_d, 0, 0, 0b01, 0b001100) 1183 F(frintx_d, 0, 0, 0b01, 0b001110) 1184 F(frinti_d, 0, 0, 0b01, 0b001111) 1185 1186 F(fcvt_sh, 0, 0, 0b11, 0b000100) 1187 F(fcvt_dh, 0, 0, 0b11, 0b000101) 1188 #undef F 1189 1190 #define F(mnemonic, M, S, type, opcode) \ 1191 void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm) { \ 1192 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1193 rm->encoding() << 16 | opcode << 12 | 0b10 << 10 | rn->encoding() << 5 | rd->encoding()); \ 1194 } 1195 1196 F(fmul_s, 0, 0, 0b00, 0b0000) 1197 F(fdiv_s, 0, 0, 0b00, 0b0001) 1198 F(fadd_s, 0, 0, 0b00, 0b0010) 1199 F(fsub_s, 0, 0, 0b00, 0b0011) 1200 F(fmax_s, 0, 0, 0b00, 0b0100) 1201 F(fmin_s, 0, 0, 0b00, 0b0101) 1202 F(fmaxnm_s, 0, 0, 0b00, 0b0110) 1203 F(fminnm_s, 0, 0, 0b00, 0b0111) 1204 F(fnmul_s, 0, 0, 0b00, 0b1000) 1205 1206 F(fmul_d, 0, 0, 0b01, 0b0000) 1207 F(fdiv_d, 0, 0, 0b01, 0b0001) 1208 F(fadd_d, 0, 0, 0b01, 0b0010) 1209 F(fsub_d, 0, 0, 0b01, 0b0011) 1210 F(fmax_d, 0, 0, 0b01, 0b0100) 1211 F(fmin_d, 0, 0, 0b01, 0b0101) 1212 F(fmaxnm_d, 0, 0, 0b01, 0b0110) 1213 F(fminnm_d, 0, 0, 0b01, 0b0111) 1214 F(fnmul_d, 0, 0, 0b01, 0b1000) 1215 #undef F 1216 1217 #define F(mnemonic, M, S, type, o1, o0) \ 1218 void mnemonic(FloatRegister rd, FloatRegister rn, FloatRegister rm, FloatRegister ra) { \ 1219 emit_int32(M << 31 | S << 29 | 0b11111 << 24 | type << 22 | o1 << 21 | rm->encoding() << 16 | \ 1220 o0 << 15 | ra->encoding() << 10 | rn->encoding() << 5 | rd->encoding()); \ 1221 } 1222 1223 F(fmadd_s, 0, 0, 0b00, 0, 0) 1224 F(fmsub_s, 0, 0, 0b00, 0, 1) 1225 F(fnmadd_s, 0, 0, 0b00, 1, 0) 1226 F(fnmsub_s, 0, 0, 0b00, 1, 1) 1227 1228 F(fmadd_d, 0, 0, 0b01, 0, 0) 1229 F(fmsub_d, 0, 0, 0b01, 0, 1) 1230 F(fnmadd_d, 0, 0, 0b01, 1, 0) 1231 F(fnmsub_d, 0, 0, 0b01, 1, 1) 1232 #undef F 1233 1234 #define F(mnemonic, M, S, type) \ 1235 void mnemonic(FloatRegister rd, int imm8) { \ 1236 assert ((imm8 >> 8) == 0, "immediate is out of range"); \ 1237 emit_int32(M << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1238 imm8 << 13 | 0b100 << 10 | rd->encoding()); \ 1239 } 1240 1241 F(fmov_s, 0, 0, 0b00) 1242 F(fmov_d, 0, 0, 0b01) 1243 #undef F 1244 1245 #define F(mnemonic, sf, S, type, rmode, opcode) \ 1246 void mnemonic(Register rd, FloatRegister rn) { \ 1247 emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1248 rmode << 19 | opcode << 16 | rn->encoding() << 5 | rd->encoding_with_zr()); \ 1249 } 1250 1251 F(fcvtns_ws, 0, 0, 0b00, 0b00, 0b000) 1252 F(fcvtnu_ws, 0, 0, 0b00, 0b00, 0b001) 1253 F(fcvtas_ws, 0, 0, 0b00, 0b00, 0b100) 1254 F(fcvtau_ws, 0, 0, 0b00, 0b00, 0b101) 1255 F(fmov_ws, 0, 0, 0b00, 0b00, 0b110) 1256 F(fcvtps_ws, 0, 0, 0b00, 0b01, 0b000) 1257 F(fcvtpu_ws, 0, 0, 0b00, 0b01, 0b001) 1258 F(fcvtms_ws, 0, 0, 0b00, 0b10, 0b000) 1259 F(fcvtmu_ws, 0, 0, 0b00, 0b10, 0b001) 1260 F(fcvtzs_ws, 0, 0, 0b00, 0b11, 0b000) 1261 F(fcvtzu_ws, 0, 0, 0b00, 0b11, 0b001) 1262 1263 F(fcvtns_wd, 0, 0, 0b01, 0b00, 0b000) 1264 F(fcvtnu_wd, 0, 0, 0b01, 0b00, 0b001) 1265 F(fcvtas_wd, 0, 0, 0b01, 0b00, 0b100) 1266 F(fcvtau_wd, 0, 0, 0b01, 0b00, 0b101) 1267 F(fcvtps_wd, 0, 0, 0b01, 0b01, 0b000) 1268 F(fcvtpu_wd, 0, 0, 0b01, 0b01, 0b001) 1269 F(fcvtms_wd, 0, 0, 0b01, 0b10, 0b000) 1270 F(fcvtmu_wd, 0, 0, 0b01, 0b10, 0b001) 1271 F(fcvtzs_wd, 0, 0, 0b01, 0b11, 0b000) 1272 F(fcvtzu_wd, 0, 0, 0b01, 0b11, 0b001) 1273 1274 F(fcvtns_xs, 1, 0, 0b00, 0b00, 0b000) 1275 F(fcvtnu_xs, 1, 0, 0b00, 0b00, 0b001) 1276 F(fcvtas_xs, 1, 0, 0b00, 0b00, 0b100) 1277 F(fcvtau_xs, 1, 0, 0b00, 0b00, 0b101) 1278 F(fcvtps_xs, 1, 0, 0b00, 0b01, 0b000) 1279 F(fcvtpu_xs, 1, 0, 0b00, 0b01, 0b001) 1280 F(fcvtms_xs, 1, 0, 0b00, 0b10, 0b000) 1281 F(fcvtmu_xs, 1, 0, 0b00, 0b10, 0b001) 1282 F(fcvtzs_xs, 1, 0, 0b00, 0b11, 0b000) 1283 F(fcvtzu_xs, 1, 0, 0b00, 0b11, 0b001) 1284 1285 F(fcvtns_xd, 1, 0, 0b01, 0b00, 0b000) 1286 F(fcvtnu_xd, 1, 0, 0b01, 0b00, 0b001) 1287 F(fcvtas_xd, 1, 0, 0b01, 0b00, 0b100) 1288 F(fcvtau_xd, 1, 0, 0b01, 0b00, 0b101) 1289 F(fmov_xd, 1, 0, 0b01, 0b00, 0b110) 1290 F(fcvtps_xd, 1, 0, 0b01, 0b01, 0b000) 1291 F(fcvtpu_xd, 1, 0, 0b01, 0b01, 0b001) 1292 F(fcvtms_xd, 1, 0, 0b01, 0b10, 0b000) 1293 F(fcvtmu_xd, 1, 0, 0b01, 0b10, 0b001) 1294 F(fcvtzs_xd, 1, 0, 0b01, 0b11, 0b000) 1295 F(fcvtzu_xd, 1, 0, 0b01, 0b11, 0b001) 1296 1297 F(fmov_xq, 1, 0, 0b10, 0b01, 0b110) 1298 #undef F 1299 1300 #define F(mnemonic, sf, S, type, rmode, opcode) \ 1301 void mnemonic(FloatRegister rd, Register rn) { \ 1302 emit_int32(sf << 31 | S << 29 | 0b11110 << 24 | type << 22 | 1 << 21 | \ 1303 rmode << 19 | opcode << 16 | rn->encoding_with_zr() << 5 | rd->encoding()); \ 1304 } 1305 1306 F(scvtf_sw, 0, 0, 0b00, 0b00, 0b010) 1307 F(ucvtf_sw, 0, 0, 0b00, 0b00, 0b011) 1308 F(fmov_sw, 0, 0, 0b00, 0b00, 0b111) 1309 F(scvtf_dw, 0, 0, 0b01, 0b00, 0b010) 1310 F(ucvtf_dw, 0, 0, 0b01, 0b00, 0b011) 1311 1312 F(scvtf_sx, 1, 0, 0b00, 0b00, 0b010) 1313 F(ucvtf_sx, 1, 0, 0b00, 0b00, 0b011) 1314 F(scvtf_dx, 1, 0, 0b01, 0b00, 0b010) 1315 F(ucvtf_dx, 1, 0, 0b01, 0b00, 0b011) 1316 F(fmov_dx, 1, 0, 0b01, 0b00, 0b111) 1317 1318 F(fmov_qx, 1, 0, 0b10, 0b01, 0b111) 1319 #undef F 1320 1321 #define F(mnemonic, opcode) \ 1322 void mnemonic(FloatRegister Vd, FloatRegister Vn) { \ 1323 emit_int32( opcode << 10 | Vn->encoding() << 5 | Vd->encoding()); \ 1324 } 1325 1326 F(aese, 0b0100111000101000010010); 1327 F(aesd, 0b0100111000101000010110); 1328 F(aesmc, 0b0100111000101000011010); 1329 F(aesimc, 0b0100111000101000011110); 1330 #undef F 1331 1332 #ifdef COMPILER2 1333 typedef VFP::double_num double_num; 1334 typedef VFP::float_num float_num; 1335 #endif 1336 1337 void vcnt(FloatRegister Dd, FloatRegister Dn, int quad = 0, int size = 0) { 1338 // emitted at VM startup to detect whether the instruction is available 1339 assert(!VM_Version::is_initialized() || VM_Version::has_simd(), "simd instruction"); 1340 assert(size == 0, "illegal size value"); 1341 emit_int32(0x0e205800 | quad << 30 | size << 22 | Dn->encoding() << 5 | Dd->encoding()); 1342 } 1343 1344 #ifdef COMPILER2 1345 void addv(FloatRegister Dd, FloatRegister Dm, int quad, int size) { 1346 // emitted at VM startup to detect whether the instruction is available 1347 assert(VM_Version::has_simd(), "simd instruction"); 1348 assert((quad & ~1) == 0, "illegal value"); 1349 assert(size >= 0 && size < 3, "illegal value"); 1350 assert(((size << 1) | quad) != 4, "illegal values (size 2, quad 0)"); 1351 emit_int32(0x0e31b800 | quad << 30 | size << 22 | Dm->encoding() << 5 | Dd->encoding()); 1352 } 1353 1354 enum VElem_Size { 1355 VELEM_SIZE_8 = 0x00, 1356 VELEM_SIZE_16 = 0x01, 1357 VELEM_SIZE_32 = 0x02, 1358 VELEM_SIZE_64 = 0x03 1359 }; 1360 1361 enum VLD_Type { 1362 VLD1_TYPE_1_REG = 0b0111, 1363 VLD1_TYPE_2_REGS = 0b1010, 1364 VLD1_TYPE_3_REGS = 0b0110, 1365 VLD1_TYPE_4_REGS = 0b0010 1366 }; 1367 1368 enum VFloat_Arith_Size { 1369 VFA_SIZE_F32 = 0b0, 1370 VFA_SIZE_F64 = 0b1 1371 }; 1372 1373 #define F(mnemonic, U, S, P) \ 1374 void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \ 1375 int size, int quad) { \ 1376 assert(VM_Version::has_simd(), "simd instruction"); \ 1377 assert(!(size == VFA_SIZE_F64 && !quad), "reserved"); \ 1378 assert((size & 1) == size, "overflow"); \ 1379 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | \ 1380 S << 23 | size << 22 | 1 << 21 | P << 11 | 1 << 10 | \ 1381 fm->encoding() << 16 | \ 1382 fn->encoding() << 5 | \ 1383 fd->encoding()); \ 1384 } 1385 1386 F(vaddF, 0, 0, 0b11010) // Vd = Vn + Vm (float) 1387 F(vsubF, 0, 1, 0b11010) // Vd = Vn - Vm (float) 1388 F(vmulF, 1, 0, 0b11011) // Vd = Vn - Vm (float) 1389 F(vdivF, 1, 0, 0b11111) // Vd = Vn / Vm (float) 1390 #undef F 1391 1392 #define F(mnemonic, U) \ 1393 void mnemonic(FloatRegister fd, FloatRegister fm, FloatRegister fn, \ 1394 int size, int quad) { \ 1395 assert(VM_Version::has_simd(), "simd instruction"); \ 1396 assert(!(size == VELEM_SIZE_64 && !quad), "reserved"); \ 1397 assert((size & 0b11) == size, "overflow"); \ 1398 int R = 0; /* rounding */ \ 1399 int S = 0; /* saturating */ \ 1400 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 | \ 1401 1 << 21 | R << 12 | S << 11 | 0b10001 << 10 | \ 1402 fm->encoding() << 16 | \ 1403 fn->encoding() << 5 | \ 1404 fd->encoding()); \ 1405 } 1406 1407 F(vshlSI, 0) // Vd = ashift(Vn,Vm) (int) 1408 F(vshlUI, 1) // Vd = lshift(Vn,Vm) (int) 1409 #undef F 1410 1411 #define F(mnemonic, U, P, M) \ 1412 void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \ 1413 int size, int quad) { \ 1414 assert(VM_Version::has_simd(), "simd instruction"); \ 1415 assert(!(size == VELEM_SIZE_64 && !quad), "reserved"); \ 1416 assert(!(size == VELEM_SIZE_64 && M), "reserved"); \ 1417 assert((size & 0b11) == size, "overflow"); \ 1418 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | size << 22 | \ 1419 1 << 21 | P << 11 | 1 << 10 | \ 1420 fm->encoding() << 16 | \ 1421 fn->encoding() << 5 | \ 1422 fd->encoding()); \ 1423 } 1424 1425 F(vmulI, 0, 0b10011, true) // Vd = Vn * Vm (int) 1426 F(vaddI, 0, 0b10000, false) // Vd = Vn + Vm (int) 1427 F(vsubI, 1, 0b10000, false) // Vd = Vn - Vm (int) 1428 #undef F 1429 1430 #define F(mnemonic, U, O) \ 1431 void mnemonic(FloatRegister fd, FloatRegister fn, FloatRegister fm, \ 1432 int quad) { \ 1433 assert(VM_Version::has_simd(), "simd instruction"); \ 1434 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | O << 22 | \ 1435 1 << 21 | 0b00011 << 11 | 1 << 10 | \ 1436 fm->encoding() << 16 | \ 1437 fn->encoding() << 5 | \ 1438 fd->encoding()); \ 1439 } 1440 1441 F(vandI, 0, 0b00) // Vd = Vn & Vm (int) 1442 F(vorI, 0, 0b10) // Vd = Vn | Vm (int) 1443 F(vxorI, 1, 0b00) // Vd = Vn ^ Vm (int) 1444 #undef F 1445 1446 void vnegI(FloatRegister fd, FloatRegister fn, int size, int quad) { 1447 int U = 1; 1448 assert(VM_Version::has_simd(), "simd instruction"); 1449 assert(quad || size != VELEM_SIZE_64, "reserved"); 1450 emit_int32(quad << 30 | U << 29 | 0b01110 << 24 | 1451 size << 22 | 0b100000101110 << 10 | 1452 fn->encoding() << 5 | 1453 fd->encoding() << 0); 1454 } 1455 1456 void vshli(FloatRegister fd, FloatRegister fn, int esize, int imm, int quad) { 1457 assert(VM_Version::has_simd(), "simd instruction"); 1458 1459 if (imm >= esize) { 1460 // maximum shift gives all zeroes, direction doesn't matter, 1461 // but only available for shift right 1462 vshri(fd, fn, esize, esize, true /* unsigned */, quad); 1463 return; 1464 } 1465 assert(imm >= 0 && imm < esize, "out of range"); 1466 1467 int imm7 = esize + imm; 1468 int immh = imm7 >> 3; 1469 assert(immh != 0, "encoding constraint"); 1470 assert((uint)immh < 16, "sanity"); 1471 assert(((immh >> 2) | quad) != 0b10, "reserved"); 1472 emit_int32(quad << 30 | 0b011110 << 23 | imm7 << 16 | 1473 0b010101 << 10 | fn->encoding() << 5 | fd->encoding() << 0); 1474 } 1475 1476 void vshri(FloatRegister fd, FloatRegister fn, int esize, int imm, 1477 bool U /* unsigned */, int quad) { 1478 assert(VM_Version::has_simd(), "simd instruction"); 1479 assert(imm > 0, "out of range"); 1480 if (imm >= esize) { 1481 // maximum shift (all zeroes) 1482 imm = esize; 1483 } 1484 int imm7 = 2 * esize - imm ; 1485 int immh = imm7 >> 3; 1486 assert(immh != 0, "encoding constraint"); 1487 assert((uint)immh < 16, "sanity"); 1488 assert(((immh >> 2) | quad) != 0b10, "reserved"); 1489 emit_int32(quad << 30 | U << 29 | 0b011110 << 23 | imm7 << 16 | 1490 0b000001 << 10 | fn->encoding() << 5 | fd->encoding() << 0); 1491 } 1492 void vshrUI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) { 1493 vshri(fd, fm, size, imm, true /* unsigned */, quad); 1494 } 1495 void vshrSI(FloatRegister fd, FloatRegister fm, int size, int imm, int quad) { 1496 vshri(fd, fm, size, imm, false /* signed */, quad); 1497 } 1498 1499 void vld1(FloatRegister Vt, Address addr, VElem_Size size, int bits) { 1500 assert(VM_Version::has_simd(), "simd instruction"); 1501 assert(bits == 128, "unsupported"); 1502 assert(addr.disp() == 0 || addr.disp() == 16, "must be"); 1503 int type = 0b11; // 2D 1504 int quad = 1; 1505 int L = 1; 1506 int opcode = VLD1_TYPE_1_REG; 1507 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1508 Vt->encoding() << 0 | addr.encoding_simd()); 1509 } 1510 1511 void vst1(FloatRegister Vt, Address addr, VElem_Size size, int bits) { 1512 assert(VM_Version::has_simd(), "simd instruction"); 1513 assert(bits == 128, "unsupported"); 1514 assert(addr.disp() == 0 || addr.disp() == 16, "must be"); 1515 int type = 0b11; // 2D 1516 int quad = 1; 1517 int L = 0; 1518 int opcode = VLD1_TYPE_1_REG; 1519 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1520 Vt->encoding() << 0 | addr.encoding_simd()); 1521 } 1522 1523 void vld1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) { 1524 assert(VM_Version::has_simd(), "simd instruction"); 1525 assert(bits == 128, "unsupported"); 1526 assert(Vt->successor() == Vt2, "Registers must be ordered"); 1527 assert(addr.disp() == 0 || addr.disp() == 32, "must be"); 1528 int type = 0b11; // 2D 1529 int quad = 1; 1530 int L = 1; 1531 int opcode = VLD1_TYPE_2_REGS; 1532 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1533 Vt->encoding() << 0 | addr.encoding_simd()); 1534 } 1535 1536 void vst1(FloatRegister Vt, FloatRegister Vt2, Address addr, VElem_Size size, int bits) { 1537 assert(VM_Version::has_simd(), "simd instruction"); 1538 assert(Vt->successor() == Vt2, "Registers must be ordered"); 1539 assert(bits == 128, "unsupported"); 1540 assert(addr.disp() == 0 || addr.disp() == 32, "must be"); 1541 int type = 0b11; // 2D 1542 int quad = 1; 1543 int L = 0; 1544 int opcode = VLD1_TYPE_2_REGS; 1545 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1546 Vt->encoding() << 0 | addr.encoding_simd()); 1547 } 1548 1549 void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1550 Address addr, VElem_Size size, int bits) { 1551 assert(VM_Version::has_simd(), "simd instruction"); 1552 assert(bits == 128, "unsupported"); 1553 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3, 1554 "Registers must be ordered"); 1555 assert(addr.disp() == 0 || addr.disp() == 48, "must be"); 1556 int type = 0b11; // 2D 1557 int quad = 1; 1558 int L = 1; 1559 int opcode = VLD1_TYPE_3_REGS; 1560 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1561 Vt->encoding() << 0 | addr.encoding_simd()); 1562 } 1563 1564 void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1565 Address addr, VElem_Size size, int bits) { 1566 assert(VM_Version::has_simd(), "simd instruction"); 1567 assert(bits == 128, "unsupported"); 1568 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3, 1569 "Registers must be ordered"); 1570 assert(addr.disp() == 0 || addr.disp() == 48, "must be"); 1571 int type = 0b11; // 2D 1572 int quad = 1; 1573 int L = 0; 1574 int opcode = VLD1_TYPE_3_REGS; 1575 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1576 Vt->encoding() << 0 | addr.encoding_simd()); 1577 } 1578 1579 void vld1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1580 FloatRegister Vt4, Address addr, VElem_Size size, int bits) { 1581 assert(VM_Version::has_simd(), "simd instruction"); 1582 assert(bits == 128, "unsupported"); 1583 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 && 1584 Vt3->successor() == Vt4, "Registers must be ordered"); 1585 assert(addr.disp() == 0 || addr.disp() == 64, "must be"); 1586 int type = 0b11; // 2D 1587 int quad = 1; 1588 int L = 1; 1589 int opcode = VLD1_TYPE_4_REGS; 1590 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1591 Vt->encoding() << 0 | addr.encoding_simd()); 1592 } 1593 1594 void vst1(FloatRegister Vt, FloatRegister Vt2, FloatRegister Vt3, 1595 FloatRegister Vt4, Address addr, VElem_Size size, int bits) { 1596 assert(VM_Version::has_simd(), "simd instruction"); 1597 assert(bits == 128, "unsupported"); 1598 assert(Vt->successor() == Vt2 && Vt2->successor() == Vt3 && 1599 Vt3->successor() == Vt4, "Registers must be ordered"); 1600 assert(addr.disp() == 0 || addr.disp() == 64, "must be"); 1601 int type = 0b11; // 2D 1602 int quad = 1; 1603 int L = 0; 1604 int opcode = VLD1_TYPE_4_REGS; 1605 emit_int32(quad << 30 | 0b11 << 26 | L << 22 | opcode << 12 | size << 10 | 1606 Vt->encoding() << 0 | addr.encoding_simd()); 1607 } 1608 1609 void rev32(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) { 1610 assert(VM_Version::has_simd(), "simd instruction"); 1611 assert(size == VELEM_SIZE_8 || size == VELEM_SIZE_16, "must be"); 1612 emit_int32(quad << 30 | 0b101110 << 24 | size << 22 | 1613 0b100000000010 << 10 | Vn->encoding() << 5 | Vd->encoding()); 1614 } 1615 1616 void eor(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, VElem_Size size, int quad) { 1617 assert(VM_Version::has_simd(), "simd instruction"); 1618 assert(size == VELEM_SIZE_8, "must be"); 1619 emit_int32(quad << 30 | 0b101110001 << 21 | Vm->encoding() << 16 | 1620 0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding()); 1621 } 1622 1623 void orr(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm, VElem_Size size, int quad) { 1624 assert(VM_Version::has_simd(), "simd instruction"); 1625 assert(size == VELEM_SIZE_8, "must be"); 1626 emit_int32(quad << 30 | 0b001110101 << 21 | Vm->encoding() << 16 | 1627 0b000111 << 10 | Vn->encoding() << 5 | Vd->encoding()); 1628 } 1629 1630 void vmovI(FloatRegister Dd, int imm8, VElem_Size size, int quad) { 1631 assert(VM_Version::has_simd(), "simd instruction"); 1632 assert(imm8 >= 0 && imm8 < 256, "out of range"); 1633 int op; 1634 int cmode; 1635 switch (size) { 1636 case VELEM_SIZE_8: 1637 op = 0; 1638 cmode = 0b1110; 1639 break; 1640 case VELEM_SIZE_16: 1641 op = 0; 1642 cmode = 0b1000; 1643 break; 1644 case VELEM_SIZE_32: 1645 op = 0; 1646 cmode = 0b0000; 1647 break; 1648 default: 1649 cmode = 0; 1650 ShouldNotReachHere(); 1651 } 1652 int abc = imm8 >> 5; 1653 int defgh = imm8 & 0b11111; 1654 emit_int32(quad << 30 | op << 29 | 0b1111 << 24 | 1655 abc << 16 | cmode << 12 | 0b01 << 10 | 1656 defgh << 5 | Dd->encoding() << 0); 1657 } 1658 1659 void vdupI(FloatRegister Dd, Register Rn, VElem_Size size, int quad) { 1660 assert(VM_Version::has_simd(), "simd instruction"); 1661 assert(size <= 3, "unallocated encoding"); 1662 assert(size != 3 || quad == 1, "reserved"); 1663 int imm5 = 1 << size; 1664 #ifdef ASSERT 1665 switch (size) { 1666 case VELEM_SIZE_8: 1667 assert(imm5 == 0b00001, "sanity"); 1668 break; 1669 case VELEM_SIZE_16: 1670 assert(imm5 == 0b00010, "sanity"); 1671 break; 1672 case VELEM_SIZE_32: 1673 assert(imm5 == 0b00100, "sanity"); 1674 break; 1675 case VELEM_SIZE_64: 1676 assert(imm5 == 0b01000, "sanity"); 1677 break; 1678 default: 1679 ShouldNotReachHere(); 1680 } 1681 #endif 1682 emit_int32(quad << 30 | 0b111 << 25 | 0b11 << 10 | 1683 imm5 << 16 | Rn->encoding() << 5 | 1684 Dd->encoding() << 0); 1685 } 1686 1687 void vdup(FloatRegister Vd, FloatRegister Vn, VElem_Size size, int quad) { 1688 assert(VM_Version::has_simd(), "simd instruction"); 1689 int index = 0; 1690 int bytes = 1 << size; 1691 int range = 16 / bytes; 1692 assert(index < range, "overflow"); 1693 1694 assert(size != VELEM_SIZE_64 || quad, "reserved"); 1695 assert(8 << VELEM_SIZE_8 == 8, "sanity"); 1696 assert(8 << VELEM_SIZE_16 == 16, "sanity"); 1697 assert(8 << VELEM_SIZE_32 == 32, "sanity"); 1698 assert(8 << VELEM_SIZE_64 == 64, "sanity"); 1699 1700 int imm5 = (index << (size + 1)) | bytes; 1701 1702 emit_int32(quad << 30 | 0b001110000 << 21 | imm5 << 16 | 0b000001 << 10 | 1703 Vn->encoding() << 5 | Vd->encoding() << 0); 1704 } 1705 1706 void vdupF(FloatRegister Vd, FloatRegister Vn, int quad) { 1707 vdup(Vd, Vn, VELEM_SIZE_32, quad); 1708 } 1709 1710 void vdupD(FloatRegister Vd, FloatRegister Vn, int quad) { 1711 vdup(Vd, Vn, VELEM_SIZE_64, quad); 1712 } 1713 #endif 1714 }; 1715 1716 1717 #endif // CPU_ARM_VM_ASSEMBLER_ARM_64_HPP