Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/cpu/aarch32/vm/assembler_aarch32.hpp
32285 views
/*1* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.3* Copyright (c) 2015, Linaro Ltd. All rights reserved.4* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.5*6* This code is free software; you can redistribute it and/or modify it7* under the terms of the GNU General Public License version 2 only, as8* published by the Free Software Foundation.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*24*/2526#ifndef CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP27#define CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP2829#include "asm/register.hpp"30#include "vm_version_aarch32.hpp"3132// Definitions of various symbolic names for machine registers3334// Here we define how many integer and double precision floating point35// registers are used for passing parameters by the C and Java calling36// conventions. Each double precision floating point register can be used37// as two single precision registers.3839class Argument VALUE_OBJ_CLASS_SPEC {40public:41enum {42n_int_register_parameters_c = 4, // c_rarg0, c_rarg1, c_rarg2, c_rarg343#ifdef HARD_FLOAT_CC44n_float_register_parameters_c = 8, // c_farg0, c_farg1, ..., c_farg745#else // HARD_FLOAT_CC46n_float_register_parameters_c = 0, // 0 registers used to pass arguments47#endif // HARD_FLOAT_CC48n_int_register_parameters_j = 4, // j_rarg0, j_rarg1, j_rarg2, j_rarg349#ifdef HARD_FLOAT_CC50n_float_register_parameters_j = 8 // j_farg0, j_farg1, ..., j_farg751#else // HARD_FLOAT_CC52n_float_register_parameters_j = 0 // 0 registers used to pass arguments53#endif // HARD_FLOAT_CC54};55};5657// Symbolic names for the register arguments used by the C calling convention58// (the calling convention for C runtime calls and calls to JNI native59// methods)6061REGISTER_DECLARATION(Register, c_rarg0, r0);62REGISTER_DECLARATION(Register, c_rarg1, r1);63REGISTER_DECLARATION(Register, c_rarg2, r2);64REGISTER_DECLARATION(Register, c_rarg3, r3);6566// Symbolic names for the register arguments used by the Java calling67// convention (the calling convention for calls to compiled Java methods)6869// We have control over the convention for Java so we can do what we please.70// What pleases us is to offset the Java calling convention so that when71// we call a suitable JNI method the arguments are lined up and we don't72// have to do much shuffling. A suitable JNI method is non-static and with73// a small number of arguments.74//75// |-----------------------------------|76// | c_rarg0 c_rarg1 c_rarg2 c_rarg3 |77// |-----------------------------------|78// | r0 r1 r2 r3 |79// |-----------------------------------|80// | j_rarg3 j_rarg0 j_rarg1 j_rarg2 |81// |-----------------------------------|828384REGISTER_DECLARATION(Register, j_rarg0, c_rarg1);85REGISTER_DECLARATION(Register, j_rarg1, c_rarg2);86REGISTER_DECLARATION(Register, j_rarg2, c_rarg3);87REGISTER_DECLARATION(Register, j_rarg3, c_rarg0);8889// Common register aliases used in assembler code9091// These registers are used to hold VM data either temporarily within a method92// or across method calls. According to AAPCS, r0-r3 and r12 are caller-saved,93// the rest are callee-saved.9495// These 4 aliases are used in the template interpreter only.9697REGISTER_DECLARATION(Register, rdispatch, r4); // Address of dispatch table98REGISTER_DECLARATION(Register, rbcp, r5); // Bytecode pointer99REGISTER_DECLARATION(Register, rlocals, r6); // Address of local variables section of current frame100REGISTER_DECLARATION(Register, rcpool, r7); // Address of constant pool cache101102// The following aliases are used in all VM components.103104REGISTER_DECLARATION(Register, rthread, r8); // Address of current thread105REGISTER_DECLARATION(Register, rscratch1, r9); // Scratch register106REGISTER_DECLARATION(Register, rmethod, r10); // Address of current method107REGISTER_DECLARATION(Register, rfp, r11); // Frame pointer108REGISTER_DECLARATION(Register, rscratch2, r12); // Scratch register109REGISTER_DECLARATION(Register, sp, r13); // Stack pointer110REGISTER_DECLARATION(Register, lr, r14); // Link register111REGISTER_DECLARATION(Register, r15_pc, r15); // Program counter112113114extern "C" void entry(CodeBuffer *cb);115116117#define assert_cond(ARG1) assert(ARG1, #ARG1)118119class Assembler;120121class Instruction_aarch32 {122unsigned insn;123#ifdef ASSERT124unsigned bits;125#endif126Assembler *assem;127128public:129130Instruction_aarch32(class Assembler *as) {131#ifdef ASSERT132bits = 0;133#endif134insn = 0;135assem = as;136}137138inline ~Instruction_aarch32();139140unsigned &get_insn() { return insn; }141#ifdef ASSERT142unsigned &get_bits() { return bits; }143#endif144145static inline int32_t extend(unsigned val, int hi = 31, int lo = 0) {146union {147unsigned u;148int n;149};150151u = val << (31 - hi);152n = n >> (31 - hi + lo);153return n;154}155156static inline uint32_t extract(uint32_t val, int msb, int lsb) {157int nbits = msb - lsb + 1;158assert_cond(msb >= lsb);159uint32_t mask = (1U << nbits) - 1;160uint32_t result = val >> lsb;161result &= mask;162return result;163}164165static inline int32_t sextract(uint32_t val, int msb, int lsb) {166uint32_t uval = extract(val, msb, lsb);167return extend(uval, msb - lsb);168}169170static void patch(address a, int msb, int lsb, unsigned long val) {171int nbits = msb - lsb + 1;172guarantee(val < (1U << nbits), "Field too big for insn");173assert_cond(msb >= lsb);174unsigned mask = (1U << nbits) - 1;175val <<= lsb;176mask <<= lsb;177unsigned target = *(unsigned *)a;178target &= ~mask;179target |= val;180*(unsigned *)a = target;181}182183static void spatch(address a, int msb, int lsb, long val) {184int nbits = msb - lsb + 1;185long chk = val >> (nbits - 1);186guarantee (chk == -1 || chk == 0, "Field too big for insn");187unsigned uval = val;188unsigned mask = (1U << nbits) - 1;189uval &= mask;190uval <<= lsb;191mask <<= lsb;192unsigned target = *(unsigned *)a;193target &= ~mask;194target |= uval;195*(unsigned *)a = target;196}197198/* void f(unsigned val, int msb, int lsb) {199int nbits = msb - lsb + 1;200guarantee(val < (1U << nbits), "Field too big for insn");201assert_cond(msb >= lsb);202unsigned mask = (1U << nbits) - 1;203val <<= lsb;204mask <<= lsb;205insn |= val;206assert_cond((bits & mask) == 0);207#ifdef ASSERT208bits |= mask;209#endif210}*/211212void f(unsigned val, int msb, int lsb) {213int nbits = msb - lsb + 1;214guarantee(val < (1U << nbits), "Field too big for insn");215assert_cond(msb >= lsb);216unsigned mask = (1U << nbits) - 1;217val <<= lsb;218mask <<= lsb;219insn &= ~mask;220insn |= val;221#ifdef ASSERT222bits |= mask;223#endif224}225226void f(unsigned val, int bit) {227f(val, bit, bit);228}229230void sf(long val, int msb, int lsb) {231int nbits = msb - lsb + 1;232long chk = val >> (nbits - 1);233guarantee (chk == -1 || chk == 0, "Field too big for insn");234unsigned uval = val;235unsigned mask = (1U << nbits) - 1;236uval &= mask;237f(uval, lsb + nbits - 1, lsb);238}239240void rf(Register r, int lsb) {241f(r->encoding_nocheck(), lsb + 3, lsb);242}243244void rf(FloatRegister r, int lsb) {245f(r->encoding_nocheck(), lsb + 4, lsb);246}247248unsigned get(int msb = 31, int lsb = 0) {249int nbits = msb - lsb + 1;250unsigned mask = ((1U << nbits) - 1) << lsb;251assert_cond((bits & mask) == mask);252return (insn & mask) >> lsb;253}254255void fixed(unsigned value, unsigned mask) {256assert_cond ((mask & bits) == 0);257#ifdef ASSERT258bits |= mask;259#endif260insn |= value;261}262};263264#define starti Instruction_aarch32 do_not_use(this); set_current(&do_not_use)265266static inline unsigned long uabs(long n) { return uabs((jlong)n); }267268#define S_DFLT ::lsl()269#define C_DFLT AL270271272// Shift for base reg + reg offset addressing273class shift_op {274public:275enum shift_kind { LSL, LSR, ASR, ROR };276private:277enum shift_source { imm_s, reg_s };278enum shift_source _source;279enum shift_kind _op;280int _shift;281Register _reg;282283bool check_valid() {284if(imm_s == _source) {285switch(_op) {286case LSL: return _shift >= 0 && _shift <= 31;287case ROR: return _shift >= 1 && _shift <= 32;288default: return _shift >= 1 && _shift <= 32;289}290}291return true; //Don't check register shifts292}293public:294// Default shift is lsl(0)295shift_op()296: _source(imm_s), _op(LSL), _shift(0) { }297shift_op(enum shift_kind op, int shift)298: _source(imm_s), _op(op), _shift(shift) {299if(!shift) {300// All zero shift encodings map to LSL 0301_shift = 0;302_op = LSL;303}304int pshift = _shift;305if(-1 == _shift && ROR == _op) {306// This is an RRX, make shift valid for the check307_shift = 1;308pshift = 0; //set to zero309}310assert(check_valid(), "Invalid shift quantity");311_shift = pshift; //restore shift312}313shift_op(enum shift_kind op, Register r)314: _source(reg_s), _op(op), _reg(r) {}315316shift_kind kind() const {317return _op;318}319320int shift() const {321assert(imm_s == _source, "Not an immediate shift");322return _shift % 32;323}324Register reg() const {325assert(reg_s == _source, "Not a register shift");326return _reg;327}328bool is_register() {329return reg_s == _source;330}331bool operator==(const shift_op& other) const {332if(imm_s == _source && imm_s == other._source) {333return _op == other._op && _shift == other._shift;334} else if (reg_s == _source && imm_s == _source) {335return _op == other._op && _reg == other._reg;336}337return false;338}339bool operator!=(const shift_op& other) const {340return !( *this == other);341}342};343class lsl : public shift_op {344public:345lsl(int sft = 0): shift_op(LSL, sft) { }346lsl(Register r): shift_op(LSL, r) { }347};348class lsr : public shift_op {349public:350lsr(int sft = 0): shift_op(LSR, sft) { }351lsr(Register r): shift_op(LSR, r) { }352};353class asr : public shift_op {354public:355asr(int sft = 0): shift_op(ASR, sft) { }356asr(Register r): shift_op(ASR, r) { }357};358class ror : public shift_op {359public:360ror(int sft = 0): shift_op(ROR, sft) {}361ror(Register r): shift_op(ROR, r) { }362};363class rrx : public shift_op {364public:365rrx(): shift_op(ROR, -1) {}366};367368369// Addressing modes370class Address VALUE_OBJ_CLASS_SPEC {371public:372enum access_mode { no_mode, imm, reg, lit };373//literal is class of imm? -> potentially have to split later if some instructions work374// with one but not other although can be determined from registers.375enum wb_mode { off, pre, post };376377enum reg_op { ADD, SUB };378379private:380Register _base;381Register _index;382int _offset;383enum access_mode _acc_mode;384enum wb_mode _wb_mode;385enum reg_op _as_op;386shift_op _shift;387388RelocationHolder _rspec;389390// Typically we use AddressLiterals we want to use their rval391// However in some situations we want the lval (effect address) of392// the item. We provide a special factory for making those lvals.393bool _is_lval;394395// If the target is far we'll need to load the ea of this to a396// register to reach it. Otherwise if near we can do PC-relative397// addressing.398address _target;399400public:401Address()402: _acc_mode(no_mode) { }403//immediate & literal404Address(Register r, enum wb_mode mode = off)405: _base(r), _index(noreg), _offset(0), _acc_mode(imm), _wb_mode(mode),406_shift(lsl()), _target(0) {407assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed.");408}409Address(Register r, int o, enum wb_mode mode = off)410: _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode),411_shift(lsl()), _target(0) {412assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed.");413}414Address(Register r, long o, enum wb_mode mode = off)415: _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode),416_shift(lsl()), _target(0) {417assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed.");418}419Address(Register r, unsigned long o, enum wb_mode mode = off)420: _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode),421_shift(lsl()), _target(0) {422assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed.");423}424Address(Register r, unsigned int o, enum wb_mode mode = off)425: _base(r), _index(noreg), _offset(o), _acc_mode(imm), _wb_mode(mode),426_shift(lsl()), _target(0) {427assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed.");428}429#ifdef ASSERT430Address(Register r, ByteSize disp)431: _base(r), _index(noreg), _offset(in_bytes(disp)), _acc_mode(imm), _wb_mode(off),432_shift(lsl()), _target(0) {433assert(!(r == r15_pc && _wb_mode == pre), "The PC can't be pre-indexed.");434}435#endif436437438//Register-offset439Address(Register r, Register r1, shift_op shift = lsl(), enum reg_op op = ADD,440enum wb_mode wbm = off)441: _base(r), _index(r1), _offset(0), _acc_mode(reg), _wb_mode(wbm), _as_op(op),442_shift(shift), _target(0) {443assert(!shift.is_register(), "Can't shift a register-offset address by a register");444}445446Address(address target, RelocationHolder const& rspec)447: _acc_mode(lit),448_base(sp),449_wb_mode(off),450_rspec(rspec),451_is_lval(false),452_target(target)453{ }454Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);455456private:457//Could be either458void AddressConstruct(Register base, RegisterOrConstant index, enum reg_op op, shift_op shift,459enum wb_mode mode);460public:461462Address(Register base, RegisterOrConstant index, enum reg_op op, enum wb_mode mode) {463AddressConstruct(base, index, op, lsl(), mode);464}465Address(Register base, RegisterOrConstant index, shift_op shift = lsl(), enum reg_op op = ADD,466enum wb_mode mode = off) {467if(shift.kind() != lsl().kind()) {468assert(index.is_register(), "should be");469}470AddressConstruct(base, index, op, shift, mode);471}472473474Register base() const {475//in aarch64 this didn't apply to preindex mode -> why?476guarantee(_acc_mode == imm || _acc_mode == reg, "wrong mode");477return _base;478}479long offset() const {480return _offset;481}482Register index() const {483return _index;484}485shift_op shift() const {486return _shift;487}488reg_op op() const {489return _as_op;490}491access_mode get_mode() const {492return _acc_mode;493}494wb_mode get_wb_mode() const {495return _wb_mode;496}497bool uses(Register reg) const { return _base == reg || _index == reg; }498address target() const { return _target; }499const RelocationHolder& rspec() const { return _rspec; }500501void encode(Instruction_aarch32 *i, CodeSection *sec, address pc) const;502503void fp_encode(Instruction_aarch32 *i, CodeSection *sec, address pc) const;504505void lea(MacroAssembler *, Register) const;506507typedef enum {508IDT_BOOLEAN = T_BOOLEAN,509IDT_CHAR = T_CHAR,510IDT_FLOAT = T_FLOAT,511IDT_DOUBLE = T_DOUBLE,512IDT_BYTE = T_BYTE,513IDT_SHORT = T_SHORT,514IDT_INT = T_INT,515IDT_LONG = T_LONG,516IDT_OBJECT = T_OBJECT,517IDT_ARRAY = T_ARRAY,518IDT_ADDRESS = T_ADDRESS,519IDT_METADATA = T_METADATA,520// not really a data type, denotes the use when address value is needed521// itself, and Address instance is not used to fetch actual data from memory522IDT_LEA = 100,523// multi-word memory access insn (ldmia/stmia etc)524IDT_MULTIWORD525} InsnDataType;526527inline static InsnDataType toInsnDataType(BasicType type) {528return (InsnDataType)type;529}530531Address safe_for(InsnDataType type, MacroAssembler *, Register temp);532bool is_safe_for(InsnDataType);533534static bool offset_ok_for_immed(long offset, InsnDataType type);535static bool shift_ok_for_index(shift_op shift, InsnDataType type);536};537538// Convience classes539class RuntimeAddress: public Address {540public:541RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {}542};543544class OopAddress: public Address {545public:546OopAddress(address target) : Address(target, relocInfo::oop_type){}547};548549class ExternalAddress: public Address {550private:551static relocInfo::relocType reloc_for_target(address target) {552// Sometimes ExternalAddress is used for values which aren't553// exactly addresses, like the card table base.554// external_word_type can't be used for values in the first page555// so just skip the reloc in that case.556return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;557}558559public:560ExternalAddress(address target) : Address(target, reloc_for_target(target)) {}561};562563class InternalAddress: public Address {564public:565InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}566};567568569const int FPUStateSizeInWords = FloatRegisterImpl::number_of_registers;570571class Assembler : public AbstractAssembler {572void emit_long(jint x) {573AbstractAssembler::emit_int32(x);574}575576public:577//TODO REMOVE shift_kind from here once done578enum shift_kind { LSL, LSR, ASR, ROR };579// NOTE RRX is a special case of ROR with shift = 0#580581// Helper functions for shifts582// Here to allow compiler to find global shift_op without :: prefix as lsl is a583// standalone instruction584#define HELPER(NAME) \585shift_op NAME(int sft = 0) { return ::NAME(sft); } \586shift_op NAME(Register r) { return ::NAME(r); }587HELPER(lsl);588HELPER(lsr);589HELPER(asr);590HELPER(ror);591shift_op rrx() { return ::rrx(); }592#undef HELPER593594typedef enum {595EQ, NE, HS, CS=HS, LO, CC=LO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV596} Condition;597598enum { instruction_size = 4 };599600static const uint32_t nop_insn = 0xe1a00000;601602Address adjust(Register base, int offset, bool preIncrement) {603if (preIncrement)604return Address(base, offset, Address::pre);605else606return Address(base, offset, Address::post);607}608609Address adjust(Register base, Register index, shift_op shift,610enum Address::reg_op op, bool preIncrement) {611return Address(base, index, shift, op, preIncrement ? Address::pre : Address::post);612}613614Address pre(Register base, int offset) {615return adjust(base, offset, true);616}617618Address pre(Register base, Register index, shift_op shift, enum Address::reg_op op) {619return adjust(base, index, shift, op, true);620}621622Address post (Register base, int offset) {623return adjust(base, offset, false);624}625626Instruction_aarch32* current;627628void set_current(Instruction_aarch32* i) { current = i; }629630void f(unsigned val, int msb, int lsb) {631current->f(val, msb, lsb);632}633void f(unsigned val, int msb) {634current->f(val, msb, msb);635}636void sf(long val, int msb, int lsb) {637current->sf(val, msb, lsb);638}639void rf(Register reg, int lsb) {640current->rf(reg, lsb);641}642void rf(FloatRegister reg, int lsb) {643current->rf(reg, lsb);644}645void fixed(unsigned value, unsigned mask) {646current->fixed(value, mask);647}648649void emit() {650emit_long(current->get_insn());651assert_cond(current->get_bits() == 0xffffffff);652current = NULL;653}654655typedef void (Assembler::* uncond_branch_insn)(address dest);656typedef void (Assembler::* cond_branch_insn)(address dest, Condition cond);657typedef void (Assembler::* cond_ldst_insn)(Register Rt, address dest, Condition cond);658typedef void (Assembler::* cond_fp_ldst_insn)(FloatRegister Vd, address dest, Condition cond);659660void wrap_label(Label &L, uncond_branch_insn insn);661void wrap_label(Label &L, Condition cond, cond_branch_insn insn);662void wrap_label(Register r, Label &L, Condition cond, cond_ldst_insn insn);663void wrap_label(FloatRegister r, Label &L, Condition cond, cond_fp_ldst_insn insn);664665#undef INSN666667// AARCH32 Instructions668// Defined roughly in the order they are found in669// ARM Archicture Reference Manual, section 5670671#define ZERO_ADDR_REG r0672#define ONES_ADDR_REG r15673674// Data processing (register & register-shifted-register)675void reg_instr(int decode, shift_op shift, Condition cond, bool s) {676f(cond, 31, 28), f(0b000, 27, 25), f(decode, 24, 21), f(s, 20);677f(shift.shift(), 11, 7), f(shift.kind(), 6, 5), f(0, 4);678}679void reg_shift_reg_instr(int decode, enum shift_op::shift_kind kind,680Condition cond, bool s) {681f(cond, 31, 28), f(0b000, 27, 25), f(decode, 24, 21), f(s, 20);682f(0, 7), f(kind, 6, 5), f(1, 4);683}684685#define INSN(NAME, decode, s_flg) \686void NAME(Register Rd, Register Rn, Register Rm, shift_op shift = S_DFLT, \687Condition cond = C_DFLT) { \688starti; \689if(shift.is_register()) { \690reg_shift_reg_instr(decode, shift.kind(), cond, s_flg); \691rf(Rn, 16), rf(Rd, 12), rf(shift.reg(), 8), rf(Rm, 0); \692} else { \693reg_instr(decode, shift, cond, s_flg); \694rf(Rn, 16), rf(Rd, 12), rf(Rm, 0); \695} \696}697INSN(andr, 0b0000, 0);698INSN(eor, 0b0001, 0);699INSN(sub, 0b0010, 0);700INSN(rsb, 0b0011, 0);701INSN(add, 0b0100, 0);702INSN(adc, 0b0101, 0);703INSN(sbc, 0b0110, 0);704INSN(rsc, 0b0111, 0);705INSN(orr, 0b1100, 0);706INSN(bic, 0b1110, 0);707708INSN(ands, 0b0000, 1);709INSN(eors, 0b0001, 1);710INSN(subs, 0b0010, 1);711INSN(rsbs, 0b0011, 1);712INSN(adds, 0b0100, 1);713INSN(adcs, 0b0101, 1);714INSN(sbcs, 0b0110, 1);715INSN(rscs, 0b0111, 1);716INSN(orrs, 0b1100, 1);717INSN(bics, 0b1110, 1);718719#undef INSN720721#define INSN(NAME, decode) \722void NAME(Register Rn, Register Rm, Condition cond) { \723NAME(Rn, Rm, S_DFLT, cond); \724} \725void NAME(Register Rn, Register Rm, shift_op shift = S_DFLT, \726Condition cond = C_DFLT) { \727starti; \728if(shift.is_register()) { \729reg_shift_reg_instr(decode, shift.kind(), cond, true); \730rf(Rn, 16), f(0b0000, 15, 12), rf(shift.reg(), 8), rf(Rm, 0); \731} else { \732reg_instr(decode, shift, cond, true); \733rf(Rn, 16), f(0, 15, 12), rf(Rm, 0); \734} \735}736INSN(tst, 0b1000);737INSN(teq, 0b1001);738INSN(cmp, 0b1010);739INSN(cmn, 0b1011);740#undef INSN741742// TODO appears that if Rd = 15 and s flag set then perhaps different method743void mov_internal(int decode, Register Rd, Register Rnm, shift_op shift, bool s, Condition cond) {744starti;745if(shift.is_register()) {746reg_shift_reg_instr(decode, shift.kind(), cond, s);747f(0b0000, 19, 16), rf(Rd, 12), rf(shift.reg(), 8), rf(Rnm, 0);748} else {749reg_instr(decode, shift, cond, s);750f(0, 19, 16), rf(Rd, 12), rf(Rnm, 0);751}752}753void mov(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) {754mov_internal(0b1101, Rd, Rm, shift, false, cond);755}756void movs(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) {757mov_internal(0b1101, Rd, Rm, shift, true, cond);758}759void mov(Register Rd, Register Rm, Condition cond = C_DFLT) {760mov_internal(0b1101, Rd, Rm, S_DFLT, false, cond);761}762void movs(Register Rd, Register Rm, Condition cond = C_DFLT) {763mov_internal(0b1101, Rd, Rm, S_DFLT, true, cond);764}765766void mvn(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) {767mov_internal(0b1111, Rd, Rm, shift, false, cond);768}769void mvns(Register Rd, Register Rm, shift_op shift, Condition cond = C_DFLT) {770mov_internal(0b1111, Rd, Rm, shift, true, cond);771}772void mvn(Register Rd, Register Rm, Condition cond = C_DFLT) {773mov_internal(0b1111, Rd, Rm, S_DFLT, false, cond);774}775void mvns(Register Rd, Register Rm, Condition cond = C_DFLT) {776mov_internal(0b1111, Rd, Rm, S_DFLT, true, cond);777}778779#define INSN(NAME, type, s_flg, ASSERTION) \780void NAME(Register Rd, Register Rm, unsigned shift, Condition cond = C_DFLT) { \781assert_cond(ASSERTION); \782if(s_flg) movs(Rd, Rm, shift_op(type, shift), cond); \783else mov(Rd, Rm, shift_op(type, shift), cond); \784}785INSN(lsl, shift_op::LSL, 0, true);786INSN(lsr, shift_op::LSR, 0, true);787INSN(asr, shift_op::ASR, 0, true);788INSN(ror, shift_op::ROR, 0, shift != 0); //shift == 0 => RRX789790INSN(lsls, shift_op::LSL, 1, true);791INSN(lsrs, shift_op::LSR, 1, true);792INSN(asrs, shift_op::ASR, 1, true);793INSN(rors, shift_op::ROR, 1, shift != 0); //shift == 0 => RRX794#undef INSN795796#define INSN(NAME, type, s_flg) \797void NAME(Register Rd, Register Rm, Condition cond = C_DFLT) { \798if(s_flg) movs(Rd, Rm, shift_op(type, 0), cond); \799else mov(Rd, Rm, shift_op(type, 0), cond); \800}801INSN(rrx, shift_op::LSR, 0);802INSN(rrxs, shift_op::LSR, 1);803#undef INSN804805//Data processing (register-shifted-register)806#define INSN(NAME, type, s_flg) \807void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \808if(s_flg) movs(Rd, Rn, shift_op(type, Rm), cond); \809else mov(Rd, Rn, shift_op(type, Rm), cond); \810}811INSN(lsl, shift_op::LSL, 0);812INSN(lsr, shift_op::LSR, 0);813INSN(asr, shift_op::ASR, 0);814INSN(ror, shift_op::ROR, 0);815816INSN(lsls, shift_op::LSL, 1);817INSN(lsrs, shift_op::LSR, 1);818INSN(asrs, shift_op::ASR, 1);819INSN(rors, shift_op::ROR, 1);820#undef INSN821822bool imm_instr(int decode, Register Rd, Register Rn, int imm, Condition cond,823bool s) {824if(!is_valid_for_imm12(imm))825return false;826{827starti;828f(cond, 31, 28), f(0b001, 27, 25), f(decode, 24, 21), f(s, 20), rf(Rn, 16);829int imm12 = encode_imm12(imm);830rf(Rd, 12), f(imm12, 11, 0);831}832return true;833}834835#define INSN(NAME, decode, s_flg) \836inline void NAME(Register Rd, Register Rn, unsigned imm, Condition cond = C_DFLT) {\837bool status = imm_instr(decode, Rd, Rn, imm, cond, s_flg); \838assert(status, "invalid imm"); \839}840INSN(andr, 0b0000, 0);841INSN(eor, 0b0001, 0);842INSN(orr, 0b1100, 0);843INSN(bic, 0b1110, 0);844845INSN(ands, 0b0000, 1);846INSN(eors, 0b0001, 1);847INSN(orrs, 0b1100, 1);848INSN(bics, 0b1110, 1);849//NOTE: arithmetic immediate instructions are defined below to allow dispatch.850#undef INSN851protected:852// Mov data to destination register in the shortest number of instructions853// possible.854void mov_immediate(Register dst, uint32_t imm32, Condition cond, bool s);855// Mov data to destination register but always emit enough instructions that would856// permit any 32-bit constant to be loaded. (Allow for rewriting later).857void mov_immediate32(Register dst, uint32_t imm32, Condition cond, bool s);858859void add_sub_imm(int decode, Register Rd, Register Rn, int imm,860Condition cond, bool s);861862public:863#define INSN(NAME, decode, s_flg) \864inline void NAME(Register Rd, Register Rn, int imm, Condition cond = C_DFLT) { \865add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \866} \867inline void NAME(Register Rd, Register Rn, unsigned imm, \868Condition cond = C_DFLT) { \869add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \870} \871inline void NAME(Register Rd, Register Rn, long imm, Condition cond = C_DFLT) { \872add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \873} \874inline void NAME(Register Rd, Register Rn, unsigned long imm, \875Condition cond = C_DFLT) { \876add_sub_imm(decode, Rd, Rn, imm, cond, s_flg); \877} \878/*Addition dispatch - place in macroassembler?*/ \879void NAME(Register Rd, Register Rn, RegisterOrConstant operand, \880Condition cond = C_DFLT) { \881if(operand.is_register()) { \882NAME(Rd, Rn, (Register)operand.as_register(), lsl(), cond); \883} else { \884NAME(Rd, Rn, (unsigned)operand.as_constant(), cond); \885} \886} \887inline void NAME(Register Rd, Register Rn, unsigned imm, Register Rtmp, \888Condition cond = C_DFLT) { \889if (Assembler::operand_valid_for_add_sub_immediate(imm)) \890NAME(Rd, Rn, imm, cond); \891else { \892mov_immediate(Rtmp, imm, cond, false); \893NAME(Rd, Rn, Rtmp, cond); \894} \895} \896//Note that the RegisterOrConstant version can't take a shift even though897// one of the instructions dispatched to can898INSN(sub, 0b0010, 0);899INSN(rsb, 0b0011, 0);900INSN(add, 0b0100, 0);901INSN(adc, 0b0101, 0);902INSN(sbc, 0b0110, 0);903INSN(rsc, 0b0111, 0);904905INSN(subs, 0b0010, 1);906INSN(rsbs, 0b0011, 1);907INSN(adds, 0b0100, 1);908INSN(adcs, 0b0101, 1);909INSN(sbcs, 0b0110, 1);910INSN(rscs, 0b0111, 1);911#undef INSN912//No need to do reverse as register subtracted from immediate913914// alias for mvn915void inv(Register Rd, Register Rn, Condition cond = C_DFLT) {916mvn(Rd, Rn, cond);917}918//alias for rsb919void neg(Register Rd, Register Rn, Condition cond = C_DFLT) {920rsb(Rd, Rn, 0, cond);921}922void negs(Register Rd, Register Rn, Condition cond = C_DFLT) {923rsbs(Rd, Rn, 0, cond);924}925926// PC-rel. addressing927void adr_encode(Register Rd, int imm, Condition cond) {928if (is_valid_for_imm12(imm) || is_valid_for_imm12(-imm)) {929add_sub_imm(0b0100, Rd, r15_pc, imm, cond, false); //opcode for add930} else {931int adjust = 0;932if (VM_Version::features() & (FT_ARMV7 | FT_ARMV6T2)) {933adjust = 8; // mov_w/mov_t934} else {935adjust = 16; // mov and 3 orr936}937mov_immediate32(Rd, imm - adjust, cond, false);938add(Rd, r15_pc, Rd, cond);939}940}941942void adr(Register Rd, address dest, Condition cond = C_DFLT);943944void adr(Register Rd, const Address &dest, Condition cond = C_DFLT);945946void adr(Register Rd, Label &L, Condition cond = C_DFLT) {947wrap_label(Rd, L, cond, &Assembler::Assembler::adr);948}949950private:951friend void entry(CodeBuffer *cb);952#define INSN(NAME, decode, s_flg) \953inline void NAME(Register Rd, unsigned imm, Condition cond = C_DFLT) { \954bool status = imm_instr(decode, Rd, ZERO_ADDR_REG, imm, cond, s_flg); \955assert(status, "invalid imm"); \956} \957inline void NAME(Register Rd, int imm, Condition cond = C_DFLT) { \958bool status = imm_instr(decode, Rd, ZERO_ADDR_REG, imm, cond, s_flg); \959assert(status, "invalid imm"); \960}961INSN(mov_i, 0b1101, 0);962INSN(mvn_i, 0b1111, 0);963964INSN(movs_i, 0b1101, 1);965INSN(mvns_i, 0b1111, 1);966#undef INSN967968void movw_i(Register Rd, unsigned imm, Condition cond = C_DFLT) {969starti;970assert(imm < (1 << 16), "Immediate too big for movw");971f(cond, 31, 28), f(0b00110000, 27, 20), f(imm >> 12, 19, 16);972rf(Rd, 12), f(imm & 0xfff, 11, 0);973}974975void movt_i(Register Rd, unsigned imm, Condition cond = C_DFLT) {976starti;977assert(imm < (1 << 16), "Immediate too big for movt");978f(cond, 31, 28), f(0b00110100, 27, 20), f(imm >> 12, 19, 16);979rf(Rd, 12), f(imm & 0xfff, 11, 0);980}981public:982983#define INSN(NAME, decode) \984inline void NAME(Register Rn, int imm, Condition cond = C_DFLT) { \985bool status = imm_instr(decode, ZERO_ADDR_REG, Rn, imm, cond, true); \986assert(status, "invalid imm"); \987} \988inline void NAME(Register Rn, unsigned imm, Condition cond = C_DFLT) { \989bool status = imm_instr(decode, ZERO_ADDR_REG, Rn, imm, cond, true); \990assert(status, "invalid imm"); \991} \992inline void NAME(Register Rn, int imm, Register Rtmp, Condition cond = C_DFLT) { \993if (Assembler::operand_valid_for_add_sub_immediate(imm)) \994NAME(Rn, imm, cond); \995else { \996mov_immediate(Rtmp, imm, cond, false); \997NAME(Rn, Rtmp, cond); \998} \999} \1000inline void NAME(Register Rn, unsigned imm, Register Rtmp, Condition cond = C_DFLT) { \1001if (Assembler::operand_valid_for_add_sub_immediate(imm)) \1002NAME(Rn, imm, cond); \1003else { \1004mov_immediate(Rtmp, imm, cond, false); \1005NAME(Rn, Rtmp, cond); \1006} \1007}1008INSN(tst, 0b1000);1009INSN(teq, 0b1001);1010INSN(cmp, 0b1010);1011INSN(cmn, 0b1011);1012#undef INSN101310141015// Multiply and multiply accumulate1016void mult_instr(int decode, Register a, Register b, Register c,1017Register d, Condition cond, bool s) {1018starti;1019f(cond, 31, 28), f(0b0000, 27, 24), f(decode, 23, 21), f(s, 20);1020rf(a, 16), rf(b, 12), rf(c, 8), rf(d, 0), f(0b1001, 7, 4);1021}10221023void mul(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) {1024mult_instr(0b000, Rd, ZERO_ADDR_REG, Rm, Rn, cond, false);1025}1026void muls(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) {1027mult_instr(0b000, Rd, ZERO_ADDR_REG, Rm, Rn, cond, true);1028}10291030void mla(Register Rd, Register Rn, Register Rm, Register Ra, Condition cond = C_DFLT) {1031mult_instr(0b001, Rd, Ra, Rm, Rn, cond, false);1032}1033void mlas(Register Rd, Register Rn, Register Rm, Register Ra, Condition cond = C_DFLT) {1034mult_instr(0b001, Rd, Ra, Rm, Rn, cond, true);1035}10361037void mls(Register Rd, Register Rn, Register Rm, Register Ra, Condition cond = C_DFLT) {1038mult_instr(0b011, Rd, Ra, Rm, Rn, cond, false);1039}10401041void umaal(Register RdLo, Register RdHi, Register Rn, Register Rm, Condition cond = C_DFLT) {1042mult_instr(0b010, RdHi, RdLo, Rm, Rn, cond, false);1043}10441045#define INSN(NAME, decode, s_flg) \1046void NAME(Register RdLo, Register RdHi, Register Rn, Register Rm, \1047Condition cond = C_DFLT) { \1048mult_instr(decode, RdHi, RdLo, Rm, Rn, cond, s_flg); \1049}1050INSN(umull, 0b100, 0);1051INSN(umlal, 0b101, 0);1052INSN(smull, 0b110, 0);1053INSN(smlal, 0b111, 0);10541055INSN(umulls, 0b100, 1);1056INSN(umlals, 0b101, 1);1057INSN(smulls, 0b110, 1);1058INSN(smlals, 0b111, 1);10591060#undef INSN10611062//Saturating addition and subtraction1063#define INSN(NAME, decode) \1064void NAME(Register Rd, Register Rm, Register Rn, Condition cond = C_DFLT) { \1065starti; \1066f(cond, 31, 28), f( 0b00010, 27, 23), f(decode, 22, 21), f(0, 20); \1067rf(Rn, 16), rf(Rd, 12), f( 0b00000101, 11, 4), rf(Rm, 0); \1068}1069INSN(qadd, 0b00);1070INSN(qsub, 0b01);1071INSN(qdadd, 0b10);1072INSN(qdsub, 0b11);1073#undef INSN10741075// Halfword multiply and multiply accumulate1076void mul_instr(int decode, Register Ra, Register Rb, Register Rc, Register Rd,1077bool N, bool M, Condition cond) {1078starti;1079f(cond, 31, 28), f(0b00010, 27, 23), f(decode, 22, 21), f(0, 20);1080rf(Ra, 16), rf(Rb, 12), rf(Rc, 8), f(1, 7), f(M, 6), f(N, 5), f(0, 4);1081rf(Rd, 0);1082}10831084#define INSN(NAME, decode, N, M) \1085void NAME(Register Rd, Register Rn, Register Rm, Register Ra, \1086Condition cond = C_DFLT) { \1087mul_instr(decode, Rd, Ra, Rm, Rn, N, M, cond); \1088}1089INSN(smlabb, 0b00, 0, 0);1090INSN(smlabt, 0b00, 0, 1)1091INSN(smlatb, 0b00, 1, 0)1092INSN(smlatt, 0b00, 1, 1)10931094INSN(smlawb, 0b01, 0, 0);1095INSN(smlawt, 0b01, 0, 1);1096#undef INSN10971098#define INSN(NAME, decode, N, M) \1099void NAME(Register RdLo, Register RdHi, Register Rn, Register Rm, \1100Condition cond = C_DFLT) { \1101mul_instr(decode, RdHi, RdLo, Rm, Rn, N, M, cond); \1102}1103INSN(smlalbb, 0b10, 0, 0);1104INSN(smlalbt, 0b10, 0, 1);1105INSN(smlaltb, 0b10, 1, 0);1106INSN(smlaltt, 0b10, 1, 1);1107#undef INSN11081109#define INSN(NAME, decode, N, M) \1110void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \1111mul_instr(decode, Rd, ZERO_ADDR_REG, Rm, Rn, N, M, cond); \1112}1113INSN(smulwb, 0b01, 1, 0);1114INSN(smulwt, 0b01, 1, 1);11151116INSN(smulbb, 0b11, 0, 0);1117INSN(smulbt, 0b11, 0, 1);1118INSN(smultb, 0b11, 1, 0);1119INSN(smultt, 0b11, 1, 1);1120#undef INSN11211122// For Extra load/store instructions, see load/store section1123// For Synchronization primitives, see load/store section11241125// MSR(immediate), and hints1126#define INSN(NAME, decode) \1127void NAME(Condition cond = C_DFLT) { \1128starti; \1129f(cond, 31, 28), f(0b001100100000, 27, 16), f(0b11110000, 15, 8); \1130f(decode, 7, 0); \1131}1132INSN(nop, 0b000);1133INSN(yield, 0b001);1134INSN(wfe, 0b010);1135INSN(wfi, 0b011);1136INSN(sev, 0b100);1137void dbg(int dbg_hint, Condition cond = C_DFLT) {1138f(cond, 31, 28), f(0b001100100000, 27, 16), f(0b11110000, 15, 8);1139f(0b1111, 7, 4); f(dbg_hint, 3, 0);1140}1141#undef INSN11421143//TODO Misc instructions1144void bkpt(unsigned imm) {1145starti;1146f(AL, 31, 28), f(0b00010010, 27, 20);1147f(imm >> 4, 19, 8), f(0b0111, 7, 4), f(imm & 0xf, 3, 0);1148}1149void hlt(unsigned imm) {1150bkpt(imm);1151// FIXME This seemed like the best option!1152}11531154// Load/store register (all modes)1155void load_store_instr(Register Rt, const Address &adr, int op, int op2, int a, int b,1156Condition cond) {1157starti;1158f(cond, 31, 28), f(op, 27, 25), f(a, 22), f(b, 20);1159if(op2 >= 0)1160f(op2, 7, 4);1161//Destination1162rf(Rt, 12);1163adr.encode(current, code_section(), pc());1164}11651166bool encodeable(int decode, address dest) {1167long offset = dest - pc();1168switch(decode) {1169case 0b010:1170// LDR, LDRB, STR, STRB1171return uabs(offset) < (1 << 12);1172case 0b000:1173//LDRD, LDRH, LDRSB, LDRSH, STRH, STRD1174return uabs(offset) < (1 << 8);1175default:1176ShouldNotReachHere();1177}1178return false;1179}1180118111821183#define INSN_INT(NAME, op, op2, a, b, isload) \1184void NAME(Register Rt, address dest, Condition cond = C_DFLT) { \1185if(encodeable(op, dest)) { /* Plan A */ \1186long offset = dest - pc(); \1187NAME(Rt, Address(r15_pc, offset), cond); \1188} else if(isload){ /* Plan B */ \1189/* TODO check we don't have to relocate this*/ \1190mov_immediate(Rt, (uint32_t)dest, cond, false); \1191NAME(Rt, Address(Rt, 0), cond); \1192} else { /* There is no plan C */ \1193ShouldNotReachHere(); \1194} \1195} \1196void NAME(Register Rt, address dest, relocInfo::relocType rtype, \1197Condition cond = C_DFLT) { \1198guarantee(rtype == relocInfo::internal_word_type, \1199"only internal_word_type relocs make sense here"); \1200NAME(Rt, InternalAddress(dest), cond); \1201} \1202void NAME(Register Rt, Label &L, Condition cond = C_DFLT) { \1203wrap_label(Rt, L, cond, &Assembler::NAME); \1204}12051206#define INSN(NAME, op, op2, a, b, isload) \1207void NAME(Register Rt, const Address &adr, Condition cond = C_DFLT) { \1208load_store_instr(Rt, adr, op, op2, a, b, cond); \1209} \1210INSN_INT(NAME, op, op2, a, b, isload);1211INSN(ldr, 0b010, -1, 0, 1, 1);1212INSN(ldrb, 0b010, -1, 1, 1, 1);12131214INSN(ldrsb, 0b000, 0b1101, 0, 1, 1);1215INSN(ldrh, 0b000, 0b1011, 0, 1, 1);1216INSN(ldrsh, 0b000, 0b1111, 0, 1, 1);12171218INSN(str, 0b010, -1, 0, 0, 0);1219INSN(strb, 0b010, -1, 1, 0, 0);1220INSN(strh, 0b000, 0b1011, 0, 0, 0);1221//Note LDRD & STRD are defined with the load/store multiple instructions12221223//TODO Need to introduce ldrsb ldrsh - then check that the encoding works properly!1224#undef INSN122512261227//Synchronization primitives1228void sync_instr(int decode, Register Ra, Register Rb, Register Rc, Register Rd,1229Condition cond) {1230starti;1231f(cond, 31, 28), f(0b0001, 27, 24), f(decode, 23, 20), rf(Ra, 16), rf(Rb, 12);1232rf(Rc, 8), f(0b1001, 7, 4), rf(Rd, 0);1233}12341235#define INSN(NAME, decode) \1236void NAME(Register Rd, Register Rt, Register Rn, Condition cond = C_DFLT) { \1237assert(r15_pc != Rn, "Unpredictable"); \1238sync_instr(decode, Rn, Rd, ONES_ADDR_REG, Rt, cond); \1239}1240INSN( strex, 0b1000);1241INSN(strexd, 0b1010);1242INSN(strexb, 0b1100);1243INSN(strexh, 0b1110);1244#undef INSN12451246#define INSN(NAME, decode) \1247void NAME(Register Rt, Register Rn, Condition cond = C_DFLT) { \1248assert(r15_pc != Rn, "Unpredictable"); \1249sync_instr(decode, Rn, Rt, ONES_ADDR_REG, ONES_ADDR_REG, cond); \1250}1251INSN(ldrex, 0b1001);1252INSN(ldrexd, 0b1011);1253INSN(ldrexb, 0b1101);1254INSN(ldrexh, 0b1111);1255#undef INSN12561257// Media instructions1258void media_instr(int decode, int decode2, Condition cond) {1259f(cond, 31, 28), f(0b011, 27, 25), f(decode, 24, 20);1260f(decode2, 7, 5), f(1, 4);1261}12621263#define INSN(NAME, decode, decode2) \1264void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \1265starti; \1266media_instr(0b00000 | decode, decode2, cond); \1267rf(Rn, 16), rf(Rd, 12), f(0b1111, 11, 8), rf(Rm, 0); \1268}1269INSN(sadd16, 0b01, 0b000);1270INSN(sasx, 0b01, 0b001);1271INSN(ssax, 0b01, 0b010);1272INSN(ssub16, 0b01, 0b011);1273INSN(sadd8, 0b01, 0b100);1274INSN(ssub8, 0b01, 0b111);1275//Saturating1276INSN(qadd16, 0b10, 0b000);1277INSN(qasx, 0b10, 0b001);1278INSN(qsax, 0b10, 0b010);1279INSN(qsub16, 0b10, 0b011);1280INSN(qadd8, 0b10, 0b100);1281INSN(qsub8, 0b10, 0b111);1282//Halving1283INSN(shadd16, 0b11, 0b000);1284INSN(shasx, 0b11, 0b001);1285INSN(shsax, 0b11, 0b010);1286INSN(shsub16, 0b11, 0b011);1287INSN(shadd8, 0b11, 0b100);1288INSN(shsub8, 0b11, 0b111);12891290//Now unsigned1291INSN(uadd16, 0b101, 0b000);1292INSN(uasx, 0b101, 0b001);1293INSN(usax, 0b101, 0b010);1294INSN(usub16, 0b101, 0b011);1295INSN(uadd8, 0b101, 0b100);1296INSN(usub8, 0b101, 0b111);1297//Saturating1298INSN(uqadd16, 0b110, 0b000);1299INSN(uqasx, 0b110, 0b001);1300INSN(uqsax, 0b110, 0b010);1301INSN(uqsub16, 0b110, 0b011);1302INSN(uqadd8, 0b110, 0b100);1303INSN(uqsub8, 0b110, 0b111);1304//Halving1305INSN(uhadd16, 0b111, 0b000);1306INSN(uhasx, 0b111, 0b001);1307INSN(uhsax, 0b111, 0b010);1308INSN(uhsub16, 0b111, 0b011);1309INSN(uhadd8, 0b111, 0b100);1310INSN(uhsub8, 0b111, 0b111);1311#undef INSN13121313//Packing, unpacking, saturation and reversal1314// Note rotation can only be one of ROR #0 ROR #8 ROR #16 ROR #241315void extend_instr(int decode, int decode2, int decode3, Register Rd, Register Rn,1316Register Rm, shift_op shift, Condition cond) {1317starti;1318assert(0 == shift.shift() ||1319shift_op::ROR == shift.kind(), "Only ROR may be used for op");1320// All zero shifts are mapped to LSL #01321int shift_enc = 0;1322switch(shift.shift()) {1323case 0: break;1324case 8: shift_enc = 1; break;1325case 16: shift_enc = 2; break;1326case 24: shift_enc = 3; break;1327default: assert(false, "Invalid shift quantity");1328}1329media_instr(0b01000 | decode, decode2, cond);1330rf(Rn, 16), rf(Rd, 12), f(shift_enc, 11, 10), f(decode3, 9, 8), rf(Rm, 0);1331}13321333#define INSN(NAME, decode, decode2) \1334void NAME(Register Rd, Register Rn, Register Rm, shift_op shift = ::ror(), \1335Condition cond = C_DFLT) { \1336assert(0xf != Rn->encoding_nocheck(), "Rn = pc makes different instruction"); \1337extend_instr(decode, decode2, 0b00, Rd, Rn, Rm, shift, cond); \1338}1339INSN(sxtab16, 0b000, 0b011);1340INSN(sxtab, 0b010, 0b011);1341INSN(sxtah, 0b011, 0b011);1342INSN(uxtab16, 0b100, 0b011);1343INSN(uxtab, 0b110, 0b011);1344INSN(uxtah, 0b111, 0b011);1345#undef INSN13461347#define INSN(NAME, decode, decode2) \1348void NAME(Register Rd, Register Rm, shift_op shift = ::ror(), \1349Condition cond = C_DFLT) { \1350extend_instr(decode, decode2, 0b00, Rd, ONES_ADDR_REG, Rm, shift, cond); \1351}1352INSN(sxtb16, 0b000, 0b011);1353INSN(sxtb, 0b010, 0b011);1354INSN(sxth, 0b011, 0b011);1355INSN(uxtb16, 0b100, 0b011);1356INSN(uxtb, 0b110, 0b011);1357INSN(uxth, 0b111, 0b011);1358#undef INSN13591360//Reverse instructions1361#define INSN(NAME, decode, decode2) \1362void NAME(Register Rd, Register Rm, Condition cond = C_DFLT) { \1363extend_instr(decode, decode2, 0b11, Rd, ONES_ADDR_REG, Rm, ::ror(24), cond); \1364}1365INSN(rev, 0b011, 0b001);1366INSN(rev16, 0b011, 0b101);1367INSN(rbit, 0b111, 0b001);1368INSN(revsh, 0b111, 0b101);1369#undef INSN13701371// Signed multiply, signed and unsigned divide1372#define INSN(NAME, decode, decode2) \1373void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \1374starti; \1375media_instr(0b10000 | decode, decode2, cond); \1376rf(Rd, 16), f(0b1111, 15, 12), rf(Rm, 8), rf(Rn, 0); \1377}1378INSN(sdiv, 0b001, 0b000);1379INSN(udiv, 0b011, 0b000);1380//TODO ALL THE REST!1381#undef INSN13821383// Remainder of things1384//TODO USAD81385#define INSN(NAME, decode, decode2) \1386void NAME(Register Rd, Register Rn, int lsb, int width, \1387Condition cond = C_DFLT) { \1388starti; \1389assert(lsb >= 0 && lsb < 32, "lsb out of range"); \1390assert(width > 0 && width <= 32 - lsb, "width out of range"); \1391media_instr(decode, decode2, cond); \1392f(width - 1, 20, 16), rf(Rd, 12), f(lsb, 11, 7), rf(Rn, 0); \1393}1394INSN(sbfx, 0b11010, 0b010);1395INSN(ubfx, 0b11110, 0b010);1396#undef INSN13971398void bfi(Register Rd, Register Rn, int lsb, int width, Condition cond = C_DFLT) {1399assert(VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7), "unsupported on the cpu");1400int msb = lsb + width - 1;1401assert(lsb >= 0 && lsb < 32, "lsb out of range");1402assert(msb < 32 && msb >= lsb, "width out of range");1403starti;1404media_instr(0b11100, 0b000, cond);1405f(msb, 20, 16), rf(Rd, 12), f(lsb, 11, 7), rf(Rn, 0);1406}14071408void bfc(Register Rd, int lsb, int width, Condition cond = C_DFLT) {1409assert(VM_Version::features() & (FT_ARMV6T2 | FT_ARMV7), "unsupported on the cpu");1410int msb = lsb + width - 1;1411assert(lsb >= 0 && lsb < 32, "lsb out of range");1412assert(msb < 32 && msb >= lsb, "width out of range");1413starti;1414media_instr(0b11100, 0b000, cond);1415f(msb, 20, 16), rf(Rd, 12), f(lsb, 11, 7), f(0b1111, 3, 0);1416}14171418//Branch, branch with link, and block data transfer14191420void block_imm_instr(int decode, int w, Register Rn, unsigned regset,1421Condition cond) {1422starti;1423f(cond, 31, 28), f(0b10, 27, 26), f(decode | (w << 1), 25, 20);1424rf(Rn, 16), f(regset, 15, 0);1425}1426#define INSN(NAME, decode) \1427void NAME(Register Rn, unsigned regset, bool wb = true, Condition cond = C_DFLT) { \1428block_imm_instr(decode, wb, Rn, regset, cond); \1429}1430INSN(stmda, 0b000000);1431INSN(stmed, 0b000000);14321433INSN(ldmda, 0b000001);1434INSN(ldmfa, 0b000001);14351436//INSN(stm, 0b001000);1437INSN(stmia, 0b001000);1438INSN(stmea, 0b001000);14391440//INSN(ldm, 0b001001);1441INSN(ldmia, 0b001001);1442INSN(ldmfd, 0b001001);14431444INSN(stmdb, 0b010000);1445INSN(stmfd, 0b010000);14461447INSN(ldmdb, 0b010001);1448INSN(ldmea, 0b010001);14491450INSN(stmib, 0b011000);1451INSN(stmfa, 0b011000);14521453INSN(ldmib, 0b011001);1454INSN(ldmed, 0b011001);1455#undef INSN14561457unsigned count_bits(unsigned val);1458bool can_ldst_multiple( unsigned regset, const Address& adr);14591460//NOTE!! Have repurposed stm and ldm for auto dispatch instructions1461#define INSN(NAME, PREFIX) \1462void NAME(unsigned regset, const Address& adr, Condition cond = C_DFLT) { \1463assert(can_ldst_multiple(regset, adr), "Can't do anything with this!"); \1464int offset = adr.offset(); \1465switch(adr.get_wb_mode()) { \1466case Address::pre: \1467if(offset > 0) PREFIX##mib(adr.base(), regset, true, cond); \1468else PREFIX##mdb(adr.base(), regset, true, cond); \1469break; \1470case Address::post: \1471if(offset > 0) PREFIX##mia(adr.base(), regset, true, cond); \1472else PREFIX##mda(adr.base(), regset, offset != 0, cond); \1473break; \1474case Address::off: \1475if(offset > 0) PREFIX##mib(adr.base(), regset, false, cond); \1476else if(!offset) PREFIX##mia(adr.base(), regset, false, cond); \1477else PREFIX##mdb(adr.base(), regset, false, cond); \1478break; \1479default: \1480ShouldNotReachHere(); \1481} \1482}1483INSN(ldm, ld);1484INSN(stm, st);1485#undef INSN14861487//Made push and pop operate on full descending stacks1488#define INSN(NAME, CNAME) \1489inline void NAME(unsigned regset, Condition cond = C_DFLT) { \1490CNAME(r13, regset, true, cond); \1491}1492INSN(pop, ldmia);1493INSN(push, stmdb);1494#undef INSN14951496public:14971498#define INSN(NAME, PREFIX, op, op2, a, b, isload) \1499void NAME(Register Rt, const Address& adr, Condition cond = C_DFLT) { \1500load_store_instr(Rt, adr, op, op2, a, b, cond); \1501} \1502INSN_INT(NAME, op, op2, a, b, isload);15031504INSN(ldrd, ld, 0b000, 0b1101, 0, 0, 1);1505INSN(strd, st, 0b000, 0b1111, 0, 0, 0);1506#undef INSN1507#undef INSN_INT15081509// Branches15101511// For immediate branches:1512// The maximum range of a branch is fixed for the aarch321513// architecture. In debug mode we shrink it in order to test1514// trampolines, but not so small that branches in the interpreter1515// are out of range.1516static const unsigned long branch_range = NOT_DEBUG(32 * M) DEBUG_ONLY(2 * M);1517static bool reachable_from_branch_at(address branch, address target) {1518return uabs(target - branch) < branch_range;1519}15201521void branch_imm_instr(int decode, address dest, Condition cond) {1522starti;1523// Correct PC for as it will be when executing this instruction1524int offset = (dest - (pc() + 8)) >> 2;1525assert(reachable_from_branch_at(pc(), dest), "branch target unreachable");1526f(cond, 31, 28), f(decode, 27, 24), sf(offset, 23, 0);1527}15281529void branch_reg_instr(int decode, Register Rm, Condition cond) {1530starti;1531f(cond, 31, 28), f(0b00010010, 27, 20);1532f(0b111111111111, 19, 8), f(decode, 7, 4), rf(Rm, 0);1533}15341535#define INSN(NAME, decode_imm, decode_reg) \1536void NAME(Register Rm, Condition cond = C_DFLT) { \1537branch_reg_instr(decode_reg, Rm, cond); \1538} \1539void NAME(address dest, Condition cond = C_DFLT) { \1540branch_imm_instr(decode_imm, dest, cond); \1541} \1542void NAME(Label &L, Condition cond = C_DFLT) { \1543wrap_label(L, cond, &Assembler::NAME); \1544} \1545void NAME(const Address &dest, Condition cond = C_DFLT) { \1546code_section()->relocate(pc(), dest.rspec()); \1547NAME(dest.target(), cond); \1548}1549//TODO assert type of address1550INSN(b, 0b1010, 0b0001); // B & BX1551INSN(bl, 0b1011, 0b0011); // BL & BLX1552#undef INSN155315541555//TODO Coprocessor instructions, and Supervisor Call155615571558// Unconditional Instructions1559enum barrier {OSHST = 0b0010, OSH,1560NSHST = 0b0110, NSH,1561ISHST = 0b1010, ISH,1562ST = 0b1110, SY};15631564void sync_instr(int decode, enum barrier option) {1565starti;1566f(0b11110, 31, 27), f(0b1010111, 26, 20), f(0b111111110000, 19, 8);1567f(decode, 7, 4), f(option, 3, 0);1568}1569void clrex() {1570sync_instr(0b0001, SY);1571}1572void dsb(enum barrier option) {1573sync_instr(0b0100, option);1574}1575void dmb(enum barrier option) {1576sync_instr(0b0101, option);1577}1578void bkpt();1579void isb() {1580sync_instr(0b0110, SY);1581}15821583// And the relevant instructions for ARMv6.15841585// MCR<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}1586void mcr(int cpc_dex, int opc1, Register Rt, int cpc_reg_dex1,1587int cpc_reg_dex2, int opc2, Condition cond = C_DFLT) {1588starti;1589f(cond, 31, 28), f(0b1110, 27, 24), f(opc1, 23, 21), f(0, 20);1590f(cpc_reg_dex1, 19, 16), rf(Rt, 12), f(cpc_dex, 11, 8);1591f(opc2, 7, 5), f(1, 4), f(cpc_reg_dex2, 3, 0);1592}15931594// These instructions do not read the value of the register passed,1595// can be any. Chosen r0.1596void cp15dmb(Condition cond = C_DFLT) {1597mcr(15, 0, r0, 7, 10, 5, cond);1598}15991600void cp15dsb(Condition cond = C_DFLT) {1601mcr(15, 0, r0, 7, 10, 4, cond);1602}16031604void cp15isb(Condition cond = C_DFLT) {1605mcr(15, 0, r0, 7, 5, 4, cond);1606}16071608enum Membar_mask_bits {1609// We can use ISH for a barrier because the ARM ARM says "This1610// architecture assumes that all Processing Elements that use the1611// same operating system or hypervisor are in the same Inner1612// Shareable shareability domain."1613StoreStore = ISHST,1614LoadStore = ISH, //ISHLD, Changed to1615LoadLoad = ISH, //ISHLD,1616StoreLoad = ISH,1617AnyAny = ISH1618};16191620void mrs(Register Rd, Condition cond = C_DFLT) {1621starti;1622f(cond, 31, 28), f(0b00010, 27, 23), f(0, 22), f(0b00, 21, 20), f(0b1111, 19, 16);1623rf(Rd, 12), f(0b000000000000, 11, 0);1624}16251626void msr(Register Rn, bool nzcvq = true, bool g = true, Condition cond = C_DFLT) {1627starti;1628f(cond, 31, 28), f(0b00010, 27, 23), f(0, 22), f(0b10, 21, 20);1629f(nzcvq ? 1 : 0, 19), f(g ? 1 : 0, 18), f(0b00, 17, 16);1630f(0b111100000000, 15, 4), rf(Rn, 0);1631}16321633// Floating point operations16341635enum fpscr_cond { FP_EQ = 0b0110 << 28,1636FP_LT = 0b1000 << 28,1637FP_GT = 0b0010 << 28,1638FP_UN = 0b0011 << 28,1639FP_MASK = 0b1111 << 28 };16401641void fp_instr_base(bool is64bit, Condition cond) {1642f(cond, 31, 28), f(0b1110, 27, 24), f(0b101, 11, 9), f(is64bit, 8), f(0, 4);1643}16441645void fp_rencode(FloatRegister reg, bool is64bit, int base, int bit) {1646int reg_val = reg->encoding_nocheck();1647if(!is64bit) {1648f( reg_val >> 1, base + 3, base);1649f( reg_val & 1, bit);1650} else {1651f( reg_val & 0xf, base + 3, base);1652f( reg_val >> 4, bit);1653}1654}16551656void fp_instr(int decode, int op, bool is64bit, FloatRegister Rd, FloatRegister Rn,1657FloatRegister Rm, Condition cond) {1658fp_instr_base(is64bit, cond);1659f(decode, 23, 20), f(op, 6);1660// Register encoding is a bit involved1661// double register passed (see 'd0'-'dN' encoding), not reencode it's number1662fp_rencode(Rn, false, 16, 7);1663fp_rencode(Rd, false, 12, 22);1664fp_rencode(Rm, false, 0, 5);1665}16661667#define INSN(NAME, decode, op, is64bit) \1668void NAME(FloatRegister Rd, FloatRegister Rn, FloatRegister Rm, \1669Condition cond = C_DFLT) { \1670starti; \1671fp_instr(decode, op, is64bit, Rd, Rn, Rm, cond); \1672}1673INSN(vmla_f32, 0b0000, 0, 0);1674INSN(vmla_f64, 0b0000, 0, 1);1675INSN(vmls_f32, 0b0000, 1, 0);1676INSN(vmls_f64, 0b0000, 1, 1);16771678INSN(vnmla_f32, 0b0001, 1, 0);1679INSN(vnmla_f64, 0b0001, 1, 1);1680INSN(vnmls_f32, 0b0001, 0, 0);1681INSN(vnmls_f64, 0b0001, 0, 1);1682INSN(vnmul_f32, 0b0010, 1, 0);1683INSN(vnmul_f64, 0b0010, 1, 1);1684INSN(vmul_f32, 0b0010, 0, 0);1685INSN(vmul_f64, 0b0010, 0, 1);16861687INSN(vadd_f32, 0b0011, 0, 0);1688INSN(vadd_f64, 0b0011, 0, 1);1689INSN(vsub_f32, 0b0011, 1, 0);1690INSN(vsub_f64, 0b0011, 1, 1);16911692INSN(vdiv_f32, 0b1000, 0, 0);1693INSN(vdiv_f64, 0b1000, 0, 1);16941695INSN(vfnma_f32, 0b1001, 1, 0);1696INSN(vfnma_f64, 0b1001, 1, 1);1697INSN(vfnms_f32, 0b1001, 0, 0);1698INSN(vfnms_f64, 0b1001, 0, 1);16991700INSN(vfma_f32, 0b1010, 0, 0);1701INSN(vfma_f64, 0b1010, 0, 1);1702INSN(vfms_f32, 0b1010, 1, 0);1703INSN(vfms_f64, 0b1010, 1, 1);1704#undef INSN170517061707void vmov_imm(FloatRegister Rd, unsigned imm, bool is64bit, Condition cond);1708void vmov_imm_zero(FloatRegister Rd, bool is64bit, Condition cond);17091710unsigned encode_float_fp_imm(float imm_f);17111712void vmov_f32(FloatRegister Rd, float imm, Condition cond = C_DFLT) {1713vmov_imm(Rd, encode_float_fp_imm(imm), false, cond);1714}17151716unsigned encode_double_fp_imm(double imm_f);17171718void vmov_f64(FloatRegister Rd, double imm, Condition cond = C_DFLT) {1719bool positive_zero = (imm == 0.0) && !signbit(imm);1720if(positive_zero) vmov_imm_zero(Rd, true, cond);1721else vmov_imm(Rd, encode_double_fp_imm(imm), true, cond);1722}172317241725#define INSN(NAME, decode, op, is64bit) \1726void NAME(FloatRegister Rd, FloatRegister Rm, Condition cond = C_DFLT) { \1727starti; \1728fp_instr_base(is64bit, cond); \1729f(0b1011, 23, 20), f(decode, 19, 16), f(op, 7, 6), f(0b00, 5, 4); \1730/* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \1731fp_rencode(Rd, false, 12, 22); \1732fp_rencode(Rm, false, 0, 5); \1733}1734INSN(vmov_f32, 0b0000, 0b01, 0);1735INSN(vmov_f64, 0b0000, 0b01, 1);1736INSN(vabs_f32, 0b0000, 0b11, 0);1737INSN(vabs_f64, 0b0000, 0b11, 1);1738INSN(vneg_f32, 0b0001, 0b01, 0);1739INSN(vneg_f64, 0b0001, 0b01, 1);1740INSN(vsqrt_f32, 0b0001, 0b11, 0);1741INSN(vsqrt_f64, 0b0001, 0b11, 1);1742#undef INSN17431744//ARM -> FP, FP -> ARM1745// NOTE - Have only implemented the double precision variant as only operating on1746// double registers - can still be used to copy single precision1747void vmov64_instr_base(FloatRegister Rm, Register Rt, Register Rt2, int op,1748Condition cond) {1749starti;1750f(cond, 31, 28), f(0b1100010, 27, 21), f(op, 20);1751rf(Rt2, 16), rf(Rt, 12), f(0b101100, 11, 6), f(1, 4);1752// double register passed (see 'd0'-'dN' encoding), not reencode it's number1753fp_rencode(Rm, false, 0, 5);1754}17551756void vmov_f64(FloatRegister Rm, Register Rt, Register Rt2, Condition cond = C_DFLT) {1757vmov64_instr_base(Rm, Rt, Rt2, 0, cond);1758}1759void vmov_f64(Register Rt, Register Rt2, FloatRegister Rm, Condition cond = C_DFLT) {1760vmov64_instr_base(Rm, Rt, Rt2, 1, cond);1761}17621763void vmov_f32(FloatRegister Rn, Register Rt, Condition cond = C_DFLT) {1764starti;1765fp_instr_base(false, cond);1766f(0b000, 23, 21), f(0, 20);1767rf(Rt, 12), f(0b101000010000, 11, 0);1768// double register passed (see 'd0'-'dN' encoding), not reencode it's number1769fp_rencode(Rn, false, 16, 7);1770}1771void vmov_f32(Register Rt, FloatRegister Rn, Condition cond = C_DFLT) {1772starti;1773fp_instr_base(false, cond);1774f(0b000, 23, 21), f(1, 20);1775rf(Rt, 12), f(0b101000010000, 11, 0);1776// double register passed (see 'd0'-'dN' encoding), not reencode it's number1777fp_rencode(Rn, false, 16, 7);1778}17791780// Floating-point comparison1781#define INSN(NAME, E, is64bit) \1782void NAME(FloatRegister Rd, int imm, Condition cond = C_DFLT) { \1783assert(0 == imm, "vector compare can only be with another vector or zero"); \1784starti; \1785fp_instr_base(is64bit, cond); \1786f(0b10110101, 23, 16), f(E, 7), f(0b1000000, 6, 0); \1787/* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \1788fp_rencode(Rd, false, 12, 22); \1789} \1790void NAME(FloatRegister Vd, FloatRegister Vm, Condition cond = C_DFLT) { \1791starti; \1792fp_instr_base(is64bit, cond); \1793f(0b10110100, 23, 16), f(E, 7), f(1, 6), f(0, 4); \1794/* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \1795fp_rencode(Vd, false, 12, 22), fp_rencode(Vm, false, 0, 5); \1796}1797INSN(vcmpe_f64, 1, 1);1798INSN(vcmpe_f32, 1, 0);1799INSN( vcmp_f64, 0, 1);1800INSN( vcmp_f32, 0, 0);1801#undef INSN18021803//Move FPSCR to ARM register1804void vmrs(Register Rt, Condition cond = C_DFLT) {1805starti;1806f(cond, 31, 28), f(0b111011110001, 27, 16), rf(Rt, 12), f(0b101000010000, 11, 0);1807}18081809//Move ARM register to FPSCR1810void vmsr(Register Rt, Condition cond = C_DFLT) {1811starti;1812f(cond, 31, 28), f(0b111011100001, 27, 16), rf(Rt, 12), f(0b101000010000, 11, 0);1813}18141815// TODO These instructions use round towards zero mode. It is possible1816// for the mode to be taken from the FPSCR however it doesn't do it currently1817#define INSN(NAME, decode2, b19, op, is64bitRd, is64bitRm, sz) \1818void NAME(FloatRegister Rd, FloatRegister Rm, Condition cond = C_DFLT) { \1819starti; \1820fp_instr_base(sz, cond); \1821f(0b1011, 23, 20), f(b19, 19), f(decode2, 18, 16), f(op, 7), f(0b100, 6, 4); \1822/* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \1823fp_rencode(Rd, false, 12, 22); \1824fp_rencode(Rm, false, 0, 5); \1825}1826INSN(vcvt_s32_f32, 0b101, 1, 1, 0, 0, 0);1827INSN(vcvt_s32_f64, 0b101, 1, 1, 0, 1, 1);1828INSN(vcvt_u32_f32, 0b100, 1, 1, 0, 0, 0);1829INSN(vcvt_u32_f64, 0b100, 1, 1, 0, 1, 1);18301831INSN(vcvt_f64_s32, 0b000, 1, 1, 1, 0, 1);1832INSN(vcvt_f64_u32, 0b000, 1, 0, 1, 0, 1);1833INSN(vcvt_f32_s32, 0b000, 1, 1, 0, 0, 0);1834INSN(vcvt_f32_u32, 0b000, 1, 0, 0, 0, 0);18351836INSN(vcvt_f32_f64, 0b111, 0, 1, 0, 1, 1);1837INSN(vcvt_f64_f32, 0b111, 0, 1, 1, 0, 0);1838#undef INSN18391840//Vector load/store1841private:1842void fp_ldst_instr(int decode, bool is64bit, const Address& adr, Condition cond);1843public:18441845#define INSN(NAME, decode, is64bit) \1846void NAME(FloatRegister Vd, const Address &adr, Condition cond = C_DFLT) { \1847starti; \1848fp_ldst_instr(decode, is64bit, adr, cond); \1849/* double register passed (see 'd0'-'dN' encoding), not reencode it's number */ \1850fp_rencode(Vd, false, 12, 22); \1851} \1852void NAME(FloatRegister Vd, address dest, Condition cond = C_DFLT) { \1853long offset = dest - pc(); \1854NAME(Vd, Address(r15_pc, offset), cond); \1855} \1856void NAME(FloatRegister Vd, address dest, relocInfo::relocType rtype, \1857Condition cond = C_DFLT) { \1858guarantee(rtype == relocInfo::internal_word_type, \1859"only internal_word_type relocs make sense here"); \1860NAME(Vd, InternalAddress(dest), cond); \1861} \1862void NAME(FloatRegister Vd, Label &L, Condition cond = C_DFLT) { \1863wrap_label(Vd, L, cond, &Assembler::NAME); \1864}1865INSN(vstr_f64, 0b10000, 1);1866INSN(vstr_f32, 0b10000, 0);1867INSN(vldr_f64, 0b10001, 1);1868INSN(vldr_f32, 0b10001, 0);1869#undef INSN18701871private:1872enum fp_mode { ia_wb, ia, db_wb };1873void fp_ldst_mul(Register Rn, int regset, bool load, bool is64bit, enum fp_mode mode, Condition cond);1874public:1875#define INSN(NAME, EXT, is64bit, load) \1876inline void NAME##ia##EXT(Register Rn, unsigned regset, bool wb = true, \1877Condition cond = C_DFLT) { \1878fp_ldst_mul(Rn, regset, load, is64bit, \1879(enum fp_mode)( ia_wb + ( wb?0:1 )), cond); \1880} \1881inline void NAME##db##EXT(Register Rn, unsigned regset, Condition cond = C_DFLT) { \1882fp_ldst_mul(Rn, regset, load, is64bit, db_wb, cond); \1883}1884INSN(vldm, _f32, 0, 1);1885INSN(vldm, _f64, 1, 1);1886INSN(vstm, _f32, 0, 0);1887INSN(vstm, _f64, 1, 0);1888#undef INSN18891890public:1891#define INSN(NAME, r) \1892inline void NAME(Register Rb, int imm) { \1893starti; \1894f(0b1111, 31, 28); \1895f(0b0101, 27, 24), f(0b01, 21, 20); \1896f(0b1111, 15, 12); \1897f(imm >= 0 ? 1 : 0, 23); \1898f(r, 22); \1899rf(Rb, 16); \1900f(imm >= 0 ? imm : -imm, 11, 0); \1901}1902INSN(pld, 1);1903INSN(pldw, 0);1904#undef INSN19051906#undef ZERO_ADDR_REG1907#undef ONES_ADDR_REG19081909/* SIMD extensions1910*1911* We just use FloatRegister in the following. They are exactly the same1912* as SIMD registers.1913*/1914public:1915enum SIMD_Align {1916ALIGN_STD = 0b00, ALIGN_64 = 0b01, ALIGN_128 = 0b10, ALIGN_256 = 0b111917};1918private:1919void simd_ld(FloatRegister, unsigned type, unsigned size, unsigned xfer_size,1920const Address &addr, enum SIMD_Align align);1921public:1922#define INSN(NAME, size) \1923inline void NAME(FloatRegister Dd, const Address &addr, enum SIMD_Align align) { \1924simd_ld(Dd, 0b0111, size, 1, addr, align); \1925} \1926inline void NAME(FloatRegister Dd, FloatRegister Dd1, const Address &addr, \1927enum SIMD_Align align) { \1928assert(Dd->successor(FloatRegisterImpl::DOUBLE) == Dd1, "Must be consecutive"); \1929simd_ld(Dd, 0b1010, size, 2, addr, align); \1930} \1931inline void NAME(FloatRegister Dd, FloatRegister Dd1, FloatRegister Dd2, \1932const Address &addr, enum SIMD_Align align) { \1933assert(Dd->successor(FloatRegisterImpl::DOUBLE) == Dd1, "Must be consecutive"); \1934assert(Dd1->successor(FloatRegisterImpl::DOUBLE) == Dd2, "Must be consecutive"); \1935simd_ld(Dd, 0b0110, size, 3, addr, align); \1936} \1937inline void NAME(FloatRegister Dd, FloatRegister Dd1, FloatRegister Dd2, \1938FloatRegister Dd3, const Address &addr, enum SIMD_Align align) { \1939assert(Dd->successor(FloatRegisterImpl::DOUBLE) == Dd1, "Must be consecutive"); \1940assert(Dd1->successor(FloatRegisterImpl::DOUBLE) == Dd2, "Must be consecutive"); \1941assert(Dd2->successor(FloatRegisterImpl::DOUBLE) == Dd3, "Must be consecutive"); \1942simd_ld(Dd, 0b0010, size, 4, addr, align); \1943}1944INSN(vld1_8, 0b00);1945INSN(vld1_16, 0b01);1946INSN(vld1_32, 0b10);1947INSN(vld1_64, 0b11);1948#undef INSN19491950private:1951void simd_vmov(FloatRegister Dd, unsigned index, Register Rt, bool advsimd,1952unsigned index_bits, unsigned bit20, unsigned opc, Condition cond);1953public:1954#define INSN(NAME, advsimd, opc, index_bits) \1955inline void NAME(FloatRegister Rd, unsigned index, Register Rt, \1956Condition cond = Assembler::AL) { \1957simd_vmov(Rd, index, Rt, advsimd, index_bits, 0, opc, cond); \1958}1959INSN(vmov_8, true, 0b1000, 2);1960INSN(vmov_16, true, 0b0001, 1);1961INSN(vmov_32, false, 0b0000, 0);1962#undef INSN1963#define INSN(NAME, advsimd, opc, index_bits) \1964inline void NAME(Register Rt, FloatRegister Rd, unsigned index, \1965Condition cond = Assembler::AL) { \1966simd_vmov(Rd, index, Rt, advsimd, index_bits, 1, opc, cond); \1967}1968INSN(vmov_8s, true, 0b01000, 3);1969INSN(vmov_16s, true, 0b00001, 2);1970INSN(vmov_8u, true, 0b11000, 3);1971INSN(vmov_16u, true, 0b10001, 2);1972INSN(vmov_32, false, 0b00000, 1);1973#undef INSN19741975private:1976void simd_eor(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm, unsigned q);1977public:1978#define INSN(NAME, q) \1979inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm) { \1980simd_eor(Dd, Dn, Dm, q); \1981}1982INSN(veor_64, 0);1983INSN(veor_128, 1);1984#undef INSN19851986private:1987void simd_vmul(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm,1988unsigned bit24, unsigned bit9, unsigned size, unsigned mul, unsigned bit6);1989public:1990#define INSN(NAME, bit24, bit9, size, mul, bit6) \1991inline void NAME(FloatRegister Dd, FloatRegister Dn, FloatRegister Dm) { \1992simd_vmul(Dd, Dn, Dm, bit24, bit9, size, mul, bit6); \1993}1994INSN(vmul_64_8, 0, 0, 0b00, 1, 0);1995INSN(vmul_64_16, 0, 0, 0b01, 1, 0);1996INSN(vmul_64_32, 0, 0, 0b10, 1, 0);1997INSN(vmulp_64_8, 1, 0, 0b00, 1, 0);1998INSN(vmul_128_8, 0, 0, 0b00, 1, 1);1999INSN(vmul_128_16, 0, 0, 0b01, 1, 1);2000INSN(vmul_128_32, 0, 0, 0b10, 1, 1);2001INSN(vmulp_128_8, 1, 0, 0b00, 1, 1);2002INSN(vmull_8s, 0, 0, 0b00, 0, 0);2003INSN(vmull_16s, 0, 0, 0b01, 0, 0);2004INSN(vmull_32s, 0, 0, 0b10, 0, 0);2005INSN(vmull_8u, 1, 0, 0b00, 0, 0);2006INSN(vmull_16u, 1, 0, 0b01, 0, 0);2007INSN(vmull_32u, 1, 0, 0b10, 0, 0);2008INSN(vmullp_8, 0, 1, 0b00, 0, 0);2009#undef INSN20102011private:2012void simd_vuzp(FloatRegister Dd, FloatRegister Dm, unsigned size, unsigned q);2013public:2014#define INSN(NAME, size, q) \2015inline void NAME(FloatRegister Dd, FloatRegister Dm) { \2016simd_vuzp(Dd, Dm, size, q); \2017}2018INSN(vuzp_64_8, 0b00, 0);2019INSN(vuzp_64_16, 0b01, 0);2020INSN(vuzp_64_32, 0b10, 0);2021INSN(vuzp_128_8, 0b00, 1);2022INSN(vuzp_128_16, 0b01, 1);2023INSN(vuzp_128_32, 0b10, 1);2024#undef INSN20252026private:2027void simd_vshl(FloatRegister Dd, FloatRegister Dm, unsigned imm, unsigned size,2028unsigned q, unsigned bit24, unsigned encode);2029public:2030#define INSN(NAME, size, q, bit24, encode, checkDd) \2031inline void NAME(FloatRegister Dd, FloatRegister Dm, unsigned imm) { \2032assert(!checkDd || (Dd->encoding() & 2) == 0, "Odd register"); \2033simd_vshl(Dd, Dm, imm, size, q, bit24, encode); \2034}2035INSN(vshl_64_8, 3, 0, 0, 0b0101, false);2036INSN(vshl_64_16, 4, 0, 0, 0b0101, false);2037INSN(vshl_64_32, 5, 0, 0, 0b0101, false);2038INSN(vshl_64_64, 6, 0, 0, 0b0101, false);2039INSN(vshl_128_8, 3, 1, 0, 0b0101, false);2040INSN(vshl_128_16, 4, 1, 0, 0b0101, false);2041INSN(vshl_128_32, 5, 1, 0, 0b0101, false);2042INSN(vshl_128_64, 6, 1, 0, 0b0101, false);2043INSN(vshll_8s, 3, 1, 0, 0b1010, true);2044INSN(vshll_8u, 3, 0, 1, 0b1010, true);2045INSN(vshll_16s, 4, 0, 0, 0b1010, true);2046INSN(vshll_16u, 4, 0, 1, 0b1010, true);2047INSN(vshll_32s, 5, 0, 0, 0b1010, true);2048INSN(vshll_32u, 5, 0, 1, 0b1010, true);2049#undef INSN20502051private:2052void simd_rev(FloatRegister Dd, FloatRegister Dm, unsigned q, unsigned size,2053unsigned op);2054public:2055#define INSN(NAME, q, size, op) \2056inline void NAME(FloatRegister Dd, FloatRegister Dm) { \2057simd_rev(Dd, Dm, q, size, op); \2058}2059INSN(vrev16_64_8, 0, 0, 2);2060INSN(vrev16_128_8, 1, 0, 2);2061INSN(vrev32_64_8, 0, 0, 1);2062INSN(vrev32_128_8, 1, 0, 1);2063INSN(vrev32_64_16, 0, 1, 1);2064INSN(vrev32_128_16, 1, 1, 1);2065INSN(vrev64_64_8, 0, 0, 0);2066INSN(vrev64_128_8, 1, 0, 0);2067INSN(vrev64_64_16, 0, 1, 0);2068INSN(vrev64_128_16, 1, 1, 0);2069INSN(vrev64_64_32, 0, 2, 0);2070INSN(vrev64_128_32, 1, 2, 0);2071#undef INSN20722073private:2074void v8_crc32(Register Rd, Register Rn, Register Rm, unsigned size, Condition cond);2075public:2076#define INSN(NAME, size) \2077inline void NAME(Register Rd, Register Rn, Register Rm, Condition cond = C_DFLT) { \2078v8_crc32(Rd, Rn, Rm, size, cond); \2079}2080INSN(crc32b, 0);2081INSN(crc32h, 1);2082INSN(crc32w, 2);2083#undef INSN20842085Assembler(CodeBuffer* code) : AbstractAssembler(code) {}20862087virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,2088Register tmp,2089int offset) {2090ShouldNotCallThis();2091return RegisterOrConstant();2092}20932094// Stack overflow checking2095virtual void bang_stack_with_offset(int offset);20962097// Immediate values checks and transformations20982099static uint32_t encode_imm12(int imm);2100static int decode_imm12(uint32_t imm12);2101static bool is_valid_for_imm12(int imm);21022103static bool is_valid_for_offset_imm(int imm, int nbits) {2104return uabs(imm) < (1u << nbits);2105}21062107static bool operand_valid_for_logical_immediate(bool is32, uint64_t imm);2108static bool operand_valid_for_add_sub_immediate(int imm);2109static bool operand_valid_for_add_sub_immediate(unsigned imm);2110static bool operand_valid_for_add_sub_immediate(unsigned long imm);2111static bool operand_valid_for_add_sub_immediate(jlong imm);2112static bool operand_valid_for_float_immediate(float imm);2113static bool operand_valid_for_double_immediate(double imm);21142115void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0);2116void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0);21172118// useful to revert back the effect of post/pre addressing modifications2119// applied to the base register2120void compensate_addr_offset(const Address &adr, Condition cond) {2121compensate_addr_offset(adr.base(), adr.index(), adr.shift(), adr.op() == Address::ADD, cond);2122}2123void compensate_addr_offset(Register Rd, Register Roff, shift_op shift, bool isAdd, Condition cond) {2124shift_op shift_back;21252126if (shift.is_register()) {2127switch (shift.kind()) {2128case shift_op::LSL:2129case shift_op::LSR:2130shift_back = asr(shift.reg());2131break;2132case shift_op::ASR:2133shift_back = lsl(shift.reg());2134break;2135case shift_op::ROR:2136Unimplemented(); // need a temp register here2137break;2138default:2139ShouldNotReachHere();2140}2141} else {2142switch (shift.kind()) {2143case shift_op::LSL:2144case shift_op::LSR:2145shift_back = asr(shift.shift());2146break;2147case shift_op::ASR:2148shift_back = lsl(shift.shift());2149break;2150case shift_op::ROR:2151shift_back = ror(32-shift.shift());2152break;2153default:2154ShouldNotReachHere();2155}2156}2157if (isAdd)2158sub(Rd, Rd, Roff, shift_back, cond);2159else2160add(Rd, Rd, Roff, shift_back, cond);2161}2162};21632164inline Assembler::Membar_mask_bits operator|(Assembler::Membar_mask_bits a,2165Assembler::Membar_mask_bits b) {2166return Assembler::Membar_mask_bits(unsigned(a)|unsigned(b));2167}21682169Instruction_aarch32::~Instruction_aarch32() {2170assem->emit();2171}21722173#undef starti21742175// Invert a condition2176inline const Assembler::Condition operator~(const Assembler::Condition cond) {2177return Assembler::Condition(int(cond) ^ 1);2178}21792180class BiasedLockingCounters;21812182extern "C" void das(uint64_t start, int len);21832184#endif // CPU_AARCH32_VM_ASSEMBLER_AARCH32_HPP218521862187