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 "gtest/gtest.h"
18 
19 #include "berberis/backend/code_emitter.h"
20 #include "berberis/backend/x86_64/machine_ir.h"
21 #include "berberis/backend/x86_64/machine_ir_builder.h"
22 #include "berberis/backend/x86_64/machine_ir_check.h"
23 #include "berberis/base/arena_alloc.h"
24 #include "berberis/guest_state/guest_addr.h"
25 
26 namespace berberis {
27 
28 namespace {
29 
TEST(MachineIR,SplitBasicBlock)30 TEST(MachineIR, SplitBasicBlock) {
31   Arena arena;
32   x86_64::MachineIR machine_ir(&arena);
33 
34   x86_64::MachineIRBuilder builder(&machine_ir);
35   auto bb = machine_ir.NewBasicBlock();
36   builder.StartBasicBlock(bb);
37 
38   builder.Gen<x86_64::MovqRegImm>(x86_64::kMachineRegRBP, 0);
39   builder.Gen<x86_64::MovqRegImm>(x86_64::kMachineRegRBP, 0);
40   builder.Gen<x86_64::MovqRegImm>(x86_64::kMachineRegRBP, 1);
41   builder.Gen<x86_64::MovqRegImm>(x86_64::kMachineRegRBP, 1);
42   builder.Gen<x86_64::MovqRegImm>(x86_64::kMachineRegRBP, 1);
43   builder.Gen<PseudoJump>(kNullGuestAddr);
44 
45   auto insn_it = bb->insn_list().begin();
46   std::advance(insn_it, 2);
47   auto new_bb = machine_ir.SplitBasicBlock(bb, insn_it);
48 
49   ASSERT_EQ(x86_64::CheckMachineIR(machine_ir), x86_64::kMachineIRCheckSuccess);
50   EXPECT_TRUE(machine_ir.bb_list().size() == 2);
51   EXPECT_EQ(bb->insn_list().size(), static_cast<unsigned int>(3));
52   EXPECT_EQ(bb->insn_list().back()->opcode(), kMachineOpPseudoBranch);
53   EXPECT_EQ(new_bb->insn_list().size(), static_cast<unsigned int>(4));
54 }
55 
TEST(MachineIR,SplitBasicBlockWithOutcomingEdges)56 TEST(MachineIR, SplitBasicBlockWithOutcomingEdges) {
57   Arena arena;
58   x86_64::MachineIR machine_ir(&arena);
59   x86_64::MachineIRBuilder builder(&machine_ir);
60 
61   auto* bb1 = machine_ir.NewBasicBlock();
62   auto* bb2 = machine_ir.NewBasicBlock();
63   auto* bb3 = machine_ir.NewBasicBlock();
64   MachineReg vreg = machine_ir.AllocVReg();
65   machine_ir.AddEdge(bb1, bb2);
66   machine_ir.AddEdge(bb1, bb3);
67 
68   builder.StartBasicBlock(bb1);
69   builder.Gen<x86_64::MovqRegImm>(vreg, 0);
70   builder.Gen<x86_64::MovqRegImm>(vreg, 0);
71   builder.Gen<PseudoCondBranch>(CodeEmitter::Condition::kZero, bb2, bb3, x86_64::kMachineRegFLAGS);
72 
73   builder.StartBasicBlock(bb2);
74   builder.Gen<x86_64::MovqRegImm>(vreg, 0);
75   builder.Gen<PseudoJump>(kNullGuestAddr);
76 
77   builder.StartBasicBlock(bb3);
78   builder.Gen<x86_64::MovqRegImm>(vreg, 0);
79   builder.Gen<PseudoJump>(kNullGuestAddr);
80 
81   auto insn_it = std::next(bb1->insn_list().begin());
82   MachineBasicBlock* new_bb = machine_ir.SplitBasicBlock(bb1, insn_it);
83 
84   ASSERT_EQ(x86_64::CheckMachineIR(machine_ir), x86_64::kMachineIRCheckSuccess);
85   EXPECT_EQ(bb1->out_edges().size(), 1UL);
86   EXPECT_EQ(bb1->out_edges().front()->src(), bb1);
87   EXPECT_EQ(bb1->out_edges().front()->dst(), new_bb);
88 
89   EXPECT_EQ(new_bb->in_edges().size(), 1UL);
90   EXPECT_EQ(new_bb->in_edges().front()->src(), bb1);
91   EXPECT_EQ(new_bb->in_edges().front()->dst(), new_bb);
92   EXPECT_EQ(new_bb->out_edges().size(), 2UL);
93   EXPECT_EQ(new_bb->out_edges().front()->src(), new_bb);
94   EXPECT_EQ(new_bb->out_edges().front()->dst(), bb2);
95   EXPECT_EQ(new_bb->out_edges().back()->src(), new_bb);
96   EXPECT_EQ(new_bb->out_edges().back()->dst(), bb3);
97 
98   EXPECT_EQ(bb2->in_edges().size(), 1UL);
99   EXPECT_EQ(bb2->in_edges().front()->src(), new_bb);
100   EXPECT_EQ(bb2->in_edges().front()->dst(), bb2);
101 
102   EXPECT_EQ(bb3->in_edges().size(), 1UL);
103   EXPECT_EQ(bb3->in_edges().front()->src(), new_bb);
104   EXPECT_EQ(bb3->in_edges().front()->dst(), bb3);
105 }
106 
107 }  // namespace
108 
109 }  // namespace berberis
110