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/x86_64/rename_copy_uses.h"
18 
19 #include "berberis/backend/common/machine_ir.h"
20 #include "berberis/backend/x86_64/machine_ir.h"
21 
22 namespace berberis::x86_64 {
23 
Get(MachineReg reg)24 MachineReg RenameCopyUsesMap::Get(MachineReg reg) {
25   MachineReg renamed = RenameDataForReg(reg).renamed;
26   if (renamed == kInvalidMachineReg) {
27     return kInvalidMachineReg;
28   }
29   if (RenameDataForReg(renamed).last_def_time > RenameDataForReg(reg).renaming_time) {
30     return kInvalidMachineReg;
31   }
32   return renamed;
33 }
34 
RenameUseIfMapped(MachineInsn * insn,int i)35 void RenameCopyUsesMap::RenameUseIfMapped(MachineInsn* insn, int i) {
36   // Narrow type uses may require a copy for register allocator to successfully handle them.
37   // TODO(b/200327919): It'd better to make CallImmArg specify the exact narrow class for
38   // the corresponding call argument. Then we wouldn't need to special case it.
39   if (insn->opcode() == kMachineOpCallImmArg || insn->RegKindAt(i).RegClass()->NumRegs() == 1) {
40     return;
41   }
42   MachineReg reg = insn->RegAt(i);
43   if (!reg.IsVReg()) {
44     return;
45   }
46   // Renaming is only possible for USE without DEF.
47   MachineReg mapped = Get(reg);
48   if (mapped != kInvalidMachineReg) {
49     insn->SetRegAt(i, mapped);
50   }
51 }
52 
ProcessDef(MachineInsn * insn,int i)53 void RenameCopyUsesMap::ProcessDef(MachineInsn* insn, int i) {
54   MachineReg reg = insn->RegAt(i);
55 
56   if (!reg.IsVReg()) {
57     return;
58   }
59 
60   RenameDataForReg(reg) = {kInvalidMachineReg, 0, time_};
61 }
62 
ProcessCopy(MachineInsn * copy)63 void RenameCopyUsesMap::ProcessCopy(MachineInsn* copy) {
64   auto dst = copy->RegAt(0);
65   auto src = copy->RegAt(1);
66   if (!dst.IsVReg() || !src.IsVReg()) {
67     return;
68   }
69 
70   if (Contains(bb_->live_out(), dst)) {
71     // If dst is a live-out then renaming it to src won't help eliminate the copy. So instead we
72     // rename src to dst. In an unlikely event when src is also a live-out it doesn't matter
73     // which one we rename.
74     RenameDataForReg(src).renamed = dst;
75     RenameDataForReg(src).renaming_time = time_;
76   } else {
77     RenameDataForReg(dst) = {src, time_, time_};
78   }
79 }
80 
StartBasicBlock(MachineBasicBlock * bb)81 void RenameCopyUsesMap::StartBasicBlock(MachineBasicBlock* bb) {
82   bb_ = bb;
83   for (auto& data : map_) {
84     data = {kInvalidMachineReg, 0, 0};
85   }
86 }
87 
RenameCopyUses(MachineIR * machine_ir)88 void RenameCopyUses(MachineIR* machine_ir) {
89   RenameCopyUsesMap map(machine_ir);
90 
91   for (auto* bb : machine_ir->bb_list()) {
92     map.StartBasicBlock(bb);
93 
94     for (MachineInsn* insn : bb->insn_list()) {
95       for (int i = 0; i < insn->NumRegOperands(); ++i) {
96         // Note that Def-Use operands cannot be renamed, so we handle them as Defs.
97         if (insn->RegKindAt(i).IsDef()) {
98           map.ProcessDef(insn, i);
99         } else {
100           map.RenameUseIfMapped(insn, i);
101         }
102       }  // for operand in insn
103 
104       // Note that we intentionally rename copy's use before attempting to create a mapping, so that
105       // the existing mappings are applied and propagated further.
106       if (insn->is_copy()) {
107         map.ProcessCopy(insn);
108       }
109       map.Tick();
110     }  // For insn in bb
111   }    // For bb in IR
112 }
113 
114 }  // namespace berberis::x86_64
115