From fca41fa22f2f8ebf61b5cd151efb0164dd2072ac Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Tue, 21 Oct 2025 10:22:01 -0700 Subject: [PATCH] [vm, compiler] Refactor IA32 leaf runtime calls to be more like the other architectures. TEST=ci Change-Id: I2e5902649df3a09c83240ecda26d0f514755e56d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/456101 Reviewed-by: Alexander Markov Commit-Queue: Ryan Macnak --- .../vm/compiler/assembler/assembler_ia32.cc | 88 +++++++++++-------- .../backend/flow_graph_compiler_ia32.cc | 48 +--------- runtime/vm/constants_ia32.h | 5 +- 3 files changed, 55 insertions(+), 86 deletions(-) diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc index 84f9888d5c7..abd267ae29e 100644 --- a/runtime/vm/compiler/assembler/assembler_ia32.cc +++ b/runtime/vm/compiler/assembler/assembler_ia32.cc @@ -1929,11 +1929,54 @@ void Assembler::PopRegister(Register r) { } void Assembler::PushRegisters(const RegisterSet& registers) { - UNIMPLEMENTED(); + const intptr_t xmm_regs_count = registers.FpuRegisterCount(); + if (xmm_regs_count > 0) { + subl(ESP, compiler::Immediate(xmm_regs_count * kFpuRegisterSize)); + // Store XMM registers with the lowest register number at the lowest + // address. + intptr_t offset = 0; + for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) { + XmmRegister xmm_reg = static_cast(i); + if (registers.ContainsFpuRegister(xmm_reg)) { + movups(Address(ESP, offset), xmm_reg); + offset += kFpuRegisterSize; + } + } + ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); + } + + // The order in which the registers are pushed must match the order + // in which the registers are encoded in the safe point's stack map. + for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) { + Register reg = static_cast(i); + if (registers.ContainsRegister(reg)) { + pushl(reg); + } + } } void Assembler::PopRegisters(const RegisterSet& registers) { - UNIMPLEMENTED(); + for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) { + Register reg = static_cast(i); + if (registers.ContainsRegister(reg)) { + popl(reg); + } + } + + const intptr_t xmm_regs_count = registers.FpuRegisterCount(); + if (xmm_regs_count > 0) { + // XMM registers have the lowest register number at the lowest address. + intptr_t offset = 0; + for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) { + XmmRegister xmm_reg = static_cast(i); + if (registers.ContainsFpuRegister(xmm_reg)) { + movups(xmm_reg, Address(ESP, offset)); + offset += kFpuRegisterSize; + } + } + ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); + addl(ESP, compiler::Immediate(offset)); + } } void Assembler::PushRegistersInOrder(std::initializer_list regs) { @@ -2610,9 +2653,8 @@ void Assembler::TransitionNativeToGenerated(Register scratch, compiler::Immediate(0)); } -static constexpr intptr_t kNumberOfVolatileCpuRegisters = 3; -static const Register volatile_cpu_registers[kNumberOfVolatileCpuRegisters] = { - EAX, ECX, EDX}; +static const RegisterSet kRuntimeCallSavedRegisters(kDartVolatileCpuRegs, + kDartVolatileFpuRegs); void Assembler::CallRuntime(const RuntimeEntry& entry, intptr_t argument_count, @@ -2635,21 +2677,7 @@ LeafRuntimeScope::LeafRuntimeScope(Assembler* assembler, __ EnterFrame(0); if (preserve_registers_) { - // Preserve volatile CPU registers. - for (intptr_t i = 0; i < kNumberOfVolatileCpuRegisters; i++) { - __ pushl(volatile_cpu_registers[i]); - } - - // Preserve all XMM registers. - __ subl(ESP, Immediate(kNumberOfXmmRegisters * kFpuRegisterSize)); - // Store XMM registers with the lowest register number at the lowest - // address. - intptr_t offset = 0; - for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { - XmmRegister xmm_reg = static_cast(reg_idx); - __ movups(Address(ESP, offset), xmm_reg); - offset += kFpuRegisterSize; - } + __ PushRegisters(kRuntimeCallSavedRegisters); } else { // These registers must always be preserved. COMPILE_ASSERT(IsCalleeSavedRegister(THR)); @@ -2674,25 +2702,9 @@ LeafRuntimeScope::~LeafRuntimeScope() { // ESP might have been modified to reserve space for arguments // and ensure proper alignment of the stack frame. // We need to restore it before restoring registers. - const intptr_t kPushedRegistersSize = - kNumberOfVolatileCpuRegisters * target::kWordSize + - kNumberOfXmmRegisters * kFpuRegisterSize; - __ leal(ESP, Address(EBP, -kPushedRegistersSize)); + __ leal(ESP, Address(EBP, -kRuntimeCallSavedRegisters.SpillSize())); - // Restore all XMM registers. - // XMM registers have the lowest register number at the lowest address. - intptr_t offset = 0; - for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { - XmmRegister xmm_reg = static_cast(reg_idx); - __ movups(xmm_reg, Address(ESP, offset)); - offset += kFpuRegisterSize; - } - __ addl(ESP, Immediate(offset)); - - // Restore volatile CPU registers. - for (intptr_t i = kNumberOfVolatileCpuRegisters - 1; i >= 0; i--) { - __ popl(volatile_cpu_registers[i]); - } + __ PopRegisters(kRuntimeCallSavedRegisters); } __ leave(); diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc index 0e05e3cc1e2..41f1b782fd5 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc @@ -699,56 +699,12 @@ void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { locs->CheckWritableInputs(); ClobberDeadTempRegisters(locs); #endif - // TODO(vegorov): consider saving only caller save (volatile) registers. - const intptr_t xmm_regs_count = locs->live_registers()->FpuRegisterCount(); - if (xmm_regs_count > 0) { - __ subl(ESP, compiler::Immediate(xmm_regs_count * kFpuRegisterSize)); - // Store XMM registers with the lowest register number at the lowest - // address. - intptr_t offset = 0; - for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) { - XmmRegister xmm_reg = static_cast(i); - if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) { - __ movups(compiler::Address(ESP, offset), xmm_reg); - offset += kFpuRegisterSize; - } - } - ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); - } - - // The order in which the registers are pushed must match the order - // in which the registers are encoded in the safe point's stack map. - for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) { - Register reg = static_cast(i); - if (locs->live_registers()->ContainsRegister(reg)) { - __ pushl(reg); - } - } + __ PushRegisters(*locs->live_registers()); } void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { - for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) { - Register reg = static_cast(i); - if (locs->live_registers()->ContainsRegister(reg)) { - __ popl(reg); - } - } - - const intptr_t xmm_regs_count = locs->live_registers()->FpuRegisterCount(); - if (xmm_regs_count > 0) { - // XMM registers have the lowest register number at the lowest address. - intptr_t offset = 0; - for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) { - XmmRegister xmm_reg = static_cast(i); - if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) { - __ movups(xmm_reg, compiler::Address(ESP, offset)); - offset += kFpuRegisterSize; - } - } - ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); - __ addl(ESP, compiler::Immediate(offset)); - } + __ PopRegisters(*locs->live_registers()); } #if defined(DEBUG) diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h index 6a5f993a6a5..c8c31728b9b 100644 --- a/runtime/vm/constants_ia32.h +++ b/runtime/vm/constants_ia32.h @@ -393,11 +393,12 @@ constexpr int kStoreBufferWrapperSize = 11; const RegList kAbiPreservedCpuRegs = (1 << EDI) | (1 << ESI) | (1 << EBX); +const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList; + // Registers available to Dart that are not preserved by runtime calls. const RegList kDartVolatileCpuRegs = kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs; - -const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList; +const RegList kDartVolatileFpuRegs = kAbiVolatileFpuRegs & ~(1 << FpuTMP); #undef R