1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "berberis/backend/common/lifetime_analysis.h"
18
19 namespace berberis {
20
GetVRegLifetime(MachineReg r,int begin)21 VRegLifetime* VRegLifetimeAnalysis::GetVRegLifetime(MachineReg r, int begin) {
22 uint32_t i = r.GetVRegIndex();
23 if (vreg_lifetimes_.size() < i + 1) {
24 vreg_lifetimes_.resize(i + 1, nullptr);
25 }
26 VRegLifetime*& lifetime = vreg_lifetimes_[i];
27 if (lifetime) {
28 // Ensure the lifetime has live range for current basic block.
29 // Use last live range begin to check that, as lifetime end might be equal
30 // to bb_tick_ both when register lives out of prev basic block and when
31 // register lives into current basic block but yet has no uses (so last
32 // live range is [bb_tick_, bb_tick_)).
33 if (lifetime->LastLiveRangeBegin() < bb_tick_) {
34 lifetime->StartLiveRange(begin);
35 }
36 } else {
37 // Newly created lifetime last live range will start at 'begin'.
38 lifetimes_->push_back(VRegLifetime(arena_, begin));
39 lifetime = &lifetimes_->back();
40 }
41 return lifetime;
42 }
43
AppendUse(const VRegUse & use)44 void VRegLifetimeAnalysis::AppendUse(const VRegUse& use) {
45 VRegLifetime* lifetime = GetVRegLifetime(use.GetVReg(), use.begin());
46 lifetime->AppendUse(use);
47 }
48
49 // Set move hint for vreg to vreg move.
TrySetMoveHint(const MachineInsn * insn)50 void VRegLifetimeAnalysis::TrySetMoveHint(const MachineInsn* insn) {
51 if (!insn->is_copy()) {
52 return;
53 }
54
55 // Copy should have 2 vreg operands.
56 DCHECK_EQ(insn->NumRegOperands(), 2);
57 MachineReg dst = insn->RegAt(0);
58 if (!dst.IsVReg()) {
59 return;
60 }
61 MachineReg src = insn->RegAt(1);
62 if (!src.IsVReg()) {
63 return;
64 }
65
66 // Lifetimes must exist.
67 vreg_lifetimes_[dst.GetVRegIndex()]->SetMoveHint(vreg_lifetimes_[src.GetVRegIndex()]);
68 }
69
AddInsn(const MachineInsnListPosition & pos)70 void VRegLifetimeAnalysis::AddInsn(const MachineInsnListPosition& pos) {
71 const MachineInsn* insn = pos.insn();
72
73 // To get lifetimes sorted by begin, first add use and use-def operands,
74 // then def-only operands.
75
76 // Walk use and use-def register operands.
77 for (int i = 0; i < insn->NumRegOperands(); ++i) {
78 // Skip non-virtual registers.
79 MachineReg r = insn->RegAt(i);
80 if (!r.IsVReg()) {
81 continue;
82 }
83
84 // Skip def-only operands.
85 const MachineRegKind& reg_kind = insn->RegKindAt(i);
86 if (!reg_kind.IsUse()) {
87 continue;
88 }
89
90 // Get range.
91 int begin = tick_;
92 int end = tick_ + (reg_kind.IsDef() ? 2 : 1);
93
94 AppendUse(VRegUse(pos, i, begin, end));
95 }
96
97 // Walk def-only register operands.
98 for (int i = 0; i < insn->NumRegOperands(); ++i) {
99 // Skip non-virtual registers.
100 MachineReg r = insn->RegAt(i);
101 if (!r.IsVReg()) {
102 continue;
103 }
104
105 // Skip use and use-def operands.
106 const MachineRegKind& reg_kind = insn->RegKindAt(i);
107 if (reg_kind.IsUse()) {
108 continue;
109 }
110
111 // Get range.
112 int begin = tick_ + 1;
113 int end = tick_ + 2;
114
115 // Append use.
116 AppendUse(VRegUse(pos, i, begin, end));
117 }
118
119 TrySetMoveHint(insn);
120
121 // Instruction have got 2 ticks:
122 // - read inputs ('use' operands)
123 // - write outputs ('def' operands)
124 tick_ += 2;
125 }
126
127 } // namespace berberis
128