diff --git a/src/backend_x64/reg_alloc.cpp b/src/backend_x64/reg_alloc.cpp index 5d2c49ab..f2eff0ef 100644 --- a/src/backend_x64/reg_alloc.cpp +++ b/src/backend_x64/reg_alloc.cpp @@ -42,85 +42,20 @@ static Xbyak::Reg HostLocToX64(HostLoc hostloc) { ASSERT_MSG(false, "This should never happen."); } -HostLoc RegAlloc::DefHostLocReg(IR::Inst* def_inst, HostLocList desired_locations) { - DEBUG_ASSERT(std::all_of(desired_locations.begin(), desired_locations.end(), HostLocIsRegister)); - DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined"); - - HostLoc location = SelectARegister(desired_locations); - - if (IsRegisterOccupied(location)) { - SpillRegister(location); - } - - LocInfo(location).Lock(); - LocInfo(location).Def(def_inst); - - DEBUG_ASSERT(LocInfo(location).IsDef()); - return location; -} - void RegAlloc::RegisterAddDef(IR::Inst* def_inst, const IR::Value& use_inst) { DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined"); if (use_inst.IsImmediate()) { - LoadImmediateIntoHostLocReg(use_inst, DefHostLocReg(def_inst, any_gpr)); + HostLoc location = ScratchHostLocReg(any_gpr); + DefineValue(def_inst, location); + LoadImmediateIntoHostLocReg(use_inst, location); return; } + use_inst.GetInst()->DecrementRemainingUses(); DEBUG_ASSERT_MSG(ValueLocation(use_inst.GetInst()), "use_inst must already be defined"); HostLoc location = *ValueLocation(use_inst.GetInst()); - LocInfo(location).AddValue(def_inst); - use_inst.GetInst()->DecrementRemainingUses(); - DEBUG_ASSERT(LocInfo(location).IsIdle()); -} - -HostLoc RegAlloc::UseDefHostLocReg(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations) { - if (!use_value.IsImmediate()) { - return UseDefHostLocReg(use_value.GetInst(), def_inst, desired_locations); - } - - return LoadImmediateIntoHostLocReg(use_value, DefHostLocReg(def_inst, desired_locations)); -} - -HostLoc RegAlloc::UseDefHostLocReg(IR::Inst* use_inst, IR::Inst* def_inst, HostLocList desired_locations) { - DEBUG_ASSERT(std::all_of(desired_locations.begin(), desired_locations.end(), HostLocIsRegister)); - DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined"); - DEBUG_ASSERT_MSG(ValueLocation(use_inst), "use_inst has not been defined"); - - if (IsLastUse(use_inst)) { - HostLoc current_location = *ValueLocation(use_inst); - auto& loc_info = LocInfo(current_location); - if (loc_info.IsIdle()) { - loc_info.Lock(); - loc_info.Def(def_inst); - DEBUG_ASSERT(loc_info.IsUseDef()); - if (HostLocIsSpill(current_location)) { - HostLoc new_location = SelectARegister(desired_locations); - if (IsRegisterOccupied(new_location)) { - SpillRegister(new_location); - } - EmitMove(new_location, current_location); - LocInfo(new_location) = LocInfo(current_location); - LocInfo(current_location) = {}; - return new_location; - } else { - return current_location; - } - } - } - - bool is_floating_point = HostLocIsXMM(*desired_locations.begin()); - if (is_floating_point) { - DEBUG_ASSERT(use_inst->GetType() == IR::Type::F32 || use_inst->GetType() == IR::Type::F64); - } - HostLoc use_reg = UseHostLocReg(use_inst, is_floating_point ? any_xmm : any_gpr); - HostLoc def_reg = DefHostLocReg(def_inst, desired_locations); - if (is_floating_point) { - code->movapd(HostLocToXmm(def_reg), HostLocToXmm(use_reg)); - } else { - code->mov(HostLocToReg64(def_reg), HostLocToReg64(use_reg)); - } - return def_reg; + DefineValue(def_inst, location); } std::tuple RegAlloc::UseDefOpArgHostLocReg(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations) { @@ -138,11 +73,12 @@ std::tuple RegAlloc::UseDefOpArgHostLocReg(IR::Value use_value, if (HostLocIsSpill(current_location)) { loc_info.Lock(); DEBUG_ASSERT(loc_info.IsUse()); - return std::make_tuple(SpillToOpArg(current_location), DefHostLocReg(def_inst, desired_locations)); + HostLoc location = ScratchHostLocReg(desired_locations); + DefineValue(def_inst, location); + return std::make_tuple(SpillToOpArg(current_location), location); } else { loc_info.Lock(); - loc_info.Def(def_inst); - DEBUG_ASSERT(loc_info.IsUseDef()); + DefineValue(def_inst, current_location); return std::make_tuple(HostLocToX64(current_location), current_location); } } @@ -150,7 +86,8 @@ std::tuple RegAlloc::UseDefOpArgHostLocReg(IR::Value use_value, } OpArg use_oparg = UseOpArg(use_value, any_gpr); - HostLoc def_reg = DefHostLocReg(def_inst, desired_locations); + HostLoc def_reg = ScratchHostLocReg(desired_locations); + DefineValue(def_inst, def_reg); return std::make_tuple(use_oparg, def_reg); } @@ -237,8 +174,7 @@ HostLoc RegAlloc::UseScratchHostLocReg(IR::Inst* use_inst, HostLocList desired_l return new_location; } else if (HostLocIsRegister(current_location)) { ASSERT(LocInfo(current_location).IsIdle() - || LocInfo(current_location).IsUse() - || LocInfo(current_location).IsUseDef()); + || LocInfo(current_location).IsUse()); if (current_location != new_location) { EmitMove(new_location, current_location); @@ -289,7 +225,7 @@ void RegAlloc::HostCall(IR::Inst* result_def, IR::Value arg0_use, IR::Value arg1 // TODO: This works but almost certainly leads to suboptimal generated code. if (result_def) { - DefHostLocReg(result_def, {ABI_RETURN}); + DefineValue(result_def, ScratchHostLocReg({ABI_RETURN})); } else { ScratchHostLocReg({ABI_RETURN}); } @@ -352,6 +288,11 @@ bool RegAlloc::IsLastUse(const IR::Inst*) const { return false; } +void RegAlloc::DefineValue(IR::Inst* def_inst, HostLoc host_loc) { + DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined"); + LocInfo(host_loc).AddValue(def_inst); +} + void RegAlloc::SpillRegister(HostLoc loc) { ASSERT_MSG(HostLocIsRegister(loc), "Only registers can be spilled"); ASSERT_MSG(IsRegisterOccupied(loc), "There is no need to spill unoccupied registers"); @@ -424,25 +365,12 @@ std::tuple RegAlloc::UseHostLoc(IR::Inst* use_inst, HostLocList d HostLoc current_location = *ValueLocation(use_inst); auto iter = std::find(desired_locations.begin(), desired_locations.end(), current_location); if (iter != desired_locations.end()) { - if (LocInfo(current_location).IsDef()) { - HostLoc new_location = SelectARegister(desired_locations); - if (IsRegisterOccupied(new_location)) { - SpillRegister(new_location); - } - EmitMove(new_location, current_location); - LocInfo(new_location).Lock(); - LocInfo(new_location).AddValue(use_inst); - use_inst->DecrementRemainingUses(); - DEBUG_ASSERT(LocInfo(new_location).IsUse()); - return std::make_tuple(new_location, false); - } else { - bool was_being_used = LocInfo(current_location).IsLocked(); - ASSERT(LocInfo(current_location).IsUse() || LocInfo(current_location).IsIdle()); - LocInfo(current_location).Lock(); - use_inst->DecrementRemainingUses(); - DEBUG_ASSERT(LocInfo(current_location).IsUse()); - return std::make_tuple(current_location, was_being_used); - } + bool was_being_used = LocInfo(current_location).IsLocked(); + ASSERT(LocInfo(current_location).IsUse() || LocInfo(current_location).IsIdle()); + LocInfo(current_location).Lock(); + use_inst->DecrementRemainingUses(); + DEBUG_ASSERT(LocInfo(current_location).IsUse()); + return std::make_tuple(current_location, was_being_used); } if (HostLocIsSpill(current_location)) { diff --git a/src/backend_x64/reg_alloc.h b/src/backend_x64/reg_alloc.h index 0b1eea15..b45280ec 100644 --- a/src/backend_x64/reg_alloc.h +++ b/src/backend_x64/reg_alloc.h @@ -31,19 +31,13 @@ public: return is_being_used; } bool IsEmpty() const { - return !is_being_used && !def && values.empty(); + return !is_being_used && values.empty(); } bool IsScratch() const { - return is_being_used && !def && values.empty(); + return is_being_used && values.empty(); } bool IsUse() const { - return is_being_used && !def && !values.empty(); - } - bool IsDef() const { - return is_being_used && def && values.empty(); - } - bool IsUseDef() const { - return is_being_used && def && !values.empty(); + return is_being_used && !values.empty(); } bool ContainsValue(const IR::Inst* inst) const { @@ -56,27 +50,16 @@ public: void AddValue(IR::Inst* inst) { values.push_back(inst); } - void Def(IR::Inst* inst) { - ASSERT(!def); - def = inst; - } void EndOfAllocScope() { const auto to_erase = std::remove_if(values.begin(), values.end(), [](const auto& inst){ return !inst->HasUses(); }); values.erase(to_erase, values.end()); - if (def) { - ASSERT(values.empty()); - AddValue(def); - def = nullptr; - } - is_being_used = false; } private: - std::vector values; // early value - IR::Inst* def = nullptr; // late value + std::vector values; bool is_being_used = false; }; @@ -86,18 +69,26 @@ public: /// Late-def Xbyak::Reg64 DefGpr(IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { - return HostLocToReg64(DefHostLocReg(def_inst, desired_locations)); + HostLoc location = ScratchHostLocReg(desired_locations); + DefineValue(def_inst, location); + return HostLocToReg64(location); } Xbyak::Xmm DefXmm(IR::Inst* def_inst, HostLocList desired_locations = any_xmm) { - return HostLocToXmm(DefHostLocReg(def_inst, desired_locations)); + HostLoc location = ScratchHostLocReg(desired_locations); + DefineValue(def_inst, location); + return HostLocToXmm(location); } void RegisterAddDef(IR::Inst* def_inst, const IR::Value& use_inst); /// Early-use, Late-def Xbyak::Reg64 UseDefGpr(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { - return HostLocToReg64(UseDefHostLocReg(use_value, def_inst, desired_locations)); + HostLoc location = UseScratchHostLocReg(use_value, desired_locations); + DefineValue(def_inst, location); + return HostLocToReg64(location); } Xbyak::Xmm UseDefXmm(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_xmm) { - return HostLocToXmm(UseDefHostLocReg(use_value, def_inst, desired_locations)); + HostLoc location = UseScratchHostLocReg(use_value, desired_locations); + DefineValue(def_inst, location); + return HostLocToXmm(location); } std::tuple UseDefOpArgGpr(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { OpArg op; @@ -152,9 +143,8 @@ private: bool IsRegisterAllocated(HostLoc loc) const; bool IsLastUse(const IR::Inst* inst) const; - HostLoc DefHostLocReg(IR::Inst* def_inst, HostLocList desired_locations); - HostLoc UseDefHostLocReg(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations); - HostLoc UseDefHostLocReg(IR::Inst* use_inst, IR::Inst* def_inst, HostLocList desired_locations); + void DefineValue(IR::Inst* def_inst, HostLoc host_loc); + std::tuple UseDefOpArgHostLocReg(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations); HostLoc UseHostLocReg(IR::Value use_value, HostLocList desired_locations); HostLoc UseHostLocReg(IR::Inst* use_inst, HostLocList desired_locations);