Path: blob/master/dep/vixl/src/aarch64/macro-assembler-aarch64.cc
4261 views
// Copyright 2015, VIXL authors1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are met:5//6// * Redistributions of source code must retain the above copyright notice,7// this list of conditions and the following disclaimer.8// * Redistributions in binary form must reproduce the above copyright notice,9// this list of conditions and the following disclaimer in the documentation10// and/or other materials provided with the distribution.11// * Neither the name of ARM Limited nor the names of its contributors may be12// used to endorse or promote products derived from this software without13// specific prior written permission.14//15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE19// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR21// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER22// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,23// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE24// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2526#include "macro-assembler-aarch64.h"2728#include <cctype>2930namespace vixl {31namespace aarch64 {323334void Pool::Release() {35if (--monitor_ == 0) {36// Ensure the pool has not been blocked for too long.37VIXL_ASSERT(masm_->GetCursorOffset() < checkpoint_);38}39}404142void Pool::SetNextCheckpoint(ptrdiff_t checkpoint) {43masm_->checkpoint_ = std::min(masm_->checkpoint_, checkpoint);44checkpoint_ = checkpoint;45}464748LiteralPool::LiteralPool(MacroAssembler* masm)49: Pool(masm),50size_(0),51first_use_(-1),52recommended_checkpoint_(kNoCheckpointRequired) {}535455LiteralPool::~LiteralPool() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION {56VIXL_ASSERT(IsEmpty());57VIXL_ASSERT(!IsBlocked());58for (std::vector<RawLiteral*>::iterator it = deleted_on_destruction_.begin();59it != deleted_on_destruction_.end();60it++) {61delete *it;62}63}646566void LiteralPool::Reset() {67std::vector<RawLiteral*>::iterator it, end;68for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {69RawLiteral* literal = *it;70if (literal->deletion_policy_ == RawLiteral::kDeletedOnPlacementByPool) {71delete literal;72}73}74entries_.clear();75size_ = 0;76first_use_ = -1;77Pool::Reset();78recommended_checkpoint_ = kNoCheckpointRequired;79}808182void LiteralPool::CheckEmitFor(size_t amount, EmitOption option) {83if (IsEmpty() || IsBlocked()) return;8485ptrdiff_t distance = masm_->GetCursorOffset() + amount - first_use_;86if (distance >= kRecommendedLiteralPoolRange) {87Emit(option);88}89}909192void LiteralPool::CheckEmitForBranch(size_t range) {93if (IsEmpty() || IsBlocked()) return;94if (GetMaxSize() >= range) Emit();95}9697// We use a subclass to access the protected `ExactAssemblyScope` constructor98// giving us control over the pools. This allows us to use this scope within99// code emitting pools without creating a circular dependency.100// We keep the constructor private to restrict usage of this helper class.101class ExactAssemblyScopeWithoutPoolsCheck : public ExactAssemblyScope {102private:103ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler* masm, size_t size)104: ExactAssemblyScope(masm,105size,106ExactAssemblyScope::kExactSize,107ExactAssemblyScope::kIgnorePools) {}108109friend void LiteralPool::Emit(LiteralPool::EmitOption);110friend void VeneerPool::Emit(VeneerPool::EmitOption, size_t);111};112113114void LiteralPool::Emit(EmitOption option) {115// There is an issue if we are asked to emit a blocked or empty pool.116VIXL_ASSERT(!IsBlocked());117VIXL_ASSERT(!IsEmpty());118119size_t pool_size = GetSize();120size_t emit_size = pool_size;121if (option == kBranchRequired) emit_size += kInstructionSize;122Label end_of_pool;123124VIXL_ASSERT(emit_size % kInstructionSize == 0);125{126CodeBufferCheckScope guard(masm_,127emit_size,128CodeBufferCheckScope::kCheck,129CodeBufferCheckScope::kExactSize);130#ifdef VIXL_DEBUG131// Also explicitly disallow usage of the `MacroAssembler` here.132masm_->SetAllowMacroInstructions(false);133#endif134if (option == kBranchRequired) {135ExactAssemblyScopeWithoutPoolsCheck eas_guard(masm_, kInstructionSize);136masm_->b(&end_of_pool);137}138139{140// Marker indicating the size of the literal pool in 32-bit words.141VIXL_ASSERT((pool_size % kWRegSizeInBytes) == 0);142ExactAssemblyScopeWithoutPoolsCheck eas_guard(masm_, kInstructionSize);143masm_->ldr(xzr, static_cast<int>(pool_size / kWRegSizeInBytes));144}145146// Now populate the literal pool.147std::vector<RawLiteral*>::iterator it, end;148for (it = entries_.begin(), end = entries_.end(); it != end; ++it) {149VIXL_ASSERT((*it)->IsUsed());150masm_->place(*it);151}152153if (option == kBranchRequired) masm_->bind(&end_of_pool);154#ifdef VIXL_DEBUG155masm_->SetAllowMacroInstructions(true);156#endif157}158159Reset();160}161162163void LiteralPool::AddEntry(RawLiteral* literal) {164// A literal must be registered immediately before its first use. Here we165// cannot control that it is its first use, but we check no code has been166// emitted since its last use.167VIXL_ASSERT(masm_->GetCursorOffset() == literal->GetLastUse());168169UpdateFirstUse(masm_->GetCursorOffset());170VIXL_ASSERT(masm_->GetCursorOffset() >= first_use_);171entries_.push_back(literal);172size_ += literal->GetSize();173}174175176void LiteralPool::UpdateFirstUse(ptrdiff_t use_position) {177first_use_ = std::min(first_use_, use_position);178if (first_use_ == -1) {179first_use_ = use_position;180SetNextRecommendedCheckpoint(GetNextRecommendedCheckpoint());181SetNextCheckpoint(first_use_ + Instruction::kLoadLiteralRange);182} else {183VIXL_ASSERT(use_position > first_use_);184}185}186187188void VeneerPool::Reset() {189Pool::Reset();190unresolved_branches_.Reset();191}192193194void VeneerPool::Release() {195if (--monitor_ == 0) {196VIXL_ASSERT(IsEmpty() || masm_->GetCursorOffset() <197unresolved_branches_.GetFirstLimit());198}199}200201202void VeneerPool::RegisterUnresolvedBranch(ptrdiff_t branch_pos,203Label* label,204ImmBranchType branch_type) {205VIXL_ASSERT(!label->IsBound());206BranchInfo branch_info = BranchInfo(branch_pos, label, branch_type);207unresolved_branches_.insert(branch_info);208UpdateNextCheckPoint();209// TODO: In debug mode register the label with the assembler to make sure it210// is bound with masm Bind and not asm bind.211}212213214void VeneerPool::DeleteUnresolvedBranchInfoForLabel(Label* label) {215if (IsEmpty()) {216VIXL_ASSERT(checkpoint_ == kNoCheckpointRequired);217return;218}219220if (label->IsLinked()) {221Label::LabelLinksIterator links_it(label);222for (; !links_it.Done(); links_it.Advance()) {223ptrdiff_t link_offset = *links_it.Current();224Instruction* link = masm_->GetInstructionAt(link_offset);225226// ADR instructions are not handled.227if (BranchTypeUsesVeneers(link->GetBranchType())) {228BranchInfo branch_info(link_offset, label, link->GetBranchType());229unresolved_branches_.erase(branch_info);230}231}232}233234UpdateNextCheckPoint();235}236237238bool VeneerPool::ShouldEmitVeneer(int64_t first_unreacheable_pc,239size_t amount) {240ptrdiff_t offset =241kPoolNonVeneerCodeSize + amount + GetMaxSize() + GetOtherPoolsMaxSize();242return (masm_->GetCursorOffset() + offset) > first_unreacheable_pc;243}244245246void VeneerPool::CheckEmitFor(size_t amount, EmitOption option) {247if (IsEmpty()) return;248249VIXL_ASSERT(masm_->GetCursorOffset() + kPoolNonVeneerCodeSize <250unresolved_branches_.GetFirstLimit());251252if (IsBlocked()) return;253254if (ShouldEmitVeneers(amount)) {255Emit(option, amount);256} else {257UpdateNextCheckPoint();258}259}260261262void VeneerPool::Emit(EmitOption option, size_t amount) {263// There is an issue if we are asked to emit a blocked or empty pool.264VIXL_ASSERT(!IsBlocked());265VIXL_ASSERT(!IsEmpty());266267Label end;268if (option == kBranchRequired) {269ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);270masm_->b(&end);271}272273// We want to avoid generating veneer pools too often, so generate veneers for274// branches that don't immediately require a veneer but will soon go out of275// range.276static const size_t kVeneerEmissionMargin = 1 * KBytes;277278for (BranchInfoSetIterator it(&unresolved_branches_); !it.Done();) {279BranchInfo* branch_info = it.Current();280if (ShouldEmitVeneer(branch_info->first_unreacheable_pc_,281amount + kVeneerEmissionMargin)) {282CodeBufferCheckScope scope(masm_,283kVeneerCodeSize,284CodeBufferCheckScope::kCheck,285CodeBufferCheckScope::kExactSize);286ptrdiff_t branch_pos = branch_info->pc_offset_;287Instruction* branch = masm_->GetInstructionAt(branch_pos);288Label* label = branch_info->label_;289290// Patch the branch to point to the current position, and emit a branch291// to the label.292Instruction* veneer = masm_->GetCursorAddress<Instruction*>();293branch->SetImmPCOffsetTarget(veneer);294{295ExactAssemblyScopeWithoutPoolsCheck guard(masm_, kInstructionSize);296masm_->b(label);297}298299// Update the label. The branch patched does not point to it any longer.300label->DeleteLink(branch_pos);301302it.DeleteCurrentAndAdvance();303} else {304it.AdvanceToNextType();305}306}307308UpdateNextCheckPoint();309310masm_->bind(&end);311}312313314MacroAssembler::MacroAssembler(byte* buffer,315size_t capacity,316PositionIndependentCodeOption pic)317: Assembler(buffer, capacity, pic),318#ifdef VIXL_DEBUG319allow_macro_instructions_(true),320#endif321generate_simulator_code_(VIXL_AARCH64_GENERATE_SIMULATOR_CODE),322sp_(sp),323tmp_list_(ip0, ip1),324v_tmp_list_(d31),325p_tmp_list_(CPURegList::Empty(CPURegister::kPRegister)),326current_scratch_scope_(NULL),327literal_pool_(this),328veneer_pool_(this),329recommended_checkpoint_(Pool::kNoCheckpointRequired),330fp_nan_propagation_(NoFPMacroNaNPropagationSelected) {331checkpoint_ = GetNextCheckPoint();332}333334335MacroAssembler::~MacroAssembler() {}336337338void MacroAssembler::Reset() {339Assembler::Reset();340341VIXL_ASSERT(!literal_pool_.IsBlocked());342literal_pool_.Reset();343veneer_pool_.Reset();344345checkpoint_ = GetNextCheckPoint();346}347348349void MacroAssembler::FinalizeCode(FinalizeOption option) {350if (!literal_pool_.IsEmpty()) {351// The user may decide to emit more code after Finalize, emit a branch if352// that's the case.353literal_pool_.Emit(option == kUnreachable ? Pool::kNoBranchRequired354: Pool::kBranchRequired);355}356VIXL_ASSERT(veneer_pool_.IsEmpty());357358Assembler::FinalizeCode();359}360361362void MacroAssembler::CheckEmitFor(size_t amount) {363CheckEmitPoolsFor(amount);364VIXL_ASSERT(GetBuffer()->HasSpaceFor(amount));365}366367368void MacroAssembler::CheckEmitPoolsFor(size_t amount) {369literal_pool_.CheckEmitFor(amount);370veneer_pool_.CheckEmitFor(amount);371checkpoint_ = GetNextCheckPoint();372}373374375int MacroAssembler::MoveImmediateHelper(MacroAssembler* masm,376const Register& rd,377uint64_t imm) {378bool emit_code = (masm != NULL);379VIXL_ASSERT(IsUint32(imm) || IsInt32(imm) || rd.Is64Bits());380// The worst case for size is mov 64-bit immediate to sp:381// * up to 4 instructions to materialise the constant382// * 1 instruction to move to sp383MacroEmissionCheckScope guard(masm);384385// Immediates on Aarch64 can be produced using an initial value, and zero to386// three move keep operations.387//388// Initial values can be generated with:389// 1. 64-bit move zero (movz).390// 2. 32-bit move inverted (movn).391// 3. 64-bit move inverted.392// 4. 32-bit orr immediate.393// 5. 64-bit orr immediate.394// Move-keep may then be used to modify each of the 16-bit half words.395//396// The code below supports all five initial value generators, and397// applying move-keep operations to move-zero and move-inverted initial398// values.399400// Try to move the immediate in one instruction, and if that fails, switch to401// using multiple instructions.402if (OneInstrMoveImmediateHelper(masm, rd, imm)) {403return 1;404} else {405int instruction_count = 0;406unsigned reg_size = rd.GetSizeInBits();407408// Generic immediate case. Imm will be represented by409// [imm3, imm2, imm1, imm0], where each imm is 16 bits.410// A move-zero or move-inverted is generated for the first non-zero or411// non-0xffff immX, and a move-keep for subsequent non-zero immX.412413uint64_t ignored_halfword = 0;414bool invert_move = false;415// If the number of 0xffff halfwords is greater than the number of 0x0000416// halfwords, it's more efficient to use move-inverted.417if (CountClearHalfWords(~imm, reg_size) >418CountClearHalfWords(imm, reg_size)) {419ignored_halfword = 0xffff;420invert_move = true;421}422423// Mov instructions can't move values into the stack pointer, so set up a424// temporary register, if needed.425UseScratchRegisterScope temps;426Register temp;427if (emit_code) {428temps.Open(masm);429temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;430}431432// Iterate through the halfwords. Use movn/movz for the first non-ignored433// halfword, and movk for subsequent halfwords.434VIXL_ASSERT((reg_size % 16) == 0);435bool first_mov_done = false;436for (unsigned i = 0; i < (reg_size / 16); i++) {437uint64_t imm16 = (imm >> (16 * i)) & 0xffff;438if (imm16 != ignored_halfword) {439if (!first_mov_done) {440if (invert_move) {441if (emit_code) masm->movn(temp, ~imm16 & 0xffff, 16 * i);442instruction_count++;443} else {444if (emit_code) masm->movz(temp, imm16, 16 * i);445instruction_count++;446}447first_mov_done = true;448} else {449// Construct a wider constant.450if (emit_code) masm->movk(temp, imm16, 16 * i);451instruction_count++;452}453}454}455456VIXL_ASSERT(first_mov_done);457458// Move the temporary if the original destination register was the stack459// pointer.460if (rd.IsSP()) {461if (emit_code) masm->mov(rd, temp);462instruction_count++;463}464return instruction_count;465}466}467468469void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {470VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) &&471((bit == -1) || (type >= kBranchTypeFirstUsingBit)));472if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {473B(static_cast<Condition>(type), label);474} else {475switch (type) {476case always:477B(label);478break;479case never:480break;481case reg_zero:482Cbz(reg, label);483break;484case reg_not_zero:485Cbnz(reg, label);486break;487case reg_bit_clear:488Tbz(reg, bit, label);489break;490case reg_bit_set:491Tbnz(reg, bit, label);492break;493default:494VIXL_UNREACHABLE();495}496}497}498499500void MacroAssembler::B(Label* label) {501// We don't need to check the size of the literal pool, because the size of502// the literal pool is already bounded by the literal range, which is smaller503// than the range of this branch.504VIXL_ASSERT(Instruction::GetImmBranchForwardRange(UncondBranchType) >505Instruction::kLoadLiteralRange);506SingleEmissionCheckScope guard(this);507b(label);508}509510511void MacroAssembler::B(Label* label, Condition cond) {512// We don't need to check the size of the literal pool, because the size of513// the literal pool is already bounded by the literal range, which is smaller514// than the range of this branch.515VIXL_ASSERT(Instruction::GetImmBranchForwardRange(CondBranchType) >516Instruction::kLoadLiteralRange);517VIXL_ASSERT(allow_macro_instructions_);518VIXL_ASSERT((cond != al) && (cond != nv));519EmissionCheckScope guard(this, 2 * kInstructionSize);520521if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {522Label done;523b(&done, InvertCondition(cond));524b(label);525bind(&done);526} else {527if (!label->IsBound()) {528veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),529label,530CondBranchType);531}532b(label, cond);533}534}535536537void MacroAssembler::Cbnz(const Register& rt, Label* label) {538// We don't need to check the size of the literal pool, because the size of539// the literal pool is already bounded by the literal range, which is smaller540// than the range of this branch.541VIXL_ASSERT(Instruction::GetImmBranchForwardRange(CompareBranchType) >542Instruction::kLoadLiteralRange);543VIXL_ASSERT(allow_macro_instructions_);544VIXL_ASSERT(!rt.IsZero());545EmissionCheckScope guard(this, 2 * kInstructionSize);546547if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {548Label done;549cbz(rt, &done);550b(label);551bind(&done);552} else {553if (!label->IsBound()) {554veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),555label,556CompareBranchType);557}558cbnz(rt, label);559}560}561562563void MacroAssembler::Cbz(const Register& rt, Label* label) {564// We don't need to check the size of the literal pool, because the size of565// the literal pool is already bounded by the literal range, which is smaller566// than the range of this branch.567VIXL_ASSERT(Instruction::GetImmBranchForwardRange(CompareBranchType) >568Instruction::kLoadLiteralRange);569VIXL_ASSERT(allow_macro_instructions_);570VIXL_ASSERT(!rt.IsZero());571EmissionCheckScope guard(this, 2 * kInstructionSize);572573if (label->IsBound() && LabelIsOutOfRange(label, CondBranchType)) {574Label done;575cbnz(rt, &done);576b(label);577bind(&done);578} else {579if (!label->IsBound()) {580veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),581label,582CompareBranchType);583}584cbz(rt, label);585}586}587588589void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {590// This is to avoid a situation where emitting a veneer for a TBZ/TBNZ branch591// can become impossible because we emit the literal pool first.592literal_pool_.CheckEmitForBranch(593Instruction::GetImmBranchForwardRange(TestBranchType));594VIXL_ASSERT(allow_macro_instructions_);595VIXL_ASSERT(!rt.IsZero());596EmissionCheckScope guard(this, 2 * kInstructionSize);597598if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {599Label done;600tbz(rt, bit_pos, &done);601b(label);602bind(&done);603} else {604if (!label->IsBound()) {605veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),606label,607TestBranchType);608}609tbnz(rt, bit_pos, label);610}611}612613614void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {615// This is to avoid a situation where emitting a veneer for a TBZ/TBNZ branch616// can become impossible because we emit the literal pool first.617literal_pool_.CheckEmitForBranch(618Instruction::GetImmBranchForwardRange(TestBranchType));619VIXL_ASSERT(allow_macro_instructions_);620VIXL_ASSERT(!rt.IsZero());621EmissionCheckScope guard(this, 2 * kInstructionSize);622623if (label->IsBound() && LabelIsOutOfRange(label, TestBranchType)) {624Label done;625tbnz(rt, bit_pos, &done);626b(label);627bind(&done);628} else {629if (!label->IsBound()) {630veneer_pool_.RegisterUnresolvedBranch(GetCursorOffset(),631label,632TestBranchType);633}634tbz(rt, bit_pos, label);635}636}637638void MacroAssembler::Bind(Label* label, BranchTargetIdentifier id) {639VIXL_ASSERT(allow_macro_instructions_);640veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);641if (id == EmitBTI_none) {642bind(label);643} else {644// Emit this inside an ExactAssemblyScope to ensure there are no extra645// instructions between the bind and the target identifier instruction.646ExactAssemblyScope scope(this, kInstructionSize);647bind(label);648if (id == EmitPACIASP) {649paciasp();650} else if (id == EmitPACIBSP) {651pacibsp();652} else {653bti(id);654}655}656}657658// Bind a label to a specified offset from the start of the buffer.659void MacroAssembler::BindToOffset(Label* label, ptrdiff_t offset) {660VIXL_ASSERT(allow_macro_instructions_);661veneer_pool_.DeleteUnresolvedBranchInfoForLabel(label);662Assembler::BindToOffset(label, offset);663}664665666void MacroAssembler::And(const Register& rd,667const Register& rn,668const Operand& operand) {669VIXL_ASSERT(allow_macro_instructions_);670LogicalMacro(rd, rn, operand, AND);671}672673674void MacroAssembler::Ands(const Register& rd,675const Register& rn,676const Operand& operand) {677VIXL_ASSERT(allow_macro_instructions_);678LogicalMacro(rd, rn, operand, ANDS);679}680681682void MacroAssembler::Tst(const Register& rn, const Operand& operand) {683VIXL_ASSERT(allow_macro_instructions_);684Ands(AppropriateZeroRegFor(rn), rn, operand);685}686687688void MacroAssembler::Bic(const Register& rd,689const Register& rn,690const Operand& operand) {691VIXL_ASSERT(allow_macro_instructions_);692LogicalMacro(rd, rn, operand, BIC);693}694695696void MacroAssembler::Bics(const Register& rd,697const Register& rn,698const Operand& operand) {699VIXL_ASSERT(allow_macro_instructions_);700LogicalMacro(rd, rn, operand, BICS);701}702703704void MacroAssembler::Orr(const Register& rd,705const Register& rn,706const Operand& operand) {707VIXL_ASSERT(allow_macro_instructions_);708LogicalMacro(rd, rn, operand, ORR);709}710711712void MacroAssembler::Orn(const Register& rd,713const Register& rn,714const Operand& operand) {715VIXL_ASSERT(allow_macro_instructions_);716LogicalMacro(rd, rn, operand, ORN);717}718719720void MacroAssembler::Eor(const Register& rd,721const Register& rn,722const Operand& operand) {723VIXL_ASSERT(allow_macro_instructions_);724LogicalMacro(rd, rn, operand, EOR);725}726727728void MacroAssembler::Eon(const Register& rd,729const Register& rn,730const Operand& operand) {731VIXL_ASSERT(allow_macro_instructions_);732LogicalMacro(rd, rn, operand, EON);733}734735736void MacroAssembler::LogicalMacro(const Register& rd,737const Register& rn,738const Operand& operand,739LogicalOp op) {740// The worst case for size is logical immediate to sp:741// * up to 4 instructions to materialise the constant742// * 1 instruction to do the operation743// * 1 instruction to move to sp744MacroEmissionCheckScope guard(this);745UseScratchRegisterScope temps(this);746// Use `rd` as a temp, if we can.747temps.Include(rd);748// We read `rn` after evaluating `operand`.749temps.Exclude(rn);750// It doesn't matter if `operand` is in `temps` (e.g. because it alises `rd`)751// because we don't need it after it is evaluated.752753if (operand.IsImmediate()) {754uint64_t immediate = operand.GetImmediate();755unsigned reg_size = rd.GetSizeInBits();756757// If the operation is NOT, invert the operation and immediate.758if ((op & NOT) == NOT) {759op = static_cast<LogicalOp>(op & ~NOT);760immediate = ~immediate;761}762763// Ignore the top 32 bits of an immediate if we're moving to a W register.764if (rd.Is32Bits()) {765// Check that the top 32 bits are consistent.766VIXL_ASSERT(((immediate >> kWRegSize) == 0) ||767((immediate >> kWRegSize) == 0xffffffff));768immediate &= kWRegMask;769}770771VIXL_ASSERT(rd.Is64Bits() || IsUint32(immediate));772773// Special cases for all set or all clear immediates.774if (immediate == 0) {775switch (op) {776case AND:777Mov(rd, 0);778return;779case ORR:780VIXL_FALLTHROUGH();781case EOR:782Mov(rd, rn);783return;784case ANDS:785VIXL_FALLTHROUGH();786case BICS:787break;788default:789VIXL_UNREACHABLE();790}791} else if ((rd.Is64Bits() && (immediate == UINT64_C(0xffffffffffffffff))) ||792(rd.Is32Bits() && (immediate == UINT64_C(0x00000000ffffffff)))) {793switch (op) {794case AND:795Mov(rd, rn);796return;797case ORR:798Mov(rd, immediate);799return;800case EOR:801Mvn(rd, rn);802return;803case ANDS:804VIXL_FALLTHROUGH();805case BICS:806break;807default:808VIXL_UNREACHABLE();809}810}811812unsigned n, imm_s, imm_r;813if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {814// Immediate can be encoded in the instruction.815LogicalImmediate(rd, rn, n, imm_s, imm_r, op);816} else {817// Immediate can't be encoded: synthesize using move immediate.818Register temp = temps.AcquireSameSizeAs(rn);819VIXL_ASSERT(!temp.Aliases(rn));820821// If the left-hand input is the stack pointer, we can't pre-shift the822// immediate, as the encoding won't allow the subsequent post shift.823PreShiftImmMode mode = rn.IsSP() ? kNoShift : kAnyShift;824Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate, mode);825826if (rd.Is(sp) || rd.Is(wsp)) {827// If rd is the stack pointer we cannot use it as the destination828// register so we use the temp register as an intermediate again.829Logical(temp, rn, imm_operand, op);830Mov(rd, temp);831} else {832Logical(rd, rn, imm_operand, op);833}834}835} else if (operand.IsExtendedRegister()) {836VIXL_ASSERT(operand.GetRegister().GetSizeInBits() <= rd.GetSizeInBits());837// Add/sub extended supports shift <= 4. We want to support exactly the838// same modes here.839VIXL_ASSERT(operand.GetShiftAmount() <= 4);840VIXL_ASSERT(841operand.GetRegister().Is64Bits() ||842((operand.GetExtend() != UXTX) && (operand.GetExtend() != SXTX)));843844Register temp = temps.AcquireSameSizeAs(rn);845VIXL_ASSERT(!temp.Aliases(rn));846EmitExtendShift(temp,847operand.GetRegister(),848operand.GetExtend(),849operand.GetShiftAmount());850Logical(rd, rn, Operand(temp), op);851} else {852// The operand can be encoded in the instruction.853VIXL_ASSERT(operand.IsShiftedRegister());854Logical(rd, rn, operand, op);855}856}857858859void MacroAssembler::Mov(const Register& rd,860const Operand& operand,861DiscardMoveMode discard_mode) {862VIXL_ASSERT(allow_macro_instructions_);863// The worst case for size is mov immediate with up to 4 instructions.864MacroEmissionCheckScope guard(this);865866if (operand.IsImmediate()) {867// Call the macro assembler for generic immediates.868Mov(rd, operand.GetImmediate());869} else if (operand.IsShiftedRegister() && (operand.GetShiftAmount() != 0)) {870// Emit a shift instruction if moving a shifted register. This operation871// could also be achieved using an orr instruction (like orn used by Mvn),872// but using a shift instruction makes the disassembly clearer.873EmitShift(rd,874operand.GetRegister(),875operand.GetShift(),876operand.GetShiftAmount());877} else if (operand.IsExtendedRegister()) {878// Emit an extend instruction if moving an extended register. This handles879// extend with post-shift operations, too.880EmitExtendShift(rd,881operand.GetRegister(),882operand.GetExtend(),883operand.GetShiftAmount());884} else {885Mov(rd, operand.GetRegister(), discard_mode);886}887}888889890void MacroAssembler::Movi16bitHelper(const VRegister& vd, uint64_t imm) {891VIXL_ASSERT(IsUint16(imm));892int byte1 = (imm & 0xff);893int byte2 = ((imm >> 8) & 0xff);894if (byte1 == byte2) {895movi(vd.Is64Bits() ? vd.V8B() : vd.V16B(), byte1);896} else if (byte1 == 0) {897movi(vd, byte2, LSL, 8);898} else if (byte2 == 0) {899movi(vd, byte1);900} else if (byte1 == 0xff) {901mvni(vd, ~byte2 & 0xff, LSL, 8);902} else if (byte2 == 0xff) {903mvni(vd, ~byte1 & 0xff);904} else {905UseScratchRegisterScope temps(this);906Register temp = temps.AcquireW();907movz(temp, imm);908dup(vd, temp);909}910}911912913void MacroAssembler::Movi32bitHelper(const VRegister& vd, uint64_t imm) {914VIXL_ASSERT(IsUint32(imm));915916uint8_t bytes[sizeof(imm)];917memcpy(bytes, &imm, sizeof(imm));918919// All bytes are either 0x00 or 0xff.920{921bool all0orff = true;922for (int i = 0; i < 4; ++i) {923if ((bytes[i] != 0) && (bytes[i] != 0xff)) {924all0orff = false;925break;926}927}928929if (all0orff == true) {930movi(vd.Is64Bits() ? vd.V1D() : vd.V2D(), ((imm << 32) | imm));931return;932}933}934935// Of the 4 bytes, only one byte is non-zero.936for (int i = 0; i < 4; i++) {937if ((imm & (0xff << (i * 8))) == imm) {938movi(vd, bytes[i], LSL, i * 8);939return;940}941}942943// Of the 4 bytes, only one byte is not 0xff.944for (int i = 0; i < 4; i++) {945uint32_t mask = ~(0xff << (i * 8));946if ((imm & mask) == mask) {947mvni(vd, ~bytes[i] & 0xff, LSL, i * 8);948return;949}950}951952// Immediate is of the form 0x00MMFFFF.953if ((imm & 0xff00ffff) == 0x0000ffff) {954movi(vd, bytes[2], MSL, 16);955return;956}957958// Immediate is of the form 0x0000MMFF.959if ((imm & 0xffff00ff) == 0x000000ff) {960movi(vd, bytes[1], MSL, 8);961return;962}963964// Immediate is of the form 0xFFMM0000.965if ((imm & 0xff00ffff) == 0xff000000) {966mvni(vd, ~bytes[2] & 0xff, MSL, 16);967return;968}969// Immediate is of the form 0xFFFFMM00.970if ((imm & 0xffff00ff) == 0xffff0000) {971mvni(vd, ~bytes[1] & 0xff, MSL, 8);972return;973}974975// Top and bottom 16-bits are equal.976if (((imm >> 16) & 0xffff) == (imm & 0xffff)) {977Movi16bitHelper(vd.Is64Bits() ? vd.V4H() : vd.V8H(), imm & 0xffff);978return;979}980981// Default case.982{983UseScratchRegisterScope temps(this);984Register temp = temps.AcquireW();985Mov(temp, imm);986dup(vd, temp);987}988}989990991void MacroAssembler::Movi64bitHelper(const VRegister& vd, uint64_t imm) {992// All bytes are either 0x00 or 0xff.993{994bool all0orff = true;995for (int i = 0; i < 8; ++i) {996int byteval = (imm >> (i * 8)) & 0xff;997if (byteval != 0 && byteval != 0xff) {998all0orff = false;999break;1000}1001}1002if (all0orff == true) {1003movi(vd, imm);1004return;1005}1006}10071008// Top and bottom 32-bits are equal.1009if (((imm >> 32) & 0xffffffff) == (imm & 0xffffffff)) {1010Movi32bitHelper(vd.Is64Bits() ? vd.V2S() : vd.V4S(), imm & 0xffffffff);1011return;1012}10131014// Default case.1015{1016UseScratchRegisterScope temps(this);1017Register temp = temps.AcquireX();1018Mov(temp, imm);1019if (vd.Is1D()) {1020fmov(vd.D(), temp);1021} else {1022dup(vd.V2D(), temp);1023}1024}1025}102610271028void MacroAssembler::Movi(const VRegister& vd,1029uint64_t imm,1030Shift shift,1031int shift_amount) {1032VIXL_ASSERT(allow_macro_instructions_);1033MacroEmissionCheckScope guard(this);1034if (shift_amount != 0 || shift != LSL) {1035movi(vd, imm, shift, shift_amount);1036} else if (vd.Is8B() || vd.Is16B()) {1037// 8-bit immediate.1038VIXL_ASSERT(IsUint8(imm));1039movi(vd, imm);1040} else if (vd.Is4H() || vd.Is8H()) {1041// 16-bit immediate.1042Movi16bitHelper(vd, imm);1043} else if (vd.Is2S() || vd.Is4S()) {1044// 32-bit immediate.1045Movi32bitHelper(vd, imm);1046} else {1047// 64-bit immediate.1048Movi64bitHelper(vd, imm);1049}1050}105110521053void MacroAssembler::Movi(const VRegister& vd, uint64_t hi, uint64_t lo) {1054// TODO: Move 128-bit values in a more efficient way.1055VIXL_ASSERT(vd.Is128Bits());1056if (hi == lo) {1057Movi(vd.V2D(), lo);1058return;1059}10601061Movi(vd.V1D(), lo);10621063if (hi != 0) {1064UseScratchRegisterScope temps(this);1065// TODO: Figure out if using a temporary V register to materialise the1066// immediate is better.1067Register temp = temps.AcquireX();1068Mov(temp, hi);1069Ins(vd.V2D(), 1, temp);1070}1071}107210731074void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {1075VIXL_ASSERT(allow_macro_instructions_);1076// The worst case for size is mvn immediate with up to 4 instructions.1077MacroEmissionCheckScope guard(this);10781079if (operand.IsImmediate()) {1080// Call the macro assembler for generic immediates.1081Mvn(rd, operand.GetImmediate());1082} else if (operand.IsExtendedRegister()) {1083// Emit two instructions for the extend case. This differs from Mov, as1084// the extend and invert can't be achieved in one instruction.1085EmitExtendShift(rd,1086operand.GetRegister(),1087operand.GetExtend(),1088operand.GetShiftAmount());1089mvn(rd, rd);1090} else {1091// Otherwise, register and shifted register cases can be handled by the1092// assembler directly, using orn.1093mvn(rd, operand);1094}1095}109610971098void MacroAssembler::Mov(const Register& rd, uint64_t imm) {1099VIXL_ASSERT(allow_macro_instructions_);1100MoveImmediateHelper(this, rd, imm);1101}110211031104void MacroAssembler::Ccmp(const Register& rn,1105const Operand& operand,1106StatusFlags nzcv,1107Condition cond) {1108VIXL_ASSERT(allow_macro_instructions_);1109if (operand.IsImmediate() && (operand.GetImmediate() < 0)) {1110ConditionalCompareMacro(rn, -operand.GetImmediate(), nzcv, cond, CCMN);1111} else {1112ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);1113}1114}111511161117void MacroAssembler::Ccmn(const Register& rn,1118const Operand& operand,1119StatusFlags nzcv,1120Condition cond) {1121VIXL_ASSERT(allow_macro_instructions_);1122if (operand.IsImmediate() && (operand.GetImmediate() < 0)) {1123ConditionalCompareMacro(rn, -operand.GetImmediate(), nzcv, cond, CCMP);1124} else {1125ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);1126}1127}112811291130void MacroAssembler::ConditionalCompareMacro(const Register& rn,1131const Operand& operand,1132StatusFlags nzcv,1133Condition cond,1134ConditionalCompareOp op) {1135VIXL_ASSERT((cond != al) && (cond != nv));1136// The worst case for size is ccmp immediate:1137// * up to 4 instructions to materialise the constant1138// * 1 instruction for ccmp1139MacroEmissionCheckScope guard(this);11401141if ((operand.IsShiftedRegister() && (operand.GetShiftAmount() == 0)) ||1142(operand.IsImmediate() &&1143IsImmConditionalCompare(operand.GetImmediate()))) {1144// The immediate can be encoded in the instruction, or the operand is an1145// unshifted register: call the assembler.1146ConditionalCompare(rn, operand, nzcv, cond, op);1147} else {1148UseScratchRegisterScope temps(this);1149// The operand isn't directly supported by the instruction: perform the1150// operation on a temporary register.1151Register temp = temps.AcquireSameSizeAs(rn);1152Mov(temp, operand);1153ConditionalCompare(rn, temp, nzcv, cond, op);1154}1155}115611571158void MacroAssembler::CselHelper(MacroAssembler* masm,1159const Register& rd,1160Operand left,1161Operand right,1162Condition cond,1163bool* should_synthesise_left,1164bool* should_synthesise_right) {1165bool emit_code = (masm != NULL);11661167VIXL_ASSERT(!emit_code || masm->allow_macro_instructions_);1168VIXL_ASSERT((cond != al) && (cond != nv));1169VIXL_ASSERT(!rd.IsZero() && !rd.IsSP());1170VIXL_ASSERT(left.IsImmediate() || !left.GetRegister().IsSP());1171VIXL_ASSERT(right.IsImmediate() || !right.GetRegister().IsSP());11721173if (should_synthesise_left != NULL) *should_synthesise_left = false;1174if (should_synthesise_right != NULL) *should_synthesise_right = false;11751176// The worst case for size occurs when the inputs are two non encodable1177// constants:1178// * up to 4 instructions to materialise the left constant1179// * up to 4 instructions to materialise the right constant1180// * 1 instruction for csel1181EmissionCheckScope guard(masm, 9 * kInstructionSize);1182UseScratchRegisterScope temps;1183if (masm != NULL) {1184temps.Open(masm);1185}11861187// Try to handle cases where both inputs are immediates.1188bool left_is_immediate = left.IsImmediate() || left.IsZero();1189bool right_is_immediate = right.IsImmediate() || right.IsZero();1190if (left_is_immediate && right_is_immediate &&1191CselSubHelperTwoImmediates(masm,1192rd,1193left.GetEquivalentImmediate(),1194right.GetEquivalentImmediate(),1195cond,1196should_synthesise_left,1197should_synthesise_right)) {1198return;1199}12001201// Handle cases where one of the two inputs is -1, 0, or 1.1202bool left_is_small_immediate =1203left_is_immediate && ((-1 <= left.GetEquivalentImmediate()) &&1204(left.GetEquivalentImmediate() <= 1));1205bool right_is_small_immediate =1206right_is_immediate && ((-1 <= right.GetEquivalentImmediate()) &&1207(right.GetEquivalentImmediate() <= 1));1208if (right_is_small_immediate || left_is_small_immediate) {1209bool swapped_inputs = false;1210if (!right_is_small_immediate) {1211std::swap(left, right);1212cond = InvertCondition(cond);1213swapped_inputs = true;1214}1215CselSubHelperRightSmallImmediate(masm,1216&temps,1217rd,1218left,1219right,1220cond,1221swapped_inputs ? should_synthesise_right1222: should_synthesise_left);1223return;1224}12251226// Otherwise both inputs need to be available in registers. Synthesise them1227// if necessary and emit the `csel`.1228if (!left.IsPlainRegister()) {1229if (emit_code) {1230Register temp = temps.AcquireSameSizeAs(rd);1231masm->Mov(temp, left);1232left = temp;1233}1234if (should_synthesise_left != NULL) *should_synthesise_left = true;1235}1236if (!right.IsPlainRegister()) {1237if (emit_code) {1238Register temp = temps.AcquireSameSizeAs(rd);1239masm->Mov(temp, right);1240right = temp;1241}1242if (should_synthesise_right != NULL) *should_synthesise_right = true;1243}1244if (emit_code) {1245VIXL_ASSERT(left.IsPlainRegister() && right.IsPlainRegister());1246if (left.GetRegister().Is(right.GetRegister())) {1247masm->Mov(rd, left.GetRegister());1248} else {1249masm->csel(rd, left.GetRegister(), right.GetRegister(), cond);1250}1251}1252}125312541255bool MacroAssembler::CselSubHelperTwoImmediates(MacroAssembler* masm,1256const Register& rd,1257int64_t left,1258int64_t right,1259Condition cond,1260bool* should_synthesise_left,1261bool* should_synthesise_right) {1262bool emit_code = (masm != NULL);1263if (should_synthesise_left != NULL) *should_synthesise_left = false;1264if (should_synthesise_right != NULL) *should_synthesise_right = false;12651266if (left == right) {1267if (emit_code) masm->Mov(rd, left);1268return true;1269} else if (left == -right) {1270if (should_synthesise_right != NULL) *should_synthesise_right = true;1271if (emit_code) {1272masm->Mov(rd, right);1273masm->Cneg(rd, rd, cond);1274}1275return true;1276}12771278if (CselSubHelperTwoOrderedImmediates(masm, rd, left, right, cond)) {1279return true;1280} else {1281std::swap(left, right);1282if (CselSubHelperTwoOrderedImmediates(masm,1283rd,1284left,1285right,1286InvertCondition(cond))) {1287return true;1288}1289}12901291// TODO: Handle more situations. For example handle `csel rd, #5, #6, cond`1292// with `cinc`.1293return false;1294}129512961297bool MacroAssembler::CselSubHelperTwoOrderedImmediates(MacroAssembler* masm,1298const Register& rd,1299int64_t left,1300int64_t right,1301Condition cond) {1302bool emit_code = (masm != NULL);13031304if ((left == 1) && (right == 0)) {1305if (emit_code) masm->cset(rd, cond);1306return true;1307} else if ((left == -1) && (right == 0)) {1308if (emit_code) masm->csetm(rd, cond);1309return true;1310}1311return false;1312}131313141315void MacroAssembler::CselSubHelperRightSmallImmediate(1316MacroAssembler* masm,1317UseScratchRegisterScope* temps,1318const Register& rd,1319const Operand& left,1320const Operand& right,1321Condition cond,1322bool* should_synthesise_left) {1323bool emit_code = (masm != NULL);1324VIXL_ASSERT((right.IsImmediate() || right.IsZero()) &&1325(-1 <= right.GetEquivalentImmediate()) &&1326(right.GetEquivalentImmediate() <= 1));1327Register left_register;13281329if (left.IsPlainRegister()) {1330left_register = left.GetRegister();1331} else {1332if (emit_code) {1333left_register = temps->AcquireSameSizeAs(rd);1334masm->Mov(left_register, left);1335}1336if (should_synthesise_left != NULL) *should_synthesise_left = true;1337}1338if (emit_code) {1339int64_t imm = right.GetEquivalentImmediate();1340Register zr = AppropriateZeroRegFor(rd);1341if (imm == 0) {1342masm->csel(rd, left_register, zr, cond);1343} else if (imm == 1) {1344masm->csinc(rd, left_register, zr, cond);1345} else {1346VIXL_ASSERT(imm == -1);1347masm->csinv(rd, left_register, zr, cond);1348}1349}1350}135113521353void MacroAssembler::Add(const Register& rd,1354const Register& rn,1355const Operand& operand,1356FlagsUpdate S) {1357VIXL_ASSERT(allow_macro_instructions_);1358if (operand.IsImmediate()) {1359int64_t imm = operand.GetImmediate();1360if ((imm < 0) && (imm != std::numeric_limits<int64_t>::min()) &&1361IsImmAddSub(-imm)) {1362AddSubMacro(rd, rn, -imm, S, SUB);1363return;1364}1365}1366AddSubMacro(rd, rn, operand, S, ADD);1367}136813691370void MacroAssembler::Adds(const Register& rd,1371const Register& rn,1372const Operand& operand) {1373Add(rd, rn, operand, SetFlags);1374}13751376#define MINMAX(V) \1377V(Smax, smax, IsInt8) \1378V(Smin, smin, IsInt8) \1379V(Umax, umax, IsUint8) \1380V(Umin, umin, IsUint8)13811382#define VIXL_DEFINE_MASM_FUNC(MASM, ASM, RANGE) \1383void MacroAssembler::MASM(const Register& rd, \1384const Register& rn, \1385const Operand& op) { \1386VIXL_ASSERT(allow_macro_instructions_); \1387if (op.IsImmediate()) { \1388int64_t imm = op.GetImmediate(); \1389if (!RANGE(imm)) { \1390UseScratchRegisterScope temps(this); \1391Register temp = temps.AcquireSameSizeAs(rd); \1392Mov(temp, imm); \1393MASM(rd, rn, temp); \1394return; \1395} \1396} \1397SingleEmissionCheckScope guard(this); \1398ASM(rd, rn, op); \1399}1400MINMAX(VIXL_DEFINE_MASM_FUNC)1401#undef VIXL_DEFINE_MASM_FUNC14021403void MacroAssembler::St2g(const Register& rt, const MemOperand& addr) {1404VIXL_ASSERT(allow_macro_instructions_);1405SingleEmissionCheckScope guard(this);1406st2g(rt, addr);1407}14081409void MacroAssembler::Stg(const Register& rt, const MemOperand& addr) {1410VIXL_ASSERT(allow_macro_instructions_);1411SingleEmissionCheckScope guard(this);1412stg(rt, addr);1413}14141415void MacroAssembler::Stgp(const Register& rt1,1416const Register& rt2,1417const MemOperand& addr) {1418VIXL_ASSERT(allow_macro_instructions_);1419SingleEmissionCheckScope guard(this);1420stgp(rt1, rt2, addr);1421}14221423void MacroAssembler::Stz2g(const Register& rt, const MemOperand& addr) {1424VIXL_ASSERT(allow_macro_instructions_);1425SingleEmissionCheckScope guard(this);1426stz2g(rt, addr);1427}14281429void MacroAssembler::Stzg(const Register& rt, const MemOperand& addr) {1430VIXL_ASSERT(allow_macro_instructions_);1431SingleEmissionCheckScope guard(this);1432stzg(rt, addr);1433}14341435void MacroAssembler::Ldg(const Register& rt, const MemOperand& addr) {1436VIXL_ASSERT(allow_macro_instructions_);1437SingleEmissionCheckScope guard(this);1438ldg(rt, addr);1439}14401441void MacroAssembler::Sub(const Register& rd,1442const Register& rn,1443const Operand& operand,1444FlagsUpdate S) {1445VIXL_ASSERT(allow_macro_instructions_);1446if (operand.IsImmediate()) {1447int64_t imm = operand.GetImmediate();1448if ((imm < 0) && (imm != std::numeric_limits<int64_t>::min()) &&1449IsImmAddSub(-imm)) {1450AddSubMacro(rd, rn, -imm, S, ADD);1451return;1452}1453}1454AddSubMacro(rd, rn, operand, S, SUB);1455}145614571458void MacroAssembler::Subs(const Register& rd,1459const Register& rn,1460const Operand& operand) {1461Sub(rd, rn, operand, SetFlags);1462}146314641465void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {1466VIXL_ASSERT(allow_macro_instructions_);1467Adds(AppropriateZeroRegFor(rn), rn, operand);1468}146914701471void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {1472VIXL_ASSERT(allow_macro_instructions_);1473Subs(AppropriateZeroRegFor(rn), rn, operand);1474}147514761477void MacroAssembler::Fcmp(const VRegister& fn, double value, FPTrapFlags trap) {1478VIXL_ASSERT(allow_macro_instructions_);1479// The worst case for size is:1480// * 1 to materialise the constant, using literal pool if necessary1481// * 1 instruction for fcmp{e}1482MacroEmissionCheckScope guard(this);1483if (value != 0.0) {1484UseScratchRegisterScope temps(this);1485VRegister tmp = temps.AcquireSameSizeAs(fn);1486Fmov(tmp, value);1487FPCompareMacro(fn, tmp, trap);1488} else {1489FPCompareMacro(fn, value, trap);1490}1491}149214931494void MacroAssembler::Fcmpe(const VRegister& fn, double value) {1495Fcmp(fn, value, EnableTrap);1496}149714981499void MacroAssembler::Fmov(VRegister vd, double imm) {1500VIXL_ASSERT(allow_macro_instructions_);1501// Floating point immediates are loaded through the literal pool.1502MacroEmissionCheckScope guard(this);1503uint64_t rawbits = DoubleToRawbits(imm);15041505if (rawbits == 0) {1506fmov(vd.D(), xzr);1507return;1508}15091510if (vd.Is1H() || vd.Is4H() || vd.Is8H()) {1511Fmov(vd, Float16(imm));1512return;1513}15141515if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {1516Fmov(vd, static_cast<float>(imm));1517return;1518}15191520VIXL_ASSERT(vd.Is1D() || vd.Is2D());1521if (IsImmFP64(rawbits)) {1522fmov(vd, imm);1523} else if (vd.IsScalar()) {1524ldr(vd,1525new Literal<double>(imm,1526&literal_pool_,1527RawLiteral::kDeletedOnPlacementByPool));1528} else {1529// TODO: consider NEON support for load literal.1530Movi(vd, rawbits);1531}1532}153315341535void MacroAssembler::Fmov(VRegister vd, float imm) {1536VIXL_ASSERT(allow_macro_instructions_);1537// Floating point immediates are loaded through the literal pool.1538MacroEmissionCheckScope guard(this);1539uint32_t rawbits = FloatToRawbits(imm);15401541if (rawbits == 0) {1542fmov(vd.S(), wzr);1543return;1544}15451546if (vd.Is1H() || vd.Is4H() || vd.Is8H()) {1547Fmov(vd, Float16(imm));1548return;1549}15501551if (vd.Is1D() || vd.Is2D()) {1552Fmov(vd, static_cast<double>(imm));1553return;1554}15551556VIXL_ASSERT(vd.Is1S() || vd.Is2S() || vd.Is4S());1557if (IsImmFP32(rawbits)) {1558fmov(vd, imm);1559} else if (vd.IsScalar()) {1560ldr(vd,1561new Literal<float>(imm,1562&literal_pool_,1563RawLiteral::kDeletedOnPlacementByPool));1564} else {1565// TODO: consider NEON support for load literal.1566Movi(vd, rawbits);1567}1568}156915701571void MacroAssembler::Fmov(VRegister vd, Float16 imm) {1572VIXL_ASSERT(allow_macro_instructions_);1573MacroEmissionCheckScope guard(this);15741575if (vd.Is1S() || vd.Is2S() || vd.Is4S()) {1576Fmov(vd, FPToFloat(imm, kIgnoreDefaultNaN));1577return;1578}15791580if (vd.Is1D() || vd.Is2D()) {1581Fmov(vd, FPToDouble(imm, kIgnoreDefaultNaN));1582return;1583}15841585VIXL_ASSERT(vd.Is1H() || vd.Is4H() || vd.Is8H());1586uint16_t rawbits = Float16ToRawbits(imm);1587if (IsImmFP16(imm)) {1588fmov(vd, imm);1589} else {1590if (vd.IsScalar()) {1591if (rawbits == 0x0) {1592fmov(vd, wzr);1593} else {1594// We can use movz instead of the literal pool.1595UseScratchRegisterScope temps(this);1596Register temp = temps.AcquireW();1597Mov(temp, rawbits);1598Fmov(vd, temp);1599}1600} else {1601// TODO: consider NEON support for load literal.1602Movi(vd, static_cast<uint64_t>(rawbits));1603}1604}1605}160616071608void MacroAssembler::Neg(const Register& rd, const Operand& operand) {1609VIXL_ASSERT(allow_macro_instructions_);1610if (operand.IsImmediate()) {1611Mov(rd, -operand.GetImmediate());1612} else {1613Sub(rd, AppropriateZeroRegFor(rd), operand);1614}1615}161616171618void MacroAssembler::Negs(const Register& rd, const Operand& operand) {1619VIXL_ASSERT(allow_macro_instructions_);1620Subs(rd, AppropriateZeroRegFor(rd), operand);1621}162216231624bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,1625uint64_t imm) {1626return OneInstrMoveImmediateHelper(this, dst, imm);1627}162816291630Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,1631uint64_t imm,1632PreShiftImmMode mode) {1633int reg_size = dst.GetSizeInBits();16341635// Encode the immediate in a single move instruction, if possible.1636if (TryOneInstrMoveImmediate(dst, imm)) {1637// The move was successful; nothing to do here.1638} else {1639// Pre-shift the immediate to the least-significant bits of the register.1640int shift_low = CountTrailingZeros(imm, reg_size);1641if (mode == kLimitShiftForSP) {1642// When applied to the stack pointer, the subsequent arithmetic operation1643// can use the extend form to shift left by a maximum of four bits. Right1644// shifts are not allowed, so we filter them out later before the new1645// immediate is tested.1646shift_low = std::min(shift_low, 4);1647}1648// TryOneInstrMoveImmediate handles `imm` with a value of zero, so shift_low1649// must lie in the range [0, 63], and the shifts below are well-defined.1650VIXL_ASSERT((shift_low >= 0) && (shift_low < 64));1651// imm_low = imm >> shift_low (with sign extension)1652uint64_t imm_low = ExtractSignedBitfield64(63, shift_low, imm);16531654// Pre-shift the immediate to the most-significant bits of the register,1655// inserting set bits in the least-significant bits.1656int shift_high = CountLeadingZeros(imm, reg_size);1657VIXL_ASSERT((shift_high >= 0) && (shift_high < 64));1658uint64_t imm_high = (imm << shift_high) | GetUintMask(shift_high);16591660if ((mode != kNoShift) && TryOneInstrMoveImmediate(dst, imm_low)) {1661// The new immediate has been moved into the destination's low bits:1662// return a new leftward-shifting operand.1663return Operand(dst, LSL, shift_low);1664} else if ((mode == kAnyShift) && TryOneInstrMoveImmediate(dst, imm_high)) {1665// The new immediate has been moved into the destination's high bits:1666// return a new rightward-shifting operand.1667return Operand(dst, LSR, shift_high);1668} else {1669Mov(dst, imm);1670}1671}1672return Operand(dst);1673}167416751676void MacroAssembler::Move(const GenericOperand& dst,1677const GenericOperand& src) {1678if (dst.Equals(src)) {1679return;1680}16811682VIXL_ASSERT(dst.IsValid() && src.IsValid());16831684// The sizes of the operands must match exactly.1685VIXL_ASSERT(dst.GetSizeInBits() == src.GetSizeInBits());1686VIXL_ASSERT(dst.GetSizeInBits() <= kXRegSize);1687int operand_size = static_cast<int>(dst.GetSizeInBits());16881689if (dst.IsCPURegister() && src.IsCPURegister()) {1690CPURegister dst_reg = dst.GetCPURegister();1691CPURegister src_reg = src.GetCPURegister();1692if (dst_reg.IsRegister() && src_reg.IsRegister()) {1693Mov(Register(dst_reg), Register(src_reg));1694} else if (dst_reg.IsVRegister() && src_reg.IsVRegister()) {1695Fmov(VRegister(dst_reg), VRegister(src_reg));1696} else {1697if (dst_reg.IsRegister()) {1698Fmov(Register(dst_reg), VRegister(src_reg));1699} else {1700Fmov(VRegister(dst_reg), Register(src_reg));1701}1702}1703return;1704}17051706if (dst.IsMemOperand() && src.IsMemOperand()) {1707UseScratchRegisterScope temps(this);1708CPURegister temp = temps.AcquireCPURegisterOfSize(operand_size);1709Ldr(temp, src.GetMemOperand());1710Str(temp, dst.GetMemOperand());1711return;1712}17131714if (dst.IsCPURegister()) {1715Ldr(dst.GetCPURegister(), src.GetMemOperand());1716} else {1717Str(src.GetCPURegister(), dst.GetMemOperand());1718}1719}172017211722void MacroAssembler::ComputeAddress(const Register& dst,1723const MemOperand& mem_op) {1724// We cannot handle pre-indexing or post-indexing.1725VIXL_ASSERT(mem_op.GetAddrMode() == Offset);1726Register base = mem_op.GetBaseRegister();1727if (mem_op.IsImmediateOffset()) {1728Add(dst, base, mem_op.GetOffset());1729} else {1730VIXL_ASSERT(mem_op.IsRegisterOffset());1731Register reg_offset = mem_op.GetRegisterOffset();1732Shift shift = mem_op.GetShift();1733Extend extend = mem_op.GetExtend();1734if (shift == NO_SHIFT) {1735VIXL_ASSERT(extend != NO_EXTEND);1736Add(dst, base, Operand(reg_offset, extend, mem_op.GetShiftAmount()));1737} else {1738VIXL_ASSERT(extend == NO_EXTEND);1739Add(dst, base, Operand(reg_offset, shift, mem_op.GetShiftAmount()));1740}1741}1742}174317441745void MacroAssembler::AddSubMacro(const Register& rd,1746const Register& rn,1747const Operand& operand,1748FlagsUpdate S,1749AddSubOp op) {1750// Worst case is add/sub immediate:1751// * up to 4 instructions to materialise the constant1752// * 1 instruction for add/sub1753MacroEmissionCheckScope guard(this);17541755if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&1756(S == LeaveFlags)) {1757// The instruction would be a nop. Avoid generating useless code.1758return;1759}17601761if ((operand.IsImmediate() && !IsImmAddSub(operand.GetImmediate())) ||1762(rn.IsZero() && !operand.IsShiftedRegister()) ||1763(operand.IsShiftedRegister() && (operand.GetShift() == ROR))) {1764UseScratchRegisterScope temps(this);1765// Use `rd` as a temp, if we can.1766temps.Include(rd);1767// We read `rn` after evaluating `operand`.1768temps.Exclude(rn);1769// It doesn't matter if `operand` is in `temps` (e.g. because it alises1770// `rd`) because we don't need it after it is evaluated.1771Register temp = temps.AcquireSameSizeAs(rn);1772if (operand.IsImmediate()) {1773PreShiftImmMode mode = kAnyShift;17741775// If the destination or source register is the stack pointer, we can1776// only pre-shift the immediate right by values supported in the add/sub1777// extend encoding.1778if (rd.IsSP()) {1779// If the destination is SP and flags will be set, we can't pre-shift1780// the immediate at all.1781mode = (S == SetFlags) ? kNoShift : kLimitShiftForSP;1782} else if (rn.IsSP()) {1783mode = kLimitShiftForSP;1784}17851786Operand imm_operand =1787MoveImmediateForShiftedOp(temp, operand.GetImmediate(), mode);1788AddSub(rd, rn, imm_operand, S, op);1789} else {1790Mov(temp, operand);1791AddSub(rd, rn, temp, S, op);1792}1793} else {1794AddSub(rd, rn, operand, S, op);1795}1796}179717981799void MacroAssembler::Adc(const Register& rd,1800const Register& rn,1801const Operand& operand) {1802VIXL_ASSERT(allow_macro_instructions_);1803AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);1804}180518061807void MacroAssembler::Adcs(const Register& rd,1808const Register& rn,1809const Operand& operand) {1810VIXL_ASSERT(allow_macro_instructions_);1811AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);1812}181318141815void MacroAssembler::Sbc(const Register& rd,1816const Register& rn,1817const Operand& operand) {1818VIXL_ASSERT(allow_macro_instructions_);1819AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);1820}182118221823void MacroAssembler::Sbcs(const Register& rd,1824const Register& rn,1825const Operand& operand) {1826VIXL_ASSERT(allow_macro_instructions_);1827AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);1828}182918301831void MacroAssembler::Ngc(const Register& rd, const Operand& operand) {1832VIXL_ASSERT(allow_macro_instructions_);1833Register zr = AppropriateZeroRegFor(rd);1834Sbc(rd, zr, operand);1835}183618371838void MacroAssembler::Ngcs(const Register& rd, const Operand& operand) {1839VIXL_ASSERT(allow_macro_instructions_);1840Register zr = AppropriateZeroRegFor(rd);1841Sbcs(rd, zr, operand);1842}184318441845void MacroAssembler::AddSubWithCarryMacro(const Register& rd,1846const Register& rn,1847const Operand& operand,1848FlagsUpdate S,1849AddSubWithCarryOp op) {1850VIXL_ASSERT(rd.GetSizeInBits() == rn.GetSizeInBits());1851// Worst case is addc/subc immediate:1852// * up to 4 instructions to materialise the constant1853// * 1 instruction for add/sub1854MacroEmissionCheckScope guard(this);1855UseScratchRegisterScope temps(this);1856// Use `rd` as a temp, if we can.1857temps.Include(rd);1858// We read `rn` after evaluating `operand`.1859temps.Exclude(rn);1860// It doesn't matter if `operand` is in `temps` (e.g. because it alises `rd`)1861// because we don't need it after it is evaluated.18621863if (operand.IsImmediate() ||1864(operand.IsShiftedRegister() && (operand.GetShift() == ROR))) {1865// Add/sub with carry (immediate or ROR shifted register.)1866Register temp = temps.AcquireSameSizeAs(rn);1867Mov(temp, operand);1868AddSubWithCarry(rd, rn, Operand(temp), S, op);1869} else if (operand.IsShiftedRegister() && (operand.GetShiftAmount() != 0)) {1870// Add/sub with carry (shifted register).1871VIXL_ASSERT(operand.GetRegister().GetSizeInBits() == rd.GetSizeInBits());1872VIXL_ASSERT(operand.GetShift() != ROR);1873VIXL_ASSERT(1874IsUintN(rd.GetSizeInBits() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2,1875operand.GetShiftAmount()));1876Register temp = temps.AcquireSameSizeAs(rn);1877EmitShift(temp,1878operand.GetRegister(),1879operand.GetShift(),1880operand.GetShiftAmount());1881AddSubWithCarry(rd, rn, Operand(temp), S, op);1882} else if (operand.IsExtendedRegister()) {1883// Add/sub with carry (extended register).1884VIXL_ASSERT(operand.GetRegister().GetSizeInBits() <= rd.GetSizeInBits());1885// Add/sub extended supports a shift <= 4. We want to support exactly the1886// same modes.1887VIXL_ASSERT(operand.GetShiftAmount() <= 4);1888VIXL_ASSERT(1889operand.GetRegister().Is64Bits() ||1890((operand.GetExtend() != UXTX) && (operand.GetExtend() != SXTX)));1891Register temp = temps.AcquireSameSizeAs(rn);1892EmitExtendShift(temp,1893operand.GetRegister(),1894operand.GetExtend(),1895operand.GetShiftAmount());1896AddSubWithCarry(rd, rn, Operand(temp), S, op);1897} else {1898// The addressing mode is directly supported by the instruction.1899AddSubWithCarry(rd, rn, operand, S, op);1900}1901}190219031904void MacroAssembler::Rmif(const Register& xn,1905unsigned shift,1906StatusFlags flags) {1907VIXL_ASSERT(allow_macro_instructions_);1908SingleEmissionCheckScope guard(this);1909rmif(xn, shift, flags);1910}191119121913void MacroAssembler::Setf8(const Register& wn) {1914VIXL_ASSERT(allow_macro_instructions_);1915SingleEmissionCheckScope guard(this);1916setf8(wn);1917}191819191920void MacroAssembler::Setf16(const Register& wn) {1921VIXL_ASSERT(allow_macro_instructions_);1922SingleEmissionCheckScope guard(this);1923setf16(wn);1924}192519261927#define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \1928void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \1929VIXL_ASSERT(allow_macro_instructions_); \1930LoadStoreMacro(REG, addr, OP); \1931}1932LS_MACRO_LIST(DEFINE_FUNCTION)1933#undef DEFINE_FUNCTION193419351936void MacroAssembler::LoadStoreMacro(const CPURegister& rt,1937const MemOperand& addr,1938LoadStoreOp op) {1939VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsImmediatePostIndex() ||1940addr.IsImmediatePreIndex() || addr.IsRegisterOffset());19411942// Worst case is ldr/str pre/post index:1943// * 1 instruction for ldr/str1944// * up to 4 instructions to materialise the constant1945// * 1 instruction to update the base1946MacroEmissionCheckScope guard(this);19471948int64_t offset = addr.GetOffset();1949unsigned access_size = CalcLSDataSize(op);19501951// Check if an immediate offset fits in the immediate field of the1952// appropriate instruction. If not, emit two instructions to perform1953// the operation.1954if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, access_size) &&1955!IsImmLSUnscaled(offset)) {1956// Immediate offset that can't be encoded using unsigned or unscaled1957// addressing modes.1958UseScratchRegisterScope temps(this);1959Register temp = temps.AcquireSameSizeAs(addr.GetBaseRegister());1960Mov(temp, addr.GetOffset());1961LoadStore(rt, MemOperand(addr.GetBaseRegister(), temp), op);1962} else if (addr.IsImmediatePostIndex() && !IsImmLSUnscaled(offset)) {1963// Post-index beyond unscaled addressing range.1964LoadStore(rt, MemOperand(addr.GetBaseRegister()), op);1965Add(addr.GetBaseRegister(), addr.GetBaseRegister(), Operand(offset));1966} else if (addr.IsImmediatePreIndex() && !IsImmLSUnscaled(offset)) {1967// Pre-index beyond unscaled addressing range.1968Add(addr.GetBaseRegister(), addr.GetBaseRegister(), Operand(offset));1969LoadStore(rt, MemOperand(addr.GetBaseRegister()), op);1970} else {1971// Encodable in one load/store instruction.1972LoadStore(rt, addr, op);1973}1974}197519761977#define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \1978void MacroAssembler::FN(const REGTYPE REG, \1979const REGTYPE REG2, \1980const MemOperand& addr) { \1981VIXL_ASSERT(allow_macro_instructions_); \1982LoadStorePairMacro(REG, REG2, addr, OP); \1983}1984LSPAIR_MACRO_LIST(DEFINE_FUNCTION)1985#undef DEFINE_FUNCTION19861987void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,1988const CPURegister& rt2,1989const MemOperand& addr,1990LoadStorePairOp op) {1991// TODO(all): Should we support register offset for load-store-pair?1992VIXL_ASSERT(!addr.IsRegisterOffset());1993// Worst case is ldp/stp immediate:1994// * 1 instruction for ldp/stp1995// * up to 4 instructions to materialise the constant1996// * 1 instruction to update the base1997MacroEmissionCheckScope guard(this);19981999int64_t offset = addr.GetOffset();2000unsigned access_size = CalcLSPairDataSize(op);20012002// Check if the offset fits in the immediate field of the appropriate2003// instruction. If not, emit two instructions to perform the operation.2004if (IsImmLSPair(offset, access_size)) {2005// Encodable in one load/store pair instruction.2006LoadStorePair(rt, rt2, addr, op);2007} else {2008Register base = addr.GetBaseRegister();2009if (addr.IsImmediateOffset()) {2010UseScratchRegisterScope temps(this);2011Register temp = temps.AcquireSameSizeAs(base);2012Add(temp, base, offset);2013LoadStorePair(rt, rt2, MemOperand(temp), op);2014} else if (addr.IsImmediatePostIndex()) {2015LoadStorePair(rt, rt2, MemOperand(base), op);2016Add(base, base, offset);2017} else {2018VIXL_ASSERT(addr.IsImmediatePreIndex());2019Add(base, base, offset);2020LoadStorePair(rt, rt2, MemOperand(base), op);2021}2022}2023}202420252026void MacroAssembler::Prfm(PrefetchOperation op, const MemOperand& addr) {2027MacroEmissionCheckScope guard(this);20282029// There are no pre- or post-index modes for prfm.2030VIXL_ASSERT(addr.IsImmediateOffset() || addr.IsRegisterOffset());20312032// The access size is implicitly 8 bytes for all prefetch operations.2033unsigned size = kXRegSizeInBytesLog2;20342035// Check if an immediate offset fits in the immediate field of the2036// appropriate instruction. If not, emit two instructions to perform2037// the operation.2038if (addr.IsImmediateOffset() && !IsImmLSScaled(addr.GetOffset(), size) &&2039!IsImmLSUnscaled(addr.GetOffset())) {2040// Immediate offset that can't be encoded using unsigned or unscaled2041// addressing modes.2042UseScratchRegisterScope temps(this);2043Register temp = temps.AcquireSameSizeAs(addr.GetBaseRegister());2044Mov(temp, addr.GetOffset());2045Prefetch(op, MemOperand(addr.GetBaseRegister(), temp));2046} else {2047// Simple register-offsets are encodable in one instruction.2048Prefetch(op, addr);2049}2050}205120522053void MacroAssembler::Push(const CPURegister& src0,2054const CPURegister& src1,2055const CPURegister& src2,2056const CPURegister& src3) {2057VIXL_ASSERT(allow_macro_instructions_);2058VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));2059VIXL_ASSERT(src0.IsValid());20602061int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();2062int size = src0.GetSizeInBytes();20632064PrepareForPush(count, size);2065PushHelper(count, size, src0, src1, src2, src3);2066}206720682069void MacroAssembler::Pop(const CPURegister& dst0,2070const CPURegister& dst1,2071const CPURegister& dst2,2072const CPURegister& dst3) {2073// It is not valid to pop into the same register more than once in one2074// instruction, not even into the zero register.2075VIXL_ASSERT(allow_macro_instructions_);2076VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3));2077VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));2078VIXL_ASSERT(dst0.IsValid());20792080int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();2081int size = dst0.GetSizeInBytes();20822083PrepareForPop(count, size);2084PopHelper(count, size, dst0, dst1, dst2, dst3);2085}208620872088void MacroAssembler::PushCPURegList(CPURegList registers) {2089VIXL_ASSERT(!registers.Overlaps(*GetScratchRegisterList()));2090VIXL_ASSERT(!registers.Overlaps(*GetScratchVRegisterList()));2091VIXL_ASSERT(allow_macro_instructions_);20922093int reg_size = registers.GetRegisterSizeInBytes();2094PrepareForPush(registers.GetCount(), reg_size);20952096// Bump the stack pointer and store two registers at the bottom.2097int size = registers.GetTotalSizeInBytes();2098const CPURegister& bottom_0 = registers.PopLowestIndex();2099const CPURegister& bottom_1 = registers.PopLowestIndex();2100if (bottom_0.IsValid() && bottom_1.IsValid()) {2101Stp(bottom_0, bottom_1, MemOperand(StackPointer(), -size, PreIndex));2102} else if (bottom_0.IsValid()) {2103Str(bottom_0, MemOperand(StackPointer(), -size, PreIndex));2104}21052106int offset = 2 * reg_size;2107while (!registers.IsEmpty()) {2108const CPURegister& src0 = registers.PopLowestIndex();2109const CPURegister& src1 = registers.PopLowestIndex();2110if (src1.IsValid()) {2111Stp(src0, src1, MemOperand(StackPointer(), offset));2112} else {2113Str(src0, MemOperand(StackPointer(), offset));2114}2115offset += 2 * reg_size;2116}2117}211821192120void MacroAssembler::PopCPURegList(CPURegList registers) {2121VIXL_ASSERT(!registers.Overlaps(*GetScratchRegisterList()));2122VIXL_ASSERT(!registers.Overlaps(*GetScratchVRegisterList()));2123VIXL_ASSERT(allow_macro_instructions_);21242125int reg_size = registers.GetRegisterSizeInBytes();2126PrepareForPop(registers.GetCount(), reg_size);212721282129int size = registers.GetTotalSizeInBytes();2130const CPURegister& bottom_0 = registers.PopLowestIndex();2131const CPURegister& bottom_1 = registers.PopLowestIndex();21322133int offset = 2 * reg_size;2134while (!registers.IsEmpty()) {2135const CPURegister& dst0 = registers.PopLowestIndex();2136const CPURegister& dst1 = registers.PopLowestIndex();2137if (dst1.IsValid()) {2138Ldp(dst0, dst1, MemOperand(StackPointer(), offset));2139} else {2140Ldr(dst0, MemOperand(StackPointer(), offset));2141}2142offset += 2 * reg_size;2143}21442145// Load the two registers at the bottom and drop the stack pointer.2146if (bottom_0.IsValid() && bottom_1.IsValid()) {2147Ldp(bottom_0, bottom_1, MemOperand(StackPointer(), size, PostIndex));2148} else if (bottom_0.IsValid()) {2149Ldr(bottom_0, MemOperand(StackPointer(), size, PostIndex));2150}2151}215221532154void MacroAssembler::PushMultipleTimes(int count, Register src) {2155VIXL_ASSERT(allow_macro_instructions_);2156int size = src.GetSizeInBytes();21572158PrepareForPush(count, size);2159// Push up to four registers at a time if possible because if the current2160// stack pointer is sp and the register size is 32, registers must be pushed2161// in blocks of four in order to maintain the 16-byte alignment for sp.2162while (count >= 4) {2163PushHelper(4, size, src, src, src, src);2164count -= 4;2165}2166if (count >= 2) {2167PushHelper(2, size, src, src, NoReg, NoReg);2168count -= 2;2169}2170if (count == 1) {2171PushHelper(1, size, src, NoReg, NoReg, NoReg);2172count -= 1;2173}2174VIXL_ASSERT(count == 0);2175}217621772178void MacroAssembler::PushHelper(int count,2179int size,2180const CPURegister& src0,2181const CPURegister& src1,2182const CPURegister& src2,2183const CPURegister& src3) {2184// Ensure that we don't unintentionally modify scratch or debug registers.2185// Worst case for size is 2 stp.2186ExactAssemblyScope scope(this,21872 * kInstructionSize,2188ExactAssemblyScope::kMaximumSize);21892190VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3));2191VIXL_ASSERT(size == src0.GetSizeInBytes());21922193// When pushing multiple registers, the store order is chosen such that2194// Push(a, b) is equivalent to Push(a) followed by Push(b).2195switch (count) {2196case 1:2197VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());2198str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));2199break;2200case 2:2201VIXL_ASSERT(src2.IsNone() && src3.IsNone());2202stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));2203break;2204case 3:2205VIXL_ASSERT(src3.IsNone());2206stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));2207str(src0, MemOperand(StackPointer(), 2 * size));2208break;2209case 4:2210// Skip over 4 * size, then fill in the gap. This allows four W registers2211// to be pushed using sp, whilst maintaining 16-byte alignment for sp at2212// all times.2213stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));2214stp(src1, src0, MemOperand(StackPointer(), 2 * size));2215break;2216default:2217VIXL_UNREACHABLE();2218}2219}222022212222void MacroAssembler::PopHelper(int count,2223int size,2224const CPURegister& dst0,2225const CPURegister& dst1,2226const CPURegister& dst2,2227const CPURegister& dst3) {2228// Ensure that we don't unintentionally modify scratch or debug registers.2229// Worst case for size is 2 ldp.2230ExactAssemblyScope scope(this,22312 * kInstructionSize,2232ExactAssemblyScope::kMaximumSize);22332234VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));2235VIXL_ASSERT(size == dst0.GetSizeInBytes());22362237// When popping multiple registers, the load order is chosen such that2238// Pop(a, b) is equivalent to Pop(a) followed by Pop(b).2239switch (count) {2240case 1:2241VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());2242ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));2243break;2244case 2:2245VIXL_ASSERT(dst2.IsNone() && dst3.IsNone());2246ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));2247break;2248case 3:2249VIXL_ASSERT(dst3.IsNone());2250ldr(dst2, MemOperand(StackPointer(), 2 * size));2251ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));2252break;2253case 4:2254// Load the higher addresses first, then load the lower addresses and skip2255// the whole block in the second instruction. This allows four W registers2256// to be popped using sp, whilst maintaining 16-byte alignment for sp at2257// all times.2258ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));2259ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));2260break;2261default:2262VIXL_UNREACHABLE();2263}2264}226522662267void MacroAssembler::PrepareForPush(int count, int size) {2268if (sp.Is(StackPointer())) {2269// If the current stack pointer is sp, then it must be aligned to 16 bytes2270// on entry and the total size of the specified registers must also be a2271// multiple of 16 bytes.2272VIXL_ASSERT((count * size) % 16 == 0);2273} else {2274// Even if the current stack pointer is not the system stack pointer (sp),2275// the system stack pointer will still be modified in order to comply with2276// ABI rules about accessing memory below the system stack pointer.2277BumpSystemStackPointer(count * size);2278}2279}228022812282void MacroAssembler::PrepareForPop(int count, int size) {2283USE(count, size);2284if (sp.Is(StackPointer())) {2285// If the current stack pointer is sp, then it must be aligned to 16 bytes2286// on entry and the total size of the specified registers must also be a2287// multiple of 16 bytes.2288VIXL_ASSERT((count * size) % 16 == 0);2289}2290}22912292void MacroAssembler::Poke(const Register& src, const Operand& offset) {2293VIXL_ASSERT(allow_macro_instructions_);2294if (offset.IsImmediate()) {2295VIXL_ASSERT(offset.GetImmediate() >= 0);2296}22972298Str(src, MemOperand(StackPointer(), offset));2299}230023012302void MacroAssembler::Peek(const Register& dst, const Operand& offset) {2303VIXL_ASSERT(allow_macro_instructions_);2304if (offset.IsImmediate()) {2305VIXL_ASSERT(offset.GetImmediate() >= 0);2306}23072308Ldr(dst, MemOperand(StackPointer(), offset));2309}231023112312void MacroAssembler::Claim(const Operand& size) {2313VIXL_ASSERT(allow_macro_instructions_);23142315if (size.IsZero()) {2316return;2317}23182319if (size.IsImmediate()) {2320VIXL_ASSERT(size.GetImmediate() > 0);2321if (sp.Is(StackPointer())) {2322VIXL_ASSERT((size.GetImmediate() % 16) == 0);2323}2324}23252326if (!sp.Is(StackPointer())) {2327BumpSystemStackPointer(size);2328}23292330Sub(StackPointer(), StackPointer(), size);2331}233223332334void MacroAssembler::Drop(const Operand& size) {2335VIXL_ASSERT(allow_macro_instructions_);23362337if (size.IsZero()) {2338return;2339}23402341if (size.IsImmediate()) {2342VIXL_ASSERT(size.GetImmediate() > 0);2343if (sp.Is(StackPointer())) {2344VIXL_ASSERT((size.GetImmediate() % 16) == 0);2345}2346}23472348Add(StackPointer(), StackPointer(), size);2349}235023512352void MacroAssembler::PushCalleeSavedRegisters() {2353// Ensure that the macro-assembler doesn't use any scratch registers.2354// 10 stp will be emitted.2355// TODO(all): Should we use GetCalleeSaved and SavedFP.2356ExactAssemblyScope scope(this, 10 * kInstructionSize);23572358// This method must not be called unless the current stack pointer is sp.2359VIXL_ASSERT(sp.Is(StackPointer()));23602361MemOperand tos(sp, -2 * static_cast<int>(kXRegSizeInBytes), PreIndex);23622363stp(x29, x30, tos);2364stp(x27, x28, tos);2365stp(x25, x26, tos);2366stp(x23, x24, tos);2367stp(x21, x22, tos);2368stp(x19, x20, tos);23692370stp(d14, d15, tos);2371stp(d12, d13, tos);2372stp(d10, d11, tos);2373stp(d8, d9, tos);2374}237523762377void MacroAssembler::PopCalleeSavedRegisters() {2378// Ensure that the macro-assembler doesn't use any scratch registers.2379// 10 ldp will be emitted.2380// TODO(all): Should we use GetCalleeSaved and SavedFP.2381ExactAssemblyScope scope(this, 10 * kInstructionSize);23822383// This method must not be called unless the current stack pointer is sp.2384VIXL_ASSERT(sp.Is(StackPointer()));23852386MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex);23872388ldp(d8, d9, tos);2389ldp(d10, d11, tos);2390ldp(d12, d13, tos);2391ldp(d14, d15, tos);23922393ldp(x19, x20, tos);2394ldp(x21, x22, tos);2395ldp(x23, x24, tos);2396ldp(x25, x26, tos);2397ldp(x27, x28, tos);2398ldp(x29, x30, tos);2399}24002401void MacroAssembler::LoadCPURegList(CPURegList registers,2402const MemOperand& src) {2403LoadStoreCPURegListHelper(kLoad, registers, src);2404}24052406void MacroAssembler::StoreCPURegList(CPURegList registers,2407const MemOperand& dst) {2408LoadStoreCPURegListHelper(kStore, registers, dst);2409}241024112412void MacroAssembler::LoadStoreCPURegListHelper(LoadStoreCPURegListAction op,2413CPURegList registers,2414const MemOperand& mem) {2415// We do not handle pre-indexing or post-indexing.2416VIXL_ASSERT(!(mem.IsPreIndex() || mem.IsPostIndex()));2417VIXL_ASSERT(!registers.Overlaps(tmp_list_));2418VIXL_ASSERT(!registers.Overlaps(v_tmp_list_));2419VIXL_ASSERT(!registers.Overlaps(p_tmp_list_));2420VIXL_ASSERT(!registers.IncludesAliasOf(sp));24212422UseScratchRegisterScope temps(this);24232424MemOperand loc = BaseMemOperandForLoadStoreCPURegList(registers, mem, &temps);2425const int reg_size = registers.GetRegisterSizeInBytes();24262427VIXL_ASSERT(IsPowerOf2(reg_size));24282429// Since we are operating on register pairs, we would like to align on double2430// the standard size; on the other hand, we don't want to insert an extra2431// operation, which will happen if the number of registers is even. Note that2432// the alignment of the base pointer is unknown here, but we assume that it2433// is more likely to be aligned.2434if (((loc.GetOffset() & (2 * reg_size - 1)) != 0) &&2435((registers.GetCount() % 2) != 0)) {2436if (op == kStore) {2437Str(registers.PopLowestIndex(), loc);2438} else {2439VIXL_ASSERT(op == kLoad);2440Ldr(registers.PopLowestIndex(), loc);2441}2442loc.AddOffset(reg_size);2443}2444while (registers.GetCount() >= 2) {2445const CPURegister& dst0 = registers.PopLowestIndex();2446const CPURegister& dst1 = registers.PopLowestIndex();2447if (op == kStore) {2448Stp(dst0, dst1, loc);2449} else {2450VIXL_ASSERT(op == kLoad);2451Ldp(dst0, dst1, loc);2452}2453loc.AddOffset(2 * reg_size);2454}2455if (!registers.IsEmpty()) {2456if (op == kStore) {2457Str(registers.PopLowestIndex(), loc);2458} else {2459VIXL_ASSERT(op == kLoad);2460Ldr(registers.PopLowestIndex(), loc);2461}2462}2463}24642465MemOperand MacroAssembler::BaseMemOperandForLoadStoreCPURegList(2466const CPURegList& registers,2467const MemOperand& mem,2468UseScratchRegisterScope* scratch_scope) {2469// If necessary, pre-compute the base address for the accesses.2470if (mem.IsRegisterOffset()) {2471Register reg_base = scratch_scope->AcquireX();2472ComputeAddress(reg_base, mem);2473return MemOperand(reg_base);24742475} else if (mem.IsImmediateOffset()) {2476int reg_size = registers.GetRegisterSizeInBytes();2477int total_size = registers.GetTotalSizeInBytes();2478int64_t min_offset = mem.GetOffset();2479int64_t max_offset =2480mem.GetOffset() + std::max(0, total_size - 2 * reg_size);2481if ((registers.GetCount() >= 2) &&2482(!Assembler::IsImmLSPair(min_offset, WhichPowerOf2(reg_size)) ||2483!Assembler::IsImmLSPair(max_offset, WhichPowerOf2(reg_size)))) {2484Register reg_base = scratch_scope->AcquireX();2485ComputeAddress(reg_base, mem);2486return MemOperand(reg_base);2487}2488}24892490return mem;2491}24922493void MacroAssembler::BumpSystemStackPointer(const Operand& space) {2494VIXL_ASSERT(!sp.Is(StackPointer()));2495// TODO: Several callers rely on this not using scratch registers, so we use2496// the assembler directly here. However, this means that large immediate2497// values of 'space' cannot be handled.2498ExactAssemblyScope scope(this, kInstructionSize);2499sub(sp, StackPointer(), space);2500}250125022503// TODO(all): Fix printf for NEON and SVE registers.25042505// This is the main Printf implementation. All callee-saved registers are2506// preserved, but NZCV and the caller-saved registers may be clobbered.2507void MacroAssembler::PrintfNoPreserve(const char* format,2508const CPURegister& arg0,2509const CPURegister& arg1,2510const CPURegister& arg2,2511const CPURegister& arg3) {2512// We cannot handle a caller-saved stack pointer. It doesn't make much sense2513// in most cases anyway, so this restriction shouldn't be too serious.2514VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer()));25152516// The provided arguments, and their proper PCS registers.2517CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};2518CPURegister pcs[kPrintfMaxArgCount];25192520int arg_count = kPrintfMaxArgCount;25212522// The PCS varargs registers for printf. Note that x0 is used for the printf2523// format string.2524static const CPURegList kPCSVarargs =2525CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count);2526static const CPURegList kPCSVarargsV =2527CPURegList(CPURegister::kVRegister, kDRegSize, 0, arg_count - 1);25282529// We can use caller-saved registers as scratch values, except for the2530// arguments and the PCS registers where they might need to go.2531UseScratchRegisterScope temps(this);2532temps.Include(kCallerSaved);2533temps.Include(kCallerSavedV);2534temps.Exclude(kPCSVarargs);2535temps.Exclude(kPCSVarargsV);2536temps.Exclude(arg0, arg1, arg2, arg3);25372538// Copies of the arg lists that we can iterate through.2539CPURegList pcs_varargs = kPCSVarargs;2540CPURegList pcs_varargs_fp = kPCSVarargsV;25412542// Place the arguments. There are lots of clever tricks and optimizations we2543// could use here, but Printf is a debug tool so instead we just try to keep2544// it simple: Move each input that isn't already in the right place to a2545// scratch register, then move everything back.2546for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {2547// Work out the proper PCS register for this argument.2548if (args[i].IsRegister()) {2549pcs[i] = pcs_varargs.PopLowestIndex().X();2550// We might only need a W register here. We need to know the size of the2551// argument so we can properly encode it for the simulator call.2552if (args[i].Is32Bits()) pcs[i] = pcs[i].W();2553} else if (args[i].IsVRegister()) {2554// In C, floats are always cast to doubles for varargs calls.2555pcs[i] = pcs_varargs_fp.PopLowestIndex().D();2556} else {2557VIXL_ASSERT(args[i].IsNone());2558arg_count = i;2559break;2560}25612562// If the argument is already in the right place, leave it where it is.2563if (args[i].Aliases(pcs[i])) continue;25642565// Otherwise, if the argument is in a PCS argument register, allocate an2566// appropriate scratch register and then move it out of the way.2567if (kPCSVarargs.IncludesAliasOf(args[i]) ||2568kPCSVarargsV.IncludesAliasOf(args[i])) {2569if (args[i].IsRegister()) {2570Register old_arg = Register(args[i]);2571Register new_arg = temps.AcquireSameSizeAs(old_arg);2572Mov(new_arg, old_arg);2573args[i] = new_arg;2574} else {2575VRegister old_arg(args[i]);2576VRegister new_arg = temps.AcquireSameSizeAs(old_arg);2577Fmov(new_arg, old_arg);2578args[i] = new_arg;2579}2580}2581}25822583// Do a second pass to move values into their final positions and perform any2584// conversions that may be required.2585for (int i = 0; i < arg_count; i++) {2586VIXL_ASSERT(pcs[i].GetType() == args[i].GetType());2587if (pcs[i].IsRegister()) {2588Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);2589} else {2590VIXL_ASSERT(pcs[i].IsVRegister());2591if (pcs[i].GetSizeInBits() == args[i].GetSizeInBits()) {2592Fmov(VRegister(pcs[i]), VRegister(args[i]));2593} else {2594Fcvt(VRegister(pcs[i]), VRegister(args[i]));2595}2596}2597}25982599// Load the format string into x0, as per the procedure-call standard.2600//2601// To make the code as portable as possible, the format string is encoded2602// directly in the instruction stream. It might be cleaner to encode it in a2603// literal pool, but since Printf is usually used for debugging, it is2604// beneficial for it to be minimally dependent on other features.2605temps.Exclude(x0);2606Label format_address;2607Adr(x0, &format_address);26082609// Emit the format string directly in the instruction stream.2610{2611BlockPoolsScope scope(this);2612// Data emitted:2613// branch2614// strlen(format) + 1 (includes null termination)2615// padding to next instruction2616// unreachable2617EmissionCheckScope guard(this,2618AlignUp(strlen(format) + 1, kInstructionSize) +26192 * kInstructionSize);2620Label after_data;2621B(&after_data);2622Bind(&format_address);2623EmitString(format);2624Unreachable();2625Bind(&after_data);2626}26272628// We don't pass any arguments on the stack, but we still need to align the C2629// stack pointer to a 16-byte boundary for PCS compliance.2630if (!sp.Is(StackPointer())) {2631Bic(sp, StackPointer(), 0xf);2632}26332634// Actually call printf. This part needs special handling for the simulator,2635// since the system printf function will use a different instruction set and2636// the procedure-call standard will not be compatible.2637if (generate_simulator_code_) {2638ExactAssemblyScope scope(this, kPrintfLength);2639hlt(kPrintfOpcode);2640dc32(arg_count); // kPrintfArgCountOffset26412642// Determine the argument pattern.2643uint32_t arg_pattern_list = 0;2644for (int i = 0; i < arg_count; i++) {2645uint32_t arg_pattern;2646if (pcs[i].IsRegister()) {2647arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;2648} else {2649VIXL_ASSERT(pcs[i].Is64Bits());2650arg_pattern = kPrintfArgD;2651}2652VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits));2653arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));2654}2655dc32(arg_pattern_list); // kPrintfArgPatternListOffset2656} else {2657Register tmp = temps.AcquireX();2658Mov(tmp, reinterpret_cast<uintptr_t>(printf));2659Blr(tmp);2660}2661}266226632664void MacroAssembler::Printf(const char* format,2665CPURegister arg0,2666CPURegister arg1,2667CPURegister arg2,2668CPURegister arg3) {2669// We can only print sp if it is the current stack pointer.2670if (!sp.Is(StackPointer())) {2671VIXL_ASSERT(!sp.Aliases(arg0));2672VIXL_ASSERT(!sp.Aliases(arg1));2673VIXL_ASSERT(!sp.Aliases(arg2));2674VIXL_ASSERT(!sp.Aliases(arg3));2675}26762677// Make sure that the macro assembler doesn't try to use any of our arguments2678// as scratch registers.2679UseScratchRegisterScope exclude_all(this);2680exclude_all.ExcludeAll();26812682// Preserve all caller-saved registers as well as NZCV.2683// If sp is the stack pointer, PushCPURegList asserts that the size of each2684// list is a multiple of 16 bytes.2685PushCPURegList(kCallerSaved);2686PushCPURegList(kCallerSavedV);26872688{2689UseScratchRegisterScope temps(this);2690// We can use caller-saved registers as scratch values (except for argN).2691temps.Include(kCallerSaved);2692temps.Include(kCallerSavedV);2693temps.Exclude(arg0, arg1, arg2, arg3);26942695// If any of the arguments are the current stack pointer, allocate a new2696// register for them, and adjust the value to compensate for pushing the2697// caller-saved registers.2698bool arg0_sp = StackPointer().Aliases(arg0);2699bool arg1_sp = StackPointer().Aliases(arg1);2700bool arg2_sp = StackPointer().Aliases(arg2);2701bool arg3_sp = StackPointer().Aliases(arg3);2702if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {2703// Allocate a register to hold the original stack pointer value, to pass2704// to PrintfNoPreserve as an argument.2705Register arg_sp = temps.AcquireX();2706Add(arg_sp,2707StackPointer(),2708kCallerSaved.GetTotalSizeInBytes() +2709kCallerSavedV.GetTotalSizeInBytes());2710if (arg0_sp) arg0 = Register(arg_sp.GetCode(), arg0.GetSizeInBits());2711if (arg1_sp) arg1 = Register(arg_sp.GetCode(), arg1.GetSizeInBits());2712if (arg2_sp) arg2 = Register(arg_sp.GetCode(), arg2.GetSizeInBits());2713if (arg3_sp) arg3 = Register(arg_sp.GetCode(), arg3.GetSizeInBits());2714}27152716// Preserve NZCV.2717Register tmp = temps.AcquireX();2718Mrs(tmp, NZCV);2719Push(tmp, xzr);2720temps.Release(tmp);27212722PrintfNoPreserve(format, arg0, arg1, arg2, arg3);27232724// Restore NZCV.2725tmp = temps.AcquireX();2726Pop(xzr, tmp);2727Msr(NZCV, tmp);2728temps.Release(tmp);2729}27302731PopCPURegList(kCallerSavedV);2732PopCPURegList(kCallerSaved);2733}27342735void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {2736VIXL_ASSERT(allow_macro_instructions_);27372738if (generate_simulator_code_) {2739// The arguments to the trace pseudo instruction need to be contiguous in2740// memory, so make sure we don't try to emit a literal pool.2741ExactAssemblyScope scope(this, kTraceLength);27422743Label start;2744bind(&start);27452746// Refer to simulator-aarch64.h for a description of the marker and its2747// arguments.2748hlt(kTraceOpcode);27492750VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kTraceParamsOffset);2751dc32(parameters);27522753VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kTraceCommandOffset);2754dc32(command);2755} else {2756// Emit nothing on real hardware.2757USE(parameters, command);2758}2759}276027612762void MacroAssembler::Log(TraceParameters parameters) {2763VIXL_ASSERT(allow_macro_instructions_);27642765if (generate_simulator_code_) {2766// The arguments to the log pseudo instruction need to be contiguous in2767// memory, so make sure we don't try to emit a literal pool.2768ExactAssemblyScope scope(this, kLogLength);27692770Label start;2771bind(&start);27722773// Refer to simulator-aarch64.h for a description of the marker and its2774// arguments.2775hlt(kLogOpcode);27762777VIXL_ASSERT(GetSizeOfCodeGeneratedSince(&start) == kLogParamsOffset);2778dc32(parameters);2779} else {2780// Emit nothing on real hardware.2781USE(parameters);2782}2783}278427852786void MacroAssembler::SetSimulatorCPUFeatures(const CPUFeatures& features) {2787ConfigureSimulatorCPUFeaturesHelper(features, kSetCPUFeaturesOpcode);2788}278927902791void MacroAssembler::EnableSimulatorCPUFeatures(const CPUFeatures& features) {2792ConfigureSimulatorCPUFeaturesHelper(features, kEnableCPUFeaturesOpcode);2793}279427952796void MacroAssembler::DisableSimulatorCPUFeatures(const CPUFeatures& features) {2797ConfigureSimulatorCPUFeaturesHelper(features, kDisableCPUFeaturesOpcode);2798}279928002801void MacroAssembler::ConfigureSimulatorCPUFeaturesHelper(2802const CPUFeatures& features, DebugHltOpcode action) {2803VIXL_ASSERT(allow_macro_instructions_);2804VIXL_ASSERT(generate_simulator_code_);28052806typedef ConfigureCPUFeaturesElementType ElementType;2807VIXL_ASSERT(CPUFeatures::kNumberOfFeatures <=2808std::numeric_limits<ElementType>::max());28092810size_t count = features.Count();28112812size_t preamble_length = kConfigureCPUFeaturesListOffset;2813size_t list_length = (count + 1) * sizeof(ElementType);2814size_t padding_length = AlignUp(list_length, kInstructionSize) - list_length;28152816size_t total_length = preamble_length + list_length + padding_length;28172818// Check the overall code size as well as the size of each component.2819ExactAssemblyScope guard_total(this, total_length);28202821{ // Preamble: the opcode itself.2822ExactAssemblyScope guard_preamble(this, preamble_length);2823hlt(action);2824}2825{ // A kNone-terminated list of features.2826ExactAssemblyScope guard_list(this, list_length);2827for (CPUFeatures::const_iterator it = features.begin();2828it != features.end();2829++it) {2830dc(static_cast<ElementType>(*it));2831}2832dc(static_cast<ElementType>(CPUFeatures::kNone));2833}2834{ // Padding for instruction alignment.2835ExactAssemblyScope guard_padding(this, padding_length);2836for (size_t size = 0; size < padding_length; size += sizeof(ElementType)) {2837// The exact value is arbitrary.2838dc(static_cast<ElementType>(CPUFeatures::kNone));2839}2840}2841}28422843void MacroAssembler::SaveSimulatorCPUFeatures() {2844VIXL_ASSERT(allow_macro_instructions_);2845VIXL_ASSERT(generate_simulator_code_);2846SingleEmissionCheckScope guard(this);2847hlt(kSaveCPUFeaturesOpcode);2848}284928502851void MacroAssembler::RestoreSimulatorCPUFeatures() {2852VIXL_ASSERT(allow_macro_instructions_);2853VIXL_ASSERT(generate_simulator_code_);2854SingleEmissionCheckScope guard(this);2855hlt(kRestoreCPUFeaturesOpcode);2856}285728582859void UseScratchRegisterScope::Open(MacroAssembler* masm) {2860VIXL_ASSERT(masm_ == NULL);2861VIXL_ASSERT(masm != NULL);2862masm_ = masm;28632864CPURegList* available = masm->GetScratchRegisterList();2865CPURegList* available_v = masm->GetScratchVRegisterList();2866CPURegList* available_p = masm->GetScratchPRegisterList();2867old_available_ = available->GetList();2868old_available_v_ = available_v->GetList();2869old_available_p_ = available_p->GetList();2870VIXL_ASSERT(available->GetType() == CPURegister::kRegister);2871VIXL_ASSERT(available_v->GetType() == CPURegister::kVRegister);2872VIXL_ASSERT(available_p->GetType() == CPURegister::kPRegister);28732874parent_ = masm->GetCurrentScratchRegisterScope();2875masm->SetCurrentScratchRegisterScope(this);2876}287728782879void UseScratchRegisterScope::Close() {2880if (masm_ != NULL) {2881// Ensure that scopes nest perfectly, and do not outlive their parents.2882// This is a run-time check because the order of destruction of objects in2883// the _same_ scope is implementation-defined, and is likely to change in2884// optimised builds.2885VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);2886masm_->SetCurrentScratchRegisterScope(parent_);28872888masm_->GetScratchRegisterList()->SetList(old_available_);2889masm_->GetScratchVRegisterList()->SetList(old_available_v_);2890masm_->GetScratchPRegisterList()->SetList(old_available_p_);28912892masm_ = NULL;2893}2894}289528962897bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const {2898return masm_->GetScratchRegisterList()->IncludesAliasOf(reg) ||2899masm_->GetScratchVRegisterList()->IncludesAliasOf(reg) ||2900masm_->GetScratchPRegisterList()->IncludesAliasOf(reg);2901}29022903Register UseScratchRegisterScope::AcquireRegisterOfSize(int size_in_bits) {2904int code = AcquireFrom(masm_->GetScratchRegisterList()).GetCode();2905return Register(code, size_in_bits);2906}290729082909VRegister UseScratchRegisterScope::AcquireVRegisterOfSize(int size_in_bits) {2910int code = AcquireFrom(masm_->GetScratchVRegisterList()).GetCode();2911return VRegister(code, size_in_bits);2912}291329142915void UseScratchRegisterScope::Release(const CPURegister& reg) {2916VIXL_ASSERT(masm_ != NULL);29172918// Release(NoReg) has no effect.2919if (reg.IsNone()) return;29202921ReleaseByCode(GetAvailableListFor(reg.GetBank()), reg.GetCode());2922}292329242925void UseScratchRegisterScope::Include(const CPURegList& list) {2926VIXL_ASSERT(masm_ != NULL);29272928// Including an empty list has no effect.2929if (list.IsEmpty()) return;2930VIXL_ASSERT(list.GetType() != CPURegister::kNoRegister);29312932RegList reg_list = list.GetList();2933if (list.GetType() == CPURegister::kRegister) {2934// Make sure that neither sp nor xzr are included the list.2935reg_list &= ~(xzr.GetBit() | sp.GetBit());2936}29372938IncludeByRegList(GetAvailableListFor(list.GetBank()), reg_list);2939}294029412942void UseScratchRegisterScope::Include(const Register& reg1,2943const Register& reg2,2944const Register& reg3,2945const Register& reg4) {2946VIXL_ASSERT(masm_ != NULL);2947RegList include =2948reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();2949// Make sure that neither sp nor xzr are included the list.2950include &= ~(xzr.GetBit() | sp.GetBit());29512952IncludeByRegList(masm_->GetScratchRegisterList(), include);2953}295429552956void UseScratchRegisterScope::Include(const VRegister& reg1,2957const VRegister& reg2,2958const VRegister& reg3,2959const VRegister& reg4) {2960RegList include =2961reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();2962IncludeByRegList(masm_->GetScratchVRegisterList(), include);2963}296429652966void UseScratchRegisterScope::Include(const CPURegister& reg1,2967const CPURegister& reg2,2968const CPURegister& reg3,2969const CPURegister& reg4) {2970RegList include = 0;2971RegList include_v = 0;2972RegList include_p = 0;29732974const CPURegister regs[] = {reg1, reg2, reg3, reg4};29752976for (size_t i = 0; i < ArrayLength(regs); i++) {2977RegList bit = regs[i].GetBit();2978switch (regs[i].GetBank()) {2979case CPURegister::kNoRegisterBank:2980// Include(NoReg) has no effect.2981VIXL_ASSERT(regs[i].IsNone());2982break;2983case CPURegister::kRRegisterBank:2984include |= bit;2985break;2986case CPURegister::kVRegisterBank:2987include_v |= bit;2988break;2989case CPURegister::kPRegisterBank:2990include_p |= bit;2991break;2992}2993}29942995IncludeByRegList(masm_->GetScratchRegisterList(), include);2996IncludeByRegList(masm_->GetScratchVRegisterList(), include_v);2997IncludeByRegList(masm_->GetScratchPRegisterList(), include_p);2998}299930003001void UseScratchRegisterScope::Exclude(const CPURegList& list) {3002ExcludeByRegList(GetAvailableListFor(list.GetBank()), list.GetList());3003}300430053006void UseScratchRegisterScope::Exclude(const Register& reg1,3007const Register& reg2,3008const Register& reg3,3009const Register& reg4) {3010RegList exclude =3011reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();3012ExcludeByRegList(masm_->GetScratchRegisterList(), exclude);3013}301430153016void UseScratchRegisterScope::Exclude(const VRegister& reg1,3017const VRegister& reg2,3018const VRegister& reg3,3019const VRegister& reg4) {3020RegList exclude_v =3021reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit();3022ExcludeByRegList(masm_->GetScratchVRegisterList(), exclude_v);3023}302430253026void UseScratchRegisterScope::Exclude(const CPURegister& reg1,3027const CPURegister& reg2,3028const CPURegister& reg3,3029const CPURegister& reg4) {3030RegList exclude = 0;3031RegList exclude_v = 0;3032RegList exclude_p = 0;30333034const CPURegister regs[] = {reg1, reg2, reg3, reg4};30353036for (size_t i = 0; i < ArrayLength(regs); i++) {3037RegList bit = regs[i].GetBit();3038switch (regs[i].GetBank()) {3039case CPURegister::kNoRegisterBank:3040// Exclude(NoReg) has no effect.3041VIXL_ASSERT(regs[i].IsNone());3042break;3043case CPURegister::kRRegisterBank:3044exclude |= bit;3045break;3046case CPURegister::kVRegisterBank:3047exclude_v |= bit;3048break;3049case CPURegister::kPRegisterBank:3050exclude_p |= bit;3051break;3052}3053}30543055ExcludeByRegList(masm_->GetScratchRegisterList(), exclude);3056ExcludeByRegList(masm_->GetScratchVRegisterList(), exclude_v);3057ExcludeByRegList(masm_->GetScratchPRegisterList(), exclude_p);3058}305930603061void UseScratchRegisterScope::ExcludeAll() {3062ExcludeByRegList(masm_->GetScratchRegisterList(),3063masm_->GetScratchRegisterList()->GetList());3064ExcludeByRegList(masm_->GetScratchVRegisterList(),3065masm_->GetScratchVRegisterList()->GetList());3066ExcludeByRegList(masm_->GetScratchPRegisterList(),3067masm_->GetScratchPRegisterList()->GetList());3068}306930703071CPURegister UseScratchRegisterScope::AcquireFrom(CPURegList* available,3072RegList mask) {3073VIXL_CHECK((available->GetList() & mask) != 0);3074CPURegister result = available->PopLowestIndex(mask);3075VIXL_ASSERT(!AreAliased(result, xzr, sp));3076return result;3077}307830793080void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) {3081ReleaseByRegList(available, static_cast<RegList>(1) << code);3082}308330843085void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available,3086RegList regs) {3087available->SetList(available->GetList() | regs);3088}308930903091void UseScratchRegisterScope::IncludeByRegList(CPURegList* available,3092RegList regs) {3093available->SetList(available->GetList() | regs);3094}309530963097void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available,3098RegList exclude) {3099available->SetList(available->GetList() & ~exclude);3100}31013102CPURegList* UseScratchRegisterScope::GetAvailableListFor(3103CPURegister::RegisterBank bank) {3104switch (bank) {3105case CPURegister::kNoRegisterBank:3106return NULL;3107case CPURegister::kRRegisterBank:3108return masm_->GetScratchRegisterList();3109case CPURegister::kVRegisterBank:3110return masm_->GetScratchVRegisterList();3111case CPURegister::kPRegisterBank:3112return masm_->GetScratchPRegisterList();3113}3114VIXL_UNREACHABLE();3115return NULL;3116}31173118} // namespace aarch643119} // namespace vixl312031213122