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