[loong64][regalloc] Improve gap resolver algorithm
Port commit a77dd89e4c
Bug: v8:5210, chromium:1269989, chromium:1313647
Change-Id: Id6ac5031aff1a63ff4bac916a4f3ab6d9d6b97ba
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3686210
Auto-Submit: Liu Yu <liuyu@loongson.cn>
Reviewed-by: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Commit-Queue: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Cr-Commit-Position: refs/heads/main@{#80910}
This commit is contained in:
parent
d173de8953
commit
2b6cbda0b4
@ -167,7 +167,8 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
|
|||||||
Assembler::Assembler(const AssemblerOptions& options,
|
Assembler::Assembler(const AssemblerOptions& options,
|
||||||
std::unique_ptr<AssemblerBuffer> buffer)
|
std::unique_ptr<AssemblerBuffer> buffer)
|
||||||
: AssemblerBase(options, std::move(buffer)),
|
: AssemblerBase(options, std::move(buffer)),
|
||||||
scratch_register_list_({t7, t6}) {
|
scratch_register_list_({t7, t6}),
|
||||||
|
scratch_fpregister_list_({f31}) {
|
||||||
reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
|
reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
|
||||||
|
|
||||||
last_trampoline_pool_end_ = 0;
|
last_trampoline_pool_end_ = 0;
|
||||||
@ -2353,10 +2354,13 @@ void Assembler::set_target_value_at(Address pc, uint64_t target,
|
|||||||
|
|
||||||
UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler)
|
UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler)
|
||||||
: available_(assembler->GetScratchRegisterList()),
|
: available_(assembler->GetScratchRegisterList()),
|
||||||
old_available_(*available_) {}
|
availablefp_(assembler->GetScratchFPRegisterList()),
|
||||||
|
old_available_(*available_),
|
||||||
|
old_availablefp_(*availablefp_) {}
|
||||||
|
|
||||||
UseScratchRegisterScope::~UseScratchRegisterScope() {
|
UseScratchRegisterScope::~UseScratchRegisterScope() {
|
||||||
*available_ = old_available_;
|
*available_ = old_available_;
|
||||||
|
*availablefp_ = old_availablefp_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Register UseScratchRegisterScope::Acquire() {
|
Register UseScratchRegisterScope::Acquire() {
|
||||||
@ -2364,10 +2368,19 @@ Register UseScratchRegisterScope::Acquire() {
|
|||||||
return available_->PopFirst();
|
return available_->PopFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DoubleRegister UseScratchRegisterScope::AcquireFp() {
|
||||||
|
DCHECK_NOT_NULL(availablefp_);
|
||||||
|
return availablefp_->PopFirst();
|
||||||
|
}
|
||||||
|
|
||||||
bool UseScratchRegisterScope::hasAvailable() const {
|
bool UseScratchRegisterScope::hasAvailable() const {
|
||||||
return !available_->is_empty();
|
return !available_->is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UseScratchRegisterScope::hasAvailableFp() const {
|
||||||
|
return !availablefp_->is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
|
||||||
|
@ -277,6 +277,10 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
|||||||
|
|
||||||
RegList* GetScratchRegisterList() { return &scratch_register_list_; }
|
RegList* GetScratchRegisterList() { return &scratch_register_list_; }
|
||||||
|
|
||||||
|
DoubleRegList* GetScratchFPRegisterList() {
|
||||||
|
return &scratch_fpregister_list_;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Code generation.
|
// Code generation.
|
||||||
|
|
||||||
@ -1065,6 +1069,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
|||||||
|
|
||||||
RegList scratch_register_list_;
|
RegList scratch_register_list_;
|
||||||
|
|
||||||
|
DoubleRegList scratch_fpregister_list_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
|
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
|
||||||
|
|
||||||
@ -1087,22 +1093,38 @@ class V8_EXPORT_PRIVATE V8_NODISCARD UseScratchRegisterScope {
|
|||||||
~UseScratchRegisterScope();
|
~UseScratchRegisterScope();
|
||||||
|
|
||||||
Register Acquire();
|
Register Acquire();
|
||||||
|
DoubleRegister AcquireFp();
|
||||||
bool hasAvailable() const;
|
bool hasAvailable() const;
|
||||||
|
bool hasAvailableFp() const;
|
||||||
|
|
||||||
void Include(const RegList& list) { *available_ |= list; }
|
void Include(const RegList& list) { *available_ |= list; }
|
||||||
|
void IncludeFp(const DoubleRegList& list) { *availablefp_ |= list; }
|
||||||
void Exclude(const RegList& list) { available_->clear(list); }
|
void Exclude(const RegList& list) { available_->clear(list); }
|
||||||
|
void ExcludeFp(const DoubleRegList& list) { availablefp_->clear(list); }
|
||||||
void Include(const Register& reg1, const Register& reg2 = no_reg) {
|
void Include(const Register& reg1, const Register& reg2 = no_reg) {
|
||||||
RegList list({reg1, reg2});
|
RegList list({reg1, reg2});
|
||||||
Include(list);
|
Include(list);
|
||||||
}
|
}
|
||||||
|
void IncludeFp(const DoubleRegister& reg1,
|
||||||
|
const DoubleRegister& reg2 = no_dreg) {
|
||||||
|
DoubleRegList list({reg1, reg2});
|
||||||
|
IncludeFp(list);
|
||||||
|
}
|
||||||
void Exclude(const Register& reg1, const Register& reg2 = no_reg) {
|
void Exclude(const Register& reg1, const Register& reg2 = no_reg) {
|
||||||
RegList list({reg1, reg2});
|
RegList list({reg1, reg2});
|
||||||
Exclude(list);
|
Exclude(list);
|
||||||
}
|
}
|
||||||
|
void ExcludeFp(const DoubleRegister& reg1,
|
||||||
|
const DoubleRegister& reg2 = no_dreg) {
|
||||||
|
DoubleRegList list({reg1, reg2});
|
||||||
|
ExcludeFp(list);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RegList* available_;
|
RegList* available_;
|
||||||
|
DoubleRegList* availablefp_;
|
||||||
RegList old_available_;
|
RegList old_available_;
|
||||||
|
DoubleRegList old_availablefp_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -1083,6 +1083,19 @@ void TurboAssembler::GenerateSwitchTable(Register index, size_t case_count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MoveCycleState {
|
||||||
|
// List of scratch registers reserved for pending moves in a move cycle, and
|
||||||
|
// which should therefore not be used as a temporary location by
|
||||||
|
// {MoveToTempLocation}.
|
||||||
|
RegList scratch_regs;
|
||||||
|
DoubleRegList scratch_fpregs;
|
||||||
|
// Available scratch registers during the move cycle resolution scope.
|
||||||
|
base::Optional<UseScratchRegisterScope> temps;
|
||||||
|
// Scratch register picked by {MoveToTempLocation}.
|
||||||
|
base::Optional<Register> scratch_reg;
|
||||||
|
base::Optional<DoubleRegister> scratch_fpreg;
|
||||||
|
};
|
||||||
|
|
||||||
#define ACCESS_MASM(masm) masm->
|
#define ACCESS_MASM(masm) masm->
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -151,8 +151,7 @@ constexpr Register cp = s7;
|
|||||||
constexpr Register kScratchReg = s3;
|
constexpr Register kScratchReg = s3;
|
||||||
constexpr Register kScratchReg2 = s4;
|
constexpr Register kScratchReg2 = s4;
|
||||||
constexpr DoubleRegister kScratchDoubleReg = f30;
|
constexpr DoubleRegister kScratchDoubleReg = f30;
|
||||||
constexpr DoubleRegister kScratchDoubleReg1 = f30;
|
constexpr DoubleRegister kScratchDoubleReg1 = f31;
|
||||||
constexpr DoubleRegister kScratchDoubleReg2 = f31;
|
|
||||||
// FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0.
|
// FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0.
|
||||||
constexpr DoubleRegister kDoubleRegZero = f29;
|
constexpr DoubleRegister kDoubleRegZero = f29;
|
||||||
|
|
||||||
|
@ -1290,6 +1290,17 @@ void TurboAssembler::GenerateSwitchTable(Register index, size_t case_count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MoveCycleState {
|
||||||
|
// List of scratch registers reserved for pending moves in a move cycle, and
|
||||||
|
// which should therefore not be used as a temporary location by
|
||||||
|
// {MoveToTempLocation}.
|
||||||
|
RegList scratch_regs;
|
||||||
|
// Available scratch registers during the move cycle resolution scope.
|
||||||
|
base::Optional<UseScratchRegisterScope> temps;
|
||||||
|
// Scratch register picked by {MoveToTempLocation}.
|
||||||
|
base::Optional<Register> scratch_reg;
|
||||||
|
};
|
||||||
|
|
||||||
#define ACCESS_MASM(masm) masm->
|
#define ACCESS_MASM(masm) masm->
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "src/codegen/assembler-inl.h"
|
#include "src/codegen/assembler-inl.h"
|
||||||
#include "src/codegen/callable.h"
|
#include "src/codegen/callable.h"
|
||||||
#include "src/codegen/loong64/constants-loong64.h"
|
#include "src/codegen/loong64/constants-loong64.h"
|
||||||
|
#include "src/codegen/machine-type.h"
|
||||||
#include "src/codegen/macro-assembler.h"
|
#include "src/codegen/macro-assembler.h"
|
||||||
#include "src/codegen/optimized-compilation-info.h"
|
#include "src/codegen/optimized-compilation-info.h"
|
||||||
#include "src/compiler/backend/code-generator-impl.h"
|
#include "src/compiler/backend/code-generator-impl.h"
|
||||||
@ -2407,6 +2408,156 @@ void CodeGenerator::FinishCode() {}
|
|||||||
void CodeGenerator::PrepareForDeoptimizationExits(
|
void CodeGenerator::PrepareForDeoptimizationExits(
|
||||||
ZoneDeque<DeoptimizationExit*>* exits) {}
|
ZoneDeque<DeoptimizationExit*>* exits) {}
|
||||||
|
|
||||||
|
void CodeGenerator::MoveToTempLocation(InstructionOperand* source) {
|
||||||
|
// Must be kept in sync with {MoveTempLocationTo}.
|
||||||
|
DCHECK(!source->IsImmediate());
|
||||||
|
auto rep = LocationOperand::cast(source)->representation();
|
||||||
|
move_cycle_.temps.emplace(tasm());
|
||||||
|
auto& temps = *move_cycle_.temps;
|
||||||
|
// Temporarily exclude the reserved scratch registers while we pick one to
|
||||||
|
// resolve the move cycle. Re-include them immediately afterwards as they
|
||||||
|
// might be needed for the move to the temp location.
|
||||||
|
temps.Exclude(move_cycle_.scratch_regs);
|
||||||
|
temps.ExcludeFp(move_cycle_.scratch_fpregs);
|
||||||
|
if (!IsFloatingPoint(rep)) {
|
||||||
|
if (temps.hasAvailable()) {
|
||||||
|
Register scratch = move_cycle_.temps->Acquire();
|
||||||
|
move_cycle_.scratch_reg.emplace(scratch);
|
||||||
|
} else if (temps.hasAvailableFp()) {
|
||||||
|
// Try to use an FP register if no GP register is available for non-FP
|
||||||
|
// moves.
|
||||||
|
FPURegister scratch = move_cycle_.temps->AcquireFp();
|
||||||
|
move_cycle_.scratch_fpreg.emplace(scratch);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DCHECK(temps.hasAvailableFp());
|
||||||
|
FPURegister scratch = move_cycle_.temps->AcquireFp();
|
||||||
|
move_cycle_.scratch_fpreg.emplace(scratch);
|
||||||
|
}
|
||||||
|
temps.Include(move_cycle_.scratch_regs);
|
||||||
|
temps.IncludeFp(move_cycle_.scratch_fpregs);
|
||||||
|
if (move_cycle_.scratch_reg.has_value()) {
|
||||||
|
// A scratch register is available for this rep.
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_reg->code());
|
||||||
|
AssembleMove(source, &scratch);
|
||||||
|
} else if (move_cycle_.scratch_fpreg.has_value()) {
|
||||||
|
// A scratch fp register is available for this rep.
|
||||||
|
if (!IsFloatingPoint(rep)) {
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_fpreg->code());
|
||||||
|
Loong64OperandConverter g(this, nullptr);
|
||||||
|
if (source->IsStackSlot()) {
|
||||||
|
__ Fld_d(g.ToDoubleRegister(&scratch), g.ToMemOperand(source));
|
||||||
|
} else {
|
||||||
|
DCHECK(source->IsRegister());
|
||||||
|
__ movgr2fr_d(g.ToDoubleRegister(&scratch), g.ToRegister(source));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_fpreg->code());
|
||||||
|
AssembleMove(source, &scratch);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The scratch registers are blocked by pending moves. Use the stack
|
||||||
|
// instead.
|
||||||
|
int new_slots = ElementSizeInPointers(rep);
|
||||||
|
Loong64OperandConverter g(this, nullptr);
|
||||||
|
if (source->IsRegister()) {
|
||||||
|
__ Push(g.ToRegister(source));
|
||||||
|
} else if (source->IsStackSlot()) {
|
||||||
|
UseScratchRegisterScope temps2(tasm());
|
||||||
|
Register scratch = temps2.Acquire();
|
||||||
|
__ Ld_d(scratch, g.ToMemOperand(source));
|
||||||
|
__ Push(scratch);
|
||||||
|
} else {
|
||||||
|
// No push instruction for this operand type. Bump the stack pointer and
|
||||||
|
// assemble the move.
|
||||||
|
int last_frame_slot_id =
|
||||||
|
frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
|
||||||
|
int sp_delta = frame_access_state_->sp_delta();
|
||||||
|
int temp_slot = last_frame_slot_id + sp_delta + new_slots;
|
||||||
|
__ Sub_d(sp, sp, Operand(new_slots * kSystemPointerSize));
|
||||||
|
AllocatedOperand temp(LocationOperand::STACK_SLOT, rep, temp_slot);
|
||||||
|
AssembleMove(source, &temp);
|
||||||
|
}
|
||||||
|
frame_access_state()->IncreaseSPDelta(new_slots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::MoveTempLocationTo(InstructionOperand* dest,
|
||||||
|
MachineRepresentation rep) {
|
||||||
|
if (move_cycle_.scratch_reg.has_value()) {
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_reg->code());
|
||||||
|
AssembleMove(&scratch, dest);
|
||||||
|
} else if (move_cycle_.scratch_fpreg.has_value()) {
|
||||||
|
if (!IsFloatingPoint(rep)) {
|
||||||
|
// We used a DoubleRegister to move a non-FP operand, change the
|
||||||
|
// representation to correctly interpret the InstructionOperand's code.
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER,
|
||||||
|
MachineRepresentation::kFloat64,
|
||||||
|
move_cycle_.scratch_fpreg->code());
|
||||||
|
Loong64OperandConverter g(this, nullptr);
|
||||||
|
if (dest->IsStackSlot()) {
|
||||||
|
__ Fst_d(g.ToDoubleRegister(&scratch), g.ToMemOperand(dest));
|
||||||
|
} else {
|
||||||
|
DCHECK(dest->IsRegister());
|
||||||
|
__ movfr2gr_d(g.ToRegister(dest), g.ToDoubleRegister(&scratch));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_fpreg->code());
|
||||||
|
AssembleMove(&scratch, dest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int new_slots = ElementSizeInPointers(rep);
|
||||||
|
frame_access_state()->IncreaseSPDelta(-new_slots);
|
||||||
|
Loong64OperandConverter g(this, nullptr);
|
||||||
|
if (dest->IsRegister()) {
|
||||||
|
__ Pop(g.ToRegister(dest));
|
||||||
|
} else if (dest->IsStackSlot()) {
|
||||||
|
UseScratchRegisterScope temps2(tasm());
|
||||||
|
Register scratch = temps2.Acquire();
|
||||||
|
__ Pop(scratch);
|
||||||
|
__ St_d(scratch, g.ToMemOperand(dest));
|
||||||
|
} else {
|
||||||
|
int last_frame_slot_id =
|
||||||
|
frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
|
||||||
|
int sp_delta = frame_access_state_->sp_delta();
|
||||||
|
int temp_slot = last_frame_slot_id + sp_delta + new_slots;
|
||||||
|
AllocatedOperand temp(LocationOperand::STACK_SLOT, rep, temp_slot);
|
||||||
|
AssembleMove(&temp, dest);
|
||||||
|
__ Add_d(sp, sp, Operand(new_slots * kSystemPointerSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Restore the default state to release the {UseScratchRegisterScope} and to
|
||||||
|
// prepare for the next cycle.
|
||||||
|
move_cycle_ = MoveCycleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::SetPendingMove(MoveOperands* move) {
|
||||||
|
InstructionOperand* src = &move->source();
|
||||||
|
InstructionOperand* dst = &move->destination();
|
||||||
|
UseScratchRegisterScope temps(tasm());
|
||||||
|
if (src->IsConstant() || (src->IsStackSlot() && dst->IsStackSlot())) {
|
||||||
|
Register temp = temps.Acquire();
|
||||||
|
move_cycle_.scratch_regs.set(temp);
|
||||||
|
}
|
||||||
|
if (src->IsAnyStackSlot() || dst->IsAnyStackSlot()) {
|
||||||
|
Loong64OperandConverter g(this, nullptr);
|
||||||
|
MemOperand src_mem = g.ToMemOperand(src);
|
||||||
|
MemOperand dst_mem = g.ToMemOperand(dst);
|
||||||
|
if (((!is_int16(src_mem.offset()) || (src_mem.offset() & 0b11) != 0) &&
|
||||||
|
(!is_int12(src_mem.offset()) && !src_mem.hasIndexReg())) ||
|
||||||
|
((!is_int16(dst_mem.offset()) || (dst_mem.offset() & 0b11) != 0) &&
|
||||||
|
(!is_int12(dst_mem.offset()) && dst_mem.hasIndexReg()))) {
|
||||||
|
Register temp = temps.Acquire();
|
||||||
|
move_cycle_.scratch_regs.set(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenerator::AssembleMove(InstructionOperand* source,
|
void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||||
InstructionOperand* destination) {
|
InstructionOperand* destination) {
|
||||||
Loong64OperandConverter g(this, nullptr);
|
Loong64OperandConverter g(this, nullptr);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "src/codegen/assembler-inl.h"
|
#include "src/codegen/assembler-inl.h"
|
||||||
#include "src/codegen/callable.h"
|
#include "src/codegen/callable.h"
|
||||||
|
#include "src/codegen/machine-type.h"
|
||||||
#include "src/codegen/macro-assembler.h"
|
#include "src/codegen/macro-assembler.h"
|
||||||
#include "src/codegen/mips64/constants-mips64.h"
|
#include "src/codegen/mips64/constants-mips64.h"
|
||||||
#include "src/codegen/optimized-compilation-info.h"
|
#include "src/codegen/optimized-compilation-info.h"
|
||||||
@ -4351,6 +4352,112 @@ void CodeGenerator::FinishCode() {}
|
|||||||
void CodeGenerator::PrepareForDeoptimizationExits(
|
void CodeGenerator::PrepareForDeoptimizationExits(
|
||||||
ZoneDeque<DeoptimizationExit*>* exits) {}
|
ZoneDeque<DeoptimizationExit*>* exits) {}
|
||||||
|
|
||||||
|
void CodeGenerator::MoveToTempLocation(InstructionOperand* source) {
|
||||||
|
// Must be kept in sync with {MoveTempLocationTo}.
|
||||||
|
DCHECK(!source->IsImmediate());
|
||||||
|
auto rep = LocationOperand::cast(source)->representation();
|
||||||
|
move_cycle_.temps.emplace(tasm());
|
||||||
|
auto& temps = *move_cycle_.temps;
|
||||||
|
// Temporarily exclude the reserved scratch registers while we pick one to
|
||||||
|
// resolve the move cycle. Re-include them immediately afterwards as they
|
||||||
|
// might be needed for the move to the temp location.
|
||||||
|
temps.Exclude(move_cycle_.scratch_regs);
|
||||||
|
if (!IsFloatingPoint(rep)) {
|
||||||
|
if (temps.hasAvailable()) {
|
||||||
|
Register scratch = move_cycle_.temps->Acquire();
|
||||||
|
move_cycle_.scratch_reg.emplace(scratch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
temps.Include(move_cycle_.scratch_regs);
|
||||||
|
|
||||||
|
if (move_cycle_.scratch_reg.has_value()) {
|
||||||
|
// A scratch register is available for this rep.
|
||||||
|
// auto& scratch_reg = *move_cycle_.scratch_reg;
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_reg->code());
|
||||||
|
AssembleMove(source, &scratch);
|
||||||
|
} else {
|
||||||
|
// The scratch registers are blocked by pending moves. Use the stack
|
||||||
|
// instead.
|
||||||
|
int new_slots = ElementSizeInPointers(rep);
|
||||||
|
MipsOperandConverter g(this, nullptr);
|
||||||
|
if (source->IsRegister()) {
|
||||||
|
__ Push(g.ToRegister(source));
|
||||||
|
} else if (source->IsStackSlot()) {
|
||||||
|
UseScratchRegisterScope temps2(tasm());
|
||||||
|
Register scratch = temps2.Acquire();
|
||||||
|
__ Ld(scratch, g.ToMemOperand(source));
|
||||||
|
__ Push(scratch);
|
||||||
|
} else {
|
||||||
|
// No push instruction for this operand type. Bump the stack pointer and
|
||||||
|
// assemble the move.
|
||||||
|
int last_frame_slot_id =
|
||||||
|
frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
|
||||||
|
int sp_delta = frame_access_state_->sp_delta();
|
||||||
|
int temp_slot = last_frame_slot_id + sp_delta + new_slots;
|
||||||
|
__ Dsubu(sp, sp, Operand(new_slots * kSystemPointerSize));
|
||||||
|
AllocatedOperand temp(LocationOperand::STACK_SLOT, rep, temp_slot);
|
||||||
|
AssembleMove(source, &temp);
|
||||||
|
}
|
||||||
|
frame_access_state()->IncreaseSPDelta(new_slots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::MoveTempLocationTo(InstructionOperand* dest,
|
||||||
|
MachineRepresentation rep) {
|
||||||
|
if (move_cycle_.scratch_reg.has_value()) {
|
||||||
|
// auto& scratch_reg = *move_cycle_.scratch_reg;
|
||||||
|
AllocatedOperand scratch(LocationOperand::REGISTER, rep,
|
||||||
|
move_cycle_.scratch_reg->code());
|
||||||
|
AssembleMove(&scratch, dest);
|
||||||
|
} else {
|
||||||
|
int new_slots = ElementSizeInPointers(rep);
|
||||||
|
frame_access_state()->IncreaseSPDelta(-new_slots);
|
||||||
|
MipsOperandConverter g(this, nullptr);
|
||||||
|
if (dest->IsRegister()) {
|
||||||
|
__ Pop(g.ToRegister(dest));
|
||||||
|
} else if (dest->IsStackSlot()) {
|
||||||
|
UseScratchRegisterScope temps2(tasm());
|
||||||
|
Register scratch = temps2.Acquire();
|
||||||
|
__ Pop(scratch);
|
||||||
|
__ Sd(scratch, g.ToMemOperand(dest));
|
||||||
|
} else {
|
||||||
|
int last_frame_slot_id =
|
||||||
|
frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
|
||||||
|
int sp_delta = frame_access_state_->sp_delta();
|
||||||
|
int temp_slot = last_frame_slot_id + sp_delta + new_slots;
|
||||||
|
AllocatedOperand temp(LocationOperand::STACK_SLOT, rep, temp_slot);
|
||||||
|
AssembleMove(&temp, dest);
|
||||||
|
__ Daddu(sp, sp, Operand(new_slots * kSystemPointerSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Restore the default state to release the {UseScratchRegisterScope} and to
|
||||||
|
// prepare for the next cycle.
|
||||||
|
move_cycle_ = MoveCycleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::SetPendingMove(MoveOperands* move) {
|
||||||
|
InstructionOperand* src = &move->source();
|
||||||
|
InstructionOperand* dst = &move->destination();
|
||||||
|
UseScratchRegisterScope temps(tasm());
|
||||||
|
if (src->IsConstant() && dst->IsFPLocationOperand()) {
|
||||||
|
MipsOperandConverter g(this, nullptr);
|
||||||
|
MemOperand src_mem = g.ToMemOperand(src);
|
||||||
|
MemOperand dst_mem = g.ToMemOperand(dst);
|
||||||
|
if (((!is_int16(src_mem.offset())) || (((src_mem.offset() & 0b111) != 0) &&
|
||||||
|
!is_int16(src_mem.offset() + 4))) ||
|
||||||
|
((!is_int16(dst_mem.offset())) || (((dst_mem.offset() & 0b111) != 0) &&
|
||||||
|
!is_int16(dst_mem.offset() + 4)))) {
|
||||||
|
Register temp = temps.Acquire();
|
||||||
|
move_cycle_.scratch_regs.set(temp);
|
||||||
|
}
|
||||||
|
} else if (src->IsAnyStackSlot() || dst->IsAnyStackSlot()) {
|
||||||
|
Register temp = temps.Acquire();
|
||||||
|
move_cycle_.scratch_regs.set(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenerator::AssembleMove(InstructionOperand* source,
|
void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||||
InstructionOperand* destination) {
|
InstructionOperand* destination) {
|
||||||
MipsOperandConverter g(this, nullptr);
|
MipsOperandConverter g(this, nullptr);
|
||||||
|
Loading…
Reference in New Issue
Block a user