Path: blob/master/src/hotspot/cpu/aarch64/assembler_aarch64.cpp
40930 views
/*1* Copyright (c) 1997, 2020, 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};4243void Assembler::emit_data64(jlong data,44relocInfo::relocType rtype,45int format) {46if (rtype == relocInfo::none) {47emit_int64(data);48} else {49emit_data64(data, Relocation::spec_simple(rtype), format);50}51}5253void Assembler::emit_data64(jlong data,54RelocationHolder const& rspec,55int format) {5657assert(inst_mark() != NULL, "must be inside InstructionMark");58// Do not use AbstractAssembler::relocate, which is not intended for59// embedded words. Instead, relocate to the enclosing instruction.60code_section()->relocate(inst_mark(), rspec, format);61emit_int64(data);62}6364extern "C" {65void das(uint64_t start, int len) {66ResourceMark rm;67len <<= 2;68if (len < 0)69Disassembler::decode((address)start + len, (address)start);70else71Disassembler::decode((address)start, (address)start + len);72}7374JNIEXPORT void das1(uintptr_t insn) {75das(insn, 1);76}77}7879#define __ as->8081void Address::lea(MacroAssembler *as, Register r) const {82Relocation* reloc = _rspec.reloc();83relocInfo::relocType rtype = (relocInfo::relocType) reloc->type();8485switch(_mode) {86case base_plus_offset: {87if (_offset == 0 && _base == r) // it's a nop88break;89if (_offset > 0)90__ add(r, _base, _offset);91else92__ sub(r, _base, -_offset);93break;94}95case base_plus_offset_reg: {96__ add(r, _base, _index, _ext.op(), MAX2(_ext.shift(), 0));97break;98}99case literal: {100if (rtype == relocInfo::none)101__ mov(r, target());102else103__ movptr(r, (uint64_t)target());104break;105}106default:107ShouldNotReachHere();108}109}110111void Assembler::adrp(Register reg1, const Address &dest, uint64_t &byte_offset) {112ShouldNotReachHere();113}114115#undef __116117#define starti Instruction_aarch64 do_not_use(this); set_current(&do_not_use)118119void Assembler::adr(Register Rd, address adr) {120intptr_t offset = adr - pc();121int offset_lo = offset & 3;122offset >>= 2;123starti;124f(0, 31), f(offset_lo, 30, 29), f(0b10000, 28, 24), sf(offset, 23, 5);125rf(Rd, 0);126}127128void Assembler::_adrp(Register Rd, address adr) {129uint64_t pc_page = (uint64_t)pc() >> 12;130uint64_t adr_page = (uint64_t)adr >> 12;131intptr_t offset = adr_page - pc_page;132int offset_lo = offset & 3;133offset >>= 2;134starti;135f(1, 31), f(offset_lo, 30, 29), f(0b10000, 28, 24), sf(offset, 23, 5);136rf(Rd, 0);137}138139#undef starti140141Address::Address(address target, relocInfo::relocType rtype) : _mode(literal){142_is_lval = false;143_target = target;144switch (rtype) {145case relocInfo::oop_type:146case relocInfo::metadata_type:147// Oops are a special case. Normally they would be their own section148// but in cases like icBuffer they are literals in the code stream that149// we don't have a section for. We use none so that we get a literal address150// which is always patchable.151break;152case relocInfo::external_word_type:153_rspec = external_word_Relocation::spec(target);154break;155case relocInfo::internal_word_type:156_rspec = internal_word_Relocation::spec(target);157break;158case relocInfo::opt_virtual_call_type:159_rspec = opt_virtual_call_Relocation::spec();160break;161case relocInfo::static_call_type:162_rspec = static_call_Relocation::spec();163break;164case relocInfo::runtime_call_type:165_rspec = runtime_call_Relocation::spec();166break;167case relocInfo::poll_type:168case relocInfo::poll_return_type:169_rspec = Relocation::spec_simple(rtype);170break;171case relocInfo::none:172_rspec = RelocationHolder::none;173break;174default:175ShouldNotReachHere();176break;177}178}179180void Assembler::b(const Address &dest) {181code_section()->relocate(pc(), dest.rspec());182b(dest.target());183}184185void Assembler::bl(const Address &dest) {186code_section()->relocate(pc(), dest.rspec());187bl(dest.target());188}189190void Assembler::adr(Register r, const Address &dest) {191code_section()->relocate(pc(), dest.rspec());192adr(r, dest.target());193}194195void Assembler::br(Condition cc, Label &L) {196if (L.is_bound()) {197br(cc, target(L));198} else {199L.add_patch_at(code(), locator());200br(cc, pc());201}202}203204void Assembler::wrap_label(Label &L,205Assembler::uncond_branch_insn insn) {206if (L.is_bound()) {207(this->*insn)(target(L));208} else {209L.add_patch_at(code(), locator());210(this->*insn)(pc());211}212}213214void Assembler::wrap_label(Register r, Label &L,215compare_and_branch_insn insn) {216if (L.is_bound()) {217(this->*insn)(r, target(L));218} else {219L.add_patch_at(code(), locator());220(this->*insn)(r, pc());221}222}223224void Assembler::wrap_label(Register r, int bitpos, Label &L,225test_and_branch_insn insn) {226if (L.is_bound()) {227(this->*insn)(r, bitpos, target(L));228} else {229L.add_patch_at(code(), locator());230(this->*insn)(r, bitpos, pc());231}232}233234void Assembler::wrap_label(Label &L, prfop op, prefetch_insn insn) {235if (L.is_bound()) {236(this->*insn)(target(L), op);237} else {238L.add_patch_at(code(), locator());239(this->*insn)(pc(), op);240}241}242243// An "all-purpose" add/subtract immediate, per ARM documentation:244// A "programmer-friendly" assembler may accept a negative immediate245// between -(2^24 -1) and -1 inclusive, causing it to convert a246// requested ADD operation to a SUB, or vice versa, and then encode247// the absolute value of the immediate as for uimm24.248void Assembler::add_sub_immediate(Register Rd, Register Rn, unsigned uimm, int op,249int negated_op) {250bool sets_flags = op & 1; // this op sets flags251union {252unsigned u;253int imm;254};255u = uimm;256bool shift = false;257bool neg = imm < 0;258if (neg) {259imm = -imm;260op = negated_op;261}262assert(Rd != sp || imm % 16 == 0, "misaligned stack");263if (imm >= (1 << 11)264&& ((imm >> 12) << 12 == imm)) {265imm >>= 12;266shift = true;267}268f(op, 31, 29), f(0b10001, 28, 24), f(shift, 23, 22), f(imm, 21, 10);269270// add/subtract immediate ops with the S bit set treat r31 as zr;271// with S unset they use sp.272if (sets_flags)273zrf(Rd, 0);274else275srf(Rd, 0);276277srf(Rn, 5);278}279280bool Assembler::operand_valid_for_add_sub_immediate(int64_t imm) {281bool shift = false;282uint64_t uimm = (uint64_t)uabs((jlong)imm);283if (uimm < (1 << 12))284return true;285if (uimm < (1 << 24)286&& ((uimm >> 12) << 12 == uimm)) {287return true;288}289return false;290}291292bool Assembler::operand_valid_for_logical_immediate(bool is32, uint64_t imm) {293return encode_logical_immediate(is32, imm) != 0xffffffff;294}295296static uint64_t doubleTo64Bits(jdouble d) {297union {298jdouble double_value;299uint64_t double_bits;300};301302double_value = d;303return double_bits;304}305306bool Assembler::operand_valid_for_float_immediate(double imm) {307// If imm is all zero bits we can use ZR as the source of a308// floating-point value.309if (doubleTo64Bits(imm) == 0)310return true;311312// Otherwise try to encode imm then convert the encoded value back313// and make sure it's the exact same bit pattern.314unsigned result = encoding_for_fp_immediate(imm);315return doubleTo64Bits(imm) == fp_immediate_for_encoding(result, true);316}317318int AbstractAssembler::code_fill_byte() {319return 0;320}321322// n.b. this is implemented in subclass MacroAssembler323void Assembler::bang_stack_with_offset(int offset) { Unimplemented(); }324325326// and now the routines called by the assembler which encapsulate the327// above encode and decode functions328329uint32_t330asm_util::encode_logical_immediate(bool is32, uint64_t imm)331{332if (is32) {333/* Allow all zeros or all ones in top 32-bits, so that334constant expressions like ~1 are permitted. */335if (imm >> 32 != 0 && imm >> 32 != 0xffffffff)336return 0xffffffff;337/* Replicate the 32 lower bits to the 32 upper bits. */338imm &= 0xffffffff;339imm |= imm << 32;340}341342return encoding_for_logical_immediate(imm);343}344345unsigned Assembler::pack(double value) {346float val = (float)value;347unsigned result = encoding_for_fp_immediate(val);348guarantee(unpack(result) == value,349"Invalid floating-point immediate operand");350return result;351}352353// Packed operands for Floating-point Move (immediate)354355static float unpack(unsigned value) {356union {357unsigned ival;358float val;359};360ival = fp_immediate_for_encoding(value, 0);361return val;362}363364address Assembler::locate_next_instruction(address inst) {365return inst + Assembler::instruction_size;366}367368369