diff --git a/src/wasm/baseline/liftoff-assembler.cc b/src/wasm/baseline/liftoff-assembler.cc index 47bc88f082..915e127572 100644 --- a/src/wasm/baseline/liftoff-assembler.cc +++ b/src/wasm/baseline/liftoff-assembler.cc @@ -16,10 +16,7 @@ namespace v8 { namespace internal { namespace wasm { -// Note: "State" suffix added to avoid jumbo conflicts with liftoff-compiler.cc -constexpr auto kRegisterState = LiftoffAssembler::VarState::kRegister; -constexpr auto kConstantState = LiftoffAssembler::VarState::kConstant; -constexpr auto kStackState = LiftoffAssembler::VarState::kStack; +using VarState = LiftoffAssembler::VarState; namespace { @@ -118,41 +115,41 @@ class StackTransferRecipe { void TransferStackSlot(const LiftoffAssembler::CacheState& dst_state, uint32_t dst_index, uint32_t src_index) { - const LiftoffAssembler::VarState& dst = dst_state.stack_state[dst_index]; - const LiftoffAssembler::VarState& src = - __ cache_state()->stack_state[src_index]; - switch (dst.loc) { - case kConstantState: - DCHECK_EQ(dst, src); - break; - case kRegisterState: - switch (src.loc) { - case kConstantState: - LoadConstant(dst.reg, WasmValue(src.i32_const)); - break; - case kRegisterState: - if (dst.reg != src.reg) MoveRegister(dst.reg, src.reg); - break; - case kStackState: - LoadStackSlot(dst.reg, src_index); - break; - } - break; - case kStackState: - switch (src.loc) { - case kConstantState: - // TODO(clemensh): Handle other types than i32. - asm_->Spill(dst_index, WasmValue(src.i32_const)); - break; - case kRegisterState: - asm_->Spill(dst_index, src.reg); - break; - case kStackState: + const VarState& dst = dst_state.stack_state[dst_index]; + const VarState& src = __ cache_state()->stack_state[src_index]; + switch (dst.loc()) { + case VarState::kStack: + switch (src.loc()) { + case VarState::kStack: if (src_index == dst_index) break; // TODO(clemensh): Implement other types than i32. asm_->MoveStackValue(dst_index, src_index, wasm::kWasmI32); break; + case VarState::kRegister: + asm_->Spill(dst_index, src.reg()); + break; + case VarState::kConstant: + // TODO(clemensh): Handle other types than i32. + asm_->Spill(dst_index, WasmValue(src.i32_const())); + break; } + break; + case VarState::kRegister: + switch (src.loc()) { + case VarState::kStack: + LoadStackSlot(dst.reg(), src_index); + break; + case VarState::kRegister: + if (dst.reg() != src.reg()) MoveRegister(dst.reg(), src.reg()); + break; + case VarState::kConstant: + LoadConstant(dst.reg(), WasmValue(src.i32_const())); + break; + } + break; + case VarState::kConstant: + DCHECK_EQ(dst, src); + break; } } @@ -204,8 +201,8 @@ void LiftoffAssembler::CacheState::InitMerge(const CacheState& source, auto& dst = stack_state[dst_idx]; auto& src = source.stack_state[src_idx]; Register reg = no_reg; - if (src.is_reg() && is_free(src.reg)) { - reg = src.reg; + if (src.is_reg() && is_free(src.reg())) { + reg = src.reg(); } else if (has_unused_register()) { reg = unused_register(); } else { @@ -225,13 +222,13 @@ void LiftoffAssembler::CacheState::InitMerge(const CacheState& source, auto& dst = stack_state[i]; auto& src = source.stack_state[i]; if (src.is_reg()) { - if (is_used(src.reg)) { + if (is_used(src.reg())) { // Keep this a stack slot (which is the initial value). DCHECK(dst.is_stack()); continue; } - dst = VarState(src.reg); - inc_used(src.reg); + dst = VarState(src.reg()); + inc_used(src.reg()); } else if (src.is_const()) { dst = src; } else { @@ -272,12 +269,12 @@ LiftoffAssembler::~LiftoffAssembler() { Register LiftoffAssembler::GetBinaryOpTargetRegister( ValueType type, PinnedRegisterScope pinned_regs) { auto& slot_lhs = *(cache_state_.stack_state.end() - 2); - if (slot_lhs.loc == kRegisterState && GetNumUses(slot_lhs.reg) == 1) { - return slot_lhs.reg; + if (slot_lhs.is_reg() && GetNumUses(slot_lhs.reg()) == 1) { + return slot_lhs.reg(); } auto& slot_rhs = *(cache_state_.stack_state.end() - 1); - if (slot_rhs.loc == kRegisterState && GetNumUses(slot_rhs.reg) == 1) { - return slot_rhs.reg; + if (slot_rhs.is_reg() && GetNumUses(slot_rhs.reg()) == 1) { + return slot_rhs.reg(); } return GetUnusedRegister(type, pinned_regs); } @@ -313,18 +310,18 @@ void LiftoffAssembler::MergeStackWith(CacheState& target, uint32_t arity) { void LiftoffAssembler::Spill(uint32_t index) { auto& slot = cache_state_.stack_state[index]; - switch (slot.loc) { - case kRegisterState: - Spill(index, slot.reg); - cache_state_.dec_used(slot.reg); - break; - case kConstantState: - Spill(index, WasmValue(slot.i32_const)); - break; - case kStackState: + switch (slot.loc()) { + case VarState::kStack: return; + case VarState::kRegister: + Spill(index, slot.reg()); + cache_state_.dec_used(slot.reg()); + break; + case VarState::kConstant: + Spill(index, WasmValue(slot.i32_const())); + break; } - slot.loc = kStackState; + slot.MakeStack(); } void LiftoffAssembler::SpillLocals() { @@ -338,20 +335,20 @@ Register LiftoffAssembler::PopToRegister(ValueType type, DCHECK(!cache_state_.stack_state.empty()); VarState slot = cache_state_.stack_state.back(); cache_state_.stack_state.pop_back(); - switch (slot.loc) { - case kRegisterState: - cache_state_.dec_used(slot.reg); - return slot.reg; - case kConstantState: { - Register reg = GetUnusedRegister(type, pinned_regs); - LoadConstant(reg, WasmValue(slot.i32_const)); - return reg; - } - case kStackState: { + switch (slot.loc()) { + case VarState::kStack: { Register reg = GetUnusedRegister(type, pinned_regs); Fill(reg, cache_state_.stack_height()); return reg; } + case VarState::kRegister: + cache_state_.dec_used(slot.reg()); + return slot.reg(); + case VarState::kConstant: { + Register reg = GetUnusedRegister(type, pinned_regs); + LoadConstant(reg, WasmValue(slot.i32_const())); + return reg; + } } UNREACHABLE(); } @@ -367,9 +364,9 @@ Register LiftoffAssembler::SpillRegister(ValueType type, for (uint32_t idx = cache_state_.stack_height() - 1;; --idx) { DCHECK_GT(cache_state_.stack_height(), idx); auto& slot = cache_state_.stack_state[idx]; - if (!slot.is_reg() || slot.reg != spill_reg) continue; + if (!slot.is_reg() || slot.reg() != spill_reg) continue; Spill(idx, spill_reg); - slot.loc = kStackState; + slot.MakeStack(); if (--remaining_uses == 0) break; } cache_state_.register_use_count[spill_reg.code()] = 0; diff --git a/src/wasm/baseline/liftoff-assembler.h b/src/wasm/baseline/liftoff-assembler.h index 93798aa6c4..20c8433acf 100644 --- a/src/wasm/baseline/liftoff-assembler.h +++ b/src/wasm/baseline/liftoff-assembler.h @@ -76,36 +76,54 @@ class LiftoffAssembler : public TurboAssembler { Register GetBinaryOpTargetRegister(ValueType, PinnedRegisterScope = {}); - struct VarState { - enum Location { kStack, kRegister, kConstant }; - Location loc; + class VarState { + public: + enum Location : uint8_t { kStack, kRegister, kConstant }; - union { - Register reg; - uint32_t i32_const; - }; - VarState() : loc(kStack) {} - explicit VarState(Register r) : loc(kRegister), reg(r) {} - explicit VarState(uint32_t value) : loc(kConstant), i32_const(value) {} + VarState() : loc_(kStack) {} + explicit VarState(Register r) : loc_(kRegister), reg_(r) {} + explicit VarState(uint32_t i32_const) + : loc_(kConstant), i32_const_(i32_const) {} bool operator==(const VarState& other) const { - if (loc != other.loc) return false; - switch (loc) { - case kRegister: - return reg == other.reg; + if (loc_ != other.loc_) return false; + switch (loc_) { case kStack: return true; + case kRegister: + return reg_ == other.reg_; case kConstant: - return i32_const == other.i32_const; + return i32_const_ == other.i32_const_; } UNREACHABLE(); } - bool is_stack() const { return loc == kStack; } - bool is_reg() const { return loc == kRegister; } - bool is_const() const { return loc == kConstant; } - }; + bool is_stack() const { return loc_ == kStack; } + bool is_reg() const { return loc_ == kRegister; } + bool is_const() const { return loc_ == kConstant; } + Location loc() const { return loc_; } + + uint32_t i32_const() const { + DCHECK_EQ(loc_, kConstant); + return i32_const_; + } + + Register reg() const { + DCHECK_EQ(loc_, kRegister); + return reg_; + } + + void MakeStack() { loc_ = kStack; } + + private: + Location loc_; + + union { + Register reg_; // used if loc_ == kRegister + uint32_t i32_const_; // used if loc_ == kConstant + }; + }; static_assert(IS_TRIVIALLY_COPYABLE(VarState), "VarState should be trivially copyable"); @@ -216,11 +234,11 @@ class LiftoffAssembler : public TurboAssembler { void DropStackSlot(VarState* slot) { // The only loc we care about is register. Other types don't occupy // anything. - if (slot->loc != VarState::kRegister) return; + if (!slot->is_reg()) return; // Free the register, then set the loc to "stack". // No need to write back, the value should be dropped. - cache_state_.dec_used(slot->reg); - slot->loc = VarState::kStack; + cache_state_.dec_used(slot->reg()); + slot->MakeStack(); } void MergeFullStackWith(CacheState&); diff --git a/src/wasm/baseline/liftoff-compiler.cc b/src/wasm/baseline/liftoff-compiler.cc index 71bf74ea52..f38b6dabad 100644 --- a/src/wasm/baseline/liftoff-compiler.cc +++ b/src/wasm/baseline/liftoff-compiler.cc @@ -308,12 +308,12 @@ class LiftoffCompiler { void GetLocal(Decoder* decoder, Value* result, const LocalIndexOperand& operand) { auto& slot = __ cache_state()->stack_state[operand.index]; - switch (slot.loc) { + switch (slot.loc()) { case kRegister: - __ PushRegister(slot.reg); + __ PushRegister(slot.reg()); break; case kConstant: - __ cache_state()->stack_state.emplace_back(slot.i32_const); + __ cache_state()->stack_state.emplace_back(slot.i32_const()); break; case kStack: { Register reg = __ GetUnusedRegister(__ local_type(operand.index)); @@ -328,24 +328,24 @@ class LiftoffCompiler { auto& state = *__ cache_state(); auto& source_slot = state.stack_state.back(); auto& target_slot = state.stack_state[local_index]; - switch (source_slot.loc) { + switch (source_slot.loc()) { case kRegister: __ DropStackSlot(&target_slot); target_slot = source_slot; - if (is_tee) state.inc_used(target_slot.reg); + if (is_tee) state.inc_used(target_slot.reg()); break; case kConstant: __ DropStackSlot(&target_slot); target_slot = source_slot; break; case kStack: { - switch (target_slot.loc) { + switch (target_slot.loc()) { case kRegister: - if (state.register_use_count[target_slot.reg.code()] == 1) { - __ Fill(target_slot.reg, state.stack_height() - 1); + if (state.register_use_count[target_slot.reg().code()] == 1) { + __ Fill(target_slot.reg(), state.stack_height() - 1); break; } else { - state.dec_used(target_slot.reg); + state.dec_used(target_slot.reg()); // and fall through to use a new register. } case kConstant: