blob: f6ee914d31819294b18b52f6328795a1f47fbce3 [file] [log] [blame]
/*
* 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