Path: blob/master/src/hotspot/cpu/aarch64/assembler_aarch64.cpp
64440 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2014, 2020 Red Hat Inc. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 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 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324#include "precompiled.hpp"25#include "asm/assembler.hpp"26#include "asm/assembler.inline.hpp"27#include "asm/macroAssembler.hpp"28#include "compiler/disassembler.hpp"29#include "immediate_aarch64.hpp"30#include "memory/resourceArea.hpp"3132#ifndef PRODUCT33const uintptr_t Assembler::asm_bp = 0x00007fffee09ac88;34#endif3536static float unpack(unsigned value);3738short Assembler::SIMD_Size_in_bytes[] = {39// T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q408, 16, 8, 16, 8, 16, 8, 16, 1641};4243Assembler::SIMD_Arrangement Assembler::_esize2arrangement_table[9][2] = {44// esize isQ:false isQ:true45/* 0 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},46/* 1 */ {T8B, T16B},47/* 2 */ {T4H, T8H},48/* 3 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},49/* 4 */ {T2S, T4S},50/* 5 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},51/* 6 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},52/* 7 */ {INVALID_ARRANGEMENT, INVALID_ARRANGEMENT},53/* 8 */ {T1D, T2D}54};555657Assembler::SIMD_Arrangement Assembler::esize2arrangement(int esize, bool isQ) {58guarantee(esize == 1 || esize == 2 || esize == 4 || esize == 8, "unsupported element size");59return _esize2arrangement_table[esize][isQ];60}6162void Assembler::emit_data64(jlong data,63relocInfo::relocType rtype,64int format) {65if (rtype == relocInfo::none) {66emit_int64(data);67} else {68emit_data64(data, Relocation::spec_simple(rtype), format);69}70}7172void Assembler::emit_data64(jlong data,73RelocationHolder const& rspec,74int format) {7576assert(inst_mark() != NULL, "must be inside InstructionMark");77// Do not use AbstractAssembler::relocate, which is not intended for78// embedded words. Instead, relocate to the enclosing instruction.79code_section()->relocate(inst_mark(), rspec, format);80emit_int64(data);81}8283extern "C" {84void das(uint64_t start, int len) {85ResourceMark rm;86len <<= 2;87if (len < 0)88Disassembler::decode((address)start + len, (address)start);89else90Disassembler::decode((address)start, (address)start + len);91}9293JNIEXPORT void das1(uintptr_t insn) {94das(insn, 1);95}96}9798#define __ as->99100void Address::lea(MacroAssembler *as, Register r) const {101Relocation* reloc = _rspec.reloc();102relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();103104switch(_mode) {105case base_plus_offset: {106if (_offset == 0 && _base == r) // it's a nop107break;108if (_offset > 0)109__ add(r, _base, _offset);110else111__ sub(r, _base, -_offset);112break;113}114case base_plus_offset_reg: {115__ add(r, _base, _index, _ext.op(), MAX2(_ext.shift(), 0));116break;117}118case literal: {119if (rtype == relocInfo::none)120__ mov(r, target());121else122__ movptr(r, (uint64_t)target());123break;124}125default:126ShouldNotReachHere();127}128}129130void Assembler::adrp(Register reg1, const Address &dest, uint64_t &byte_offset) {131ShouldNotReachHere();132}133134#undef __135136#define starti Instruction_aarch64 do_not_use(this); set_current(&do_not_use)137138void Assembler::adr(Register Rd, address adr) {139intptr_t offset = adr - pc();140int offset_lo = offset & 3;141offset >>= 2;142starti;143f(0, 31), f(offset_lo, 30, 29), f(0b10000, 28, 24), sf(offset, 23, 5);144rf(Rd, 0);145}146147void Assembler::_adrp(Register Rd, address adr) {148uint64_t pc_page = (uint64_t)pc() >> 12;149uint64_t adr_page = (uint64_t)adr >> 12;150intptr_t offset = adr_page - pc_page;151int offset_lo = offset & 3;152offset >>= 2;153starti;154f(1, 31), f(offset_lo, 30, 29), f(0b10000, 28, 24), sf(offset, 23, 5);155rf(Rd, 0);156}157158#undef starti159160Address::Address(address target, relocInfo::relocType rtype) : _mode(literal){161_is_lval = false;162_target = target;163switch (rtype) {164case relocInfo::oop_type:165case relocInfo::metadata_type:166// Oops are a special case. Normally they would be their own section167// but in cases like icBuffer they are literals in the code stream that168// we don't have a section for. We use none so that we get a literal address169// which is always patchable.170break;171case relocInfo::external_word_type:172_rspec = external_word_Relocation::spec(target);173break;174case relocInfo::internal_word_type:175_rspec = internal_word_Relocation::spec(target);176break;177case relocInfo::opt_virtual_call_type:178_rspec = opt_virtual_call_Relocation::spec();179break;180case relocInfo::static_call_type:181_rspec = static_call_Relocation::spec();182break;183case relocInfo::runtime_call_type:184_rspec = runtime_call_Relocation::spec();185break;186case relocInfo::poll_type:187case relocInfo::poll_return_type:188_rspec = Relocation::spec_simple(rtype);189break;190case relocInfo::none:191_rspec = RelocationHolder::none;192break;193default:194ShouldNotReachHere();195break;196}197}198199void Assembler::b(const Address &dest) {200code_section()->relocate(pc(), dest.rspec());201b(dest.target());202}203204void Assembler::bl(const Address &dest) {205code_section()->relocate(pc(), dest.rspec());206bl(dest.target());207}208209void Assembler::adr(Register r, const Address &dest) {210code_section()->relocate(pc(), dest.rspec());211adr(r, dest.target());212}213214void Assembler::br(Condition cc, Label &L) {215if (L.is_bound()) {216br(cc, target(L));217} else {218L.add_patch_at(code(), locator());219br(cc, pc());220}221}222223void Assembler::wrap_label(Label &L,224Assembler::uncond_branch_insn insn) {225if (L.is_bound()) {226(this->*insn)(target(L));227} else {228L.add_patch_at(code(), locator());229(this->*insn)(pc());230}231}232233void Assembler::wrap_label(Register r, Label &L,234compare_and_branch_insn insn) {235if (L.is_bound()) {236(this->*insn)(r, target(L));237} else {238L.add_patch_at(code(), locator());239(this->*insn)(r, pc());240}241}242243void Assembler::wrap_label(Register r, int bitpos, Label &L,244test_and_branch_insn insn) {245if (L.is_bound()) {246(this->*insn)(r, bitpos, target(L));247} else {248L.add_patch_at(code(), locator());249(this->*insn)(r, bitpos, pc());250}251}252253void Assembler::wrap_label(Label &L, prfop op, prefetch_insn insn) {254if (L.is_bound()) {255(this->*insn)(target(L), op);256} else {257L.add_patch_at(code(), locator());258(this->*insn)(pc(), op);259}260}261262// An "all-purpose" add/subtract immediate, per ARM documentation:263// A "programmer-friendly" assembler may accept a negative immediate264// between -(2^24 -1) and -1 inclusive, causing it to convert a265// requested ADD operation to a SUB, or vice versa, and then encode266// the absolute value of the immediate as for uimm24.267void Assembler::add_sub_immediate(Register Rd, Register Rn, unsigned uimm, int op,268int negated_op) {269bool sets_flags = op & 1; // this op sets flags270union {271unsigned u;272int imm;273};274u = uimm;275bool shift = false;276bool neg = imm < 0;277if (neg) {278imm = -imm;279op = negated_op;280}281assert(Rd != sp || imm % 16 == 0, "misaligned stack");282if (imm >= (1 << 11)283&& ((imm >> 12) << 12 == imm)) {284imm >>= 12;285shift = true;286}287f(op, 31, 29), f(0b10001, 28, 24), f(shift, 23, 22), f(imm, 21, 10);288289// add/subtract immediate ops with the S bit set treat r31 as zr;290// with S unset they use sp.291if (sets_flags)292zrf(Rd, 0);293else294srf(Rd, 0);295296srf(Rn, 5);297}298299bool Assembler::operand_valid_for_add_sub_immediate(int64_t imm) {300bool shift = false;301uint64_t uimm = (uint64_t)uabs((jlong)imm);302if (uimm < (1 << 12))303return true;304if (uimm < (1 << 24)305&& ((uimm >> 12) << 12 == uimm)) {306return true;307}308return false;309}310311bool Assembler::operand_valid_for_logical_immediate(bool is32, uint64_t imm) {312return encode_logical_immediate(is32, imm) != 0xffffffff;313}314315static uint64_t doubleTo64Bits(jdouble d) {316union {317jdouble double_value;318uint64_t double_bits;319};320321double_value = d;322return double_bits;323}324325bool Assembler::operand_valid_for_float_immediate(double imm) {326// If imm is all zero bits we can use ZR as the source of a327// floating-point value.328if (doubleTo64Bits(imm) == 0)329return true;330331// Otherwise try to encode imm then convert the encoded value back332// and make sure it's the exact same bit pattern.333unsigned result = encoding_for_fp_immediate(imm);334return doubleTo64Bits(imm) == fp_immediate_for_encoding(result, true);335}336337int AbstractAssembler::code_fill_byte() {338return 0;339}340341// n.b. this is implemented in subclass MacroAssembler342void Assembler::bang_stack_with_offset(int offset) { Unimplemented(); }343344345// and now the routines called by the assembler which encapsulate the346// above encode and decode functions347348uint32_t349asm_util::encode_logical_immediate(bool is32, uint64_t imm)350{351if (is32) {352/* Allow all zeros or all ones in top 32-bits, so that353constant expressions like ~1 are permitted. */354if (imm >> 32 != 0 && imm >> 32 != 0xffffffff)355return 0xffffffff;356/* Replicate the 32 lower bits to the 32 upper bits. */357imm &= 0xffffffff;358imm |= imm << 32;359}360361return encoding_for_logical_immediate(imm);362}363364unsigned Assembler::pack(double value) {365float val = (float)value;366unsigned result = encoding_for_fp_immediate(val);367guarantee(unpack(result) == value,368"Invalid floating-point immediate operand");369return result;370}371372// Packed operands for Floating-point Move (immediate)373374static float unpack(unsigned value) {375union {376unsigned ival;377float val;378};379ival = fp_immediate_for_encoding(value, 0);380return val;381}382383address Assembler::locate_next_instruction(address inst) {384return inst + Assembler::instruction_size;385}386387388