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 <array>
18
19 #include "berberis/backend/x86_64/machine_ir.h"
20 #include "berberis/base/logging.h"
21 #include "berberis/guest_state/guest_addr.h"
22
23 namespace berberis {
24
25 namespace x86_64 {
26
27 namespace {
28
29 constexpr MachineInsnInfo kCallImmInfo = {
30 kMachineOpCallImm,
31 26,
32 {
33 {&kRAX, MachineRegKind::kDef}, {&kRDI, MachineRegKind::kDef},
34 {&kRSI, MachineRegKind::kDef}, {&kRDX, MachineRegKind::kDef},
35 {&kRCX, MachineRegKind::kDef}, {&kR8, MachineRegKind::kDef},
36 {&kR9, MachineRegKind::kDef}, {&kR10, MachineRegKind::kDef},
37 {&kR11, MachineRegKind::kDef}, {&kXMM0, MachineRegKind::kDef},
38 {&kXMM1, MachineRegKind::kDef}, {&kXMM2, MachineRegKind::kDef},
39 {&kXMM3, MachineRegKind::kDef}, {&kXMM4, MachineRegKind::kDef},
40 {&kXMM5, MachineRegKind::kDef}, {&kXMM6, MachineRegKind::kDef},
41 {&kXMM7, MachineRegKind::kDef}, {&kXMM8, MachineRegKind::kDef},
42 {&kXMM9, MachineRegKind::kDef}, {&kXMM10, MachineRegKind::kDef},
43 {&kXMM11, MachineRegKind::kDef}, {&kXMM12, MachineRegKind::kDef},
44 {&kXMM13, MachineRegKind::kDef}, {&kXMM14, MachineRegKind::kDef},
45 {&kXMM15, MachineRegKind::kDef}, {&kFLAGS, MachineRegKind::kDef},
46 },
47 kMachineInsnSideEffects};
48
49 constexpr MachineInsnInfo kCallImmIntArgInfo = {kMachineOpCallImmArg,
50 1,
51 {{&kReg64, MachineRegKind::kUse}},
52 // Is implicitly part of CallImm.
53 kMachineInsnSideEffects};
54
55 constexpr MachineInsnInfo kCallImmXmmArgInfo = {kMachineOpCallImmArg,
56 1,
57 {{&kXmmReg, MachineRegKind::kUse}},
58 // Is implicitly part of CallImm.
59 kMachineInsnSideEffects};
60
61 constexpr MachineRegKind kPseudoCondBranchInfo[] = {{&kFLAGS, MachineRegKind::kUse}};
62
63 constexpr MachineRegKind kPseudoIndirectJumpInfo[] = {{&kGeneralReg64, MachineRegKind::kUse}};
64
65 constexpr MachineRegKind kPseudoCopyReg32Info[] = {{&kReg32, MachineRegKind::kDef},
66 {&kReg32, MachineRegKind::kUse}};
67
68 constexpr MachineRegKind kPseudoCopyReg64Info[] = {{&kReg64, MachineRegKind::kDef},
69 {&kReg64, MachineRegKind::kUse}};
70
71 constexpr MachineRegKind kPseudoCopyXmmInfo[] = {{&kXmmReg, MachineRegKind::kDef},
72 {&kXmmReg, MachineRegKind::kUse}};
73
74 constexpr MachineRegKind kPseudoDefXmmInfo[] = {{&kXmmReg, MachineRegKind::kDef}};
75
76 constexpr MachineRegKind kPseudoDefReg64Info[] = {{&kReg64, MachineRegKind::kDef}};
77
78 constexpr MachineRegKind kPseudoReadFlagsInfo[] = {{&kRAX, MachineRegKind::kDef},
79 {&kFLAGS, MachineRegKind::kUse}};
80
81 constexpr MachineRegKind kPseudoWriteFlagsInfo[] = {{&kRAX, MachineRegKind::kUseDef},
82 {&kFLAGS, MachineRegKind::kDef}};
83
84 } // namespace
85
CallImm(uint64_t imm)86 CallImm::CallImm(uint64_t imm) : MachineInsnX86_64(&kCallImmInfo), custom_avx256_abi_{false} {
87 set_imm(imm);
88 }
89
GetIntArgIndex(int i)90 int CallImm::GetIntArgIndex(int i) {
91 constexpr int kIntArgIndex[] = {
92 1, // RDI
93 2, // RSI
94 3, // RDX
95 4, // RCX
96 5, // R8
97 6, // R9
98 };
99
100 CHECK_LT(static_cast<unsigned>(i), std::size(kIntArgIndex));
101 return kIntArgIndex[i];
102 }
103
GetXmmArgIndex(int i)104 int CallImm::GetXmmArgIndex(int i) {
105 constexpr int kXmmArgIndex[] = {
106 9, // XMM0
107 10, // XMM1
108 11, // XMM2
109 12, // XMM3
110 13, // XMM4
111 14, // XMM5
112 15, // XMM6
113 16, // XMM7
114 };
115
116 CHECK_LT(static_cast<unsigned>(i), std::size(kXmmArgIndex));
117 return kXmmArgIndex[i];
118 }
119
GetFlagsArgIndex()120 int CallImm::GetFlagsArgIndex() {
121 return 25; // FLAGS
122 }
123
IntResultAt(int i) const124 MachineReg CallImm::IntResultAt(int i) const {
125 constexpr int kIntResultIndex[] = {
126 0, // RAX
127 3, // RDX
128 };
129
130 CHECK_LT(static_cast<unsigned>(i), std::size(kIntResultIndex));
131 return RegAt(kIntResultIndex[i]);
132 }
133
XmmResultAt(int i) const134 MachineReg CallImm::XmmResultAt(int i) const {
135 constexpr int kXmmResultIndex[] = {
136 9, // XMM0
137 10, // XMM1
138 };
139
140 CHECK_LT(static_cast<unsigned>(i), std::size(kXmmResultIndex));
141 return RegAt(kXmmResultIndex[i]);
142 }
143
CallImmArg(MachineReg arg,CallImm::RegType reg_type)144 CallImmArg::CallImmArg(MachineReg arg, CallImm::RegType reg_type)
145 : MachineInsnX86_64((reg_type == CallImm::kIntRegType) ? &kCallImmIntArgInfo
146 : &kCallImmXmmArgInfo) {
147 SetRegAt(0, arg);
148 }
149
150 #include "insn-inl_x86_64.h" // NOLINT generated file!
151
152 } // namespace x86_64
153
154 const MachineOpcode PseudoBranch::kOpcode = kMachineOpPseudoBranch;
155 using Assembler = x86_64::Assembler;
156
PseudoBranch(const MachineBasicBlock * then_bb)157 PseudoBranch::PseudoBranch(const MachineBasicBlock* then_bb)
158 : MachineInsn(kMachineOpPseudoBranch, 0, nullptr, nullptr, kMachineInsnSideEffects),
159 then_bb_(then_bb) {}
160
161 const MachineOpcode PseudoCondBranch::kOpcode = kMachineOpPseudoCondBranch;
162
PseudoCondBranch(Assembler::Condition cond,const MachineBasicBlock * then_bb,const MachineBasicBlock * else_bb,MachineReg eflags)163 PseudoCondBranch::PseudoCondBranch(Assembler::Condition cond,
164 const MachineBasicBlock* then_bb,
165 const MachineBasicBlock* else_bb,
166 MachineReg eflags)
167 : MachineInsn(kMachineOpPseudoCondBranch,
168 1,
169 x86_64::kPseudoCondBranchInfo,
170 &eflags_,
171 kMachineInsnSideEffects),
172 cond_(cond),
173 then_bb_(then_bb),
174 else_bb_(else_bb),
175 eflags_(eflags) {}
176
PseudoJump(GuestAddr target,Kind kind)177 PseudoJump::PseudoJump(GuestAddr target, Kind kind)
178 : MachineInsn(kMachineOpPseudoJump, 0, nullptr, nullptr, kMachineInsnSideEffects),
179 target_(target),
180 kind_(kind) {}
181
PseudoIndirectJump(MachineReg src)182 PseudoIndirectJump::PseudoIndirectJump(MachineReg src)
183 : MachineInsn(kMachineOpPseudoIndirectJump,
184 1,
185 x86_64::kPseudoIndirectJumpInfo,
186 &src_,
187 kMachineInsnSideEffects),
188 src_(src) {}
189
190 const MachineOpcode PseudoCopy::kOpcode = kMachineOpPseudoCopy;
191
192 // Reg class of correct size is essential for current spill/reload code!!!
PseudoCopy(MachineReg dst,MachineReg src,int size)193 PseudoCopy::PseudoCopy(MachineReg dst, MachineReg src, int size)
194 : MachineInsn(kMachineOpPseudoCopy,
195 2,
196 size > 8 ? x86_64::kPseudoCopyXmmInfo
197 : size > 4 ? x86_64::kPseudoCopyReg64Info
198 : x86_64::kPseudoCopyReg32Info,
199 regs_,
200 kMachineInsnCopy),
201 regs_{dst, src} {}
202
PseudoDefXReg(MachineReg reg)203 PseudoDefXReg::PseudoDefXReg(MachineReg reg)
204 : MachineInsn(kMachineOpPseudoDefXReg,
205 1,
206 x86_64::kPseudoDefXmmInfo,
207 ®_,
208 kMachineInsnDefault),
209 reg_{reg} {}
210
PseudoDefReg(MachineReg reg)211 PseudoDefReg::PseudoDefReg(MachineReg reg)
212 : MachineInsn(kMachineOpPseudoDefReg,
213 1,
214 x86_64::kPseudoDefReg64Info,
215 ®_,
216 kMachineInsnDefault),
217 reg_{reg} {}
218
219 const MachineOpcode PseudoReadFlags::kOpcode = kMachineOpPseudoReadFlags;
220
PseudoReadFlags(WithOverflowEnum with_overflow,MachineReg dst,MachineReg flags)221 PseudoReadFlags::PseudoReadFlags(WithOverflowEnum with_overflow, MachineReg dst, MachineReg flags)
222 : MachineInsn(kMachineOpPseudoReadFlags,
223 2,
224 x86_64::kPseudoReadFlagsInfo,
225 regs_,
226 kMachineInsnDefault),
227 regs_{dst, flags},
228 with_overflow_(with_overflow == kWithOverflow) {}
229
PseudoReadFlags(const PseudoReadFlags & other)230 PseudoReadFlags::PseudoReadFlags(const PseudoReadFlags& other) : MachineInsn(other) {
231 with_overflow_ = other.with_overflow_;
232 for (size_t i = 0; i < std::size(regs_); i++) {
233 regs_[i] = other.regs_[i];
234 }
235
236 SetRegs(regs_);
237 }
238
239 const MachineOpcode PseudoWriteFlags::kOpcode = kMachineOpPseudoWriteFlags;
240
PseudoWriteFlags(MachineReg src,MachineReg flags)241 PseudoWriteFlags::PseudoWriteFlags(MachineReg src, MachineReg flags)
242 : MachineInsn(kMachineOpPseudoWriteFlags,
243 2,
244 x86_64::kPseudoWriteFlagsInfo,
245 regs_,
246 kMachineInsnDefault),
247 regs_{src, flags} {}
248
249 } // namespace berberis
250