| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "berberis/backend/common/lifetime_analysis.h" |
| |
| namespace berberis { |
| |
| VRegLifetime* VRegLifetimeAnalysis::GetVRegLifetime(MachineReg r, int begin) { |
| uint32_t i = r.GetVRegIndex(); |
| if (vreg_lifetimes_.size() < i + 1) { |
| vreg_lifetimes_.resize(i + 1, nullptr); |
| } |
| VRegLifetime*& lifetime = vreg_lifetimes_[i]; |
| if (lifetime) { |
| // Ensure the lifetime has live range for current basic block. |
| // Use last live range begin to check that, as lifetime end might be equal |
| // to bb_tick_ both when register lives out of prev basic block and when |
| // register lives into current basic block but yet has no uses (so last |
| // live range is [bb_tick_, bb_tick_)). |
| if (lifetime->LastLiveRangeBegin() < bb_tick_) { |
| lifetime->StartLiveRange(begin); |
| } |
| } else { |
| // Newly created lifetime last live range will start at 'begin'. |
| lifetimes_->push_back(VRegLifetime(arena_, begin)); |
| lifetime = &lifetimes_->back(); |
| } |
| return lifetime; |
| } |
| |
| void VRegLifetimeAnalysis::AppendUse(const VRegUse& use) { |
| VRegLifetime* lifetime = GetVRegLifetime(use.GetVReg(), use.begin()); |
| lifetime->AppendUse(use); |
| } |
| |
| // Set move hint for vreg to vreg move. |
| void VRegLifetimeAnalysis::TrySetMoveHint(const MachineInsn* insn) { |
| if (!insn->is_copy()) { |
| return; |
| } |
| |
| // Copy should have 2 vreg operands. |
| DCHECK_EQ(insn->NumRegOperands(), 2); |
| MachineReg dst = insn->RegAt(0); |
| if (!dst.IsVReg()) { |
| return; |
| } |
| MachineReg src = insn->RegAt(1); |
| if (!src.IsVReg()) { |
| return; |
| } |
| |
| // Lifetimes must exist. |
| vreg_lifetimes_[dst.GetVRegIndex()]->SetMoveHint(vreg_lifetimes_[src.GetVRegIndex()]); |
| } |
| |
| void VRegLifetimeAnalysis::AddInsn(const MachineInsnListPosition& pos) { |
| const MachineInsn* insn = pos.insn(); |
| |
| // To get lifetimes sorted by begin, first add use and use-def operands, |
| // then def-only operands. |
| |
| // Walk use and use-def register operands. |
| for (int i = 0; i < insn->NumRegOperands(); ++i) { |
| // Skip non-virtual registers. |
| MachineReg r = insn->RegAt(i); |
| if (!r.IsVReg()) { |
| continue; |
| } |
| |
| // Skip def-only operands. |
| const MachineRegKind& reg_kind = insn->RegKindAt(i); |
| if (!reg_kind.IsUse()) { |
| continue; |
| } |
| |
| // Get range. |
| int begin = tick_; |
| int end = tick_ + (reg_kind.IsDef() ? 2 : 1); |
| |
| AppendUse(VRegUse(pos, i, begin, end)); |
| } |
| |
| // Walk def-only register operands. |
| for (int i = 0; i < insn->NumRegOperands(); ++i) { |
| // Skip non-virtual registers. |
| MachineReg r = insn->RegAt(i); |
| if (!r.IsVReg()) { |
| continue; |
| } |
| |
| // Skip use and use-def operands. |
| const MachineRegKind& reg_kind = insn->RegKindAt(i); |
| if (reg_kind.IsUse()) { |
| continue; |
| } |
| |
| // Get range. |
| int begin = tick_ + 1; |
| int end = tick_ + 2; |
| |
| // Append use. |
| AppendUse(VRegUse(pos, i, begin, end)); |
| } |
| |
| TrySetMoveHint(insn); |
| |
| // Instruction have got 2 ticks: |
| // - read inputs ('use' operands) |
| // - write outputs ('def' operands) |
| tick_ += 2; |
| } |
| |
| } // namespace berberis |