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