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/machine_ir_test_corpus.h"
18
19 #include <tuple>
20
21 #include "berberis/backend/code_emitter.h"
22 #include "berberis/backend/common/machine_ir.h"
23 #include "berberis/backend/x86_64/machine_ir.h"
24 #include "berberis/backend/x86_64/machine_ir_builder.h"
25 #include "berberis/guest_state/guest_addr.h"
26
27 namespace berberis {
28
29 std::tuple<const MachineBasicBlock*,
30 const MachineBasicBlock*,
31 const MachineBasicBlock*,
32 MachineReg,
33 MachineReg>
BuildDataFlowAcrossBasicBlocks(x86_64::MachineIR * machine_ir)34 BuildDataFlowAcrossBasicBlocks(x86_64::MachineIR* machine_ir) {
35 x86_64::MachineIRBuilder builder(machine_ir);
36 MachineReg vreg1 = machine_ir->AllocVReg();
37 MachineReg vreg2 = machine_ir->AllocVReg();
38
39 auto* bb1 = machine_ir->NewBasicBlock();
40 auto* bb2 = machine_ir->NewBasicBlock();
41 auto* bb3 = machine_ir->NewBasicBlock();
42
43 machine_ir->AddEdge(bb1, bb2);
44 machine_ir->AddEdge(bb2, bb3);
45
46 builder.StartBasicBlock(bb1);
47 builder.Gen<x86_64::MovqRegImm>(vreg1, 0);
48 builder.Gen<x86_64::MovqRegImm>(vreg2, 0);
49 builder.Gen<PseudoBranch>(bb2);
50
51 builder.StartBasicBlock(bb2);
52 builder.Gen<x86_64::MovqRegReg>(x86_64::kMachineRegRAX, vreg2);
53 builder.Gen<PseudoBranch>(bb3);
54
55 builder.StartBasicBlock(bb3);
56 builder.Gen<x86_64::MovqRegReg>(x86_64::kMachineRegRAX, vreg1);
57 builder.Gen<PseudoJump>(kNullGuestAddr);
58
59 return {bb1, bb2, bb3, vreg1, vreg2};
60 }
61
62 std::tuple<const MachineBasicBlock*, const MachineBasicBlock*, const MachineBasicBlock*, MachineReg>
BuildDataFlowFromTwoPreds(x86_64::MachineIR * machine_ir)63 BuildDataFlowFromTwoPreds(x86_64::MachineIR* machine_ir) {
64 x86_64::MachineIRBuilder builder(machine_ir);
65 MachineReg vreg = machine_ir->AllocVReg();
66
67 // BB1 BB2
68 // \ /
69 // BB3
70 //
71 auto* bb1 = machine_ir->NewBasicBlock();
72 auto* bb2 = machine_ir->NewBasicBlock();
73 auto* bb3 = machine_ir->NewBasicBlock();
74
75 machine_ir->AddEdge(bb1, bb3);
76 machine_ir->AddEdge(bb2, bb3);
77
78 builder.StartBasicBlock(bb1);
79 builder.Gen<x86_64::MovqRegImm>(vreg, 0);
80 builder.Gen<PseudoBranch>(bb3);
81
82 builder.StartBasicBlock(bb2);
83 builder.Gen<x86_64::MovqRegImm>(vreg, 1);
84 builder.Gen<PseudoBranch>(bb3);
85
86 builder.StartBasicBlock(bb3);
87 builder.Gen<x86_64::MovqRegReg>(x86_64::kMachineRegRAX, vreg);
88 builder.Gen<PseudoJump>(kNullGuestAddr);
89
90 return {bb1, bb2, bb3, vreg};
91 }
92
93 std::tuple<const MachineBasicBlock*, const MachineBasicBlock*, const MachineBasicBlock*, MachineReg>
BuildDataFlowToTwoSuccs(x86_64::MachineIR * machine_ir)94 BuildDataFlowToTwoSuccs(x86_64::MachineIR* machine_ir) {
95 x86_64::MachineIRBuilder builder(machine_ir);
96 MachineReg vreg = machine_ir->AllocVReg();
97
98 // BB1
99 // / \
100 // BB2 BB3
101 //
102 auto* bb1 = machine_ir->NewBasicBlock();
103 auto* bb2 = machine_ir->NewBasicBlock();
104 auto* bb3 = machine_ir->NewBasicBlock();
105
106 machine_ir->AddEdge(bb1, bb2);
107 machine_ir->AddEdge(bb1, bb3);
108
109 builder.StartBasicBlock(bb1);
110 builder.Gen<x86_64::MovqRegImm>(vreg, 0);
111 builder.Gen<PseudoCondBranch>(CodeEmitter::Condition::kZero, bb2, bb3, x86_64::kMachineRegFLAGS);
112
113 builder.StartBasicBlock(bb2);
114 builder.Gen<x86_64::MovqRegReg>(x86_64::kMachineRegRAX, vreg);
115 builder.Gen<PseudoJump>(kNullGuestAddr);
116
117 builder.StartBasicBlock(bb3);
118 builder.Gen<x86_64::MovqRegReg>(x86_64::kMachineRegRAX, vreg);
119 builder.Gen<PseudoJump>(kNullGuestAddr);
120
121 return {bb1, bb2, bb3, vreg};
122 }
123
124 std::tuple<const MachineBasicBlock*,
125 const MachineBasicBlock*,
126 const MachineBasicBlock*,
127 const MachineBasicBlock*>
BuildDiamondControlFlow(x86_64::MachineIR * machine_ir)128 BuildDiamondControlFlow(x86_64::MachineIR* machine_ir) {
129 x86_64::MachineIRBuilder builder(machine_ir);
130 MachineReg vreg = machine_ir->AllocVReg();
131
132 //
133 // BB1
134 // / \
135 // BB2 BB3
136 // \ /
137 // BB4
138 //
139 auto* bb1 = machine_ir->NewBasicBlock();
140 auto* bb2 = machine_ir->NewBasicBlock();
141 auto* bb3 = machine_ir->NewBasicBlock();
142 auto* bb4 = machine_ir->NewBasicBlock();
143
144 machine_ir->AddEdge(bb1, bb2);
145 machine_ir->AddEdge(bb1, bb3);
146 machine_ir->AddEdge(bb2, bb4);
147 machine_ir->AddEdge(bb3, bb4);
148
149 builder.StartBasicBlock(bb1);
150 builder.Gen<x86_64::MovqRegImm>(vreg, 0);
151 builder.Gen<PseudoCondBranch>(CodeEmitter::Condition::kZero, bb2, bb3, x86_64::kMachineRegFLAGS);
152
153 builder.StartBasicBlock(bb2);
154 builder.Gen<PseudoBranch>(bb4);
155
156 builder.StartBasicBlock(bb3);
157 builder.Gen<PseudoBranch>(bb4);
158
159 builder.StartBasicBlock(bb4);
160 builder.Gen<PseudoJump>(kNullGuestAddr);
161
162 return {bb1, bb2, bb3, bb4};
163 }
164
165 std::tuple<const MachineBasicBlock*,
166 const MachineBasicBlock*,
167 const MachineBasicBlock*,
168 const MachineBasicBlock*,
169 MachineReg>
BuildDataFlowAcrossEmptyLoop(x86_64::MachineIR * machine_ir)170 BuildDataFlowAcrossEmptyLoop(x86_64::MachineIR* machine_ir) {
171 x86_64::MachineIRBuilder builder(machine_ir);
172 MachineReg vreg = machine_ir->AllocVReg();
173
174 // BB1
175 // |
176 // BB2 <-
177 // | \ |
178 // BB4 BB3
179 //
180 // Moves must be built for all loop blocks (BB2 and BB3).
181 auto* bb1 = machine_ir->NewBasicBlock();
182 auto* bb2 = machine_ir->NewBasicBlock();
183 auto* bb3 = machine_ir->NewBasicBlock();
184 auto* bb4 = machine_ir->NewBasicBlock();
185
186 machine_ir->AddEdge(bb1, bb2);
187 machine_ir->AddEdge(bb2, bb3);
188 machine_ir->AddEdge(bb3, bb2);
189 machine_ir->AddEdge(bb2, bb4);
190
191 builder.StartBasicBlock(bb1);
192 builder.Gen<x86_64::MovqRegImm>(vreg, 0);
193 builder.Gen<PseudoBranch>(bb2);
194
195 builder.StartBasicBlock(bb2);
196 builder.Gen<PseudoCondBranch>(CodeEmitter::Condition::kZero, bb3, bb4, x86_64::kMachineRegFLAGS);
197
198 builder.StartBasicBlock(bb3);
199 builder.Gen<PseudoBranch>(bb2);
200
201 builder.StartBasicBlock(bb4);
202 builder.Gen<x86_64::MovqRegReg>(x86_64::kMachineRegRAX, vreg);
203 builder.Gen<PseudoJump>(kNullGuestAddr);
204
205 return {bb1, bb2, bb3, bb4, vreg};
206 }
207
208 } // namespace berberis
209