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