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